ci: the compilation of the c samples in the documentation is separate from the TDengine build
This commit is contained in:
commit
e5dbf39e86
|
@ -426,6 +426,10 @@ pipeline {
|
|||
cd ${WKC}/tests/parallel_test
|
||||
./run_check_assert_container.sh -d ${WKDIR}
|
||||
'''
|
||||
sh '''
|
||||
cd ${WKC}/tests/parallel_test
|
||||
./run_check_void_container.sh -d ${WKDIR}
|
||||
'''
|
||||
sh '''
|
||||
date
|
||||
rm -rf ${WKC}/debug
|
||||
|
|
|
@ -7,7 +7,17 @@ ADD_CUSTOM_COMMAND(OUTPUT ${PREPARE_ENV_CMD}
|
|||
COMMAND ${CMAKE_COMMAND} -E make_directory ${TD_TESTS_OUTPUT_DIR}/cfg/
|
||||
COMMAND ${CMAKE_COMMAND} -E make_directory ${TD_TESTS_OUTPUT_DIR}/log/
|
||||
COMMAND ${CMAKE_COMMAND} -E make_directory ${TD_TESTS_OUTPUT_DIR}/data/
|
||||
COMMAND ${CMAKE_COMMAND} -E echo dataDir ${TD_TESTS_OUTPUT_DIR}/data > ${TD_TESTS_OUTPUT_DIR}/cfg/taos.cfg
|
||||
COMMAND ${CMAKE_COMMAND} -E echo firstEp localhost:6030 > ${TD_TESTS_OUTPUT_DIR}/cfg/taos.cfg
|
||||
COMMAND ${CMAKE_COMMAND} -E echo fqdn localhost >> ${TD_TESTS_OUTPUT_DIR}/cfg/taos.cfg
|
||||
COMMAND ${CMAKE_COMMAND} -E echo serverPort 6030 >> ${TD_TESTS_OUTPUT_DIR}/cfg/taos.cfg
|
||||
COMMAND ${CMAKE_COMMAND} -E echo debugFlag 135 >> ${TD_TESTS_OUTPUT_DIR}/cfg/taos.cfg
|
||||
COMMAND ${CMAKE_COMMAND} -E echo asyncLog 0 >> ${TD_TESTS_OUTPUT_DIR}/cfg/taos.cfg
|
||||
COMMAND ${CMAKE_COMMAND} -E echo supportVnodes 1024 >> ${TD_TESTS_OUTPUT_DIR}/cfg/taos.cfg
|
||||
COMMAND ${CMAKE_COMMAND} -E echo numOfLogLines 300000000 >> ${TD_TESTS_OUTPUT_DIR}/cfg/taos.cfg
|
||||
COMMAND ${CMAKE_COMMAND} -E echo logKeepDays -1 >> ${TD_TESTS_OUTPUT_DIR}/cfg/taos.cfg
|
||||
COMMAND ${CMAKE_COMMAND} -E echo checkpointInterval 60 >> ${TD_TESTS_OUTPUT_DIR}/cfg/taos.cfg
|
||||
COMMAND ${CMAKE_COMMAND} -E echo snodeAddress 127.0.0.1:873 >> ${TD_TESTS_OUTPUT_DIR}/cfg/taos.cfg
|
||||
COMMAND ${CMAKE_COMMAND} -E echo dataDir ${TD_TESTS_OUTPUT_DIR}/data >> ${TD_TESTS_OUTPUT_DIR}/cfg/taos.cfg
|
||||
COMMAND ${CMAKE_COMMAND} -E echo logDir ${TD_TESTS_OUTPUT_DIR}/log >> ${TD_TESTS_OUTPUT_DIR}/cfg/taos.cfg
|
||||
COMMAND ${CMAKE_COMMAND} -E echo charset UTF-8 >> ${TD_TESTS_OUTPUT_DIR}/cfg/taos.cfg
|
||||
COMMAND ${CMAKE_COMMAND} -E echo monitor 0 >> ${TD_TESTS_OUTPUT_DIR}/cfg/taos.cfg
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
*
|
||||
!*.c
|
||||
!.gitignore
|
|
@ -0,0 +1,21 @@
|
|||
// compile with
|
||||
// gcc connect_example.c -o connect_example -ltaos
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "taosws.h"
|
||||
|
||||
int main() {
|
||||
ws_enable_log("debug");
|
||||
char *dsn = "ws://localhost:6041";
|
||||
WS_TAOS *taos = ws_connect(dsn);
|
||||
if (taos == NULL) {
|
||||
fprintf(stderr, "Failed to connect to %s, ErrCode: 0x%x, ErrMessage: %s.\n", dsn, ws_errno(NULL), ws_errstr(NULL));
|
||||
return -1;
|
||||
}
|
||||
fprintf(stdout, "Connected to %s successfully.\n", dsn);
|
||||
|
||||
/* put your code here for read and write */
|
||||
|
||||
// close & clean
|
||||
ws_close(taos);
|
||||
}
|
|
@ -0,0 +1,69 @@
|
|||
/*
|
||||
* Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
// TAOS standard API example. The same syntax as MySQL, but only a subset
|
||||
// to compile: gcc -o create_db_demo create_db_demo.c -ltaos
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "taosws.h"
|
||||
|
||||
static int DemoCreateDB() {
|
||||
ws_enable_log("debug");
|
||||
// ANCHOR: create_db_and_table
|
||||
int code = 0;
|
||||
char *dsn = "ws://localhost:6041";
|
||||
// connect
|
||||
WS_TAOS *taos = ws_connect(dsn);
|
||||
|
||||
if (taos == NULL) {
|
||||
fprintf(stderr, "Failed to connect to %s, ErrCode: 0x%x, ErrMessage: %s.\n", dsn, ws_errno(NULL), ws_errstr(NULL));
|
||||
return -1;
|
||||
}
|
||||
|
||||
// create database
|
||||
WS_RES *result = ws_query(taos, "CREATE DATABASE IF NOT EXISTS power");
|
||||
code = ws_errno(result);
|
||||
if (code != 0) {
|
||||
fprintf(stderr, "Failed to create database power, ErrCode: 0x%x, ErrMessage: %s.\n", code, ws_errstr(result));
|
||||
ws_close(taos);
|
||||
return -1;
|
||||
}
|
||||
ws_free_result(result);
|
||||
fprintf(stdout, "Create database power successfully.\n");
|
||||
|
||||
// create table
|
||||
const char *sql =
|
||||
"CREATE STABLE IF NOT EXISTS power.meters (ts TIMESTAMP, current FLOAT, voltage INT, phase FLOAT) TAGS (groupId "
|
||||
"INT, location BINARY(24))";
|
||||
result = ws_query(taos, sql);
|
||||
code = ws_errno(result);
|
||||
if (code != 0) {
|
||||
fprintf(stderr, "Failed to create stable power.meters, ErrCode: 0x%x, ErrMessage: %s\n.", code, ws_errstr(result));
|
||||
ws_close(taos);
|
||||
return -1;
|
||||
}
|
||||
ws_free_result(result);
|
||||
fprintf(stdout, "Create stable power.meters successfully.\n");
|
||||
|
||||
// close & clean
|
||||
ws_close(taos);
|
||||
return 0;
|
||||
// ANCHOR_END: create_db_and_table
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) { return DemoCreateDB(); }
|
|
@ -0,0 +1,67 @@
|
|||
/*
|
||||
* Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
// TAOS standard API example. The same syntax as MySQL, but only a subset
|
||||
// to compile: gcc -o insert_data_demo insert_data_demo.c -ltaos
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "taosws.h"
|
||||
|
||||
static int DemoInsertData() {
|
||||
// ANCHOR: insert_data
|
||||
int code = 0;
|
||||
char *dsn = "ws://localhost:6041";
|
||||
// connect
|
||||
WS_TAOS *taos = ws_connect(dsn);
|
||||
if (taos == NULL) {
|
||||
fprintf(stderr, "Failed to connect to %s, ErrCode: 0x%x, ErrMessage: %s.\n", dsn, ws_errno(NULL), ws_errstr(NULL));
|
||||
return -1;
|
||||
}
|
||||
|
||||
// insert data, please make sure the database and table are already created
|
||||
const char *sql =
|
||||
"INSERT INTO "
|
||||
"power.d1001 USING power.meters TAGS(2,'California.SanFrancisco') "
|
||||
"VALUES "
|
||||
"(NOW + 1a, 10.30000, 219, 0.31000) "
|
||||
"(NOW + 2a, 12.60000, 218, 0.33000) "
|
||||
"(NOW + 3a, 12.30000, 221, 0.31000) "
|
||||
"power.d1002 USING power.meters TAGS(3, 'California.SanFrancisco') "
|
||||
"VALUES "
|
||||
"(NOW + 1a, 10.30000, 218, 0.25000) ";
|
||||
WS_RES *result = ws_query(taos, sql);
|
||||
code = ws_errno(result);
|
||||
if (code != 0) {
|
||||
fprintf(stderr, "Failed to insert data to power.meters, sql: %s, ErrCode: 0x%x, ErrMessage: %s\n.", sql, code,
|
||||
ws_errstr(result));
|
||||
ws_close(taos);
|
||||
return -1;
|
||||
}
|
||||
ws_free_result(result);
|
||||
|
||||
// you can check affectedRows here
|
||||
int rows = ws_affected_rows(result);
|
||||
fprintf(stdout, "Successfully inserted %d rows into power.meters.\n", rows);
|
||||
|
||||
// close & clean
|
||||
ws_close(taos);
|
||||
return 0;
|
||||
// ANCHOR_END: insert_data
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) { return DemoInsertData(); }
|
|
@ -0,0 +1,70 @@
|
|||
/*
|
||||
* Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
// TAOS standard API example. The same syntax as MySQL, but only a subset
|
||||
// to compile: gcc -o query_data_demo query_data_demo.c -ltaos
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "taosws.h"
|
||||
|
||||
static int DemoQueryData() {
|
||||
// ANCHOR: query_data
|
||||
int code = 0;
|
||||
char *dsn = "ws://localhost:6041";
|
||||
|
||||
// connect
|
||||
WS_TAOS *taos = ws_connect(dsn);
|
||||
if (taos == NULL) {
|
||||
fprintf(stderr, "Failed to connect to %s, ErrCode: 0x%x, ErrMessage: %s.\n", dsn, ws_errno(NULL), ws_errstr(NULL));
|
||||
return -1;
|
||||
}
|
||||
|
||||
// query data, please make sure the database and table are already created
|
||||
const char *sql = "SELECT ts, current, location FROM power.meters limit 100";
|
||||
WS_RES *result = ws_query(taos, sql);
|
||||
code = ws_errno(result);
|
||||
if (code != 0) {
|
||||
fprintf(stderr, "Failed to query data from power.meters, sql: %s, ErrCode: 0x%x, ErrMessage: %s\n.", sql, code,
|
||||
ws_errstr(result));
|
||||
ws_close(taos);
|
||||
return -1;
|
||||
}
|
||||
|
||||
WS_ROW row = NULL;
|
||||
int rows = 0;
|
||||
int num_fields = ws_field_count(result);
|
||||
const WS_FIELD *fields = ws_fetch_fields(result);
|
||||
|
||||
fprintf(stdout, "query successfully, got %d fields, the sql is: %s.\n", num_fields, sql);
|
||||
|
||||
// fetch the records row by row
|
||||
while ((row = ws_fetch_row(result))) {
|
||||
// Add your data processing logic here
|
||||
|
||||
rows++;
|
||||
}
|
||||
fprintf(stdout, "total rows: %d\n", rows);
|
||||
ws_free_result(result);
|
||||
|
||||
// close & clean
|
||||
ws_close(taos);
|
||||
return 0;
|
||||
// ANCHOR_END: query_data
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) { return DemoQueryData(); }
|
|
@ -0,0 +1,121 @@
|
|||
/*
|
||||
* Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
// TAOS standard API example. The same syntax as MySQL, but only a subset
|
||||
// to compile: gcc -o sml_insert_demo sml_insert_demo.c -ltaos
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "taosws.h"
|
||||
|
||||
static int DemoSmlInsert() {
|
||||
// ANCHOR: schemaless
|
||||
int code = 0;
|
||||
char *dsn = "ws://localhost:6041";
|
||||
|
||||
// connect
|
||||
WS_TAOS *taos = ws_connect(dsn);
|
||||
if (taos == NULL) {
|
||||
fprintf(stderr, "Failed to connect to %s, ErrCode: 0x%x, ErrMessage: %s.\n", dsn, ws_errno(NULL), ws_errstr(NULL));
|
||||
return -1;
|
||||
}
|
||||
|
||||
// create database
|
||||
WS_RES *result = ws_query(taos, "CREATE DATABASE IF NOT EXISTS power");
|
||||
code = ws_errno(result);
|
||||
if (code != 0) {
|
||||
fprintf(stderr, "Failed to create database power, ErrCode: 0x%x, ErrMessage: %s.\n", code, ws_errstr(result));
|
||||
ws_close(taos);
|
||||
return -1;
|
||||
}
|
||||
ws_free_result(result);
|
||||
|
||||
// use database
|
||||
result = ws_query(taos, "USE power");
|
||||
code = ws_errno(result);
|
||||
if (code != 0) {
|
||||
fprintf(stderr, "Failed to execute use power, ErrCode: 0x%x, ErrMessage: %s\n.", code, ws_errstr(result));
|
||||
ws_close(taos);
|
||||
return -1;
|
||||
}
|
||||
ws_free_result(result);
|
||||
|
||||
// schemaless demo data
|
||||
char *line_demo =
|
||||
"meters,groupid=2,location=California.SanFrancisco current=10.3000002f64,voltage=219i32,phase=0.31f64 "
|
||||
"1626006833639";
|
||||
char *telnet_demo = "metric_telnet 1707095283260 4 host=host0 interface=eth0";
|
||||
char *json_demo =
|
||||
"{\"metric\": \"metric_json\",\"timestamp\": 1626846400,\"value\": 10.3, \"tags\": {\"groupid\": 2, "
|
||||
"\"location\": \"California.SanFrancisco\", \"id\": \"d1001\"}}";
|
||||
|
||||
// influxdb line protocol
|
||||
char *lines[] = {line_demo};
|
||||
int totalLines = 0;
|
||||
result = ws_schemaless_insert_raw(taos, line_demo, strlen(line_demo), &totalLines, WS_TSDB_SML_LINE_PROTOCOL,
|
||||
WS_TSDB_SML_TIMESTAMP_MILLI_SECONDS);
|
||||
code = ws_errno(result);
|
||||
if (code != 0) {
|
||||
fprintf(stderr, "Failed to insert schemaless line data, data: %s, ErrCode: 0x%x, ErrMessage: %s\n.", line_demo,
|
||||
code, ws_errstr(result));
|
||||
ws_close(taos);
|
||||
return -1;
|
||||
}
|
||||
|
||||
fprintf(stdout, "Insert %d rows of schemaless line data successfully.\n", totalLines);
|
||||
ws_free_result(result);
|
||||
|
||||
// opentsdb telnet protocol
|
||||
totalLines = 0;
|
||||
result = ws_schemaless_insert_raw(taos, telnet_demo, strlen(telnet_demo), &totalLines, WS_TSDB_SML_TELNET_PROTOCOL,
|
||||
WS_TSDB_SML_TIMESTAMP_MILLI_SECONDS);
|
||||
code = ws_errno(result);
|
||||
if (code != 0) {
|
||||
fprintf(stderr, "Failed to insert schemaless telnet data, data: %s, ErrCode: 0x%x, ErrMessage: %s\n.", telnet_demo,
|
||||
code, ws_errstr(result));
|
||||
ws_close(taos);
|
||||
return -1;
|
||||
}
|
||||
|
||||
fprintf(stdout, "Insert %d rows of schemaless telnet data successfully.\n", totalLines);
|
||||
ws_free_result(result);
|
||||
|
||||
// opentsdb json protocol
|
||||
char *jsons[1] = {0};
|
||||
// allocate memory for json data. can not use static memory.
|
||||
totalLines = 0;
|
||||
result = ws_schemaless_insert_raw(taos, json_demo, strlen(json_demo), &totalLines, WS_TSDB_SML_JSON_PROTOCOL,
|
||||
WS_TSDB_SML_TIMESTAMP_MILLI_SECONDS);
|
||||
code = ws_errno(result);
|
||||
if (code != 0) {
|
||||
free(jsons[0]);
|
||||
fprintf(stderr, "Failed to insert schemaless json data, Server: %s, ErrCode: 0x%x, ErrMessage: %s\n.", json_demo,
|
||||
code, ws_errstr(result));
|
||||
ws_close(taos);
|
||||
return -1;
|
||||
}
|
||||
free(jsons[0]);
|
||||
|
||||
fprintf(stdout, "Insert %d rows of schemaless json data successfully.\n", totalLines);
|
||||
ws_free_result(result);
|
||||
|
||||
// close & clean
|
||||
ws_close(taos);
|
||||
return 0;
|
||||
// ANCHOR_END: schemaless
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) { return DemoSmlInsert(); }
|
|
@ -0,0 +1,183 @@
|
|||
/*
|
||||
* Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
// TAOS standard API example. The same syntax as MySQL, but only a subset
|
||||
// to compile: gcc -o stmt_insert_demo stmt_insert_demo.c -ltaos
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/time.h>
|
||||
#include "taosws.h"
|
||||
|
||||
/**
|
||||
* @brief execute sql only.
|
||||
*
|
||||
* @param taos
|
||||
* @param sql
|
||||
*/
|
||||
void executeSQL(WS_TAOS *taos, const char *sql) {
|
||||
WS_RES *res = ws_query(taos, sql);
|
||||
int code = ws_errno(res);
|
||||
if (code != 0) {
|
||||
fprintf(stderr, "%s\n", ws_errstr(res));
|
||||
ws_free_result(res);
|
||||
ws_close(taos);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
ws_free_result(res);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief check return status and exit program when error occur.
|
||||
*
|
||||
* @param stmt
|
||||
* @param code
|
||||
* @param msg
|
||||
*/
|
||||
void checkErrorCode(WS_STMT *stmt, int code, const char *msg) {
|
||||
if (code != 0) {
|
||||
fprintf(stderr, "%s. code: %d, error: %s\n", msg, code, ws_stmt_errstr(stmt));
|
||||
ws_stmt_close(stmt);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
int64_t ts;
|
||||
float current;
|
||||
int voltage;
|
||||
float phase;
|
||||
} Row;
|
||||
|
||||
int num_of_sub_table = 10;
|
||||
int num_of_row = 10;
|
||||
int total_affected = 0;
|
||||
/**
|
||||
* @brief insert data using stmt API
|
||||
*
|
||||
* @param taos
|
||||
*/
|
||||
void insertData(WS_TAOS *taos) {
|
||||
// init
|
||||
WS_STMT *stmt = ws_stmt_init(taos);
|
||||
if (stmt == NULL) {
|
||||
fprintf(stderr, "Failed to init ws_stmt, error: %s\n", ws_stmt_errstr(NULL));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
// prepare
|
||||
const char *sql = "INSERT INTO ? USING meters TAGS(?,?) VALUES (?,?,?,?)";
|
||||
int code = ws_stmt_prepare(stmt, sql, 0);
|
||||
checkErrorCode(stmt, code, "Failed to execute ws_stmt_prepare");
|
||||
for (int i = 1; i <= num_of_sub_table; i++) {
|
||||
char table_name[20];
|
||||
sprintf(table_name, "d_bind_%d", i);
|
||||
char location[20];
|
||||
sprintf(location, "location_%d", i);
|
||||
|
||||
// set table name and tags
|
||||
WS_MULTI_BIND tags[2];
|
||||
// groupId
|
||||
tags[0].buffer_type = TSDB_DATA_TYPE_INT;
|
||||
tags[0].buffer_length = sizeof(int);
|
||||
tags[0].length = (int32_t *)&tags[0].buffer_length;
|
||||
tags[0].buffer = &i;
|
||||
tags[0].is_null = NULL;
|
||||
tags[0].num = 1;
|
||||
// location
|
||||
tags[1].buffer_type = TSDB_DATA_TYPE_BINARY;
|
||||
tags[1].buffer_length = strlen(location);
|
||||
tags[1].length = (int32_t *)&tags[1].buffer_length;
|
||||
tags[1].buffer = location;
|
||||
tags[1].is_null = NULL;
|
||||
tags[1].num = 1;
|
||||
code = ws_stmt_set_tbname_tags(stmt, table_name, tags, 2);
|
||||
checkErrorCode(stmt, code, "Failed to set table name and tags\n");
|
||||
|
||||
// insert rows
|
||||
WS_MULTI_BIND params[4];
|
||||
// ts
|
||||
params[0].buffer_type = TSDB_DATA_TYPE_TIMESTAMP;
|
||||
params[0].buffer_length = sizeof(int64_t);
|
||||
params[0].length = (int32_t *)¶ms[0].buffer_length;
|
||||
params[0].is_null = NULL;
|
||||
params[0].num = 1;
|
||||
// current
|
||||
params[1].buffer_type = TSDB_DATA_TYPE_FLOAT;
|
||||
params[1].buffer_length = sizeof(float);
|
||||
params[1].length = (int32_t *)¶ms[1].buffer_length;
|
||||
params[1].is_null = NULL;
|
||||
params[1].num = 1;
|
||||
// voltage
|
||||
params[2].buffer_type = TSDB_DATA_TYPE_INT;
|
||||
params[2].buffer_length = sizeof(int);
|
||||
params[2].length = (int32_t *)¶ms[2].buffer_length;
|
||||
params[2].is_null = NULL;
|
||||
params[2].num = 1;
|
||||
// phase
|
||||
params[3].buffer_type = TSDB_DATA_TYPE_FLOAT;
|
||||
params[3].buffer_length = sizeof(float);
|
||||
params[3].length = (int32_t *)¶ms[3].buffer_length;
|
||||
params[3].is_null = NULL;
|
||||
params[3].num = 1;
|
||||
|
||||
for (int j = 0; j < num_of_row; j++) {
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv, NULL);
|
||||
long long milliseconds = tv.tv_sec * 1000LL + tv.tv_usec / 1000; // current timestamp in milliseconds
|
||||
int64_t ts = milliseconds + j;
|
||||
float current = (float)rand() / RAND_MAX * 30;
|
||||
int voltage = rand() % 300;
|
||||
float phase = (float)rand() / RAND_MAX;
|
||||
params[0].buffer = &ts;
|
||||
params[1].buffer = ¤t;
|
||||
params[2].buffer = &voltage;
|
||||
params[3].buffer = &phase;
|
||||
// bind param
|
||||
code = ws_stmt_bind_param_batch(stmt, params, 4);
|
||||
checkErrorCode(stmt, code, "Failed to bind param");
|
||||
}
|
||||
// add batch
|
||||
code = ws_stmt_add_batch(stmt);
|
||||
checkErrorCode(stmt, code, "Failed to add batch");
|
||||
// execute batch
|
||||
int affected_rows = 0;
|
||||
code = ws_stmt_execute(stmt, &affected_rows);
|
||||
checkErrorCode(stmt, code, "Failed to exec stmt");
|
||||
// get affected rows
|
||||
int affected = ws_stmt_affected_rows_once(stmt);
|
||||
total_affected += affected;
|
||||
}
|
||||
fprintf(stdout, "Successfully inserted %d rows to power.meters.\n", total_affected);
|
||||
ws_stmt_close(stmt);
|
||||
}
|
||||
|
||||
int main() {
|
||||
int code = 0;
|
||||
char *dsn = "ws://localhost:6041";
|
||||
WS_TAOS *taos = ws_connect(dsn);
|
||||
if (taos == NULL) {
|
||||
fprintf(stderr, "Failed to connect to %s, ErrCode: 0x%x, ErrMessage: %s.\n", dsn, ws_errno(NULL), ws_errstr(NULL));
|
||||
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);
|
||||
ws_close(taos);
|
||||
}
|
|
@ -0,0 +1,488 @@
|
|||
/*
|
||||
* Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
// to compile: gcc -o tmq_demo tmq_demo.c -ltaos -lpthread
|
||||
|
||||
#include <assert.h>
|
||||
#include <pthread.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
#include "taosws.h"
|
||||
|
||||
volatile int thread_stop = 0;
|
||||
static int running = 1;
|
||||
static int count = 0;
|
||||
const char* topic_name = "topic_meters";
|
||||
|
||||
typedef struct {
|
||||
const char* enable_auto_commit;
|
||||
const char* auto_commit_interval_ms;
|
||||
const char* group_id;
|
||||
const char* client_id;
|
||||
const char* td_connect_host;
|
||||
const char* td_connect_port;
|
||||
const char* td_connect_user;
|
||||
const char* td_connect_pass;
|
||||
const char* auto_offset_reset;
|
||||
} ConsumerConfig;
|
||||
|
||||
ConsumerConfig config = {.enable_auto_commit = "true",
|
||||
.auto_commit_interval_ms = "1000",
|
||||
.group_id = "group1",
|
||||
.client_id = "client1",
|
||||
.td_connect_host = "localhost",
|
||||
.td_connect_port = "6030",
|
||||
.td_connect_user = "root",
|
||||
.td_connect_pass = "taosdata",
|
||||
.auto_offset_reset = "latest"};
|
||||
|
||||
void* prepare_data(void* arg) {
|
||||
int code = 0;
|
||||
char* dsn = "ws://localhost:6041";
|
||||
WS_TAOS* pConn = ws_connect(dsn);
|
||||
if (pConn == NULL) {
|
||||
fprintf(stderr, "Failed to connect to %s, ErrCode: 0x%x, ErrMessage: %s.\n", dsn, ws_errno(NULL), ws_errstr(NULL));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
WS_RES* pRes;
|
||||
int i = 1;
|
||||
|
||||
while (!thread_stop) {
|
||||
char buf[200] = {0};
|
||||
i++;
|
||||
snprintf(
|
||||
buf, sizeof(buf),
|
||||
"INSERT INTO power.d1001 USING power.meters TAGS(2,'California.SanFrancisco') VALUES (NOW + %da, 10.30000, "
|
||||
"219, 0.31000)",
|
||||
i);
|
||||
|
||||
pRes = ws_query(pConn, buf);
|
||||
code = ws_errno(pRes);
|
||||
if (code != 0) {
|
||||
fprintf(stderr, "Failed to insert data to power.meters, ErrCode: 0x%x, ErrMessage: %s.\n", code, ws_errstr(pRes));
|
||||
}
|
||||
ws_free_result(pRes);
|
||||
sleep(1);
|
||||
}
|
||||
fprintf(stdout, "Prepare data thread exit\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// ANCHOR: msg_process
|
||||
int32_t msg_process(WS_RES* msg) {
|
||||
int32_t rows = 0;
|
||||
const char* topicName = ws_tmq_get_topic_name(msg);
|
||||
const char* dbName = ws_tmq_get_db_name(msg);
|
||||
int32_t vgroupId = ws_tmq_get_vgroup_id(msg);
|
||||
|
||||
while (true) {
|
||||
// get one row data from message
|
||||
WS_ROW row = ws_fetch_row(msg);
|
||||
if (row == NULL) break;
|
||||
|
||||
// Add your data processing logic here
|
||||
|
||||
rows++;
|
||||
}
|
||||
|
||||
return rows;
|
||||
}
|
||||
// ANCHOR_END: msg_process
|
||||
|
||||
WS_TAOS* init_env() {
|
||||
int code = 0;
|
||||
char* dsn = "ws://localhost:6041";
|
||||
WS_TAOS* pConn = ws_connect(dsn);
|
||||
if (pConn == NULL) {
|
||||
fprintf(stderr, "Failed to connect to %s, ErrCode: 0x%x, ErrMessage: %s.\n", dsn, ws_errno(NULL), ws_errstr(NULL));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
WS_RES* pRes;
|
||||
// drop database if exists
|
||||
pRes = ws_query(pConn, "DROP TOPIC IF EXISTS topic_meters");
|
||||
code = ws_errno(pRes);
|
||||
if (code != 0) {
|
||||
fprintf(stderr, "Failed to drop topic_meters, ErrCode: 0x%x, ErrMessage: %s.\n", code, ws_errstr(pRes));
|
||||
goto END;
|
||||
}
|
||||
ws_free_result(pRes);
|
||||
|
||||
pRes = ws_query(pConn, "DROP DATABASE IF EXISTS power");
|
||||
code = ws_errno(pRes);
|
||||
if (code != 0) {
|
||||
fprintf(stderr, "Failed to drop database power, ErrCode: 0x%x, ErrMessage: %s.\n", code, ws_errstr(pRes));
|
||||
goto END;
|
||||
}
|
||||
ws_free_result(pRes);
|
||||
|
||||
// create database
|
||||
pRes = ws_query(pConn, "CREATE DATABASE power PRECISION 'ms' WAL_RETENTION_PERIOD 3600");
|
||||
code = ws_errno(pRes);
|
||||
if (code != 0) {
|
||||
fprintf(stderr, "Failed to create power, ErrCode: 0x%x, ErrMessage: %s.\n", code, ws_errstr(pRes));
|
||||
goto END;
|
||||
}
|
||||
ws_free_result(pRes);
|
||||
|
||||
// create super table
|
||||
pRes =
|
||||
ws_query(pConn,
|
||||
"CREATE STABLE IF NOT EXISTS power.meters (ts TIMESTAMP, current FLOAT, voltage INT, phase FLOAT) TAGS "
|
||||
"(groupId INT, location BINARY(24))");
|
||||
code = ws_errno(pRes);
|
||||
if (code != 0) {
|
||||
fprintf(stderr, "Failed to create super table meters, ErrCode: 0x%x, ErrMessage: %s.\n", code, ws_errstr(pRes));
|
||||
goto END;
|
||||
}
|
||||
ws_free_result(pRes);
|
||||
|
||||
return pConn;
|
||||
|
||||
END:
|
||||
ws_free_result(pRes);
|
||||
ws_close(pConn);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void deinit_env(WS_TAOS* pConn) {
|
||||
if (pConn) ws_close(pConn);
|
||||
}
|
||||
|
||||
int32_t create_topic(WS_TAOS* pConn) {
|
||||
WS_RES* pRes;
|
||||
int code = 0;
|
||||
|
||||
if (!pConn) {
|
||||
fprintf(stderr, "Invalid input parameter.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
pRes = ws_query(pConn, "USE power");
|
||||
code = ws_errno(pRes);
|
||||
if (ws_errno(pRes) != 0) {
|
||||
fprintf(stderr, "Failed to use power, ErrCode: 0x%x, ErrMessage: %s.\n", code, ws_errstr(pRes));
|
||||
return -1;
|
||||
}
|
||||
ws_free_result(pRes);
|
||||
|
||||
pRes = ws_query(
|
||||
pConn,
|
||||
"CREATE TOPIC IF NOT EXISTS topic_meters AS SELECT ts, current, voltage, phase, groupid, location FROM meters");
|
||||
code = ws_errno(pRes);
|
||||
if (code != 0) {
|
||||
fprintf(stderr, "Failed to create topic topic_meters, ErrCode: 0x%x, ErrMessage: %s.\n", code, ws_errstr(pRes));
|
||||
return -1;
|
||||
}
|
||||
ws_free_result(pRes);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t drop_topic(WS_TAOS* pConn) {
|
||||
WS_RES* pRes;
|
||||
int code = 0;
|
||||
|
||||
if (!pConn) {
|
||||
fprintf(stderr, "Invalid input parameter.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
pRes = ws_query(pConn, "USE power");
|
||||
code = ws_errno(pRes);
|
||||
if (ws_errno(pRes) != 0) {
|
||||
fprintf(stderr, "Failed to use power, ErrCode: 0x%x, ErrMessage: %s.\n", code, ws_errstr(pRes));
|
||||
return -1;
|
||||
}
|
||||
ws_free_result(pRes);
|
||||
|
||||
pRes = ws_query(pConn, "DROP TOPIC IF EXISTS topic_meters");
|
||||
code = ws_errno(pRes);
|
||||
if (code != 0) {
|
||||
fprintf(stderr, "Failed to drop topic topic_meters, ErrCode: 0x%x, ErrMessage: %s.\n", code, ws_errstr(pRes));
|
||||
return -1;
|
||||
}
|
||||
ws_free_result(pRes);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void tmq_commit_cb_print(ws_tmq_t* tmq, int32_t code, void* param) {
|
||||
count += 1;
|
||||
fprintf(stdout, "tmq_commit_cb_print() code: %d, tmq: %p, param: %p, count: %d.\n", code, tmq, param, count);
|
||||
}
|
||||
|
||||
// ANCHOR: create_consumer_1
|
||||
ws_tmq_t* build_consumer(const ConsumerConfig* config) {
|
||||
ws_tmq_conf_res_t code;
|
||||
ws_tmq_t* tmq = NULL;
|
||||
|
||||
// create a configuration object
|
||||
ws_tmq_conf_t* conf = ws_tmq_conf_new();
|
||||
|
||||
// set the configuration parameters
|
||||
code = ws_tmq_conf_set(conf, "enable.auto.commit", config->enable_auto_commit);
|
||||
if (WS_TMQ_CONF_OK != code) {
|
||||
ws_tmq_conf_destroy(conf);
|
||||
return NULL;
|
||||
}
|
||||
code = ws_tmq_conf_set(conf, "auto.commit.interval.ms", config->auto_commit_interval_ms);
|
||||
if (WS_TMQ_CONF_OK != code) {
|
||||
ws_tmq_conf_destroy(conf);
|
||||
return NULL;
|
||||
}
|
||||
code = ws_tmq_conf_set(conf, "group.id", config->group_id);
|
||||
if (WS_TMQ_CONF_OK != code) {
|
||||
ws_tmq_conf_destroy(conf);
|
||||
return NULL;
|
||||
}
|
||||
code = ws_tmq_conf_set(conf, "client.id", config->client_id);
|
||||
if (WS_TMQ_CONF_OK != code) {
|
||||
ws_tmq_conf_destroy(conf);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
code = ws_tmq_conf_set(conf, "auto.offset.reset", config->auto_offset_reset);
|
||||
if (WS_TMQ_CONF_OK != code) {
|
||||
ws_tmq_conf_destroy(conf);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// create a consumer object
|
||||
tmq = ws_tmq_consumer_new(conf, "taos://localhost:6041", NULL, 0);
|
||||
|
||||
_end:
|
||||
// destroy the configuration object
|
||||
ws_tmq_conf_destroy(conf);
|
||||
return tmq;
|
||||
}
|
||||
// ANCHOR_END: create_consumer_1
|
||||
|
||||
// ANCHOR: build_topic_list
|
||||
// build a topic list used to subscribe
|
||||
ws_tmq_list_t* build_topic_list() {
|
||||
// create a empty topic list
|
||||
ws_tmq_list_t* topicList = ws_tmq_list_new();
|
||||
|
||||
// append topic name to the list
|
||||
int32_t code = ws_tmq_list_append(topicList, topic_name);
|
||||
if (code) {
|
||||
// if failed, destroy the list and return NULL
|
||||
ws_tmq_list_destroy(topicList);
|
||||
fprintf(stderr,
|
||||
"Failed to create topic_list, topic: %s, groupId: %s, clientId: %s, ErrCode: 0x%x, ErrMessage: %s.\n",
|
||||
topic_name, config.group_id, config.client_id, code, ws_tmq_errstr(NULL));
|
||||
return NULL;
|
||||
}
|
||||
// if success, return the list
|
||||
return topicList;
|
||||
}
|
||||
// ANCHOR_END: build_topic_list
|
||||
|
||||
// ANCHOR: basic_consume_loop
|
||||
void basic_consume_loop(ws_tmq_t* tmq) {
|
||||
int32_t totalRows = 0; // total rows consumed
|
||||
int32_t msgCnt = 0; // total messages consumed
|
||||
int32_t timeout = 5000; // poll timeout
|
||||
|
||||
while (running) {
|
||||
// poll message from TDengine
|
||||
WS_RES* tmqmsg = ws_tmq_consumer_poll(tmq, timeout);
|
||||
if (tmqmsg) {
|
||||
msgCnt++;
|
||||
|
||||
// Add your data processing logic here
|
||||
totalRows += msg_process(tmqmsg);
|
||||
|
||||
// free the message
|
||||
ws_free_result(tmqmsg);
|
||||
}
|
||||
if (msgCnt > 50) {
|
||||
// consume 50 messages and break
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// print the result: total messages and total rows consumed
|
||||
fprintf(stdout, "%d msg consumed, include %d rows\n", msgCnt, totalRows);
|
||||
}
|
||||
// ANCHOR_END: basic_consume_loop
|
||||
|
||||
// ANCHOR: consume_repeatly
|
||||
void consume_repeatly(ws_tmq_t* tmq) {
|
||||
int32_t numOfAssignment = 0;
|
||||
ws_tmq_topic_assignment* pAssign = NULL;
|
||||
|
||||
// get the topic assignment
|
||||
int32_t code = ws_tmq_get_topic_assignment(tmq, topic_name, &pAssign, &numOfAssignment);
|
||||
if (code != 0 || pAssign == NULL || numOfAssignment == 0) {
|
||||
fprintf(stderr, "Failed to get assignment, topic: %s, groupId: %s, clientId: %s, ErrCode: 0x%x, ErrMessage: %s.\n",
|
||||
topic_name, config.group_id, config.client_id, code, ws_tmq_errstr(tmq));
|
||||
return;
|
||||
}
|
||||
|
||||
// seek to the earliest offset
|
||||
for (int32_t i = 0; i < numOfAssignment; ++i) {
|
||||
ws_tmq_topic_assignment* p = &pAssign[i];
|
||||
|
||||
code = ws_tmq_offset_seek(tmq, topic_name, p->vgId, p->begin);
|
||||
if (code != 0) {
|
||||
fprintf(stderr,
|
||||
"Failed to seek offset, topic: %s, groupId: %s, clientId: %s, vgId: %d, ErrCode: 0x%x, ErrMessage: %s.\n",
|
||||
topic_name, config.group_id, config.client_id, p->vgId, code, ws_tmq_errstr(tmq));
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (code == 0) fprintf(stdout, "Assignment seek to beginning successfully.\n");
|
||||
|
||||
// free the assignment array
|
||||
ws_tmq_free_assignment(pAssign, numOfAssignment);
|
||||
|
||||
// let's consume the messages again
|
||||
basic_consume_loop(tmq);
|
||||
}
|
||||
// ANCHOR_END: consume_repeatly
|
||||
|
||||
// ANCHOR: manual_commit
|
||||
void manual_commit(ws_tmq_t* tmq) {
|
||||
int32_t totalRows = 0; // total rows consumed
|
||||
int32_t msgCnt = 0; // total messages consumed
|
||||
int32_t timeout = 5000; // poll timeout
|
||||
|
||||
while (running) {
|
||||
// poll message from TDengine
|
||||
WS_RES* tmqmsg = ws_tmq_consumer_poll(tmq, timeout);
|
||||
if (tmqmsg) {
|
||||
msgCnt++;
|
||||
// process the message
|
||||
totalRows += msg_process(tmqmsg);
|
||||
// commit the message
|
||||
int32_t code = ws_tmq_commit_sync(tmq, tmqmsg);
|
||||
if (code) {
|
||||
fprintf(stderr,
|
||||
"Failed to commit offset, topic: %s, groupId: %s, clientId: %s, ErrCode: 0x%x, ErrMessage: %s.\n",
|
||||
topic_name, config.group_id, config.client_id, code, ws_tmq_errstr(tmq));
|
||||
// free the message
|
||||
ws_free_result(tmqmsg);
|
||||
break;
|
||||
} else {
|
||||
fprintf(stdout, "Commit offset manually successfully.\n");
|
||||
}
|
||||
// free the message
|
||||
ws_free_result(tmqmsg);
|
||||
}
|
||||
if (msgCnt > 50) {
|
||||
// consume 50 messages and break
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// print the result: total messages and total rows consumed
|
||||
fprintf(stdout, "%d msg consumed, include %d rows.\n", msgCnt, totalRows);
|
||||
}
|
||||
// ANCHOR_END: manual_commit
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
int32_t code;
|
||||
pthread_t thread_id;
|
||||
|
||||
WS_TAOS* pConn = init_env();
|
||||
if (pConn == NULL) {
|
||||
fprintf(stderr, "Failed to init env.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (create_topic(pConn) < 0) {
|
||||
fprintf(stderr, "Failed to create topic.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (pthread_create(&thread_id, NULL, &prepare_data, NULL)) {
|
||||
fprintf(stderr, "Failed to create thread.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// ANCHOR: create_consumer_2
|
||||
ws_tmq_t* tmq = build_consumer(&config);
|
||||
if (NULL == tmq) {
|
||||
fprintf(stderr, "Failed to create native consumer, host: %s, groupId: %s, , clientId: %s.\n",
|
||||
config.td_connect_host, config.group_id, config.client_id);
|
||||
return -1;
|
||||
} else {
|
||||
fprintf(stdout, "Create consumer successfully, host: %s, groupId: %s, clientId: %s.\n", config.td_connect_host,
|
||||
config.group_id, config.client_id);
|
||||
}
|
||||
|
||||
// ANCHOR_END: create_consumer_2
|
||||
|
||||
// ANCHOR: subscribe_3
|
||||
ws_tmq_list_t* topic_list = build_topic_list();
|
||||
if (NULL == topic_list) {
|
||||
fprintf(stderr, "Failed to create topic_list, topic: %s, groupId: %s, clientId: %s.\n", topic_name, config.group_id,
|
||||
config.client_id);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((code = ws_tmq_subscribe(tmq, topic_list))) {
|
||||
fprintf(stderr,
|
||||
"Failed to subscribe topic_list, topic: %s, groupId: %s, clientId: %s, ErrCode: 0x%x, ErrMessage: %s.\n",
|
||||
topic_name, config.group_id, config.client_id, code, ws_tmq_errstr(tmq));
|
||||
} else {
|
||||
fprintf(stdout, "Subscribe topics successfully.\n");
|
||||
}
|
||||
|
||||
ws_tmq_list_destroy(topic_list);
|
||||
|
||||
basic_consume_loop(tmq);
|
||||
// ANCHOR_END: subscribe_3
|
||||
|
||||
consume_repeatly(tmq);
|
||||
|
||||
manual_commit(tmq);
|
||||
|
||||
// ANCHOR: unsubscribe_and_close
|
||||
// unsubscribe the topic
|
||||
code = ws_tmq_unsubscribe(tmq);
|
||||
if (code) {
|
||||
fprintf(stderr,
|
||||
"Failed to unsubscribe consumer, topic: %s, groupId: %s, clientId: %s, ErrCode: 0x%x, ErrMessage: %s.\n",
|
||||
topic_name, config.group_id, config.client_id, code, ws_tmq_errstr(tmq));
|
||||
} else {
|
||||
fprintf(stdout, "Consumer unsubscribed successfully.\n");
|
||||
}
|
||||
|
||||
// close the consumer
|
||||
code = ws_tmq_consumer_close(tmq);
|
||||
if (code) {
|
||||
fprintf(stderr, "Failed to close consumer, topic: %s, groupId: %s, clientId: %s, ErrCode: 0x%x, ErrMessage: %s.\n",
|
||||
topic_name, config.group_id, config.client_id, code, ws_tmq_errstr(tmq));
|
||||
} else {
|
||||
fprintf(stdout, "Consumer closed successfully.\n");
|
||||
}
|
||||
// ANCHOR_END: unsubscribe_and_close
|
||||
|
||||
thread_stop = 1;
|
||||
pthread_join(thread_id, NULL);
|
||||
|
||||
if (drop_topic(pConn) < 0) {
|
||||
fprintf(stderr, "Failed to drop topic.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
deinit_env(pConn);
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,71 @@
|
|||
/*
|
||||
* Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
// TAOS standard API example. The same syntax as MySQL, but only a subset
|
||||
// to compile: gcc -o with_reqid_demo with_reqid_demo.c -ltaos
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "taosws.h"
|
||||
|
||||
static int DemoWithReqId() {
|
||||
// ANCHOR: with_reqid
|
||||
int code = 0;
|
||||
char *dsn = "ws://localhost:6041";
|
||||
|
||||
// connect
|
||||
WS_TAOS *taos = ws_connect(dsn);
|
||||
if (taos == NULL) {
|
||||
fprintf(stderr, "Failed to connect to %s, ErrCode: 0x%x, ErrMessage: %s.\n", dsn, ws_errno(NULL), ws_errstr(NULL));
|
||||
return -1;
|
||||
}
|
||||
|
||||
const char *sql = "SELECT ts, current, location FROM power.meters limit 1";
|
||||
// query data with reqid
|
||||
long reqid = 3L;
|
||||
WS_RES *result = ws_query_with_reqid(taos, sql, reqid);
|
||||
code = ws_errno(result);
|
||||
if (code != 0) {
|
||||
fprintf(stderr, "Failed to execute sql withQID: %ld, ErrCode: 0x%x, ErrMessage: %s\n.", reqid, code,
|
||||
ws_errstr(result));
|
||||
ws_close(taos);
|
||||
return -1;
|
||||
}
|
||||
|
||||
WS_ROW row = NULL;
|
||||
int rows = 0;
|
||||
int num_fields = ws_field_count(result);
|
||||
const WS_FIELD *fields = ws_fetch_fields(result);
|
||||
|
||||
fprintf(stdout, "query successfully, got %d fields, the sql is: %s.\n", num_fields, sql);
|
||||
|
||||
// fetch the records row by row
|
||||
while ((row = ws_fetch_row(result))) {
|
||||
// Add your data processing logic here
|
||||
|
||||
rows++;
|
||||
}
|
||||
fprintf(stdout, "total rows: %d\n", rows);
|
||||
ws_free_result(result);
|
||||
|
||||
// close & clean
|
||||
ws_close(taos);
|
||||
return 0;
|
||||
// ANCHOR_END: with_reqid
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) { return DemoWithReqId(); }
|
|
@ -4,7 +4,6 @@
|
|||
"main": "index.js",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@tdengine/client": "^3.0.1",
|
||||
"@tdengine/rest": "^3.0.0"
|
||||
"@tdengine/websocket": "^3.1.0"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,6 +34,7 @@ async function json_tag_example() {
|
|||
|
||||
} catch (err) {
|
||||
console.error(`Failed to create database example_json_tag or stable stb, ErrCode: ${err.code}, ErrMessage: ${err.message}`);
|
||||
throw err;
|
||||
} finally {
|
||||
if (wsSql) {
|
||||
await wsSql.close();
|
||||
|
@ -78,9 +79,10 @@ async function all_type_example() {
|
|||
let row = wsRows.getData();
|
||||
console.log(row);
|
||||
}
|
||||
|
||||
|
||||
} catch (err) {
|
||||
console.error(`Failed to create database all_type_example or stable stb, ErrCode: ${err.code}, ErrMessage: ${err.message}`);
|
||||
throw err;
|
||||
} finally {
|
||||
if (wsSql) {
|
||||
await wsSql.close();
|
||||
|
@ -91,7 +93,7 @@ async function all_type_example() {
|
|||
|
||||
async function test() {
|
||||
await json_tag_example()
|
||||
await all_type_example()
|
||||
await all_type_example()
|
||||
taos.destroy();
|
||||
}
|
||||
|
||||
|
|
|
@ -46,6 +46,7 @@ async function json_tag_example() {
|
|||
|
||||
} catch (err) {
|
||||
console.error(`Failed to create database example_json_tag or stable stb, ErrCode: ${err.code}, ErrMessage: ${err.message}`);
|
||||
throw err
|
||||
} finally {
|
||||
if (wsSql) {
|
||||
await wsSql.close();
|
||||
|
@ -125,6 +126,7 @@ async function all_type_example() {
|
|||
|
||||
} catch (err) {
|
||||
console.error(`Failed to create database all_type_example or stable stb, ErrCode: ${err.code}, ErrMessage: ${err.message}`);
|
||||
throw err;
|
||||
} finally {
|
||||
if (stmt) {
|
||||
await stmt.close();
|
||||
|
@ -136,10 +138,7 @@ async function all_type_example() {
|
|||
|
||||
}
|
||||
|
||||
|
||||
|
||||
async function test() {
|
||||
taos.setLevel("debug")
|
||||
async function test() {
|
||||
await json_tag_example()
|
||||
await all_type_example()
|
||||
taos.destroy();
|
||||
|
|
|
@ -1,53 +0,0 @@
|
|||
const taos = require("@tdengine/websocket");
|
||||
|
||||
var host = null;
|
||||
for(var i = 2; i < global.process.argv.length; i++){
|
||||
var key = global.process.argv[i].split("=")[0];
|
||||
var value = global.process.argv[i].split("=")[1];
|
||||
if("host" == key){
|
||||
host = value;
|
||||
}
|
||||
}
|
||||
|
||||
if(host == null){
|
||||
console.log("Usage: node nodejsChecker.js host=<hostname> port=<port>");
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
let dbData = ["{\"metric\": \"meter_current\",\"timestamp\": 1626846402,\"value\": 10.3, \"tags\": {\"groupid\": 2, \"location\": \"California.SanFrancisco\", \"id\": \"d1001\"}}",
|
||||
"{\"metric\": \"meter_current\",\"timestamp\": 1626846403,\"value\": 10.3, \"tags\": {\"groupid\": 2, \"location\": \"California.SanFrancisco\", \"id\": \"d1002\"}}",
|
||||
"{\"metric\": \"meter_current\",\"timestamp\": 1626846404,\"value\": 10.3, \"tags\": {\"groupid\": 2, \"location\": \"California.SanFrancisco\", \"id\": \"d1003\"}}"]
|
||||
|
||||
async function createConnect() {
|
||||
let dsn = 'ws://' + host + ':6041'
|
||||
let conf = new taos.WSConfig(dsn);
|
||||
conf.setUser('root');
|
||||
conf.setPwd('taosdata');
|
||||
conf.setDb('power');
|
||||
return await taos.sqlConnect(conf);
|
||||
}
|
||||
|
||||
async function test() {
|
||||
let wsSql = null;
|
||||
let wsRows = null;
|
||||
let reqId = 0;
|
||||
try {
|
||||
wsSql = await createConnect()
|
||||
await wsSql.exec('CREATE DATABASE IF NOT EXISTS power KEEP 3650 DURATION 10 BUFFER 16 WAL_LEVEL 1;', reqId++);
|
||||
await wsSql.schemalessInsert([dbData], taos.SchemalessProto.OpenTSDBJsonFormatProtocol, taos.Precision.SECONDS, 0);
|
||||
}
|
||||
catch (err) {
|
||||
console.error(err.code, err.message);
|
||||
}
|
||||
finally {
|
||||
if (wsRows) {
|
||||
await wsRows.close();
|
||||
}
|
||||
if (wsSql) {
|
||||
await wsSql.close();
|
||||
}
|
||||
taos.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
test()
|
|
@ -15,8 +15,8 @@ async function createConnect() {
|
|||
return wsSql;
|
||||
}
|
||||
|
||||
|
||||
async function test() {
|
||||
let dsn = 'ws://localhost:6041'
|
||||
let wsSql = null;
|
||||
let wsRows = null;
|
||||
let ttl = 0;
|
||||
|
@ -29,6 +29,7 @@ async function test() {
|
|||
}
|
||||
catch (err) {
|
||||
console.error(`Failed to insert data with schemaless, ErrCode: ${err.code}, ErrMessage: ${err.message}`);
|
||||
throw err;
|
||||
}
|
||||
finally {
|
||||
if (wsRows) {
|
||||
|
@ -40,4 +41,5 @@ async function test() {
|
|||
taos.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
test()
|
||||
|
|
|
@ -10,11 +10,9 @@ for(var i = 2; i < global.process.argv.length; i++){
|
|||
}
|
||||
|
||||
if(host == null){
|
||||
console.log("Usage: node nodejsChecker.js host=<hostname> port=<port>");
|
||||
process.exit(0);
|
||||
host = 'localhost';
|
||||
}
|
||||
|
||||
|
||||
async function createConnect() {
|
||||
let dsn = 'ws://' + host + ':6041'
|
||||
console.log(dsn)
|
||||
|
@ -41,7 +39,7 @@ async function test() {
|
|||
taosResult = await wsSql.exec('USE power', reqId++);
|
||||
console.log(taosResult);
|
||||
|
||||
taosResult = await wsSql.exec('CREATE STABLE IF NOT EXISTS meters (_ts timestamp, current float, voltage int, phase float) TAGS (location binary(64), groupId int);', reqId++);
|
||||
taosResult = await wsSql.exec('CREATE STABLE IF NOT EXISTS meters (ts timestamp, current float, voltage int, phase float) TAGS (location binary(64), groupId int);', reqId++);
|
||||
console.log(taosResult);
|
||||
|
||||
taosResult = await wsSql.exec('DESCRIBE meters', reqId++);
|
||||
|
@ -62,6 +60,7 @@ async function test() {
|
|||
}
|
||||
catch (err) {
|
||||
console.error(err.code, err.message);
|
||||
throw err;
|
||||
}
|
||||
finally {
|
||||
if (wsRows) {
|
||||
|
|
|
@ -41,6 +41,7 @@ async function createDbAndTable() {
|
|||
console.log("Create stable power.meters successfully");
|
||||
} catch (err) {
|
||||
console.error(`Failed to create database power or stable meters, ErrCode: ${err.code}, ErrMessage: ${err.message}`);
|
||||
throw err;
|
||||
} finally {
|
||||
if (wsSql) {
|
||||
await wsSql.close();
|
||||
|
@ -53,21 +54,23 @@ async function createDbAndTable() {
|
|||
// ANCHOR: insertData
|
||||
async function insertData() {
|
||||
let wsSql = null
|
||||
let insertQuery = "INSERT INTO " +
|
||||
"power.d1001 USING power.meters (location, groupId) TAGS('California.SanFrancisco', 2) " +
|
||||
"VALUES " +
|
||||
"(NOW + 1a, 10.30000, 219, 0.31000) " +
|
||||
"(NOW + 2a, 12.60000, 218, 0.33000) " +
|
||||
"(NOW + 3a, 12.30000, 221, 0.31000) " +
|
||||
"power.d1002 USING power.meters (location, groupId) TAGS('California.SanFrancisco', 3) " +
|
||||
"VALUES " +
|
||||
"(NOW + 1a, 10.30000, 218, 0.25000) ";
|
||||
|
||||
try {
|
||||
wsSql = await createConnect();
|
||||
let insertQuery = "INSERT INTO " +
|
||||
"power.d1001 USING power.meters (location, groupId) TAGS('California.SanFrancisco', 2) " +
|
||||
"VALUES " +
|
||||
"(NOW + 1a, 10.30000, 219, 0.31000) " +
|
||||
"(NOW + 2a, 12.60000, 218, 0.33000) " +
|
||||
"(NOW + 3a, 12.30000, 221, 0.31000) " +
|
||||
"power.d1002 USING power.meters TAGS('California.SanFrancisco', 3) " +
|
||||
"VALUES " +
|
||||
"(NOW + 1a, 10.30000, 218, 0.25000) ";
|
||||
taosResult = await wsSql.exec(insertQuery);
|
||||
console.log("Successfully inserted " + taosResult.getAffectRows() + " rows to power.meters.");
|
||||
} catch (err) {
|
||||
console.error(`Failed to insert data to power.meters, sql: ${insertQuery}, ErrCode: ${err.code}, ErrMessage: ${err.message}`);
|
||||
throw err;
|
||||
} finally {
|
||||
if (wsSql) {
|
||||
await wsSql.close();
|
||||
|
@ -91,6 +94,7 @@ async function queryData() {
|
|||
}
|
||||
catch (err) {
|
||||
console.error(`Failed to query data from power.meters, sql: ${sql}, ErrCode: ${err.code}, ErrMessage: ${err.message}`);
|
||||
throw err;
|
||||
}
|
||||
finally {
|
||||
if (wsRows) {
|
||||
|
@ -118,6 +122,7 @@ async function sqlWithReqid() {
|
|||
}
|
||||
catch (err) {
|
||||
console.error(`Failed to query data from power.meters, reqId: ${reqId}, ErrCode: ${err.code}, ErrMessage: ${err.message}`);
|
||||
throw err;
|
||||
}
|
||||
finally {
|
||||
if (wsRows) {
|
||||
|
@ -135,7 +140,7 @@ async function test() {
|
|||
await insertData();
|
||||
await queryData();
|
||||
await sqlWithReqid();
|
||||
taos.destroy();
|
||||
taos.destroy();
|
||||
}
|
||||
|
||||
test()
|
||||
|
|
|
@ -23,7 +23,7 @@ async function prepare() {
|
|||
return wsSql
|
||||
}
|
||||
|
||||
(async () => {
|
||||
async function test() {
|
||||
let stmt = null;
|
||||
let connector = null;
|
||||
try {
|
||||
|
@ -60,6 +60,7 @@ async function prepare() {
|
|||
}
|
||||
catch (err) {
|
||||
console.error(`Failed to insert to table meters using stmt, ErrCode: ${err.code}, ErrMessage: ${err.message}`);
|
||||
throw err;
|
||||
}
|
||||
finally {
|
||||
if (stmt) {
|
||||
|
@ -70,4 +71,6 @@ async function prepare() {
|
|||
}
|
||||
taos.destroy();
|
||||
}
|
||||
})();
|
||||
}
|
||||
|
||||
test()
|
|
@ -1,58 +0,0 @@
|
|||
const taos = require("@tdengine/websocket");
|
||||
|
||||
var host = null;
|
||||
for(var i = 2; i < global.process.argv.length; i++){
|
||||
var key = global.process.argv[i].split("=")[0];
|
||||
var value = global.process.argv[i].split("=")[1];
|
||||
if("host" == key){
|
||||
host = value;
|
||||
}
|
||||
}
|
||||
|
||||
if(host == null){
|
||||
console.log("Usage: node nodejsChecker.js host=<hostname> port=<port>");
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
let dbData = ["meters.current 1648432611249 10.3 location=California.SanFrancisco groupid=2",
|
||||
"meters.current 1648432611250 12.6 location=California.SanFrancisco groupid=2",
|
||||
"meters.current 1648432611249 10.8 location=California.LosAngeles groupid=3",
|
||||
"meters.current 1648432611250 11.3 location=California.LosAngeles groupid=3",
|
||||
"meters.voltage 1648432611249 219 location=California.SanFrancisco groupid=2",
|
||||
"meters.voltage 1648432611250 218 location=California.SanFrancisco groupid=2",
|
||||
"meters.voltage 1648432611249 221 location=California.LosAngeles groupid=3",
|
||||
"meters.voltage 1648432611250 217 location=California.LosAngeles groupid=3",];
|
||||
|
||||
async function createConnect() {
|
||||
let dsn = 'ws://' + host + ':6041'
|
||||
let conf = new taos.WSConfig(dsn);
|
||||
conf.setUser('root');
|
||||
conf.setPwd('taosdata');
|
||||
|
||||
return await taos.sqlConnect(conf);
|
||||
}
|
||||
|
||||
async function test() {
|
||||
let wsSql = null;
|
||||
let wsRows = null;
|
||||
let reqId = 0;
|
||||
try {
|
||||
wsSql = await createConnect()
|
||||
await wsSql.exec('create database if not exists power KEEP 3650 DURATION 10 BUFFER 16 WAL_LEVEL 1;', reqId++);
|
||||
await wsSql.exec('use power', reqId++);
|
||||
await wsSql.schemalessInsert(dbData, taos.SchemalessProto.OpenTSDBTelnetLineProtocol, taos.Precision.MILLI_SECONDS, 0);
|
||||
}
|
||||
catch (err) {
|
||||
console.error(err.code, err.message);
|
||||
}
|
||||
finally {
|
||||
if (wsRows) {
|
||||
await wsRows.close();
|
||||
}
|
||||
if (wsSql) {
|
||||
await wsSql.close();
|
||||
}
|
||||
taos.destroy();
|
||||
}
|
||||
}
|
||||
test()
|
|
@ -1,3 +1,4 @@
|
|||
const { sleep } = require("@tdengine/websocket");
|
||||
const taos = require("@tdengine/websocket");
|
||||
|
||||
// ANCHOR: create_consumer
|
||||
|
@ -49,12 +50,20 @@ async function prepare() {
|
|||
|
||||
let createTopic = `CREATE TOPIC IF NOT EXISTS ${topics[0]} AS SELECT * FROM ${db}.${stable}`;
|
||||
await wsSql.exec(createTopic);
|
||||
await wsSql.close();
|
||||
}
|
||||
|
||||
|
||||
for (let i = 0; i < 10; i++) {
|
||||
async function insert() {
|
||||
let conf = new taos.WSConfig('ws://localhost:6041');
|
||||
conf.setUser('root');
|
||||
conf.setPwd('taosdata');
|
||||
conf.setDb('power');
|
||||
let wsSql = await taos.sqlConnect(conf);
|
||||
for (let i = 0; i < 50; i++) {
|
||||
await wsSql.exec(`INSERT INTO d1001 USING ${stable} (location, groupId) TAGS ("California.SanFrancisco", 3) VALUES (NOW, ${10 + i}, ${200 + i}, ${0.32 + i})`);
|
||||
await sleep(100);
|
||||
}
|
||||
wsSql.close();
|
||||
await wsSql.close();
|
||||
}
|
||||
|
||||
async function subscribe(consumer) {
|
||||
|
@ -82,13 +91,17 @@ async function test() {
|
|||
let consumer = null;
|
||||
try {
|
||||
await prepare();
|
||||
consumer = await createConsumer()
|
||||
await subscribe(consumer)
|
||||
consumer = await createConsumer();
|
||||
const allPromises = [];
|
||||
allPromises.push(subscribe(consumer));
|
||||
allPromises.push(insert());
|
||||
await Promise.all(allPromises);
|
||||
await consumer.unsubscribe();
|
||||
console.log("Consumer unsubscribed successfully.");
|
||||
}
|
||||
catch (err) {
|
||||
console.error(`Failed to unsubscribe consumer, topic: ${topic}, groupId: ${groupId}, clientId: ${clientId}, ErrCode: ${err.code}, ErrMessage: ${err.message}`);
|
||||
throw err;
|
||||
}
|
||||
finally {
|
||||
if (consumer) {
|
||||
|
|
|
@ -1,41 +1,45 @@
|
|||
const { sleep } = require("@tdengine/websocket");
|
||||
const taos = require("@tdengine/websocket");
|
||||
|
||||
const db = 'power';
|
||||
const stable = 'meters';
|
||||
const url = 'ws://localhost:6041';
|
||||
const topic = 'topic_meters'
|
||||
const topics = [topic];
|
||||
const groupId = "group1";
|
||||
const clientId = "client1";
|
||||
|
||||
|
||||
// ANCHOR: create_consumer
|
||||
async function createConsumer() {
|
||||
|
||||
let groupId = "group1";
|
||||
let clientId = "client1";
|
||||
let configMap = new Map([
|
||||
[taos.TMQConstants.GROUP_ID, "group1"],
|
||||
[taos.TMQConstants.CLIENT_ID, 'client1'],
|
||||
[taos.TMQConstants.GROUP_ID, groupId],
|
||||
[taos.TMQConstants.CLIENT_ID, clientId],
|
||||
[taos.TMQConstants.CONNECT_USER, "root"],
|
||||
[taos.TMQConstants.CONNECT_PASS, "taosdata"],
|
||||
[taos.TMQConstants.AUTO_OFFSET_RESET, "latest"],
|
||||
[taos.TMQConstants.WS_URL, 'ws://localhost:6041'],
|
||||
[taos.TMQConstants.WS_URL, url],
|
||||
[taos.TMQConstants.ENABLE_AUTO_COMMIT, 'true'],
|
||||
[taos.TMQConstants.AUTO_COMMIT_INTERVAL_MS, '1000']
|
||||
]);
|
||||
try {
|
||||
return await taos.tmqConnect(configMap);
|
||||
conn = await taos.tmqConnect(configMap);
|
||||
console.log(`Create consumer successfully, host: ${url}, groupId: ${groupId}, clientId: ${clientId}`)
|
||||
return conn;
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
console.error(`Failed to create websocket consumer, topic: ${topic}, groupId: ${groupId}, clientId: ${clientId}, ErrCode: ${err.code}, ErrMessage: ${err.message}`);
|
||||
throw err;
|
||||
}
|
||||
|
||||
}
|
||||
// ANCHOR_END: create_consumer
|
||||
|
||||
async function prepare() {
|
||||
let conf = new taos.WSConfig('ws://localhost:6041');
|
||||
let conf = new taos.WSConfig('ws://192.168.1.98:6041');
|
||||
conf.setUser('root');
|
||||
conf.setPwd('taosdata');
|
||||
conf.setDb('power');
|
||||
const createDB = `CREATE DATABASE IF NOT EXISTS ${db} KEEP 3650 DURATION 10 BUFFER 16 WAL_LEVEL 1;`;
|
||||
const createDB = `CREATE DATABASE IF NOT EXISTS ${db}`;
|
||||
const createStable = `CREATE STABLE IF NOT EXISTS ${db}.${stable} (ts timestamp, current float, voltage int, phase float) TAGS (location binary(64), groupId int);`;
|
||||
|
||||
let wsSql = await taos.sqlConnect(conf);
|
||||
|
@ -44,58 +48,63 @@ async function prepare() {
|
|||
|
||||
let createTopic = `CREATE TOPIC IF NOT EXISTS ${topics[0]} AS SELECT * FROM ${db}.${stable}`;
|
||||
await wsSql.exec(createTopic);
|
||||
await wsSql.close();
|
||||
}
|
||||
|
||||
|
||||
for (let i = 0; i < 10; i++) {
|
||||
async function insert() {
|
||||
let conf = new taos.WSConfig('ws://localhost:6041');
|
||||
conf.setUser('root');
|
||||
conf.setPwd('taosdata');
|
||||
conf.setDb('power');
|
||||
let wsSql = await taos.sqlConnect(conf);
|
||||
for (let i = 0; i < 1; i++) {
|
||||
await wsSql.exec(`INSERT INTO d1001 USING ${stable} (location, groupId) TAGS ("California.SanFrancisco", 3) VALUES (NOW, ${10 + i}, ${200 + i}, ${0.32 + i})`);
|
||||
}
|
||||
await wsSql.close();
|
||||
}
|
||||
|
||||
// ANCHOR: subscribe
|
||||
// ANCHOR: offset
|
||||
async function subscribe(consumer) {
|
||||
try {
|
||||
await consumer.subscribe(['topic_meters']);
|
||||
for (let i = 0; i < 50; i++) {
|
||||
let res = await consumer.poll(100);
|
||||
for (let [key, value] of res) {
|
||||
// Add your data processing logic here
|
||||
console.log(`data: ${key} ${value}`);
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(`Failed to poll data, topic: ${topic}, groupId: ${groupId}, clientId: ${clientId}, ErrCode: ${err.code}, ErrMessage: ${err.message}`);
|
||||
throw err;
|
||||
}
|
||||
|
||||
}
|
||||
// ANCHOR_END: subscribe
|
||||
|
||||
// ANCHOR: offset
|
||||
async function test() {
|
||||
let consumer = null;
|
||||
try {
|
||||
await prepare();
|
||||
let consumer = await createConsumer()
|
||||
await consumer.subscribe(['topic_meters']);
|
||||
let res = new Map();
|
||||
while (res.size == 0) {
|
||||
res = await consumer.poll(100);
|
||||
await consumer.commit();
|
||||
}
|
||||
|
||||
let assignment = await consumer.assignment();
|
||||
await consumer.seekToBeginning(assignment);
|
||||
console.log("Assignment seek to beginning successfully");
|
||||
} catch (err) {
|
||||
console.error(`Failed to seek offset, topic: ${topic}, groupId: ${groupId}, clientId: ${clientId}, ErrCode: ${err.code}, ErrMessage: ${err.message}`);
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
// ANCHOR_END: offset
|
||||
|
||||
async function test() {
|
||||
let consumer = null;
|
||||
try {
|
||||
await prepare();
|
||||
consumer = await createConsumer();
|
||||
const allPromises = [];
|
||||
allPromises.push(subscribe(consumer));
|
||||
allPromises.push(insert());
|
||||
await Promise.all(allPromises);
|
||||
await consumer.unsubscribe();
|
||||
console.log("Consumer unsubscribed successfully.");
|
||||
}
|
||||
catch (err) {
|
||||
console.error(`Failed to seek offset, topic: ${topic}, groupId: ${groupId}, clientId: ${clientId}, ErrCode: ${err.code}, ErrMessage: ${err.message}`);
|
||||
console.error(`Failed to consumer, topic: ${topic}, groupId: ${groupId}, clientId: ${clientId}, ErrCode: ${err.code}, ErrMessage: ${err.message}`);
|
||||
throw err;
|
||||
}
|
||||
finally {
|
||||
if (consumer) {
|
||||
await consumer.close();
|
||||
console.log("Consumer closed successfully.");
|
||||
}
|
||||
taos.destroy();
|
||||
}
|
||||
}
|
||||
// ANCHOR_END: offset
|
||||
|
||||
test()
|
||||
|
|
|
@ -15,6 +15,7 @@ def create_connection():
|
|||
print(f"Connected to {host}:{port} successfully.");
|
||||
except Exception as err:
|
||||
print(f"Failed to connect to {host}:{port} , ErrMessage:{err}")
|
||||
raise err
|
||||
finally:
|
||||
if conn:
|
||||
conn.close()
|
||||
|
|
|
@ -15,7 +15,7 @@ def create_connection():
|
|||
print(f"Connected to {host}:{port} successfully.");
|
||||
except Exception as err:
|
||||
print(f"Failed to connect to {host}:{port} , ErrMessage:{err}")
|
||||
|
||||
raise err
|
||||
return conn
|
||||
# ANCHOR_END: connect
|
||||
|
||||
|
@ -28,6 +28,7 @@ def create_db_table(conn):
|
|||
conn.execute("CREATE TABLE IF NOT EXISTS `d0` USING `meters` (groupId, location) TAGS(0, 'Los Angles')")
|
||||
except Exception as err:
|
||||
print(f'Exception {err}')
|
||||
raise err
|
||||
# ANCHOR_END: create_db
|
||||
|
||||
def insert(conn):
|
||||
|
@ -42,9 +43,10 @@ def insert(conn):
|
|||
"""
|
||||
try:
|
||||
inserted = conn.execute(sql)
|
||||
assert inserted == 8
|
||||
assert inserted == 4
|
||||
except Exception as err:
|
||||
print(f'Exception111 {err}')
|
||||
raise err
|
||||
# ANCHOR_END: insert
|
||||
|
||||
def query(conn):
|
||||
|
@ -58,6 +60,7 @@ def query(conn):
|
|||
print(row)
|
||||
except Exception as err:
|
||||
print(f'Exception {err}')
|
||||
raise err
|
||||
# ANCHOR_END: query
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
|
|
@ -21,6 +21,7 @@ try:
|
|||
|
||||
except Exception as err:
|
||||
print(f"Failed to create database power or stable meters, ErrMessage:{err}")
|
||||
raise err
|
||||
finally:
|
||||
if conn:
|
||||
conn.close()
|
||||
|
|
|
@ -20,6 +20,7 @@ try:
|
|||
|
||||
except Exception as err:
|
||||
print(f"Failed to create database power or stable meters, ErrMessage:{err}")
|
||||
raise err
|
||||
finally:
|
||||
if conn:
|
||||
conn.close()
|
||||
|
|
|
@ -21,6 +21,7 @@ try:
|
|||
|
||||
except Exception as err:
|
||||
print(f"Failed to create database power or stable meters, ErrMessage:{err}")
|
||||
raise err
|
||||
finally:
|
||||
if conn:
|
||||
conn.close()
|
||||
|
|
|
@ -22,6 +22,7 @@ try:
|
|||
|
||||
except Exception as err:
|
||||
print(f"Failed to insert data to power.meters, sql: {sql}, ErrMessage: {err}.")
|
||||
raise err
|
||||
finally:
|
||||
if conn:
|
||||
conn.close()
|
||||
|
|
|
@ -21,6 +21,7 @@ try:
|
|||
|
||||
except Exception as err:
|
||||
print(f"Failed to insert data to power.meters, sql:{sql}, ErrMessage:{err}.")
|
||||
raise err
|
||||
finally:
|
||||
if conn:
|
||||
conn.close()
|
||||
|
|
|
@ -22,6 +22,7 @@ try:
|
|||
|
||||
except Exception as err:
|
||||
print(f"Failed to insert data to power.meters, sql: {sql}, ErrMessage: {err}.")
|
||||
raise err
|
||||
finally:
|
||||
if conn:
|
||||
conn.close()
|
||||
|
|
|
@ -16,6 +16,7 @@ try:
|
|||
|
||||
except Exception as err:
|
||||
print(f"Failed to query data from power.meters, sql: {sql}, ErrMessage:{err}")
|
||||
raise err
|
||||
finally:
|
||||
if conn:
|
||||
conn.close()
|
||||
|
|
|
@ -15,3 +15,4 @@ try:
|
|||
|
||||
except Exception as err:
|
||||
print(f"Failed to query data from power.meters, sql: {sql}, ErrMessage:{err}")
|
||||
raise err
|
||||
|
|
|
@ -15,6 +15,7 @@ try:
|
|||
|
||||
except Exception as err:
|
||||
print(f"Failed to query data from power.meters, sql: {sql}, ErrMessage:{err}")
|
||||
raise err
|
||||
finally:
|
||||
if conn:
|
||||
conn.close()
|
||||
|
|
|
@ -18,7 +18,7 @@ try:
|
|||
|
||||
except Exception as err:
|
||||
print(f"Failed to execute sql with reqId:{reqId}, ErrMessage:{err}")
|
||||
|
||||
raise err
|
||||
finally:
|
||||
if conn:
|
||||
conn.close()
|
||||
|
|
|
@ -16,3 +16,4 @@ try:
|
|||
|
||||
except Exception as err:
|
||||
print(f"Failed to execute sql with reqId:{reqId}, ErrMessage:{err}")
|
||||
raise err
|
||||
|
|
|
@ -19,6 +19,7 @@ try:
|
|||
|
||||
except Exception as err:
|
||||
print(f"Failed to execute sql with reqId:{reqId}, ErrMessage:{err}")
|
||||
raise err
|
||||
finally:
|
||||
if conn:
|
||||
conn.close()
|
||||
|
|
|
@ -35,6 +35,7 @@ try:
|
|||
print("Inserted data with schemaless successfully.");
|
||||
except Exception as err:
|
||||
print(f"Failed to insert data with schemaless, ErrMessage:{err}")
|
||||
raise err
|
||||
finally:
|
||||
if conn:
|
||||
conn.close()
|
||||
|
|
|
@ -75,8 +75,6 @@ def schemaless_insert():
|
|||
conn.close()
|
||||
|
||||
if __name__ == "__main__":
|
||||
try:
|
||||
prepare()
|
||||
schemaless_insert()
|
||||
except Exception as err:
|
||||
print(f"Failed to insert data with schemaless, err:{err}")
|
||||
prepare()
|
||||
schemaless_insert()
|
||||
|
||||
|
|
|
@ -57,6 +57,7 @@ try:
|
|||
|
||||
except Exception as err:
|
||||
print(f"Failed to insert to table meters using stmt, ErrMessage:{err}")
|
||||
raise err
|
||||
finally:
|
||||
if stmt:
|
||||
stmt.close()
|
||||
|
|
|
@ -62,6 +62,7 @@ try:
|
|||
|
||||
except Exception as err:
|
||||
print(f"Failed to insert to table meters using stmt, ErrMessage:{err}")
|
||||
raise err
|
||||
finally:
|
||||
if stmt:
|
||||
stmt.close()
|
||||
|
|
|
@ -152,6 +152,7 @@ def unsubscribe(consumer):
|
|||
print("Consumer unsubscribed successfully.");
|
||||
except Exception as err:
|
||||
print(f"Failed to unsubscribe consumer. topic: {topic}, groupId: {groupId}, clientId: {clientId}, ErrMessage:{err}.")
|
||||
raise err
|
||||
finally:
|
||||
if consumer:
|
||||
consumer.close()
|
||||
|
@ -166,7 +167,6 @@ if __name__ == "__main__":
|
|||
subscribe(consumer)
|
||||
seek_offset(consumer)
|
||||
commit_offset(consumer)
|
||||
except Exception as err:
|
||||
print(f"Failed to execute consumer example, topic: {topic}, groupId: {groupId}, clientId: {clientId}, ErrMessage:{err}.")
|
||||
finally:
|
||||
unsubscribe(consumer);
|
||||
if consumer:
|
||||
unsubscribe(consumer);
|
||||
|
|
|
@ -31,7 +31,7 @@ def prepareMeta():
|
|||
|
||||
# create super table
|
||||
rowsAffected = conn.execute(
|
||||
"CREATE TABLE IF NOT EXISTS `meters` (`ts` TIMESTAMP, `current` FLOAT, `voltage` INT, `phase` FLOAT) TAGS (`groupid` INT, `location` BINARY(16))"
|
||||
"CREATE TABLE IF NOT EXISTS `meters` (`ts` TIMESTAMP, `current` FLOAT, `voltage` INT, `phase` FLOAT) TAGS (`groupid` INT, `location` BINARY(64))"
|
||||
)
|
||||
assert rowsAffected == 0
|
||||
|
||||
|
@ -155,6 +155,7 @@ def unsubscribe(consumer):
|
|||
print("Consumer unsubscribed successfully.");
|
||||
except Exception as err:
|
||||
print(f"Failed to unsubscribe consumer. topic: {topic}, groupId: {groupId}, clientId: {clientId}, ErrMessage:{err}.")
|
||||
raise err
|
||||
finally:
|
||||
if consumer:
|
||||
consumer.close()
|
||||
|
@ -170,7 +171,6 @@ if __name__ == "__main__":
|
|||
subscribe(consumer)
|
||||
seek_offset(consumer)
|
||||
commit_offset(consumer)
|
||||
except Exception as err:
|
||||
print(f"Failed to execute consumer example, topic: {topic}, groupId: {groupId}, clientId: {clientId}, ErrMessage:{err}.")
|
||||
finally:
|
||||
unsubscribe(consumer)
|
||||
if consumer:
|
||||
unsubscribe(consumer)
|
||||
|
|
|
@ -83,7 +83,6 @@ async fn main() -> anyhow::Result<()> {
|
|||
eprintln!("Failed to execute insert: {:?}", e);
|
||||
}
|
||||
tokio::time::sleep(Duration::from_millis(10)).await;
|
||||
println!("Succed to execute insert 1 row");
|
||||
}
|
||||
});
|
||||
});
|
||||
|
|
|
@ -181,7 +181,7 @@ INTERVAL(interval_val [, interval_offset])
|
|||
- FILL:用于指定窗口区间数据缺失的情况下,数据的填充模式。
|
||||
|
||||
对于时间窗口,interval_val 和 sliding_val 都表示时间段, 语法上支持三种方式。例如:
|
||||
1. INTERVAL(1s, 500a) SLIDING(1s),带时间单位的形式,其中的时间单位是单字符表示, 分别为: a (毫秒), b (纳秒), d (天), h (小时), m (分钟), n (月), s (秒), u (微妙), w (周), y (年);
|
||||
1. INTERVAL(1s, 500a) SLIDING(1s),带时间单位的形式,其中的时间单位是单字符表示, 分别为: a (毫秒), b (纳秒), d (天), h (小时), m (分钟), n (月), s (秒), u (微秒), w (周), y (年);
|
||||
2. INTERVAL(1000, 500) SLIDING(1000),不带时间单位的形式,将使用查询库的时间精度作为默认时间单位,当存在多个库时默认采用精度更高的库;
|
||||
3. INTERVAL('1s', '500a') SLIDING('1s'),带时间单位的字符串形式,字符串内部不能有任何空格等其它字符。
|
||||
|
||||
|
|
|
@ -208,3 +208,15 @@ CSV 文件中的每个 Row 配置一个 OPC 数据点位。Row 的规则如下
|
|||
### 8. 创建完成
|
||||
|
||||
点击 **提交** 按钮,完成创建 OPC UA 到 TDengine 的数据同步任务,回到**数据源列表**页面可查看任务执行情况。
|
||||
|
||||
## 增加数据点位
|
||||
|
||||
在任务运行中,点击 **编辑**,点击 **增加数据点位** 按钮,追加数据点位到 CSV 文件中。
|
||||
|
||||

|
||||
|
||||
在弹出的表单中,填写数据点位的信息。
|
||||
|
||||

|
||||
|
||||
点击 **确定** 按钮,完成数据点位的追加。
|
|
@ -182,3 +182,15 @@ CSV 文件中的每个 Row 配置一个 OPC 数据点位。Row 的规则如下
|
|||
### 7. 创建完成
|
||||
|
||||
点击 **提交** 按钮,完成创建 OPC DA 到 TDengine 的数据同步任务,回到**数据源列表**页面可查看任务执行情况。
|
||||
|
||||
## 增加数据点位
|
||||
|
||||
在任务运行中,点击 **编辑**,点击 **增加数据点位** 按钮,追加数据点位到 CSV 文件中。
|
||||
|
||||

|
||||
|
||||
在弹出的表单中,填写数据点位的信息。
|
||||
|
||||

|
||||
|
||||
点击 **确定** 按钮,完成数据点位的追加。
|
|
@ -44,8 +44,50 @@ TDengine 可以高效地从 Kafka 读取数据并将其写入 TDengine,以实
|
|||
|
||||
如果服务端开启了 SASL 认证机制,此处需要启用 SASL 并配置相关内容,目前支持 PLAIN/SCRAM-SHA-256/GSSAPI 三种认证机制,请按实际情况进行选择。
|
||||
|
||||
#### 4.1. PLAIN 认证
|
||||
|
||||
选择 `PLAIN` 认证机制,输入用户名和密码:
|
||||
|
||||

|
||||
|
||||
#### 4.1. SCRAM(SCRAM-SHA-256) 认证
|
||||
|
||||
选择 `SCRAM-SHA-256` 认证机制,输入用户名和密码:
|
||||
|
||||

|
||||
|
||||
#### 4.3. GSSAPI 认证
|
||||
|
||||
选择 `GSSAPI` ,将通过 [RDkafka 客户端](https://github.com/confluentinc/librdkafka) 调用 GSSAPI 应用 Kerberos 认证机制:
|
||||
|
||||

|
||||
|
||||
需要输入的信息有:
|
||||
|
||||
- Kerberos 服务名,一般是 `kafka`;
|
||||
- Kerberos 认证主体,即认证用户名,例如 `kafkaclient`;
|
||||
- Kerberos 初始化命令(可选,一般不用填写);
|
||||
- Kerberos 密钥表,需提供文件并上传;
|
||||
|
||||
以上信息均需由 Kafka 服务管理者提供。
|
||||
|
||||
除此之外,在服务器上需要配置 [Kerberos](https://web.mit.edu/kerberos/) 认证服务。在 Ubuntu 下使用 `apt install krb5-user` ;在 CentOS 下,使用 `yum install krb5-workstation`;即可。
|
||||
|
||||
配置完成后,可以使用 [kcat](https://github.com/edenhill/kcat) 工具进行 Kafka 主题消费验证:
|
||||
|
||||
```bash
|
||||
kcat <topic> \
|
||||
-b <kafka-server:port> \
|
||||
-G kcat \
|
||||
-X security.protocol=SASL_PLAINTEXT \
|
||||
-X sasl.mechanism=GSSAPI \
|
||||
-X sasl.kerberos.keytab=</path/to/kafkaclient.keytab> \
|
||||
-X sasl.kerberos.principal=<kafkaclient> \
|
||||
-X sasl.kerberos.service.name=kafka
|
||||
```
|
||||
|
||||
如果出现错误:“Server xxxx not found in kerberos database”,则需要配置 Kafka 节点对应的域名并在 Kerberos 客户端配置文件 `/etc/krb5.conf` 中配置反向域名解析 `rdns = true`。
|
||||
|
||||
### 5. 配置 SSL 证书
|
||||
|
||||
如果服务端开启了 SSL 加密认证,此处需要启用 SSL 并配置相关内容。
|
||||
|
@ -160,4 +202,4 @@ json 数据支持 JSONObject 或者 JSONArray,使用 json 解析器可以解
|
|||
|
||||
### 9. 创建完成
|
||||
|
||||
点击 **提交** 按钮,完成创建 Kafka 到 TDengine 的数据同步任务,回到**数据源列表**页面可查看任务执行情况。
|
||||
点击 **提交** 按钮,完成创建 Kafka 到 TDengine 的数据同步任务,回到**数据源列表**页面可查看任务执行情况。
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 43 KiB |
Binary file not shown.
After Width: | Height: | Size: 20 KiB |
Binary file not shown.
After Width: | Height: | Size: 175 KiB |
Binary file not shown.
After Width: | Height: | Size: 67 KiB |
|
@ -387,7 +387,19 @@ DSN 的详细说明和如何使用详见 [连接功能](../../reference/connecto
|
|||
- `reconnectIntervalMs`:重连间隔毫秒时间,默认为 2000。
|
||||
</TabItem>
|
||||
<TabItem label="C" value="c">
|
||||
C/C++ 语言连接器使用 `taos_connect()` 函数用于建立与 TDengine 数据库的连接。其参数详细说明如下:
|
||||
**Websocket 连接**
|
||||
C/C++ 语言连接器 Websocket 连接方式使用 `ws_connect()` 函数用于建立与 TDengine 数据库的连接。其参数为 DSN 描述字符串,其基本结构如下:
|
||||
|
||||
```text
|
||||
<driver>[+<protocol>]://[[<username>:<password>@]<host>:<port>][/<database>][?<p1>=<v1>[&<p2>=<v2>]]
|
||||
|------|------------|---|-----------|-----------|------|------|------------|-----------------------|
|
||||
|driver| protocol | | username | password | host | port | database | params |
|
||||
```
|
||||
|
||||
DSN 的详细说明和如何使用详见 [连接功能](../../reference/connector/cpp/#dsn)
|
||||
|
||||
**原生连接**
|
||||
C/C++ 语言连接器原生连接方式使用 `taos_connect()` 函数用于建立与 TDengine 数据库的连接。其参数详细说明如下:
|
||||
|
||||
- `host`:要连接的数据库服务器的主机名或IP地址。如果是本地数据库,可以使用 `"localhost"`。
|
||||
- `user`:用于登录数据库的用户名。
|
||||
|
@ -440,7 +452,10 @@ C/C++ 语言连接器使用 `taos_connect()` 函数用于建立与 TDengine 数
|
|||
```
|
||||
</TabItem>
|
||||
<TabItem label="C" value="c">
|
||||
不支持
|
||||
```c
|
||||
{{#include docs/examples/c-ws/connect_example.c}}
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem label="REST API" value="rest">
|
||||
不支持
|
||||
|
|
|
@ -68,9 +68,15 @@ REST API:直接调用 `taosadapter` 提供的 REST API 接口,进行数据
|
|||
```
|
||||
</TabItem>
|
||||
<TabItem label="C" value="c">
|
||||
```c
|
||||
|
||||
```c title="Websocket 连接"
|
||||
{{#include docs/examples/c-ws/create_db_demo.c:create_db_and_table}}
|
||||
```
|
||||
|
||||
```c title="原生连接"
|
||||
{{#include docs/examples/c/create_db_demo.c:create_db_and_table}}
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem label="REST API" value="rest">
|
||||
|
||||
|
@ -144,7 +150,12 @@ NOW 为系统内部函数,默认为客户端所在计算机当前时间。 NOW
|
|||
```
|
||||
</TabItem>
|
||||
<TabItem label="C" value="c">
|
||||
```c
|
||||
|
||||
```c title="Websocket 连接"
|
||||
{{#include docs/examples/c-ws/insert_data_demo.c:insert_data}}
|
||||
```
|
||||
|
||||
```c title="原生连接"
|
||||
{{#include docs/examples/c/insert_data_demo.c:insert_data}}
|
||||
```
|
||||
|
||||
|
@ -218,7 +229,12 @@ rust 连接器还支持使用 **serde** 进行反序列化行为结构体的结
|
|||
```
|
||||
</TabItem>
|
||||
<TabItem label="C" value="c">
|
||||
```c
|
||||
|
||||
```c title="Websocket 连接"
|
||||
{{#include docs/examples/c-ws/query_data_demo.c:query_data}}
|
||||
```
|
||||
|
||||
```c title="原生连接"
|
||||
{{#include docs/examples/c/query_data_demo.c:query_data}}
|
||||
```
|
||||
</TabItem>
|
||||
|
@ -293,9 +309,15 @@ reqId 可用于请求链路追踪,reqId 就像分布式系统中的 traceId
|
|||
```
|
||||
</TabItem>
|
||||
<TabItem label="C" value="c">
|
||||
```c
|
||||
|
||||
```c "Websocket 连接"
|
||||
{{#include docs/examples/c-ws/with_reqid_demo.c:with_reqid}}
|
||||
```
|
||||
|
||||
```c "原生连接"
|
||||
{{#include docs/examples/c/with_reqid_demo.c:with_reqid}}
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem label="REST API" value="rest">
|
||||
|
||||
|
|
|
@ -237,7 +237,10 @@ writer.write(lineDemo, SchemalessProtocolType.LINE, SchemalessTimestampType.NANO
|
|||
```
|
||||
</TabItem>
|
||||
<TabItem label="C" value="c">
|
||||
不支持
|
||||
|
||||
```c
|
||||
{{#include docs/examples/c-ws/sml_insert_demo.c:schemaless}}
|
||||
```
|
||||
</TabItem>
|
||||
<TabItem label="REST API" value="rest">
|
||||
不支持
|
||||
|
|
|
@ -64,7 +64,9 @@ import TabItem from "@theme/TabItem";
|
|||
```
|
||||
</TabItem>
|
||||
<TabItem label="C" value="c">
|
||||
不支持
|
||||
```c
|
||||
{{#include docs/examples/c-ws/stmt_insert_demo.c}}
|
||||
```
|
||||
</TabItem>
|
||||
<TabItem label="REST API" value="rest">
|
||||
不支持
|
||||
|
|
|
@ -28,21 +28,21 @@ TDengine 消费者的概念跟 Kafka 类似,消费者通过订阅主题来接
|
|||
### 创建参数
|
||||
创建消费者的参数较多,非常灵活的支持了各种连接类型、 Offset 提交方式、压缩、重连、反序列化等特性。各语言连接器都适用的通用基础配置项如下表所示:
|
||||
|
||||
| 参数名称 | 类型 | 参数说明 | 备注 |
|
||||
| :-----------------------: | :-----: | ----------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `td.connect.ip` | string | 服务端的 IP 地址 | |
|
||||
| `td.connect.user` | string | 用户名 | |
|
||||
| `td.connect.pass` | string | 密码 | |
|
||||
| `td.connect.port` | integer | 服务端的端口号 | |
|
||||
| `group.id` | string | 消费组 ID,同一消费组共享消费进度 | <br />**必填项**。最大长度:192。<br />每个topic最多可建立 100 个 consumer group |
|
||||
| `client.id` | string | 客户端 ID | 最大长度:192 |
|
||||
| `auto.offset.reset` | enum | 消费组订阅的初始位置 | <br />`earliest`: default(version < 3.2.0.0);从头开始订阅; <br/>`latest`: default(version >= 3.2.0.0);仅从最新数据开始订阅; <br/>`none`: 没有提交的 offset 无法订阅 |
|
||||
| `enable.auto.commit` | boolean | 是否启用消费位点自动提交,true: 自动提交,客户端应用无需commit;false:客户端应用需要自行commit | 默认值为 true |
|
||||
| `auto.commit.interval.ms` | integer | 消费记录自动提交消费位点时间间隔,单位为毫秒 | 默认值为 5000 |
|
||||
| `msg.with.table.name` | boolean | 是否允许从消息中解析表名, 不适用于列订阅(列订阅时可将 tbname 作为列写入 subquery 语句)(从3.2.0.0版本该参数废弃,恒为true) | 默认关闭 |
|
||||
| `enable.replay` | boolean | 是否开启数据回放功能 | 默认关闭 |
|
||||
| `session.timeout.ms` | integer | consumer 心跳丢失后超时时间,超时后会触发 rebalance 逻辑,成功后该 consumer 会被删除(从3.3.3.0版本开始支持) | 默认值为 12000,取值范围 [6000, 1800000] |
|
||||
| `max.poll.interval.ms` | integer | consumer poll 拉取数据间隔的最长时间,超过该时间,会认为该 consumer 离线,触发rebalance 逻辑,成功后该 consumer 会被删除(从3.3.3.0版本开始支持) | 默认值为 300000,[1000,INT32_MAX] |
|
||||
| 参数名称 | 类型 | 参数说明 | 备注 |
|
||||
| :-----------------------: | :-----: | ------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `td.connect.ip` | string | 服务端的 IP 地址 | |
|
||||
| `td.connect.user` | string | 用户名 | |
|
||||
| `td.connect.pass` | string | 密码 | |
|
||||
| `td.connect.port` | integer | 服务端的端口号 | |
|
||||
| `group.id` | string | 消费组 ID,同一消费组共享消费进度 | <br />**必填项**。最大长度:192。<br />每个topic最多可建立 100 个 consumer group |
|
||||
| `client.id` | string | 客户端 ID | 最大长度:192 |
|
||||
| `auto.offset.reset` | enum | 消费组订阅的初始位置 | <br />`earliest`: default(version < 3.2.0.0);从头开始订阅; <br/>`latest`: default(version >= 3.2.0.0);仅从最新数据开始订阅; <br/>`none`: 没有提交的 offset 无法订阅 |
|
||||
| `enable.auto.commit` | boolean | 是否启用消费位点自动提交,true: 自动提交,客户端应用无需commit;false:客户端应用需要自行commit | 默认值为 true |
|
||||
| `auto.commit.interval.ms` | integer | 消费记录自动提交消费位点时间间隔,单位为毫秒 | 默认值为 5000 |
|
||||
| `msg.with.table.name` | boolean | 是否允许从消息中解析表名, 不适用于列订阅(列订阅时可将 tbname 作为列写入 subquery 语句)(从3.2.0.0版本该参数废弃,恒为true) | 默认关闭 |
|
||||
| `enable.replay` | boolean | 是否开启数据回放功能 | 默认关闭 |
|
||||
| `session.timeout.ms` | integer | consumer 心跳丢失后超时时间,超时后会触发 rebalance 逻辑,成功后该 consumer 会被删除(从3.3.3.0版本开始支持) | 默认值为 12000,取值范围 [6000, 1800000] |
|
||||
| `max.poll.interval.ms` | integer | consumer poll 拉取数据间隔的最长时间,超过该时间,会认为该 consumer 离线,触发rebalance 逻辑,成功后该 consumer 会被删除(从3.3.3.0版本开始支持) | 默认值为 300000,[1000,INT32_MAX] |
|
||||
|
||||
|
||||
下面是各语言连接器创建参数:
|
||||
|
@ -94,8 +94,8 @@ Rust 连接器创建消费者的参数为 DSN, 可以设置的参数列表请
|
|||
|
||||
</TabItem>
|
||||
<TabItem label="C" value="c">
|
||||
|
||||
同通用基础配置项。
|
||||
- Websocket 连接: 因为使用 dsn,不需要 `td.connect.ip`,`td.connect.port`,`td.connect.user` 和 `td.connect.pass` 四个配置项,其余同通用配置项。
|
||||
- 原生连接: 同通用基础配置项。
|
||||
|
||||
</TabItem>
|
||||
<TabItem label="REST API" value="rest">
|
||||
|
@ -154,7 +154,15 @@ Rust 连接器创建消费者的参数为 DSN, 可以设置的参数列表请
|
|||
```
|
||||
</TabItem>
|
||||
<TabItem label="C" value="c">
|
||||
不支持
|
||||
```c
|
||||
{{#include docs/examples/c-ws/tmq_demo.c:create_consumer_1}}
|
||||
```
|
||||
|
||||
```c
|
||||
{{#include docs/examples/c-ws/tmq_demo.c:create_consumer_2}}
|
||||
```
|
||||
|
||||
调用 `build_consumer` 函数尝试获取消费者实例 `tmq`。成功则打印成功日志,失败则打印失败日志。
|
||||
</TabItem>
|
||||
<TabItem label="REST API" value="rest">
|
||||
不支持
|
||||
|
@ -283,7 +291,29 @@ Rust 连接器创建消费者的参数为 DSN, 可以设置的参数列表请
|
|||
```
|
||||
</TabItem>
|
||||
<TabItem label="C" value="c">
|
||||
不支持
|
||||
```c
|
||||
{{#include docs/examples/c-ws/tmq_demo.c:build_topic_list}}
|
||||
```
|
||||
|
||||
```c
|
||||
{{#include docs/examples/c-ws/tmq_demo.c:basic_consume_loop}}
|
||||
```
|
||||
|
||||
```c
|
||||
{{#include docs/examples/c-ws/tmq_demo.c:msg_process}}
|
||||
```
|
||||
|
||||
```c
|
||||
{{#include docs/examples/c-ws/tmq_demo.c:subscribe_3}}
|
||||
```
|
||||
|
||||
订阅消费数据步骤:
|
||||
1. 调用 `ws_build_topic_list` 函数创建一个主题列表 `topic_list`。
|
||||
2. 如果 `topic_list` 为 `NULL`,表示创建失败,函数返回 `-1`。
|
||||
3. 使用 `ws_tmq_subscribe` 函数订阅 `tmq` 指定的主题列表。如果订阅失败,打印错误信息。
|
||||
4. 销毁主题列表 `topic_list` 以释放资源。
|
||||
5. 调用 `basic_consume_loop` 函数开始基本的消费循环,处理订阅的消息。
|
||||
|
||||
</TabItem>
|
||||
<TabItem label="REST API" value="rest">
|
||||
不支持
|
||||
|
@ -427,7 +457,17 @@ Rust 连接器创建消费者的参数为 DSN, 可以设置的参数列表请
|
|||
```
|
||||
</TabItem>
|
||||
<TabItem label="C" value="c">
|
||||
不支持
|
||||
```c
|
||||
{{#include docs/examples/c-ws/tmq_demo.c:consume_repeatly}}
|
||||
```
|
||||
|
||||
1. 通过 `ws_tmq_get_topic_assignment` 函数获取特定主题的分配信息,包括分配的数量和具体分配详情。
|
||||
2. 如果获取分配信息失败,则打印错误信息并返回。
|
||||
3. 对于每个分配,使用 `ws_tmq_offset_seek` 函数将消费者的偏移量设置到最早的偏移量。
|
||||
4. 如果设置偏移量失败,则打印错误信息。
|
||||
5. 释放分配信息数组以释放资源。
|
||||
6. 调用 `basic_consume_loop` 函数开始新的消费循环,处理消息。
|
||||
|
||||
</TabItem>
|
||||
<TabItem label="REST API" value="rest">
|
||||
不支持
|
||||
|
@ -554,7 +594,12 @@ Rust 连接器创建消费者的参数为 DSN, 可以设置的参数列表请
|
|||
```
|
||||
</TabItem>
|
||||
<TabItem label="C" value="c">
|
||||
不支持
|
||||
```c
|
||||
{{#include docs/examples/c-ws/tmq_demo.c:manual_commit}}
|
||||
```
|
||||
|
||||
可以通过 `ws_tmq_commit_sync` 函数来手工提交消费进度。
|
||||
|
||||
</TabItem>
|
||||
<TabItem label="REST API" value="rest">
|
||||
不支持
|
||||
|
@ -662,7 +707,9 @@ Rust 连接器创建消费者的参数为 DSN, 可以设置的参数列表请
|
|||
```
|
||||
</TabItem>
|
||||
<TabItem label="C" value="c">
|
||||
不支持
|
||||
```c
|
||||
{{#include docs/examples/c-ws/tmq_demo.c:unsubscribe_and_close}}
|
||||
```
|
||||
</TabItem>
|
||||
<TabItem label="REST API" value="rest">
|
||||
不支持
|
||||
|
@ -777,7 +824,13 @@ Rust 连接器创建消费者的参数为 DSN, 可以设置的参数列表请
|
|||
</details>
|
||||
</TabItem>
|
||||
<TabItem label="C" value="c">
|
||||
不支持
|
||||
<details>
|
||||
<summary>完整代码示例</summary>
|
||||
```c
|
||||
{{#include docs/examples/c-ws/tmq_demo.c}}
|
||||
```
|
||||
</details>
|
||||
|
||||
</TabItem>
|
||||
<TabItem label="REST API" value="rest">
|
||||
不支持
|
||||
|
|
|
@ -14,7 +14,8 @@ description: 让开发者能够快速上手的指南
|
|||
7. 在很多场景下(如车辆管理),应用需要获取每个数据采集点的最新状态,那么建议你采用 TDengine 的 Cache 功能,而不用单独部署 Redis 等缓存软件。
|
||||
8. 如果你发现 TDengine 的函数无法满足你的要求,那么你可以使用用户自定义函数(UDF)来解决问题。
|
||||
|
||||
本部分内容就是按照上述顺序组织的。为便于理解,TDengine 为每个功能和每个支持的编程语言都提供了示例代码。如果你希望深入了解 SQL 的使用,需要查看[SQL 手册](../reference/taos-sql/)。如果想更深入地了解各连接器的使用,请阅读[连接器参考指南](../reference/connector/)。如果还希望想将 TDengine 与第三方系统集成起来,比如 Grafana, 请参考[第三方工具](../third-party/)。
|
||||
本部分内容就是按照上述顺序组织的。为便于理解,TDengine 为每个功能和每个支持的编程语言都提供了示例代码,位于 [示例代码](https://github.com/taosdata/TDengine/tree/main/docs/examples)。所有示例代码都会有 CI 保证正确性,脚本位于 [示例代码 CI](https://github.com/taosdata/TDengine/tree/main/tests/docs-examples-test)。
|
||||
如果你希望深入了解 SQL 的使用,需要查看[SQL 手册](../reference/taos-sql/)。如果想更深入地了解各连接器的使用,请阅读[连接器参考指南](../reference/connector/)。如果还希望想将 TDengine 与第三方系统集成起来,比如 Grafana, 请参考[第三方工具](../third-party/)。
|
||||
|
||||
如果在开发过程中遇到任何问题,请点击每个页面下方的["反馈问题"](https://github.com/taosdata/TDengine/issues/new/choose), 在 GitHub 上直接递交 Issue。
|
||||
|
||||
|
|
|
@ -421,7 +421,6 @@ taosX 会将监控指标上报给 taosKeeper,这些监控指标会被 taosKeep
|
|||
| write_raw_fails | 本次运行写入 raw meta 失败的次数 |
|
||||
| success_blocks | 本次写入成功的数据块数 |
|
||||
|
||||
|
||||
### taosX 其他数据源 任务
|
||||
|
||||
这些数据源包括: InfluxDB,OpenTSDB,OPC UA,OPC DA,PI,CSV,MQTT,AVEVA Historian 和 Kafka。
|
||||
|
@ -452,3 +451,93 @@ taosX 会将监控指标上报给 taosKeeper,这些监控指标会被 taosKeep
|
|||
| written_blocks | 本次运行此任务写人成功的 raw block 数 |
|
||||
| failed_blocks | 本次运行此任务写入失败的 raw block 数 |
|
||||
|
||||
## taosX 数据解析插件
|
||||
|
||||
接入 kafka / mqtt 消息中间件时,需要对原始数据进行解析,如果使用 json/regex 等模式解析器无法满足解析需求,同时 UDT(自定义解析脚本) 也无法满足性能要求时,可以自定义数据解析插件。
|
||||
|
||||
### 插件概述
|
||||
|
||||
taosX Parser 插件是一个要求用 C/Rust 语言开发的 C ABI 兼容动态库,该动态库要实现约定的 API 并编译为在 taosX 所在运行环境中能够正确运行的动态库,然后复制到约定位置由 taosX 在运行时加载,并在处理数据的 Parsing 阶段调用。
|
||||
|
||||
### 插件部署
|
||||
|
||||
完成插件开发后,编译环境需要和目标运行环境兼容,将编译好的插件动态库复制到插件目录下,taosX 启动后,系统首次使用插件时初始化加载插件。可以在 explorer 的 kafka 或者 mqtt 数据接入配置页面中,检查是否加载成功。如下图,如果加载成功,则在解析器选择列表中展示出来。
|
||||
|
||||

|
||||
|
||||
插件目录在 `taosx.toml` 配置文件中复用 plugins 配置,追加`/parsers`作为插件安装路径,默认值在 UNIX 环境下为 `/usr/local/taos/plugins/parsers`,在 Windows 下为 `C:\TDengine\plugins\parsers`。
|
||||
|
||||
### 插件 api 说明
|
||||
|
||||
#### 1. 获取插件名称
|
||||
|
||||
获取插件名,用于前端显示。
|
||||
|
||||
**函数签名**:const char* parser_name()
|
||||
|
||||
**返回值**:字符串。
|
||||
|
||||
#### 2. 获取插件版本
|
||||
|
||||
插件版本,方便问题定位。
|
||||
|
||||
**函数签名**:const char* parser_version()
|
||||
|
||||
**返回值**:字符串。
|
||||
|
||||
#### 3. 配置解析器
|
||||
|
||||
将一个字符串参数解析为一个配置对象,仅插件内部使用。
|
||||
|
||||
**函数签名**:parser_resp_t parser_new(char* ctx, uint32_t len);
|
||||
|
||||
char* ctx: 用户自定义配置字符串。
|
||||
|
||||
uint32_t len: 该字符串的二进制长度(不含 `\0`)。
|
||||
|
||||
**返回值**:
|
||||
|
||||
``` c
|
||||
struct parser_resp_t {
|
||||
int e; // 0 if success.
|
||||
void* p; // Success if contains.
|
||||
}
|
||||
```
|
||||
|
||||
当创建对象失败时,e 不为 0。
|
||||
|
||||
当创建成功时,e = 0,p 为解析器对象。
|
||||
|
||||
#### 4. 解析数据
|
||||
|
||||
**函数签名**:
|
||||
|
||||
对输入 payload 进行解析,返回结果为 JSON 格式 [u8] 。返回的 JSON 将使用默认的 JSON 解析器进行完全解码(展开根数组和所有的对象)。
|
||||
|
||||
``` c
|
||||
const char* parser_mutate(
|
||||
void* parser,
|
||||
const uint8_t* in_ptr, uint32_t in_len,
|
||||
const void* uint8_t* out_ptr, uint32_t* out_len
|
||||
);
|
||||
```
|
||||
|
||||
`void* parser`: parser_new 生成的对象指针;
|
||||
|
||||
`const uint8_t* in_ptr`:输入 Payload 的指针;
|
||||
|
||||
`uint32_t in_len`: 输入 Payload 的 bytes 长度(不含 `\0`);
|
||||
|
||||
`const void* uint8_t* out_ptr`:输出 JSON 字符串的指针(不含 \0)。当 out_ptr 指向为空时,表示输出为空。
|
||||
|
||||
`uint32_t * out_len`:输出 JSON 字符串长度。
|
||||
|
||||
**返回值**: 当调用成功时,返回值为 NULL。
|
||||
|
||||
#### 5. 释放解析器
|
||||
|
||||
释放解析器对象内存。
|
||||
|
||||
**函数签名**: void parser_free(void* parser);
|
||||
|
||||
void* parser: parser_new 生成的对象指针。
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 27 KiB |
|
@ -80,7 +80,6 @@ database_option: {
|
|||
|
||||
```sql
|
||||
create database if not exists db vgroups 10 buffer 10
|
||||
|
||||
```
|
||||
|
||||
以上示例创建了一个有 10 个 vgroup 名为 db 的数据库, 其中每个 vnode 分配 10MB 的写入缓存
|
||||
|
|
|
@ -1214,7 +1214,7 @@ TO_TIMESTAMP(ts_str_literal, format_str_literal)
|
|||
- 如果没有指定完整的时间,那么默认时间值为指定或默认时区的 `1970-01-01 00:00:00`, 未指定部分使用该默认值中的对应部分. 暂不支持只指定年日而不指定月日的格式, 如'yyyy-mm-DDD', 支持'yyyy-mm-DD'.
|
||||
- 如果格式串中有`AM`, `PM`等, 那么小时必须是12小时制, 范围必须是01-12.
|
||||
- `to_timestamp`转换具有一定的容错机制, 在格式串和时间戳串不完全对应时, 有时也可转换, 如: `to_timestamp('200101/2', 'yyyyMM1/dd')`, 格式串中多出来的1会被丢弃. 格式串与时间戳串中多余的空格字符(空格, tab等)也会被 自动忽略. 如`to_timestamp(' 23 年 - 1 月 - 01 日 ', 'yy 年-MM月-dd日')` 可以被成功转换. 虽然`MM`等字段需要两个数字对应(只有一位时前面补0), 在`to_timestamp`时, 一个数字也可以成功转换.
|
||||
- 输出时间戳的精度与查询表的精度相同, 若查询未指定表, 则输出精度为毫秒. 如`select to_timestamp('2023-08-1 10:10:10.123456789', 'yyyy-mm-dd hh:mi:ss.ns')`的输出将会把微妙和纳秒进行截断. 如果指定一张纳秒表, 那么就不会发生截断, 如`select to_timestamp('2023-08-1 10:10:10.123456789', 'yyyy-mm-dd hh:mi:ss.ns') from db_ns.table_ns limit 1`.
|
||||
- 输出时间戳的精度与查询表的精度相同, 若查询未指定表, 则输出精度为毫秒. 如`select to_timestamp('2023-08-1 10:10:10.123456789', 'yyyy-mm-dd hh:mi:ss.ns')`的输出将会把微秒和纳秒进行截断. 如果指定一张纳秒表, 那么就不会发生截断, 如`select to_timestamp('2023-08-1 10:10:10.123456789', 'yyyy-mm-dd hh:mi:ss.ns') from db_ns.table_ns limit 1`.
|
||||
|
||||
|
||||
### 时间和日期函数
|
||||
|
|
|
@ -41,9 +41,11 @@ TDengine 支持 `UNION ALL` 和 `UNION` 操作符。UNION ALL 将查询返回的
|
|||
| 5 | IS [NOT] NULL | 所有类型 | 是否为空值 |
|
||||
| 6 | [NOT] BETWEEN AND | 除 BOOL、BLOB、MEDIUMBLOB、JSON 和 GEOMETRY 外的所有类型 | 闭区间比较 |
|
||||
| 7 | IN | 除 BLOB、MEDIUMBLOB 和 JSON 外的所有类型,且不可以为表的时间戳主键列 | 与列表内的任意值相等 |
|
||||
| 8 | LIKE | BINARY、NCHAR 和 VARCHAR | 通配符匹配 |
|
||||
| 9 | MATCH, NMATCH | BINARY、NCHAR 和 VARCHAR | 正则表达式匹配 |
|
||||
| 10 | CONTAINS | JSON | JSON 中是否存在某键 |
|
||||
| 8 | NOT IN | 除 BLOB、MEDIUMBLOB 和 JSON 外的所有类型,且不可以为表的时间戳主键列 | 与列表内的任意值都不相等 |
|
||||
| 9 | LIKE | BINARY、NCHAR 和 VARCHAR | 通配符匹配所指定的模式串 |
|
||||
| 10 | NOT LIKE | BINARY、NCHAR 和 VARCHAR | 通配符不匹配所指定的模式串 |
|
||||
| 11 | MATCH, NMATCH | BINARY、NCHAR 和 VARCHAR | 正则表达式匹配 |
|
||||
| 12 | CONTAINS | JSON | JSON 中是否存在某键 |
|
||||
|
||||
LIKE 条件使用通配符字符串进行匹配检查,规则如下:
|
||||
|
||||
|
|
|
@ -28,7 +28,7 @@ TSMA只能基于超级表和普通表创建, 不能基于子表创建.
|
|||
|
||||
由于TSMA输出为一张超级表, 因此输出表的行长度受最大行长度限制, 不同函数的`中间结果`大小各异, 一般都大于原始数据大小, 若输出表的行长度大于最大行长度限制, 将会报`Row length exceeds max length`错误. 此时需要减少函数个数或者将常用的函数进行分组拆分到多个TSMA中.
|
||||
|
||||
窗口大小的限制为[1m ~ 1y/12n]. INTERVAL 的单位与查询中INTERVAL子句相同, 如 a (毫秒), b (纳秒), h (小时), m (分钟), s (秒), u (微妙), d (天), w(周), n(月), y(年).
|
||||
窗口大小的限制为[1m ~ 1y/12n]. INTERVAL 的单位与查询中INTERVAL子句相同, 如 a (毫秒), b (纳秒), h (小时), m (分钟), s (秒), u (微秒), d (天), w(周), n(月), y(年).
|
||||
|
||||
TSMA为库内对象, 但名字全局唯一. 集群内一共可创建TSMA个数受参数`maxTsmaNum`限制, 参数默认值为3, 范围: [0-3]. 注意, 由于TSMA后台计算使用流计算, 因此每创建一条TSMA, 将会创建一条流, 因此能够创建的TSMA条数也受当前已经存在的流条数和最大可创建流条数限制.
|
||||
|
||||
|
|
|
@ -4,8 +4,615 @@ title: C/C++ Connector
|
|||
toc_max_heading_level: 4
|
||||
---
|
||||
|
||||
C/C++ 开发人员可以使用 TDengine 的客户端驱动,即 C/C++连接器 (以下都用 TDengine 客户端驱动表示),开发自己的应用来连接 TDengine 集群完成数据存储、查询以及其他功能。TDengine 客户端驱动的 API 类似于 MySQL 的 C API。应用程序使用时,需要包含 TDengine 头文件 _taos.h_,里面列出了提供的 API 的函数原型;应用程序还要链接到所在平台上对应的动态库。
|
||||
C/C++ 开发人员可以使用 TDengine 的客户端驱动,即 C/C++连接器 (以下都用 TDengine 客户端驱动表示),开发自己的应用来连接 TDengine 集群完成数据存储、查询以及其他功能。TDengine 客户端驱动的 API 类似于 MySQL 的 C API。应用程序使用时,需要包含 TDengine 头文件,里面列出了提供的 API 的函数原型;应用程序还要链接到所在平台上对应的动态库。
|
||||
TDengine 的客户端驱动提供了 taosws 和 taos 两个动态库,分别支持 Websocket 连接和原生连接。 Websocket 连接和原生连接的区别是 Websocket 连接方式不要求客户端和服务端版本完全匹配,而原生连接要求,在性能上 Websocket 连接方式也接近于原生连接,一般我们推荐使用 Websocket 连接方式。
|
||||
|
||||
下面我们分开介绍两种连接方式的使用方法。
|
||||
|
||||
|
||||
## Websocket 连接方式
|
||||
|
||||
Websocket 连接方式需要使用 taosws.h 头文件和 taosws 动态库。
|
||||
|
||||
```c
|
||||
#include <taosws.h>
|
||||
```
|
||||
|
||||
TDengine 服务端或客户端安装后,`taosws.h` 位于:
|
||||
|
||||
- Linux:`/usr/local/taos/include`
|
||||
- Windows:`C:\TDengine\include`
|
||||
- macOS:`/usr/local/include`
|
||||
|
||||
TDengine 客户端驱动的动态库位于:
|
||||
|
||||
- Linux: `/usr/local/taos/driver/libtaosws.so`
|
||||
- Windows: `C:\TDengine\taosws.dll`
|
||||
- macOS: `/usr/local/lib/libtaosws.dylib`
|
||||
|
||||
### 支持的平台
|
||||
|
||||
请参考[支持的平台列表](../#支持的平台)
|
||||
|
||||
### 版本历史
|
||||
|
||||
| TDengine 客户端版本 | 主要变化 | TDengine 版本 |
|
||||
| :------------------: | :---------------------------: | :----------------: |
|
||||
| 3.3.3.0 | 首次发布,提供了 SQL执行,参数绑定,无模式写入和数据订阅等全面功能支持。 | 3.3.2.0及更高版本 |
|
||||
|
||||
|
||||
### 错误码
|
||||
|
||||
在 C 接口的设计中,错误码采用整数类型表示,每个错误码都对应一个特定的错误状态。如未特别说明,当 API 的返回值是整数时,_0_ 代表成功,其它是代表失败原因的错误码,当返回值是指针时, _NULL_ 表示失败。
|
||||
Websocket 连接方式单独的错误码在 `taosws.h` 中,
|
||||
|
||||
|
||||
| 错误码 | 错误描述 | 可能的出错场景或者可能的原因 | 建议用户采取的措施 |
|
||||
| ------- | -------- | ---------------------------- | ------------------ |
|
||||
| 0xE000 | DSN 错误 | DSN 不符合规范 | 检查 dsn 字符串是否符合规范 |
|
||||
| 0xE001 | 内部错误 | 不确定 | 保留现场和日志,github上报issue |
|
||||
| 0xE002 | 连接关闭 | 网络断开 | 请检查网络状况,查看 `taosadapter` 日志。 |
|
||||
| 0xE003 | 发送超时 | 网络断开 | 请检查网络状况 |
|
||||
| 0xE004 | 接收超时 | 慢查询,或者网络断开 | 排查 `taosadapter` 日志 |
|
||||
|
||||
其余错误码请参考同目录下 `taoserror.h` 文件,详细的原生连接错误码说明参考:[错误码](../../../reference/error-code)。
|
||||
:::info
|
||||
WebSocket 连接方式错误码只保留了原生连接错误码的后两个字节。
|
||||
:::
|
||||
|
||||
### 示例程序
|
||||
|
||||
本节展示了使用客户端驱动访问 TDengine 集群的常见访问方式的示例代码。
|
||||
|
||||
- 同步查询示例:[同步查询](https://github.com/taosdata/TDengine/tree/main/docs/examples/c-ws/query_data_demo.c)
|
||||
|
||||
- 参数绑定示例:[参数绑定](https://github.com/taosdata/TDengine/tree/main/docs/examples/c-ws/stmt_insert_demo.c)
|
||||
|
||||
- 无模式写入示例:[无模式写入](https://github.com/taosdata/TDengine/tree/main/docs/examples/c-ws/sml_insert_demo.c)
|
||||
|
||||
- 订阅和消费示例:[订阅和消费](https://github.com/taosdata/TDengine/tree/main/docs/examples/c-ws/tmq_demo.c)
|
||||
|
||||
:::info
|
||||
更多示例代码及下载请见 [GitHub](https://github.com/taosdata/TDengine/tree/main/docs/examples/c-ws)。
|
||||
:::
|
||||
|
||||
### API 参考
|
||||
|
||||
以下分别介绍 TDengine 客户端驱动的 DSN、基础 API、同步查询 API、参数绑定 API、无模式写入 API 和 数据订阅订阅 API。
|
||||
|
||||
#### DSN
|
||||
|
||||
C/C++ Websocket 连接器通过 DSN 连接描述字符串来表示连接信息。
|
||||
DSN 描述字符串基本结构如下:
|
||||
|
||||
```text
|
||||
<driver>[+<protocol>]://[[<username>:<password>@]<host>:<port>][/<database>][?<p1>=<v1>[&<p2>=<v2>]]
|
||||
|------|------------|---|-----------|-----------|------|------|------------|-----------------------|
|
||||
|driver| protocol | | username | password | host | port | database | params |
|
||||
```
|
||||
|
||||
各部分意义见下表:
|
||||
|
||||
- **driver**: 必须指定驱动名以便连接器选择何种方式创建连接,支持如下驱动名:
|
||||
- **taos**: 默认驱动,支持 SQL 执行,参数绑定,无模式写入。
|
||||
- **tmq**: 使用 TMQ 订阅数据。
|
||||
- **protocol**: 显示指定以何种方式建立连接,例如:`taos+ws://localhost:6041` 指定以 Websocket 方式建立连接。
|
||||
- **http/ws**: 使用 Websocket 协议。
|
||||
- **https/wss**: 在 Websocket 连接方式下显示启用 SSL/TLS 协议。
|
||||
|
||||
- **username/password**: 用于创建连接的用户名及密码。
|
||||
- **host/port**: 指定创建连接的服务器及端口,当不指定服务器地址及端口时 Websocket 连接默认为 `localhost:6041` 。
|
||||
- **database**: 指定默认连接的数据库名,可选参数。
|
||||
- **params**:其他可选参数。
|
||||
|
||||
一个完整的 DSN 描述字符串示例如下:`taos+ws://localhost:6041/test`, 表示使用 Websocket(`ws`)方式通过 `6041` 端口连接服务器 `localhost`,并指定默认数据库为 `test`。
|
||||
|
||||
#### 基础 API
|
||||
|
||||
基础 API 用于完成创建数据库连接等工作,为其它 API 的执行提供运行时环境。
|
||||
|
||||
- `char *ws_get_client_info()`
|
||||
- **接口说明**:获取客户端版本信息。
|
||||
- **返回值**:返回客户端版本信息。
|
||||
|
||||
- `WS_TAOS *ws_connect(const char *dsn)`
|
||||
- **接口说明**:创建数据库连接,初始化连接上下文。
|
||||
- **参数说明**:
|
||||
- dsn:[入参] 连接信息,见上文 DSN 章节。
|
||||
- **返回值**:返回数据库连接,返回值为空表示失败。应用程序需要保存返回的参数,以便后续使用。
|
||||
:::info
|
||||
同一进程可以根据不同的 dsn 连接多个 TDengine 集群
|
||||
:::
|
||||
|
||||
- `const char *ws_get_server_info(WS_TAOS *taos)`
|
||||
- **接口说明**:获取服务端版本信息。
|
||||
- **参数说明**:
|
||||
- taos:[入参] 指向数据库连接的指针,数据库连接是通过 `ws_connect()` 函数建立。
|
||||
- **返回值**:返回获取服务端版本信息。
|
||||
|
||||
- `int32_t ws_select_db(WS_TAOS *taos, const char *db)`
|
||||
- **接口说明**:将当前的缺省数据库设置为 `db`。
|
||||
- **参数说明**:
|
||||
- taos:[入参] 指向数据库连接的指针,数据库连接是通过 `ws_connect()` 函数建立。
|
||||
- db:[入参] 数据库名称。
|
||||
- **返回值**:`0`:成功,非 `0`:失败,详情请参考错误码页面。
|
||||
|
||||
- `int32_t ws_get_current_db(WS_TAOS *taos, char *database, int len, int *required)`
|
||||
- **接口说明**:获取当前数据库名称。
|
||||
- **参数说明**:
|
||||
- taos:[入参] 指向数据库连接的指针,数据库连接是通过 `ws_connect()` 函数建立。
|
||||
- database:[出参] 存储当前数据库名称。
|
||||
- len:[入参] database 的空间大小。
|
||||
- required:[出参] 存储当前数据库名称所需的空间(包含最后的'\0')。
|
||||
- **返回值**:`0`:成功,`-1`:失败,可调用函数 ws_errstr(NULL) 获取更详细的错误信息。
|
||||
- 如果,database == NULL 或者 len\<=0 返回失败。
|
||||
- 如果,len 小于 存储数据库名称所需的空间(包含最后的'\0'),返回失败,database 里赋值截断的数据,以'\0'结尾。
|
||||
- 如果,len 大于等于 存储数据库名称所需的空间(包含最后的'\0'),返回成功,database 里赋值以'\0‘结尾数据库名称。
|
||||
|
||||
- `int32_t ws_close(WS_TAOS *taos);`
|
||||
- **接口说明**:关闭连接。
|
||||
- **参数说明**:
|
||||
- taos:[入参] 指向数据库连接的指针,数据库连接是通过 `ws_connect()` 函数建立。
|
||||
- **返回值**:`0`:成功,非 `0`:失败,详情请参考错误码页面。
|
||||
|
||||
#### 同步查询
|
||||
|
||||
本小节介绍 API 均属于同步接口。应用调用后,会阻塞等待响应,直到获得返回结果或错误信息。
|
||||
|
||||
- `WS_RES *ws_query(WS_TAOS *taos, const char *sql)`
|
||||
- **接口说明**:执行 SQL 语句,可以是 DQL、DML 或 DDL 语句。
|
||||
- **参数说明**:
|
||||
- taos:[入参] 指向数据库连接的指针,数据库连接是通过 `ws_connect()` 函数建立。
|
||||
- sql:[入参] 需要执行 SQL 语句。
|
||||
- **返回值**:不能通过返回值是否是 `NULL` 来判断执行结果是否失败,而是需要调用 `ws_errno()` 函数解析结果集中的错误代码来进行判断。
|
||||
- ws_errno 返回值:`0`:成功,`-1`:失败,详情请调用 ws_errstr 函数来获取错误提示。
|
||||
|
||||
- `int32_t ws_result_precision(const WS_RES *rs)`
|
||||
- **接口说明**:返回结果集时间戳字段的精度类别。
|
||||
- **参数说明**:
|
||||
- res:[入参] 结果集。
|
||||
- **返回值**:`0`:毫秒,`1`:微秒,`2`:纳秒。
|
||||
|
||||
- `WS_ROW ws_fetch_row(WS_RES *rs)`
|
||||
- **接口说明**:按行获取查询结果集中的数据。
|
||||
- **参数说明**:
|
||||
- res:[入参] 结果集。
|
||||
- **返回值**:非 `NULL`:成功,`NULL`:失败,可调用函数 ws_errstr(NULL) 获取更详细的错误信息。
|
||||
|
||||
- `int32_t ws_fetch_raw_block(WS_RES *rs, const void **pData, int32_t *numOfRows)`
|
||||
- **接口说明**:批量获取查询结果集中的数据。
|
||||
- **参数说明**:
|
||||
- res:[入参] 结果集。
|
||||
- pData:[出参] 用于存储从结果集中获取一个数据块。
|
||||
- numOfRows:[出参] 用于存储从结果集中获取数据块包含的行数。
|
||||
- **返回值**:`0`:成功。非 `0`:失败,详情请参考错误码页面。
|
||||
|
||||
- `int32_t ws_num_fields(const WS_RES *rs)` 和 `int32_t ws_field_count(const WS_RES *rs)`
|
||||
- **接口说明**:这两个 API 等价,用于获取查询结果集中的列数。
|
||||
- **参数说明**:
|
||||
- res:[入参] 结果集。
|
||||
- **返回值**:返回值为结果集中列的数量。
|
||||
|
||||
- `int32_t ws_affected_rows(const WS_RES *rs)`
|
||||
- **接口说明**:获取被所执行的 SQL 语句影响的行数。
|
||||
- **参数说明**:
|
||||
- res:[入参] 结果集。
|
||||
- **返回值**:返回值表示受影响的行数。
|
||||
|
||||
- `int64_t ws_affected_rows64(const WS_RES *rs)`
|
||||
- **接口说明**:获取被所执行的 SQL 语句影响的行数。
|
||||
- **参数说明**:
|
||||
- res:[入参] 结果集。
|
||||
- **返回值**:返回值表示受影响的行数。
|
||||
|
||||
- `const struct WS_FIELD *ws_fetch_fields(WS_RES *rs)`
|
||||
- **接口说明**:获取查询结果集每列数据的属性(列的名称、列的数据类型、列的长度),与 `ws_num_fields()` 配合使用,可用来解析 `ws_fetch_row()` 返回的一个元组(一行)的数据。
|
||||
- **参数说明**:
|
||||
- res:[入参] 结果集。
|
||||
- **返回值**:非 `NULL`:成功,返回一个指向 WS_FIELD 结构体的指针,每个元素代表一列的元数据。`NULL`:失败。
|
||||
|
||||
- `int32_t ws_stop_query(WS_RES *rs)`
|
||||
- **接口说明**:停止当前查询的执行。
|
||||
- **参数说明**:
|
||||
- res:[入参] 结果集。
|
||||
- **返回值**:`0`:成功。非 `0`:失败,详情请参考错误码页面。
|
||||
|
||||
- `int32_t ws_free_result(WS_RES *rs)`
|
||||
- **接口说明**:释放查询结果集以及相关的资源。查询完成后,务必调用该 API 释放资源,否则可能导致应用内存泄露。但也需注意,释放资源后,如果再调用 `ws_fetch_fields()` 等获取查询结果的函数,将导致应用崩溃。
|
||||
- **参数说明**:
|
||||
- res:[入参] 结果集。
|
||||
- **返回值**:`0`:成功。非 `0`:失败,详情请参考错误码页面。
|
||||
|
||||
- `const char *ws_errstr(WS_RES *rs)`
|
||||
- **接口说明**:获取最近一次 API 调用失败的原因,返回值为字符串标识的错误提示信息。
|
||||
- **参数说明**:
|
||||
- res:[入参] 结果集。
|
||||
- **返回值**:字符串标识的错误提示信息。
|
||||
|
||||
- `int32_t ws_errno(WS_RES *rs)`
|
||||
- **接口说明**:获取最近一次 API 调用失败的原因,返回值为错误代码。
|
||||
- **参数说明**:
|
||||
- res:[入参] 结果集。
|
||||
- **返回值**:字符串标识的错误提示信息。
|
||||
|
||||
:::note
|
||||
TDengine 推荐数据库应用的每个线程都建立一个独立的连接,或基于线程建立连接池。不要在应用中将该连接 (WS_TAOS\*) 结构体传递到不同的线程共享使用。
|
||||
另一个需要注意的是,在上述同步 API 执行过程中,不能调用类似 pthread_cancel 之类的 API 来强制结束线程,因为涉及一些模块的同步操作,如果强制结束线程有可能造成包括但不限于死锁等异常状况。
|
||||
|
||||
:::
|
||||
|
||||
#### 参数绑定
|
||||
|
||||
除了直接调用 `ws_query()` 通过执行 SQL 进行数据写入,TDengine 也提供了支持参数绑定的 Prepare API,风格与 MySQL 类似,目前也仅支持用问号 `?` 来代表待绑定的参数。
|
||||
|
||||
通过参数绑定接口写入数据时,可以避免 SQL 语法解析的资源消耗,从而在绝大多数情况下显著提升写入性能。此时的典型操作步骤如下:
|
||||
|
||||
1. 调用 `ws_stmt_init()` 创建参数绑定对象;
|
||||
2. 调用 `ws_stmt_prepare()` 解析 INSERT 语句;
|
||||
3. 如果 INSERT 语句中预留了表名但没有预留 TAGS,那么调用 `ws_stmt_set_tbname()` 来设置表名;
|
||||
4. 如果 INSERT 语句中既预留了表名又预留了 TAGS(例如 INSERT 语句采取的是自动建表的方式),那么调用 `ws_stmt_set_tbname_tags()` 来设置表名和 TAGS 的值;
|
||||
5. 调用 `ws_stmt_bind_param_batch()` 以多行的方式设置 VALUES 的值;
|
||||
6. 调用 `ws_stmt_add_batch()` 把当前绑定的参数加入批处理;
|
||||
7. 可以重复第 3 ~ 6 步,为批处理加入更多的数据行;
|
||||
8. 调用 `ws_stmt_execute()` 执行已经准备好的批处理指令;
|
||||
9. 执行完毕,调用 `ws_stmt_close()` 释放所有资源。
|
||||
|
||||
说明:如果 `ws_stmt_execute()` 执行成功,假如不需要改变 SQL 语句的话,那么是可以复用 `ws_stmt_prepare()` 的解析结果,直接进行第 3 ~ 6 步绑定新数据的。但如果执行出错,那么并不建议继续在当前的环境上下文下继续工作,而是建议释放资源,然后从 `ws_stmt_init()` 步骤重新开始。
|
||||
|
||||
接口相关的具体函数如下(也可以参考 [stmt_insert_demo.c](https://github.com/taosdata/TDengine/blob/develop/docs/examples/c-ws/stmt_insert_demo.c) 文件中使用对应函数的方式):
|
||||
|
||||
- `WS_STMT *ws_stmt_init(const WS_TAOS *taos)`
|
||||
- **接口说明**:初始化一个预编译的 SQL 语句对象。
|
||||
- **参数说明**:
|
||||
- taos:[入参] 指向数据库连接的指针,数据库连接是通过 `ws_connect()` 函数建立。
|
||||
- **返回值**:非 `NULL`:成功,返回一个指向 WS_STMT 结构体的指针,该结构体表示预编译的 SQL 语句对象。`NULL`:失败,详情请调用 ws_stmt_errstr() 函数来获取错误提示。
|
||||
|
||||
- `int ws_stmt_prepare(WS_STMT *stmt, const char *sql, unsigned long len)`
|
||||
- **接口说明**:解析一条预编译的 SQL 语句,将解析结果和参数信息绑定到 stmt 上。
|
||||
- **参数说明**:
|
||||
- stmt:[入参] 指向一个有效的预编译的 SQL 语句对象指针。
|
||||
- sql:[入参] 需要解析的 SQL 语句。
|
||||
- len:[入参] 参数 sql 的长度。如果参数 len 大于 0,将使用此参数作为 SQL 语句的长度,如等于 0,将自动判断 SQL 语句的长度。
|
||||
- **返回值**:`0`:成功。非 `0`:失败,详情请参考错误码页面。
|
||||
|
||||
- `int ws_stmt_bind_param_batch(WS_STMT *stmt, const WS_MULTI_BIND *bind, uint32_t len)`
|
||||
- **接口说明**:以多列的方式传递待绑定的数据,需要保证这里传递的数据列的顺序、列的数量与 SQL 语句中的 VALUES 参数完全一致。
|
||||
- **参数说明**:
|
||||
- stmt:[入参] 指向一个有效的预编译的 SQL 语句对象指针。
|
||||
- bind:[入参] 指向一个有效的 WS_MULTI_BIND 结构体指针,该结构体包含了要批量绑定到 SQL 语句中的参数列表。
|
||||
- len: [入参] bind 数组的元素个数。
|
||||
- **返回值**:`0`:成功。非 `0`:失败,详情请参考错误码页面。
|
||||
|
||||
- `int ws_stmt_set_tbname(WS_STMT *stmt, const char *name)`
|
||||
- **接口说明**:(仅支持用于替换 INSERT 语句中的参数值)当 SQL 语句中的表名使用了 `?` 占位时,可以使用此函数绑定一个具体的表名。
|
||||
- **参数说明**:
|
||||
- stmt:[入参] 指向一个有效的预编译的 SQL 语句对象指针。
|
||||
- name:[入参] 指向一个包含子表名称的字符串常量。
|
||||
- **返回值**:`0`:成功。非 `0`:失败,详情请参考错误码页面。
|
||||
|
||||
- `int ws_stmt_set_tbname_tags(WS_STMT *stmt,
|
||||
const char *name,
|
||||
const WS_MULTI_BIND *bind,
|
||||
uint32_t len);`
|
||||
- **接口说明**:(仅支持用于替换 INSERT 语句中的参数值)当 SQL 语句中的表名和 TAGS 都使用了 `?` 占位时,可以使用此函数绑定具体的表名和具体的 TAGS 取值。最典型的使用场景是使用了自动建表功能的 INSERT 语句(目前版本不支持指定具体的 TAGS 列)。TAGS 参数中的列数量需要与 SQL 语句中要求的 TAGS 数量完全一致。
|
||||
- **参数说明**:
|
||||
- stmt:[入参] 指向一个有效的预编译的 SQL 语句对象指针。
|
||||
- name:[入参] 指向一个包含子表名称的字符串常量。
|
||||
- tags:[入参] 指向一个有效的 WS_MULTI_BIND 结构体指针,该结构体包含了子表标签的值。
|
||||
- len:[入参] bind 数组的元素个数。
|
||||
- **返回值**:`0`:成功。非 `0`:失败,详情请参考错误码页面。
|
||||
|
||||
- `int ws_stmt_add_batch(WS_STMT *stmt)`
|
||||
- **接口说明**:将当前绑定的参数加入批处理中,调用此函数后,可以再次调用 `ws_stmt_bind_param_batch()` 绑定新的参数。需要注意,此函数仅支持 INSERT/IMPORT 语句,如果是 SELECT 等其他 SQL 语句,将返回错误。
|
||||
- stmt:[入参] 指向一个有效的预编译的 SQL 语句对象指针。
|
||||
- **返回值**:`0`:成功。非 `0`:失败,详情请参考错误码页面。
|
||||
|
||||
- `int ws_stmt_execute(WS_STMT *stmt, int32_t *affected_rows)`
|
||||
- **接口说明**:执行准备好的语句。目前,一条语句只能执行一次。
|
||||
- stmt:[入参] 指向一个有效的预编译的 SQL 语句对象指针。
|
||||
- affected_rows:[出参] 成功写入的行数。
|
||||
- **返回值**:`0`:成功。非 `0`:失败,详情请参考错误码页面。
|
||||
|
||||
- `int ws_stmt_affected_rows(WS_STMT *stmt)`
|
||||
- **接口说明**:获取执行预编译 SQL 语句后受影响的行数。
|
||||
- stmt:[入参] 指向一个有效的预编译的 SQL 语句对象指针。
|
||||
- **返回值**:返回受影响的行数。
|
||||
|
||||
- `int ws_stmt_affected_rows_once(WS_STMT *stmt)`
|
||||
- **接口说明**:获取执行一次绑定语句影响的行数。
|
||||
- stmt:[入参] 指向一个有效的预编译的 SQL 语句对象指针。
|
||||
- **返回值**:返回受影响的行数。
|
||||
|
||||
- `int32_t ws_stmt_close(WS_STMT *stmt)`
|
||||
- **接口说明**:执行完毕,释放所有资源。
|
||||
- stmt:[入参] 指向一个有效的预编译的 SQL 语句对象指针。
|
||||
- **返回值**:`0`:成功。非 `0`:失败,详情请参考错误码页面。
|
||||
|
||||
- `const char *ws_stmt_errstr(WS_STMT *stmt)`
|
||||
- **接口说明**:用于在其他 STMT API 返回错误(返回错误码或空指针)时获取错误信息。
|
||||
- stmt:[入参] 指向一个有效的预编译的 SQL 语句对象指针。
|
||||
- **返回值**:返回一个指向包含错误信息的字符串的指针。
|
||||
|
||||
#### 无模式写入
|
||||
|
||||
除了使用 SQL 方式或者使用参数绑定 API 写入数据外,还可以使用 Schemaless 的方式完成写入。Schemaless 可以免于预先创建超级表/数据子表的数据结构,而是可以直接写入数据,TDengine 系统会根据写入的数据内容自动创建和维护所需要的表结构。Schemaless 的使用方式详见 [Schemaless 写入](../../../develop/schemaless/) 章节,这里介绍与之配套使用的 C/C++ API。
|
||||
- `WS_RES *ws_schemaless_insert_raw(WS_TAOS *taos,
|
||||
const char *lines,
|
||||
int len,
|
||||
int32_t *totalRows,
|
||||
int protocal,
|
||||
int precision)`
|
||||
- **接口说明**:执行无模式的批量插入操作,将行协议的文本数据写入到 TDengine 中。通过传递的参数lines指针和长度len来表示数据,为了解决原始接口数据包含'\0'而被截断的问题。
|
||||
- taos:[入参] 指向数据库连接的指针,数据库连接是通过 `ws_connect()` 函数建立。
|
||||
- lines:[入参] 文本数据。满足解析格式要求的无模式文本字符串。
|
||||
- len:[入参] 数据缓冲区 lines 的总长度(字节数)。
|
||||
- totalRows:[出参] 指向一个整数指针,用于返回成功插入的记录总数。
|
||||
- protocol:[入参] 行协议类型,用于标识文本数据格式。
|
||||
- precision:[入参] 文本数据中的时间戳精度字符串。
|
||||
- **返回值**:返回一个指向 WS_RES 结构体的指针,该结构体包含了插入操作的结果。应用可以通过使用 `ws_errstr()` 获得错误信息,也可以使用 `ws_errno()` 获得错误码。在某些情况下,返回的 WS_RES 为 `NULL`,此时仍然可以调用 `ws_errno()` 来安全地获得错误码信息。
|
||||
返回的 WS_RES 需要调用方来负责释放,否则会出现内存泄漏。
|
||||
|
||||
**说明**
|
||||
协议类型是枚举类型,包含以下三种格式:
|
||||
|
||||
- WS_TSDB_SML_LINE_PROTOCOL:InfluxDB 行协议(Line Protocol)
|
||||
- WS_TSDB_SML_TELNET_PROTOCOL: OpenTSDB Telnet 文本行协议
|
||||
- WS_TSDB_SML_JSON_PROTOCOL: OpenTSDB Json 协议格式
|
||||
|
||||
时间戳分辨率的定义,定义在 `taosws.h` 文件中,具体内容如下:
|
||||
|
||||
- WS_TSDB_SML_TIMESTAMP_NOT_CONFIGURED = 0,
|
||||
- WS_TSDB_SML_TIMESTAMP_HOURS,
|
||||
- WS_TSDB_SML_TIMESTAMP_MINUTES,
|
||||
- WS_TSDB_SML_TIMESTAMP_SECONDS,
|
||||
- WS_TSDB_SML_TIMESTAMP_MILLI_SECONDS,
|
||||
- WS_TSDB_SML_TIMESTAMP_MICRO_SECONDS,
|
||||
- WS_TSDB_SML_TIMESTAMP_NANO_SECONDS
|
||||
|
||||
需要注意的是,时间戳分辨率参数只在协议类型为 `WS_SML_LINE_PROTOCOL` 的时候生效。
|
||||
对于 OpenTSDB 的文本协议,时间戳的解析遵循其官方解析规则 — 按照时间戳包含的字符的数量来确认时间精度。
|
||||
|
||||
**schemaless 其他相关的接口**
|
||||
|
||||
- `WS_RES *ws_schemaless_insert_raw_with_reqid(WS_TAOS *taos,
|
||||
const char *lines,
|
||||
int len,
|
||||
int32_t *totalRows,
|
||||
int protocal,
|
||||
int precision,
|
||||
uint64_t reqid)`
|
||||
- **接口说明**:执行无模式的批量插入操作,将行协议的文本数据写入到 TDengine 中。通过传递的参数lines指针和长度len来表示数据,为了解决原始接口数据包含'\0'而被截断的问题。通过传递参数reqid来跟踪整个的函数调用链情况。
|
||||
- taos:[入参] 指向数据库连接的指针,数据库连接是通过 `ws_connect()` 函数建立。
|
||||
- lines:[入参] 文本数据。满足解析格式要求的无模式文本字符串。
|
||||
- len:[入参] 数据缓冲区 lines 的总长度(字节数)。
|
||||
- totalRows:[出参] 指向一个整数指针,用于返回成功插入的记录总数。
|
||||
- protocol:[入参] 行协议类型,用于标识文本数据格式。
|
||||
- precision:[入参] 文本数据中的时间戳精度字符串。
|
||||
- reqid:[入参] 指定的请求 ID,用于跟踪调用请求。请求 ID (reqid) 可以用于在客户端和服务器端之间建立请求和响应之间的关联,对于分布式系统中的跟踪和调试非常有用。
|
||||
- **返回值**:返回一个指向 WS_RES 结构体的指针,该结构体包含了插入操作的结果。应用可以通过使用 `ws_errstr()` 获得错误信息,也可以使用 `ws_errno()` 获得错误码。在某些情况下,返回的 WS_RES 为 `NULL`,此时仍然可以调用 `ws_errno()` 来安全地获得错误码信息。
|
||||
返回的 WS_RES 需要调用方来负责释放,否则会出现内存泄漏。
|
||||
|
||||
- `WS_RES *ws_schemaless_insert_raw_ttl(WS_TAOS *taos,
|
||||
const char *lines,
|
||||
int len,
|
||||
int32_t *totalRows,
|
||||
int protocal,
|
||||
int precision,
|
||||
int ttl)`
|
||||
- **接口说明**:执行无模式的批量插入操作,将行协议的文本数据写入到 TDengine 中。通过传递的参数lines指针和长度len来表示数据,为了解决原始接口数据包含'\0'而被截断的问题。通过传递ttl参数来控制建表的ttl到期时间。
|
||||
- taos:[入参] 指向数据库连接的指针,数据库连接是通过 `ws_connect()` 函数建立。
|
||||
- lines:[入参] 文本数据。满足解析格式要求的无模式文本字符串。
|
||||
- len:[入参] 数据缓冲区 lines 的总长度(字节数)。
|
||||
- totalRows:[出参] 指向一个整数指针,用于返回成功插入的记录总数。
|
||||
- protocol:[入参] 行协议类型,用于标识文本数据格式。
|
||||
- precision:[入参] 文本数据中的时间戳精度字符串。
|
||||
- ttl:[入参] 指定的生存时间(TTL),单位为天。记录在超过这个生存时间后会被自动删除。
|
||||
- **返回值**:返回一个指向 WS_RES 结构体的指针,该结构体包含了插入操作的结果。应用可以通过使用 `ws_errstr()` 获得错误信息,也可以使用 `ws_errno()` 获得错误码。在某些情况下,返回的 WS_RES 为 `NULL`,此时仍然可以调用 `ws_errno()` 来安全地获得错误码信息。
|
||||
返回的 WS_RES 需要调用方来负责释放,否则会出现内存泄漏。
|
||||
|
||||
- `WS_RES *ws_schemaless_insert_raw_ttl_with_reqid(WS_TAOS *taos,
|
||||
const char *lines,
|
||||
int len,
|
||||
int32_t *totalRows,
|
||||
int protocal,
|
||||
int precision,
|
||||
int ttl,
|
||||
uint64_t reqid)`
|
||||
- **接口说明**:执行无模式的批量插入操作,将行协议的文本数据写入到 TDengine 中。通过传递的参数lines指针和长度len来表示数据,为了解决原始接口数据包含'\0'而被截断的问题。通过传递ttl参数来控制建表的ttl到期时间。通过传递参数reqid来跟踪整个的函数调用链情况。
|
||||
- taos:[入参] 指向数据库连接的指针,数据库连接是通过 `ws_connect()` 函数建立。
|
||||
- lines:[入参] 文本数据。满足解析格式要求的无模式文本字符串。
|
||||
- len:[入参] 数据缓冲区 lines 的总长度(字节数)。
|
||||
- totalRows:[出参] 指向一个整数指针,用于返回成功插入的记录总数。
|
||||
- protocol:[入参] 行协议类型,用于标识文本数据格式。
|
||||
- precision:[入参] 文本数据中的时间戳精度字符串。
|
||||
- ttl:[入参] 指定的生存时间(TTL),单位为天。记录在超过这个生存时间后会被自动删除。
|
||||
- reqid:[入参] 指定的请求 ID,用于跟踪调用请求。请求 ID (reqid) 可以用于在客户端和服务器端之间建立请求和响应之间的关联,对于分布式系统中的跟踪和调试非常有用。
|
||||
- **返回值**:返回一个指向 WS_RES 结构体的指针,该结构体包含了插入操作的结果。应用可以通过使用 `ws_errstr()` 获得错误信息,也可以使用 `ws_errno()` 获得错误码。在某些情况下,返回的 WS_RES 为 `NULL`,此时仍然可以调用 `ws_errno()` 来安全地获得错误码信息。
|
||||
返回的 WS_RES 需要调用方来负责释放,否则会出现内存泄漏。
|
||||
|
||||
**说明**
|
||||
- 上面这3个接口是扩展接口,主要用于在 schemaless 写入时传递 ttl、reqid 参数,可以根据需要使用。
|
||||
- 带 ttl 的接口可以传递 ttl 参数来控制建表的ttl到期时间。
|
||||
- 带 reqid 的接口可以通过传递 reqid 参数来追踪整个的调用链。
|
||||
|
||||
#### 数据订阅
|
||||
- `const char *ws_tmq_errstr(ws_tmq_t *tmq)`
|
||||
- **接口说明**:用于获取数据订阅的错误信息。
|
||||
- tmq:[入参] 指向一个有效的 ws_tmq_t 结构体指针,该结构体代表一个 TMQ 消费者对象。
|
||||
- **返回值**:返回一个指向包含错误信息字符串的指针,返回值非NULL,但是错误信息可能为空字符串。
|
||||
|
||||
- `ws_tmq_conf_t *ws_tmq_conf_new(void);`
|
||||
- **接口说明**:创建一个新的 TMQ 配置对象。
|
||||
- **返回值**:非 `NULL`:成功,返回一个指向 ws_tmq_conf_t 结构体的指针,该结构体用于配置 TMQ 的行为和特性。`NULL`:失败,可调用函数 ws_errstr(NULL) 获取更详细的错误信息。
|
||||
|
||||
- `enum ws_tmq_conf_res_t ws_tmq_conf_set(ws_tmq_conf_t *conf, const char *key, const char *value)`
|
||||
- **接口说明**:设置 TMQ 配置对象中的配置项,用于配置消费参数。
|
||||
- conf:[入参] 指向一个有效的 ws_tmq_conf_t 结构体指针,该结构体代表一个 TMQ 配置对象。
|
||||
- key:[入参] 数配置项的键名。
|
||||
- value:[入参] 配置项的值。
|
||||
- **返回值**:返回一个 ws_tmq_conf_res_t 枚举值,表示配置设置的结果。
|
||||
- WS_TMQ_CONF_OK:成功设置配置项。
|
||||
- WS_TMQ_CONF_INVALID_KEY:键值无效。
|
||||
- WS_TMQ_CONF_UNKNOWN:键名无效。
|
||||
|
||||
- `int32_t ws_tmq_conf_destroy(ws_tmq_conf_t *conf)`
|
||||
- **接口说明**:销毁一个 TMQ 配置对象并释放相关资源。
|
||||
- conf:[入参] 指向一个有效的 ws_tmq_conf_t 结构体指针,该结构体代表一个 TMQ 配置对象。
|
||||
- **返回值**:`0`:成功。非 `0`:失败,可调用函数 `ws_tmq_errstr(NULL)` 获取更详细的错误信息。
|
||||
|
||||
- `ws_tmq_list_t *ws_tmq_list_new(void)`
|
||||
- **接口说明**:用于创建一个 ws_tmq_list_t 结构体,用于存储订阅的 topic。
|
||||
- **返回值**:非 `NULL`:成功,返回一个指向 ws_tmq_list_t 结构体的指针。`NULL`:失败,可调用函数 `ws_tmq_errstr(NULL)` 获取更详细的错误信息。
|
||||
|
||||
- `int32_t ws_tmq_list_append(ws_tmq_list_t *list, const char *topic)`
|
||||
- **接口说明**:用于向 ws_tmq_list_t 结构体中添加一个 topic。
|
||||
- list:[入参] 指向一个有效的 ws_tmq_list_t 结构体指针,该结构体代表一个 TMQ 列表对象。
|
||||
- topic:[入参] topic 名称。
|
||||
- **返回值**:`0`:成功。非 `0`:失败,可调用函数 `ws_tmq_errstr(NULL)` 获取更详细的错误信息。
|
||||
|
||||
- `int32_t ws_tmq_list_destroy(ws_tmq_list_t *list);`
|
||||
- **接口说明**:用于销毁 ws_tmq_list_t 结构体,ws_tmq_list_new 的结果需要通过该接口销毁。
|
||||
- list:[入参] 指向一个有效的 ws_tmq_list_t 结构体指针,该结构体代表一个 TMQ 列表对象。
|
||||
- **返回值**:`0`:成功。非 `0`:失败,可调用函数 `ws_tmq_errstr(NULL)` 获取更详细的错误信息。
|
||||
|
||||
- `int32_t ws_tmq_list_get_size(ws_tmq_list_t *list);`
|
||||
- **接口说明**:用于获取 ws_tmq_list_t 结构体中 topic 的个数。
|
||||
- list:[入参] 指向一个有效的 ws_tmq_list_t 结构体指针,该结构体代表一个 TMQ 列表对象。
|
||||
- **返回值**:`>=0`:成功,返回 ws_tmq_list_t 结构体中 topic 的个数。`-1`:失败,表示输入参数 list 为 NULL 。
|
||||
|
||||
- `char **ws_tmq_list_to_c_array(const ws_tmq_list_t *list, uint32_t *topic_num);`
|
||||
- **接口说明**:用于将 ws_tmq_list_t 结构体转换为 C 数组,数组每个元素为字符串指针。
|
||||
- list:[入参] 指向一个有效的 ws_tmq_list_t 结构体指针,该结构体代表一个 TMQ 列表对象。
|
||||
- topic_num:[入参] list 的元素个数。
|
||||
- **返回值**:非 `NULL`:成功,返回 c 数组, 每个元素是字符串指针,代表一个 topic 名称。`NULL`:失败,表示输入参数 list 为 NULL 。
|
||||
|
||||
- `ws_tmq_t *ws_tmq_consumer_new(ws_tmq_conf_t *conf, const char *dsn, char *errstr, int errstr_len)`
|
||||
- **接口说明**:用于创建一个 ws_tmq_t 结构体,用于消费数据,消费完数据后需调用 tmq_consumer_close 关闭消费者。
|
||||
- conf:[入参] 指向一个有效的 ws_tmq_conf_t 结构体指针,该结构体代表一个 TMQ 配置对象。
|
||||
- dsn:[入参] dsn 信息字符串,具体可参考上面 DSN 章节。一个常见的合法 dsn 为 "tmq+ws://root:taosdata@localhost:6041"。
|
||||
- errstr:[出参] 指向一个有效的字符缓冲区指针,用于接收创建过程中可能产生的错误信息。内存的申请/释放由调用者负责。
|
||||
- errstrLen:[入参] 指定 errstr 缓冲区的大小(以字节为单位)。
|
||||
- **返回值**:非 `NULL`:成功,返回一个指向 ws_tmq_t 结构体的指针,该结构体代表一个 TMQ 消费者对象。。`NULL`:失败,错误信息存储在参数 errstr 中 。
|
||||
|
||||
- `int32_t ws_tmq_subscribe(ws_tmq_t *tmq, const ws_tmq_list_t *topic_list)`
|
||||
- **接口说明**:用于订阅 topic 列表,消费完数据后,需调用 ws_tmq_subscribe 取消订阅。
|
||||
- tmq:[入参] 指向一个有效的 ws_tmq_t 结构体指针,该结构体代表一个 TMQ 消费者对象。
|
||||
- topic_list:[入参] 指向一个有效的 ws_tmq_list_t 结构体指针,该结构体包含一个或多个主题名称,目前仅支持一个主题名称。
|
||||
- **返回值**:`0`:成功。非 `0`:失败,可调用函数 `ws_tmq_errstr(tmq)` 获取更详细的错误信息。
|
||||
|
||||
- `int32_t ws_tmq_unsubscribe(ws_tmq_t *tmq)`
|
||||
- **接口说明**:用于取消订阅的 topic 列表。需与 ws_tmq_subscribe 配合使用。
|
||||
- tmq:[入参] 指向一个有效的 ws_tmq_t 结构体指针,该结构体代表一个 TMQ 消费者对象。
|
||||
- **返回值**:`0`:成功。非 `0`:失败,可调用函数 `ws_tmq_errstr(tmq)` 获取更详细的错误信息。
|
||||
|
||||
- `WS_RES *ws_tmq_consumer_poll(ws_tmq_t *tmq, int64_t timeout)`
|
||||
- **接口说明**:用于轮询消费数据,每一个消费者,只能单线程调用该接口。
|
||||
- tmq:[入参] 指向一个有效的 ws_tmq_t 结构体指针,该结构体代表一个 TMQ 消费者对象。
|
||||
- timeout:[入参] 轮询的超时时间,单位为毫秒,负数表示默认超时1秒。
|
||||
- **返回值**:非 `NULL`:成功,返回一个指向 WS_RES 结构体的指针,该结构体包含了接收到的消息。`NULL`:失败,表示没有数据。WS_RES 结果和 taos_query 返回结果一致,可通过查询的各种接口获取 WS_RES 里的信息,比如 schema 等。
|
||||
|
||||
- `int32_t ws_tmq_consumer_close(ws_tmq_t *tmq)`
|
||||
- **接口说明**:用于关闭 ws_tmq_t 结构体。需与 ws_tmq_consumer_new 配合使用。
|
||||
- tmq:[入参] 指向一个有效的 ws_tmq_t 结构体指针,该结构体代表一个 TMQ 消费者对象。
|
||||
- **返回值**:`0`:成功。非 `0`:失败,可调用函数 `ws_tmq_errstr(tmq)` 获取更详细的错误信息。
|
||||
|
||||
- `int32_t ws_tmq_get_topic_assignment(ws_tmq_t *tmq,
|
||||
const char *pTopicName,
|
||||
struct ws_tmq_topic_assignment **assignment,
|
||||
int32_t *numOfAssignment)`
|
||||
- **接口说明**:返回当前 consumer 分配的 vgroup 的信息,每个 vgroup 的信息包括 vgId,wal 的最大最小 offset,以及当前消费到的 offset。
|
||||
- tmq:[入参] 指向一个有效的 ws_tmq_t 结构体指针,该结构体代表一个 TMQ 消费者对象。
|
||||
- pTopicName:[入参] 要查询分配信息的主题名称。
|
||||
- assignment:[出参] 指向一个 tmq_topic_assignment 结构体指针的指针,用于接收分配信息。数据大小为 numOfAssignment,需要通过 tmq_free_assignment 接口释放。
|
||||
- numOfAssignment:[出参] 指向一个整数指针,用于接收分配给该 consumer 有效的 vgroup 个数。
|
||||
- **返回值**:`0`:成功。非 `0`:失败,可调用函数 `ws_tmq_errstr(tmq)` 获取更详细的错误信息。
|
||||
|
||||
- `int32_t ws_tmq_free_assignment(struct ws_tmq_topic_assignment *pAssignment, int32_t numOfAssignment)`
|
||||
- **接口说明**:返回当前consumer分配的vgroup的信息,每个vgroup的信息包括vgId,wal的最大最小offset,以及当前消费到的offset。
|
||||
- pAssignment:[入参] 指向一个有效的 ws_tmq_topic_assignment 结构体数组的指针,该数组包含了 vgroup 分配信息。
|
||||
- numOfAssignment:[入参] pAssignment 指向的数组元素个数。
|
||||
- **返回值**:`0`:成功。非 `0`:失败,可调用函数 `ws_tmq_errstr(tmq)` 获取更详细的错误信息。
|
||||
|
||||
- `int64_t ws_tmq_committed(ws_tmq_t *tmq, const char *pTopicName, int32_t vgId)`
|
||||
- **接口说明**:获取 TMQ 消费者对象对特定 topic 和 vgroup 的已提交偏移量。
|
||||
- tmq:[入参] 指向一个有效的 ws_tmq_t 结构体指针,该结构体代表一个 TMQ 消费者对象。
|
||||
- pTopicName:[入参] 要查询已提交偏移量的主题名称。
|
||||
- vgId:[入参] vgroup 的 ID。
|
||||
- **返回值**:`>=0`:成功,返回一个 int64_t 类型的值,表示已提交的偏移量。`<0`:失败,返回值就是错误码,可调用函数 `ws_tmq_errstr(tmq)` 获取更详细的错误信息。
|
||||
|
||||
- `int32_t ws_tmq_commit_sync(ws_tmq_t *tmq, const WS_RES *rs)`
|
||||
- **接口说明**:同步提交 TMQ 消费者对象处理的消息偏移量。
|
||||
- tmq:[入参] 指向一个有效的 ws_tmq_t 结构体指针,该结构体代表一个 TMQ 消费者对象。
|
||||
- rs:[入参] 指向一个有效的 WS_RES 结构体指针,该结构体包含了已处理的消息。如果为 NULL,提交当前 consumer 所有消费的 vgroup 的当前进度。
|
||||
- **返回值**:`0`:成功,已经成功提交偏移量。非 `0`:失败,可调用函数 `ws_tmq_errstr(tmq)` 获取更详细的错误信息。
|
||||
|
||||
- `int32_t ws_tmq_commit_offset_sync(ws_tmq_t *tmq,
|
||||
const char *pTopicName,
|
||||
int32_t vgId,
|
||||
int64_t offset)`
|
||||
- **接口说明**:同步提交 TMQ 消费者对象的特定主题和 vgroup 的偏移量。
|
||||
- tmq:[入参] 指向一个有效的 ws_tmq_t 结构体指针,该结构体代表一个 TMQ 消费者对象。
|
||||
- pTopicName:[入参] 要提交偏移量的主题名称。
|
||||
- vgId:[入参] 虚拟组 vgroup 的 ID。
|
||||
- offset:[入参] 要提交的偏移量。
|
||||
- **返回值**:`0`:成功,已经成功提交偏移量。非 `0`:失败,可调用函数 `ws_tmq_errstr(tmq)` 获取更详细的错误信息。
|
||||
|
||||
- `int64_t ws_tmq_position(ws_tmq_t *tmq, const char *pTopicName, int32_t vgId)`
|
||||
- **接口说明**:获取当前消费位置,即已消费到的数据位置的下一个位置.
|
||||
- tmq:[入参] 指向一个有效的 ws_tmq_t 结构体指针,该结构体代表一个 TMQ 消费者对象。
|
||||
- pTopicName:[入参] 要查询当前位置的主题名称。
|
||||
- vgId:[入参] 虚拟组 vgroup 的 ID。
|
||||
- **返回值**:`>=0`:成功,返回一个 int64_t 类型的值,表示当前位置的偏移量。`<0`:失败,返回值就是错误码,可调用函数 `ws_tmq_errstr(tmq)` 获取更详细的错误信息。
|
||||
|
||||
- `int32_t ws_tmq_offset_seek(ws_tmq_t *tmq, const char *pTopicName, int32_t vgId, int64_t offset)`
|
||||
- **接口说明**:将 TMQ 消费者对象在某个特定 topic 和 vgroup 的偏移量设置到指定的位置。
|
||||
- tmq:[入参] 指向一个有效的 ws_tmq_t 结构体指针,该结构体代表一个 TMQ 消费者对象。
|
||||
- pTopicName:[入参] 要查询当前位置的主题名称。
|
||||
- vgId:[入参] 虚拟组 vgroup 的 ID。
|
||||
- offset:[入参] 虚拟组 vgroup 的 ID。
|
||||
- **返回值**:`0`:成功,非 `0`:失败,可调用函数 `ws_tmq_errstr(tmq)` 获取更详细的错误信息。
|
||||
|
||||
- `int64_t ws_tmq_get_vgroup_offset(const WS_RES *rs)`
|
||||
- **接口说明**:从 TMQ 消费者获取的消息结果中提取虚拟组(vgroup)的当前消费数据位置的偏移量。
|
||||
- res:[入参] 指向一个有效的 WS_RES 结构体指针,该结构体包含了从 TMQ 消费者轮询得到的消息。
|
||||
- **返回值**:`>=0`:成功,返回一个 int64_t 类型的值,表示当前消费位置的偏移量。`<0`:失败,返回值就是错误码,可调用函数 `ws_tmq_errstr(tmq)` 获取更详细的错误信息。
|
||||
|
||||
- `int32_t ws_tmq_get_vgroup_id(const WS_RES *rs)`
|
||||
- **接口说明**:从 TMQ 消费者获取的消息结果中提取所属虚拟组(vgroup)的 ID。
|
||||
- res:[入参] 指向一个有效的 WS_RES 结构体指针,该结构体包含了从 TMQ 消费者轮询得到的消息。
|
||||
- **返回值**:`>=0`:成功,返回一个 int32_t 类型的值,表示虚拟组(vgroup)的 ID。`<0`:失败,返回值就是错误码,可调用函数 `ws_tmq_errstr(tmq)` 获取更详细的错误信息。
|
||||
|
||||
- `const char *ws_tmq_get_table_name(const WS_RES *rs)`
|
||||
- **接口说明**:从 TMQ 消费者获取的消息结果中获取所属的表名。
|
||||
- res:[入参] 指向一个有效的 WS_RES 结构体指针,该结构体包含了从 TMQ 消费者轮询得到的消息。
|
||||
- **返回值**:非 `NULL`:成功,返回一个 const char * 类型的指针,指向表名字符串。`NULL`:失败,非法的输入参数。
|
||||
|
||||
- `enum ws_tmq_res_t ws_tmq_get_res_type(const WS_RES *rs)`
|
||||
- **接口说明**:从 TMQ 消费者获取的消息结果中获取消息类型。
|
||||
- res:[入参] 指向一个有效的 WS_RES 结构体指针,该结构体包含了从 TMQ 消费者轮询得到的消息。
|
||||
- **返回值**:返回一个 ws_tmq_res_t 类型的枚举值,表示消息类型。
|
||||
- ws_tmq_res_t 表示消费到的数据类型,定义如下:
|
||||
```
|
||||
typedef enum ws_tmq_res_t {
|
||||
WS_TMQ_RES_INVALID = -1, // 无效
|
||||
WS_TMQ_RES_DATA = 1, // 数据类型
|
||||
WS_TMQ_RES_TABLE_META = 2, // 元数据类型
|
||||
WS_TMQ_RES_METADATA = 3 // 既有元数据类型又有数据类型,即自动建表
|
||||
} tmq_res_t;
|
||||
```
|
||||
|
||||
- `const char *ws_tmq_get_topic_name(const WS_RES *rs)`
|
||||
- **接口说明**:从 TMQ 消费者获取的消息结果中获取所属的 topic 名称。
|
||||
- res:[入参] 指向一个有效的 WS_RES 结构体指针,该结构体包含了从 TMQ 消费者轮询得到的消息。
|
||||
- **返回值**:非 `NULL`:成功,返回一个 const char * 类型的指针,指向 topic 名称字符串。`NULL`:失败,非法的输入参数。
|
||||
|
||||
- `const char *ws_tmq_get_db_name(const WS_RES *rs)`
|
||||
- **接口说明**:从 TMQ 消费者获取的消息结果中获取所属的数据库名称。
|
||||
- res:[入参] 指向一个有效的 WS_RES 结构体指针,该结构体包含了从 TMQ 消费者轮询得到的消息。
|
||||
- **返回值**:非 `NULL`:成功,返回一个 const char * 类型的指针,指向数据库名称字符串。`NULL`:失败,非法的输入参数。
|
||||
|
||||
## 原生连接方式
|
||||
原生连接方式需要使用 taos.h 头文件和 taos 动态库。
|
||||
```c
|
||||
#include <taos.h>
|
||||
```
|
||||
|
@ -22,21 +629,21 @@ TDengine 客户端驱动的动态库位于:
|
|||
- Windows: `C:\TDengine\taos.dll`
|
||||
- macOS: `/usr/local/lib/libtaos.dylib`
|
||||
|
||||
## 支持的平台
|
||||
### 支持的平台
|
||||
|
||||
请参考[支持的平台列表](../#支持的平台)
|
||||
|
||||
## 支持的版本
|
||||
### 支持的版本
|
||||
|
||||
TDengine 客户端驱动的版本号与 TDengine 服务端的版本号是一一对应的强对应关系,建议使用与 TDengine 服务端完全相同的客户端驱动。虽然低版本的客户端驱动在前三段版本号一致(即仅第四段版本号不同)的情况下也能够与高版本的服务端相兼容,但这并非推荐用法。强烈不建议使用高版本的客户端驱动访问低版本的服务端。
|
||||
|
||||
## 错误码
|
||||
### 错误码
|
||||
|
||||
在 C 接口的设计中,错误码采用整数类型表示,每个错误码都对应一个特定的错误状态。如未特别说明,当 API 的返回值是整数时,_0_ 代表成功,其它是代表失败原因的错误码,当返回值是指针时, _NULL_ 表示失败。
|
||||
所有的错误码以及对应的原因描述在 `taoserror.h` 文件中。
|
||||
详细的错误码说明参考:[错误码](../../../reference/error-code)
|
||||
|
||||
## 示例程序
|
||||
### 示例程序
|
||||
|
||||
本节展示了使用客户端驱动访问 TDengine 集群的常见访问方式的示例代码。
|
||||
|
||||
|
@ -57,11 +664,11 @@ TDengine 客户端驱动的版本号与 TDengine 服务端的版本号是一一
|
|||
|
||||
:::
|
||||
|
||||
## API 参考
|
||||
### API 参考
|
||||
|
||||
以下分别介绍 TDengine 客户端驱动的基础 API、同步 API、异步 API、订阅 API 和无模式写入 API。
|
||||
以下分别介绍 TDengine 客户端驱动的基础 API、同步 API、异步 API、参数绑定 API,无模式写入 API 和数据订阅 API。
|
||||
|
||||
### 基础 API
|
||||
#### 基础 API
|
||||
|
||||
基础 API 用于完成创建数据库连接等工作,为其它 API 的执行提供运行时环境。
|
||||
|
||||
|
@ -145,7 +752,7 @@ TDengine 客户端驱动的版本号与 TDengine 服务端的版本号是一一
|
|||
- **参数说明**:
|
||||
- taos:[入参] 指向数据库连接的指针,数据库连接是通过 `taos_connect()` 函数建立。
|
||||
|
||||
### 同步查询
|
||||
#### 同步查询
|
||||
|
||||
本小节介绍 API 均属于同步接口。应用调用后,会阻塞等待响应,直到获得返回结果或错误信息。
|
||||
|
||||
|
@ -228,7 +835,7 @@ TDengine 客户端驱动的版本号与 TDengine 服务端的版本号是一一
|
|||
|
||||
:::
|
||||
|
||||
### 异步查询
|
||||
#### 异步查询
|
||||
|
||||
TDengine 还提供性能更高的异步 API 处理数据插入、查询操作。在软硬件环境相同的情况下,异步 API 处理数据插入的速度比同步 API 快 2 ~ 4 倍。异步 API 采用非阻塞式的调用方式,在系统真正完成某个具体数据库操作前,立即返回。调用的线程可以去处理其他工作,从而可以提升整个应用的性能。异步 API 在网络延迟严重的情况下,优势尤为突出。
|
||||
|
||||
|
@ -252,7 +859,7 @@ TDengine 还提供性能更高的异步 API 处理数据插入、查询操作。
|
|||
|
||||
TDengine 的异步 API 均采用非阻塞调用模式。应用程序可以用多线程同时打开多张表,并可以同时对每张打开的表进行查询或者插入操作。需要指出的是,**客户端应用必须确保对同一张表的操作完全串行化**,即对同一个表的插入或查询操作未完成时(未返回时),不能够执行第二个插入或查询操作。
|
||||
|
||||
### 参数绑定
|
||||
#### 参数绑定
|
||||
|
||||
除了直接调用 `taos_query()` 进行查询,TDengine 也提供了支持参数绑定的 Prepare API,风格与 MySQL 类似,目前也仅支持用问号 `?` 来代表待绑定的参数。
|
||||
|
||||
|
@ -350,7 +957,7 @@ TDengine 的异步 API 均采用非阻塞调用模式。应用程序可以用多
|
|||
- stmt:[入参] 指向一个有效的预编译的 SQL 语句对象指针。
|
||||
- **返回值**:返回一个指向包含错误信息的字符串的指针。
|
||||
|
||||
### 无模式写入
|
||||
#### 无模式写入
|
||||
|
||||
除了使用 SQL 方式或者使用参数绑定 API 写入数据外,还可以使用 Schemaless 的方式完成写入。Schemaless 可以免于预先创建超级表/数据子表的数据结构,而是可以直接写入数据,TDengine 系统会根据写入的数据内容自动创建和维护所需要的表结构。Schemaless 的使用方式详见 [Schemaless 写入](../../../develop/schemaless/) 章节,这里介绍与之配套使用的 C/C++ API。
|
||||
|
||||
|
@ -474,7 +1081,7 @@ TDengine 的异步 API 均采用非阻塞调用模式。应用程序可以用多
|
|||
- 带_ttl的接口可以传递ttl参数来控制建表的ttl到期时间。
|
||||
- 带_reqid的接口可以通过传递reqid参数来追踪整个的调用链。
|
||||
|
||||
### 数据订阅
|
||||
#### 数据订阅
|
||||
- `const char *tmq_err2str(int32_t code)`
|
||||
- **接口说明**:用于将数据订阅的错误码转换为错误信息。
|
||||
- code:[入参] 数据订阅的错误码。
|
||||
|
@ -584,7 +1191,7 @@ TDengine 的异步 API 均采用非阻塞调用模式。应用程序可以用多
|
|||
- **接口说明**:获取 TMQ 消费者对象对特定 topic 和 vgroup 的已提交偏移量。
|
||||
- tmq:[入参] 指向一个有效的 tmq_t 结构体指针,该结构体代表一个 TMQ 消费者对象。
|
||||
- pTopicName:[入参] 要查询已提交偏移量的主题名称。
|
||||
- assignment:[入参] vgroup 的 ID。
|
||||
- vgId:[入参] vgroup 的 ID。
|
||||
- **返回值**:`>=0`:成功,返回一个 int64_t 类型的值,表示已提交的偏移量。`<0`:失败,返回值就是错误码,可调用函数 `char *tmq_err2str(int32_t code)` 获取更详细的错误信息。
|
||||
|
||||
- `int32_t tmq_commit_sync(tmq_t *tmq, const TAOS_RES *msg)`
|
||||
|
@ -604,6 +1211,8 @@ TDengine 的异步 API 均采用非阻塞调用模式。应用程序可以用多
|
|||
- **接口说明**:同步提交 TMQ 消费者对象的特定主题和 vgroup 的偏移量。
|
||||
- tmq:[入参] 指向一个有效的 tmq_t 结构体指针,该结构体代表一个 TMQ 消费者对象。
|
||||
- pTopicName:[入参] 要提交偏移量的主题名称。
|
||||
- vgId:[入参] 虚拟组 vgroup 的 ID。
|
||||
- offset:[入参] 要提交的偏移量。
|
||||
- **返回值**:`0`:成功,已经成功提交偏移量。非 `0`:失败,可调用函数 `char *tmq_err2str(int32_t code)` 获取更详细的错误信息。
|
||||
|
||||
- `void tmq_commit_offset_async(tmq_t *tmq, const char *pTopicName, int32_t vgId, int64_t offset, tmq_commit_cb *cb, void *param)`
|
||||
|
|
|
@ -113,11 +113,11 @@ DSN 描述字符串基本结构如下:
|
|||
各部分意义见下表:
|
||||
|
||||
- **driver**: 必须指定驱动名以便连接器选择何种方式创建连接,支持如下驱动名:
|
||||
- **taos**: 表名使用 TDengine 连接器驱动。
|
||||
- **taos**: 使用 TDengine 连接器驱动,默认是使用 taos 驱动。
|
||||
- **tmq**: 使用 TMQ 订阅数据。
|
||||
- **protocol**: 显示指定以何种方式建立连接,例如:`taos+ws://localhost:6041` 指定以 Websocket 方式建立连接。
|
||||
- **http/ws**: 使用 Websocket 创建连接。
|
||||
- **https/wss**: 在 Websocket 连接方式下显示启用 SSL/TLS 连接。
|
||||
- **protocol**: 显示指定以何种方式建立连接,例如:`taos+ws://localhost:6041` 指定以 Websocket 方式建立连接。
|
||||
- **username/password**: 用于创建连接的用户名及密码。
|
||||
- **host/port**: 指定创建连接的服务器及端口,当不指定服务器地址及端口时(`taos://`),原生连接默认为 `localhost:6030`,Websocket 连接默认为 `localhost:6041` 。
|
||||
- **database**: 指定默认连接的数据库名,可选参数。
|
||||
|
@ -522,6 +522,6 @@ Offset 结构体提供了获取当前消息所属的数据库,主题和分区
|
|||
|
||||
## 附录
|
||||
- Rust 连接器文档:https://docs.rs/taos
|
||||
- Rust 连接器项目地址: https://github.com/taosdata/rust-connector-taos
|
||||
- Rust 连接器项目地址: https://github.com/taosdata/taos-connector-rust
|
||||
- deadpool 连接池: https://crates.io/crates/deadpool
|
||||
- r2d2 连接池: https://crates.io/crates/r2d2
|
||||
|
|
|
@ -85,8 +85,6 @@ Node.js 连接器目前仅支持 Websocket 连接器, 其通过 taosAdapter
|
|||
| [sql_example](https://github.com/taosdata/TDengine/tree/main/docs/examples/node/websocketexample/sql_example.js) | 基本的使用如如建立连接,执行 SQL 等操作。 |
|
||||
| [stmt_example](https://github.com/taosdata/TDengine/tree/main/docs/examples/node/websocketexample/stmt_example.js) | 绑定参数插入的示例。 | |
|
||||
| [line_example](https://github.com/taosdata/TDengine/tree/main/docs/examples/node/websocketexample/line_example.js) | 行协议写入示例。 |
|
||||
| [telnet_line_example](https://github.com/taosdata/TDengine/tree/main/docs/examples/node/websocketexample/telnet_line_example.js) | OpenTSDB Telnet 行协议写入示例。 |
|
||||
| [json_line_example](https://github.com/taosdata/TDengine/tree/main/docs/examples/node/websocketexample/json_line_example.js) | OpenTSDB JSON 行协议写入示例。 |
|
||||
| [tmq_example](https://github.com/taosdata/TDengine/tree/main/docs/examples/node/websocketexample/tmq_example.js) | 订阅的使用示例。 |
|
||||
| [all_type_query](https://github.com/taosdata/TDengine/tree/main/docs/examples/node/websocketexample/all_type_query.js) | 支持全部类型示例。 |
|
||||
| [all_type_stmt](https://github.com/taosdata/TDengine/tree/main/docs/examples/node/websocketexample/all_type_stmt.js) | 参数绑定支持全部类型示例。 |
|
||||
|
|
|
@ -28,14 +28,14 @@ TDengine 提供了丰富的应用程序开发接口,为了便于用户快速
|
|||
|
||||
TDengine 版本更新往往会增加新的功能特性,列表中的连接器版本为连接器最佳适配版本。
|
||||
|
||||
| **TDengine 版本** | **Java** | **Python** | **Go** | **C#** | **Node.js** | **Rust** |
|
||||
| ---------------------- | ----------- | ------------------------------------------- | ------------ | ------------- | --------------- | -------- |
|
||||
| **3.3.0.0 及以上** | 3.3.0及以上 | taospy 2.7.15及以上,taos-ws-py 0.3.2及以上 | 3.5.5及以上 | 3.1.3及以上 | 3.1.0及以上 | 当前版本 |
|
||||
| **3.0.0.0 及以上** | 3.0.2以上 | 当前版本 | 3.0 分支 | 3.0.0 | 3.1.0 | 当前版本 |
|
||||
| **2.4.0.14 及以上** | 2.0.38 | 当前版本 | develop 分支 | 1.0.2 - 1.0.6 | 2.0.10 - 2.0.12 | 当前版本 |
|
||||
| **2.4.0.4 - 2.4.0.13** | 2.0.37 | 当前版本 | develop 分支 | 1.0.2 - 1.0.6 | 2.0.10 - 2.0.12 | 当前版本 |
|
||||
| **2.2.x.x ** | 2.0.36 | 当前版本 | master 分支 | n/a | 2.0.7 - 2.0.9 | 当前版本 |
|
||||
| **2.0.x.x ** | 2.0.34 | 当前版本 | master 分支 | n/a | 2.0.1 - 2.0.6 | 当前版本 |
|
||||
| **TDengine 版本** | **Java** | **Python** | **Go** | **C#** | **Node.js** | **Rust** | **C/C++** |
|
||||
| ---------------------- | ----------- | ------------------------------------------- | ------------ | ------------- | --------------- | -------- | -------------------- |
|
||||
| **3.3.0.0 及以上** | 3.3.0及以上 | taospy 2.7.15及以上,taos-ws-py 0.3.2及以上 | 3.5.5及以上 | 3.1.3及以上 | 3.1.0及以上 | 当前版本 | 与 TDengine 相同版本 |
|
||||
| **3.0.0.0 及以上** | 3.0.2以上 | 当前版本 | 3.0 分支 | 3.0.0 | 3.1.0 | 当前版本 | 与 TDengine 相同版本 |
|
||||
| **2.4.0.14 及以上** | 2.0.38 | 当前版本 | develop 分支 | 1.0.2 - 1.0.6 | 2.0.10 - 2.0.12 | 当前版本 | 与 TDengine 相同版本 |
|
||||
| **2.4.0.4 - 2.4.0.13** | 2.0.37 | 当前版本 | develop 分支 | 1.0.2 - 1.0.6 | 2.0.10 - 2.0.12 | 当前版本 | 与 TDengine 相同版本 |
|
||||
| **2.2.x.x ** | 2.0.36 | 当前版本 | master 分支 | n/a | 2.0.7 - 2.0.9 | 当前版本 | 与 TDengine 相同版本 |
|
||||
| **2.0.x.x ** | 2.0.34 | 当前版本 | master 分支 | n/a | 2.0.1 - 2.0.6 | 当前版本 | 与 TDengine 相同版本 |
|
||||
|
||||
## 功能特性
|
||||
|
||||
|
@ -43,13 +43,13 @@ TDengine 版本更新往往会增加新的功能特性,列表中的连接器
|
|||
|
||||
### 使用原生接口(taosc)
|
||||
|
||||
| **功能特性** | **Java** | **Python** | **Go** | **C#** | **Rust** |
|
||||
| ------------------- | -------- | ---------- | ------ | ------ | -------- |
|
||||
| **连接管理** | 支持 | 支持 | 支持 | 支持 | 支持 |
|
||||
| **执行 SQL** | 支持 | 支持 | 支持 | 支持 | 支持 |
|
||||
| **参数绑定** | 支持 | 支持 | 支持 | 支持 | 支持 |
|
||||
| **数据订阅(TMQ)** | 支持 | 支持 | 支持 | 支持 | 支持 |
|
||||
| **无模式写入** | 支持 | 支持 | 支持 | 支持 | 支持 |
|
||||
| **功能特性** | **Java** | **Python** | **Go** | **C#** | **Rust** | **C/C++** |
|
||||
| ------------------- | -------- | ---------- | ------ | ------ | -------- | --------- |
|
||||
| **连接管理** | 支持 | 支持 | 支持 | 支持 | 支持 | 支持 |
|
||||
| **执行 SQL** | 支持 | 支持 | 支持 | 支持 | 支持 | 支持 |
|
||||
| **参数绑定** | 支持 | 支持 | 支持 | 支持 | 支持 | 支持 |
|
||||
| **数据订阅(TMQ)** | 支持 | 支持 | 支持 | 支持 | 支持 | 支持 |
|
||||
| **无模式写入** | 支持 | 支持 | 支持 | 支持 | 支持 | 支持 |
|
||||
|
||||
:::info
|
||||
由于不同编程语言数据库框架规范不同,并不意味着所有 C/C++ 接口都需要对应封装支持。
|
||||
|
@ -64,13 +64,13 @@ TDengine 版本更新往往会增加新的功能特性,列表中的连接器
|
|||
|
||||
### 使用 Websocket 接口
|
||||
|
||||
| **功能特性** | **Java** | **Python** | **Go** | **C#** | **Node.js** | **Rust** |
|
||||
| ------------------- | -------- | ---------- | ------ | ------ | ----------- | -------- |
|
||||
| **连接管理** | 支持 | 支持 | 支持 | 支持 | 支持 | 支持 |
|
||||
| **执行 SQL** | 支持 | 支持 | 支持 | 支持 | 支持 | 支持 |
|
||||
| **参数绑定** | 支持 | 支持 | 支持 | 支持 | 支持 | 支持 |
|
||||
| **数据订阅(TMQ)** | 支持 | 支持 | 支持 | 支持 | 支持 | 支持 |
|
||||
| **无模式写入** | 支持 | 支持 | 支持 | 支持 | 支持 | 支持 |
|
||||
| **功能特性** | **Java** | **Python** | **Go** | **C#** | **Node.js** | **Rust** | **C/C++** |
|
||||
| ------------------- | -------- | ---------- | ------ | ------ | ----------- | -------- | --------- |
|
||||
| **连接管理** | 支持 | 支持 | 支持 | 支持 | 支持 | 支持 | 支持 |
|
||||
| **执行 SQL** | 支持 | 支持 | 支持 | 支持 | 支持 | 支持 | 支持 |
|
||||
| **参数绑定** | 支持 | 支持 | 支持 | 支持 | 支持 | 支持 | 支持 |
|
||||
| **数据订阅(TMQ)** | 支持 | 支持 | 支持 | 支持 | 支持 | 支持 | 支持 |
|
||||
| **无模式写入** | 支持 | 支持 | 支持 | 支持 | 支持 | 支持 | 支持 |
|
||||
|
||||
:::warning
|
||||
- 无论选用何种编程语言的连接器,2.0 及以上版本的 TDengine 推荐数据库应用的每个线程都建立一个独立的连接,或基于线程建立连接池,以避免连接内的“USE statement”状态量在线程之间相互干扰(但连接的查询和写入操作都是线程安全的)。
|
||||
|
|
|
@ -7,11 +7,11 @@ description: "TDengine 服务端、客户端和连接器支持的平台列表"
|
|||
## TDengine 服务端支持的平台列表
|
||||
|
||||
| | **Windows server 2016/2019** | **Windows 10/11** | **CentOS 7.9/8** | **Ubuntu 18 以上** | **统信 UOS** | **银河/中标麒麟** | **凝思 V60/V80** | **macOS** |
|
||||
| ------------ | ---------------------------- | ----------------- | ---------------- | ---------------- | ------------ | ----------------- | ---------------- | --------- |
|
||||
| X64 | ●/E | ●/E | ● | ● | ●/E | ●/E | ●/E | ● |
|
||||
| 树莓派 ARM64 | | | ● | | | | | |
|
||||
| 华为云 ARM64 | | | | ● | | | | |
|
||||
| M1 | | | | | | | | ● |
|
||||
| ------------ | ---------------------------- | ----------------- | ---------------- | ------------------ | ------------ | ----------------- | ---------------- | --------- |
|
||||
| X64 | ●/E | ●/E | ● | ● | ●/E | ●/E | ●/E | ● |
|
||||
| 树莓派 ARM64 | | | ● | | | | | |
|
||||
| 华为云 ARM64 | | | | ● | | | | |
|
||||
| M1 | | | | | | | | ● |
|
||||
|
||||
注:1) ● 表示经过官方测试验证, ○ 表示非官方测试验证,E 表示仅企业版支持。
|
||||
2) 社区版仅支持主流操作系统的较新版本,包括 Ubuntu 18+/CentOS 7+/RedHat/Debian/CoreOS/FreeBSD/OpenSUSE/SUSE Linux/Fedora/macOS 等。如果有其他操作系统及版本的需求,请联系企业版支持。
|
||||
|
@ -31,6 +31,7 @@ description: "TDengine 服务端、客户端和连接器支持的平台列表"
|
|||
| **Go** | ● | ● | ● | ● | ● |
|
||||
| **NodeJs** | ● | ● | ● | ○ | ○ |
|
||||
| **C#** | ● | ● | ○ | ○ | ○ |
|
||||
| **Rust** | ● | ● | ○ | ● | ● |
|
||||
| **RESTful** | ● | ● | ● | ● | ● |
|
||||
|
||||
注:● 表示官方测试验证通过,○ 表示非官方测试验证通过,-- 表示未经验证。
|
||||
|
|
|
@ -32,7 +32,6 @@ extern int32_t tsS3PageCacheSize;
|
|||
extern int32_t tsS3UploadDelaySec;
|
||||
|
||||
int32_t s3Init();
|
||||
void s3CleanUp();
|
||||
int32_t s3CheckCfg();
|
||||
int32_t s3PutObjectFromFile(const char *file, const char *object);
|
||||
int32_t s3PutObjectFromFile2(const char *file, const char *object, int8_t withcp);
|
||||
|
|
|
@ -153,7 +153,6 @@ char *tTagValToData(const STagVal *pTagVal, bool isJson);
|
|||
int32_t tEncodeTag(SEncoder *pEncoder, const STag *pTag);
|
||||
int32_t tDecodeTag(SDecoder *pDecoder, STag **ppTag);
|
||||
int32_t tTagToValArray(const STag *pTag, SArray **ppArray);
|
||||
void tTagSetCid(const STag *pTag, int16_t iTag, int16_t cid);
|
||||
void debugPrintSTag(STag *pTag, const char *tag, int32_t ln); // TODO: remove
|
||||
int32_t parseJsontoTagData(const char *json, SArray *pTagVals, STag **ppTag, void *pMsgBuf);
|
||||
|
||||
|
|
|
@ -37,9 +37,9 @@ extern taos_collector_registry_t *TAOS_COLLECTOR_REGISTRY_DEFAULT;
|
|||
|
||||
/**
|
||||
* @brief Initializes the default collector registry and enables metric collection on the executing process
|
||||
* @return A non-zero integer value upon failure
|
||||
* @return
|
||||
*/
|
||||
int taos_collector_registry_default_init(void);
|
||||
void taos_collector_registry_default_init(void);
|
||||
|
||||
/**
|
||||
* @brief Constructs a taos_collector_registry_t*
|
||||
|
|
|
@ -76,7 +76,6 @@ typedef int (*__compar_fn_t)(const void *, const void *);
|
|||
|
||||
char *strsep(char **stringp, const char *delim);
|
||||
char *getpass(const char *prefix);
|
||||
char *strndup(const char *s, int n);
|
||||
|
||||
// for send function in tsocket.c
|
||||
#define MSG_NOSIGNAL 0
|
||||
|
|
|
@ -51,6 +51,7 @@ typedef enum { M2C = 0, C2M } ConvType;
|
|||
#define strtod STR_TO_LD_FUNC_TAOS_FORBID
|
||||
#define strtold STR_TO_D_FUNC_TAOS_FORBID
|
||||
#define strtof STR_TO_F_FUNC_TAOS_FORBID
|
||||
#define strndup STR_TO_F_FUNC_TAOS_FORBID
|
||||
#endif
|
||||
|
||||
#define tstrncpy(dst, src, size) \
|
||||
|
@ -101,8 +102,9 @@ int8_t taosStr2Int8(const char *str, char **pEnd, int32_t radix);
|
|||
uint8_t taosStr2UInt8(const char *str, char **pEnd, int32_t radix);
|
||||
double taosStr2Double(const char *str, char **pEnd);
|
||||
float taosStr2Float(const char *str, char **pEnd);
|
||||
int32_t taosHex2Ascii(const char *z, uint32_t n, void** data, uint32_t* size);
|
||||
int32_t taosAscii2Hex(const char *z, uint32_t n, void** data, uint32_t* size);
|
||||
int32_t taosHex2Ascii(const char *z, uint32_t n, void **data, uint32_t *size);
|
||||
int32_t taosAscii2Hex(const char *z, uint32_t n, void **data, uint32_t *size);
|
||||
char *taosStrndup(const char *s, int n);
|
||||
//int32_t taosBin2Ascii(const char *z, uint32_t n, void** data, uint32_t* size);
|
||||
bool isHex(const char* z, uint32_t n);
|
||||
bool isValidateHex(const char* z, uint32_t n);
|
||||
|
|
|
@ -72,8 +72,8 @@ extern "C" {
|
|||
#ifdef TD_TSZ
|
||||
extern bool lossyFloat;
|
||||
extern bool lossyDouble;
|
||||
int32_t tsCompressInit(char *lossyColumns, float fPrecision, double dPrecision, uint32_t maxIntervals,
|
||||
uint32_t intervals, int32_t ifAdtFse, const char *compressor);
|
||||
void tsCompressInit(char *lossyColumns, float fPrecision, double dPrecision, uint32_t maxIntervals, uint32_t intervals,
|
||||
int32_t ifAdtFse, const char *compressor);
|
||||
|
||||
void tsCompressExit();
|
||||
|
||||
|
@ -153,11 +153,10 @@ int32_t tsDecompressBigint(void *pIn, int32_t nIn, int32_t nEle, void *pOut, int
|
|||
int32_t getWordLength(char type);
|
||||
|
||||
int32_t tsDecompressIntImpl_Hw(const char *const input, const int32_t nelements, char *const output, const char type);
|
||||
int32_t tsDecompressFloatImplAvx512(const char *const input, const int32_t nelements, char *const output);
|
||||
int32_t tsDecompressFloatImplAvx2(const char *const input, const int32_t nelements, char *const output);
|
||||
int32_t tsDecompressTimestampAvx512(const char *const input, const int32_t nelements, char *const output,
|
||||
bool bigEndian);
|
||||
int32_t tsDecompressTimestampAvx2(const char *const input, const int32_t nelements, char *const output, bool bigEndian);
|
||||
void tsDecompressFloatImplAvx512(const char *const input, const int32_t nelements, char *const output);
|
||||
void tsDecompressFloatImplAvx2(const char *const input, const int32_t nelements, char *const output);
|
||||
void tsDecompressTimestampAvx512(const char *const input, const int32_t nelements, char *const output, bool bigEndian);
|
||||
void tsDecompressTimestampAvx2(const char *const input, const int32_t nelements, char *const output, bool bigEndian);
|
||||
|
||||
/*************************************************************************
|
||||
* REGULAR COMPRESSION 2
|
||||
|
|
|
@ -116,23 +116,14 @@ function install_bin() {
|
|||
${csudo}cp -r ${script_dir}/bin/* ${install_main_dir}/bin && ${csudo}chmod 0555 ${install_main_dir}/bin/*
|
||||
|
||||
#Make link
|
||||
[ -x ${install_main_dir}/bin/${clientName} ] && ${csudo}ln -s ${install_main_dir}/bin/${clientName} ${bin_link_dir}/${clientName} || :
|
||||
[ -x ${install_main_dir}/bin/${clientName2} ] && ${csudo}ln -s ${install_main_dir}/bin/${clientName2} ${bin_link_dir}/${clientName2} || :
|
||||
if [ "$osType" != "Darwin" ]; then
|
||||
[ -x ${install_main_dir}/bin/${demoName2} ] && ${csudo}ln -s ${install_main_dir}/bin/${demoName2} ${bin_link_dir}/${demoName2} || :
|
||||
fi
|
||||
[ -x ${install_main_dir}/bin/remove_client.sh ] && ${csudo}ln -s ${install_main_dir}/bin/remove_client.sh ${bin_link_dir}/${uninstallScript} || :
|
||||
[ -x ${install_main_dir}/bin/set_core.sh ] && ${csudo}ln -s ${install_main_dir}/bin/set_core.sh ${bin_link_dir}/set_core || :
|
||||
|
||||
if [ "$verMode" == "cluster" ] && [ "$clientName" != "$clientName2" ]; then
|
||||
#Make link
|
||||
[ -x ${install_main_dir}/bin/${clientName2} ] && ${csudo}ln -s ${install_main_dir}/bin/${clientName2} ${bin_link_dir}/${clientName2} || :
|
||||
if [ "$osType" != "Darwin" ]; then
|
||||
[ -x ${install_main_dir}/bin/${demoName2} ] && ${csudo}ln -s ${install_main_dir}/bin/${demoName2} ${bin_link_dir}/${demoName2} || :
|
||||
[ -x ${install_main_dir}/bin/${benchmarkName2} ] && ${csudo}ln -s ${install_main_dir}/bin/${benchmarkName2} ${bin_link_dir}/${benchmarkName2} || :
|
||||
[ -x ${install_main_dir}/bin/${dumpName2} ] && ${csudo}ln -s ${install_main_dir}/bin/${dumpName2} ${bin_link_dir}/${dumpName2} || :
|
||||
fi
|
||||
[ -x ${install_main_dir}/bin/remove_client.sh ] && ${csudo}ln -sf ${install_main_dir}/bin/remove_client.sh ${bin_link_dir}/${uninstallScript2} || :
|
||||
fi
|
||||
[ -x ${install_main_dir}/bin/set_core.sh ] && ${csudo}ln -s ${install_main_dir}/bin/set_core.sh ${bin_link_dir}/set_core || :
|
||||
[ -x ${install_main_dir}/bin/${benchmarkName2} ] && ${csudo}ln -s ${install_main_dir}/bin/${benchmarkName2} ${bin_link_dir}/${benchmarkName2} || :
|
||||
[ -x ${install_main_dir}/bin/${dumpName2} ] && ${csudo}ln -s ${install_main_dir}/bin/${dumpName2} ${bin_link_dir}/${dumpName2} || :
|
||||
}
|
||||
|
||||
function clean_lib() {
|
||||
|
|
|
@ -26,10 +26,10 @@ extern "C" {
|
|||
#include "query.h"
|
||||
#include "taos.h"
|
||||
#include "tcommon.h"
|
||||
#include "tmisce.h"
|
||||
#include "tdef.h"
|
||||
#include "thash.h"
|
||||
#include "tlist.h"
|
||||
#include "tmisce.h"
|
||||
#include "tmsg.h"
|
||||
#include "tmsgtype.h"
|
||||
#include "trpc.h"
|
||||
|
@ -86,7 +86,7 @@ typedef struct {
|
|||
int8_t threadStop;
|
||||
int8_t quitByKill;
|
||||
TdThread thread;
|
||||
TdThreadMutex lock; // used when app init and cleanup
|
||||
TdThreadMutex lock; // used when app init and cleanup
|
||||
SHashObj* appSummary;
|
||||
SHashObj* appHbHash; // key: clusterId
|
||||
SArray* appHbMgrs; // SArray<SAppHbMgr*> one for each cluster
|
||||
|
@ -95,11 +95,11 @@ typedef struct {
|
|||
} SClientHbMgr;
|
||||
|
||||
typedef struct SQueryExecMetric {
|
||||
int64_t start; // start timestamp, us
|
||||
int64_t ctgStart; // start to parse, us
|
||||
int64_t execStart; // start to parse, us
|
||||
int64_t start; // start timestamp, us
|
||||
int64_t ctgStart; // start to parse, us
|
||||
int64_t execStart; // start to parse, us
|
||||
|
||||
int64_t parseCostUs;
|
||||
int64_t parseCostUs;
|
||||
int64_t ctgCostUs;
|
||||
int64_t analyseCostUs;
|
||||
int64_t planCostUs;
|
||||
|
@ -193,7 +193,7 @@ typedef struct SReqResultInfo {
|
|||
char** convertBuf;
|
||||
TAOS_ROW row;
|
||||
SResultColumn* pCol;
|
||||
uint64_t numOfRows; // from int32_t change to int64_t
|
||||
uint64_t numOfRows; // from int32_t change to int64_t
|
||||
uint64_t totalRows;
|
||||
uint64_t current;
|
||||
bool localResultFetched;
|
||||
|
@ -319,12 +319,14 @@ void syncCatalogFn(SMetaData* pResult, void* param, int32_t code);
|
|||
TAOS_RES* taosQueryImpl(TAOS* taos, const char* sql, bool validateOnly, int8_t source);
|
||||
TAOS_RES* taosQueryImplWithReqid(TAOS* taos, const char* sql, bool validateOnly, int64_t reqid);
|
||||
|
||||
void taosAsyncQueryImpl(uint64_t connId, const char* sql, __taos_async_fn_t fp, void* param, bool validateOnly, int8_t source);
|
||||
void taosAsyncQueryImpl(uint64_t connId, const char* sql, __taos_async_fn_t fp, void* param, bool validateOnly,
|
||||
int8_t source);
|
||||
void taosAsyncQueryImplWithReqid(uint64_t connId, const char* sql, __taos_async_fn_t fp, void* param, bool validateOnly,
|
||||
int64_t reqid);
|
||||
void taosAsyncFetchImpl(SRequestObj *pRequest, __taos_async_fn_t fp, void *param);
|
||||
int32_t clientParseSql(void* param, const char* dbName, const char* sql, bool parseOnly, const char* effectiveUser, SParseSqlRes* pRes);
|
||||
void syncQueryFn(void* param, void* res, int32_t code);
|
||||
void taosAsyncFetchImpl(SRequestObj* pRequest, __taos_async_fn_t fp, void* param);
|
||||
int32_t clientParseSql(void* param, const char* dbName, const char* sql, bool parseOnly, const char* effectiveUser,
|
||||
SParseSqlRes* pRes);
|
||||
void syncQueryFn(void* param, void* res, int32_t code);
|
||||
|
||||
int32_t getVersion1BlockMetaSize(const char* p, int32_t numOfCols);
|
||||
|
||||
|
@ -333,7 +335,7 @@ static FORCE_INLINE SReqResultInfo* tmqGetCurResInfo(TAOS_RES* res) {
|
|||
return (SReqResultInfo*)&msg->common.resInfo;
|
||||
}
|
||||
|
||||
int32_t tmqGetNextResInfo(TAOS_RES* res, bool convertUcs4, SReqResultInfo** pResInfo);
|
||||
int32_t tmqGetNextResInfo(TAOS_RES* res, bool convertUcs4, SReqResultInfo** pResInfo);
|
||||
static FORCE_INLINE SReqResultInfo* tscGetCurResInfo(TAOS_RES* res) {
|
||||
if (TD_RES_QUERY(res)) return &(((SRequestObj*)res)->body.resInfo);
|
||||
return tmqGetCurResInfo(res);
|
||||
|
@ -349,8 +351,8 @@ __async_send_cb_fn_t getMsgRspHandle(int32_t msgType);
|
|||
|
||||
SMsgSendInfo* buildMsgInfoImpl(SRequestObj* pReqObj);
|
||||
|
||||
int32_t createTscObj(const char *user, const char *auth, const char *db, int32_t connType, SAppInstInfo *pAppInfo,
|
||||
STscObj **p);
|
||||
int32_t createTscObj(const char* user, const char* auth, const char* db, int32_t connType, SAppInstInfo* pAppInfo,
|
||||
STscObj** p);
|
||||
void destroyTscObj(void* pObj);
|
||||
STscObj* acquireTscObj(int64_t rid);
|
||||
void releaseTscObj(int64_t rid);
|
||||
|
@ -358,7 +360,7 @@ void destroyAppInst(void* pAppInfo);
|
|||
|
||||
uint64_t generateRequestId();
|
||||
|
||||
int32_t createRequest(uint64_t connId, int32_t type, int64_t reqid, SRequestObj **pRequest);
|
||||
int32_t createRequest(uint64_t connId, int32_t type, int64_t reqid, SRequestObj** pRequest);
|
||||
void destroyRequest(SRequestObj* pRequest);
|
||||
SRequestObj* acquireRequest(int64_t rid);
|
||||
int32_t releaseRequest(int64_t rid);
|
||||
|
@ -372,9 +374,9 @@ void resetConnectDB(STscObj* pTscObj);
|
|||
|
||||
int taos_options_imp(TSDB_OPTION option, const char* str);
|
||||
|
||||
int32_t openTransporter(const char* user, const char* auth, int32_t numOfThreads, void **pDnodeConn);
|
||||
void tscStopCrashReport();
|
||||
void cleanupAppInfo();
|
||||
int32_t openTransporter(const char* user, const char* auth, int32_t numOfThreads, void** pDnodeConn);
|
||||
void tscStopCrashReport();
|
||||
void cleanupAppInfo();
|
||||
|
||||
typedef struct AsyncArg {
|
||||
SRpcMsg msg;
|
||||
|
@ -402,17 +404,17 @@ int32_t hbMgrInit();
|
|||
void hbMgrCleanUp();
|
||||
|
||||
// cluster level
|
||||
int32_t appHbMgrInit(SAppInstInfo *pAppInstInfo, char *key, SAppHbMgr **pAppHbMgr);
|
||||
void appHbMgrCleanup(void);
|
||||
void hbRemoveAppHbMrg(SAppHbMgr** pAppHbMgr);
|
||||
void destroyAllRequests(SHashObj* pRequests);
|
||||
void stopAllRequests(SHashObj* pRequests);
|
||||
int32_t appHbMgrInit(SAppInstInfo* pAppInstInfo, char* key, SAppHbMgr** pAppHbMgr);
|
||||
void appHbMgrCleanup(void);
|
||||
void hbRemoveAppHbMrg(SAppHbMgr** pAppHbMgr);
|
||||
void destroyAllRequests(SHashObj* pRequests);
|
||||
void stopAllRequests(SHashObj* pRequests);
|
||||
|
||||
//SAppInstInfo* getAppInstInfo(const char* clusterKey);
|
||||
// SAppInstInfo* getAppInstInfo(const char* clusterKey);
|
||||
|
||||
// conn level
|
||||
int32_t hbRegisterConn(SAppHbMgr* pAppHbMgr, int64_t tscRefId, int64_t clusterId, int8_t connType);
|
||||
void hbDeregisterConn(STscObj* pTscObj, SClientHbKey connKey);
|
||||
void hbDeregisterConn(STscObj* pTscObj, SClientHbKey connKey);
|
||||
|
||||
typedef struct SSqlCallbackWrapper {
|
||||
SParseContext* pParseCtx;
|
||||
|
@ -421,9 +423,9 @@ typedef struct SSqlCallbackWrapper {
|
|||
void* pPlanInfo;
|
||||
} SSqlCallbackWrapper;
|
||||
|
||||
void setQueryRequest(int64_t rId);
|
||||
SRequestObj* launchQueryImpl(SRequestObj* pRequest, SQuery* pQuery, bool keepQuery, void** res);
|
||||
int32_t scheduleQuery(SRequestObj* pRequest, SQueryPlan* pDag, SArray* pNodeList);
|
||||
void setQueryRequest(int64_t rId);
|
||||
void launchQueryImpl(SRequestObj* pRequest, SQuery* pQuery, bool keepQuery, void** res);
|
||||
int32_t scheduleQuery(SRequestObj* pRequest, SQueryPlan* pDag, SArray* pNodeList);
|
||||
void launchAsyncQuery(SRequestObj* pRequest, SQuery* pQuery, SMetaData* pResultMeta, SSqlCallbackWrapper* pWrapper);
|
||||
int32_t refreshMeta(STscObj* pTscObj, SRequestObj* pRequest);
|
||||
int32_t updateQnodeList(SAppInstInfo* pInfo, SArray* pNodeList);
|
||||
|
@ -431,20 +433,21 @@ void doAsyncQuery(SRequestObj* pRequest, bool forceUpdateMeta);
|
|||
int32_t removeMeta(STscObj* pTscObj, SArray* tbList, bool isView);
|
||||
int32_t handleAlterTbExecRes(void* res, struct SCatalog* pCatalog);
|
||||
int32_t handleCreateTbExecRes(void* res, SCatalog* pCatalog);
|
||||
int32_t qnodeRequired(SRequestObj* pRequest, bool *required);
|
||||
int32_t qnodeRequired(SRequestObj* pRequest, bool* required);
|
||||
void continueInsertFromCsv(SSqlCallbackWrapper* pWrapper, SRequestObj* pRequest);
|
||||
void destorySqlCallbackWrapper(SSqlCallbackWrapper* pWrapper);
|
||||
void handleQueryAnslyseRes(SSqlCallbackWrapper *pWrapper, SMetaData *pResultMeta, int32_t code);
|
||||
void restartAsyncQuery(SRequestObj *pRequest, int32_t code);
|
||||
int32_t buildPreviousRequest(SRequestObj *pRequest, const char* sql, SRequestObj** pNewRequest);
|
||||
int32_t prepareAndParseSqlSyntax(SSqlCallbackWrapper **ppWrapper, SRequestObj *pRequest, bool updateMetaForce);
|
||||
void handleQueryAnslyseRes(SSqlCallbackWrapper* pWrapper, SMetaData* pResultMeta, int32_t code);
|
||||
void restartAsyncQuery(SRequestObj* pRequest, int32_t code);
|
||||
int32_t buildPreviousRequest(SRequestObj* pRequest, const char* sql, SRequestObj** pNewRequest);
|
||||
int32_t prepareAndParseSqlSyntax(SSqlCallbackWrapper** ppWrapper, SRequestObj* pRequest, bool updateMetaForce);
|
||||
void returnToUser(SRequestObj* pRequest);
|
||||
void stopAllQueries(SRequestObj *pRequest);
|
||||
void stopAllQueries(SRequestObj* pRequest);
|
||||
void doRequestCallback(SRequestObj* pRequest, int32_t code);
|
||||
void freeQueryParam(SSyncQueryParam* param);
|
||||
|
||||
#ifdef TD_ENTERPRISE
|
||||
int32_t clientParseSqlImpl(void* param, const char* dbName, const char* sql, bool parseOnly, const char* effeciveUser, SParseSqlRes* pRes);
|
||||
int32_t clientParseSqlImpl(void* param, const char* dbName, const char* sql, bool parseOnly, const char* effeciveUser,
|
||||
SParseSqlRes* pRes);
|
||||
#endif
|
||||
|
||||
#define TSC_ERR_RET(c) \
|
||||
|
@ -474,13 +477,9 @@ int32_t clientParseSqlImpl(void* param, const char* dbName, const char* sql, boo
|
|||
|
||||
void slowQueryLog(int64_t rid, bool killed, int32_t code, int32_t cost);
|
||||
|
||||
enum {
|
||||
MONITORSQLTYPESELECT = 0,
|
||||
MONITORSQLTYPEINSERT = 1,
|
||||
MONITORSQLTYPEDELETE = 2
|
||||
};
|
||||
enum { MONITORSQLTYPESELECT = 0, MONITORSQLTYPEINSERT = 1, MONITORSQLTYPEDELETE = 2 };
|
||||
|
||||
void sqlReqLog(int64_t rid, bool killed, int32_t code, int8_t type);
|
||||
void sqlReqLog(int64_t rid, bool killed, int32_t code, int8_t type);
|
||||
|
||||
void tmqMgmtClose(void);
|
||||
|
||||
|
|
|
@ -197,7 +197,12 @@ static int32_t generateWriteSlowLog(STscObj *pTscObj, SRequestObj *pRequest, int
|
|||
ENV_JSON_FALSE_CHECK(cJSON_AddItemToObject(json, "db", cJSON_CreateString("")));
|
||||
}
|
||||
|
||||
char *value = cJSON_PrintUnformatted(json);
|
||||
char *value = cJSON_PrintUnformatted(json);
|
||||
if (value == NULL) {
|
||||
tscError("failed to print json");
|
||||
code = TSDB_CODE_FAILED;
|
||||
goto _end;
|
||||
}
|
||||
MonitorSlowLogData data = {0};
|
||||
data.clusterId = pTscObj->pAppInfo->clusterId;
|
||||
data.type = SLOW_LOG_WRITE;
|
||||
|
|
|
@ -679,9 +679,15 @@ _return:
|
|||
return TSDB_CODE_SUCCESS;
|
||||
}
|
||||
|
||||
void freeVgList(void* list) {
|
||||
SArray* pList = *(SArray**)list;
|
||||
taosArrayDestroy(pList);
|
||||
}
|
||||
|
||||
int32_t buildAsyncExecNodeList(SRequestObj* pRequest, SArray** pNodeList, SArray* pMnodeList, SMetaData* pResultMeta) {
|
||||
SArray* pDbVgList = NULL;
|
||||
SArray* pQnodeList = NULL;
|
||||
FDelete fp = NULL;
|
||||
int32_t code = 0;
|
||||
|
||||
switch (tsQueryPolicy) {
|
||||
|
@ -705,6 +711,43 @@ int32_t buildAsyncExecNodeList(SRequestObj* pRequest, SArray** pNodeList, SArray
|
|||
goto _return;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
fp = freeVgList;
|
||||
|
||||
int32_t dbNum = taosArrayGetSize(pRequest->dbList);
|
||||
if (dbNum > 0) {
|
||||
SCatalog* pCtg = NULL;
|
||||
SAppInstInfo* pInst = pRequest->pTscObj->pAppInfo;
|
||||
code = catalogGetHandle(pInst->clusterId, &pCtg);
|
||||
if (code != TSDB_CODE_SUCCESS) {
|
||||
goto _return;
|
||||
}
|
||||
|
||||
pDbVgList = taosArrayInit(dbNum, POINTER_BYTES);
|
||||
if (NULL == pDbVgList) {
|
||||
code = terrno;
|
||||
goto _return;
|
||||
}
|
||||
SArray* pVgList = NULL;
|
||||
for (int32_t i = 0; i < dbNum; ++i) {
|
||||
char* dbFName = taosArrayGet(pRequest->dbList, i);
|
||||
SRequestConnInfo conn = {.pTrans = pInst->pTransporter,
|
||||
.requestId = pRequest->requestId,
|
||||
.requestObjRefId = pRequest->self,
|
||||
.mgmtEps = getEpSet_s(&pInst->mgmtEp)};
|
||||
|
||||
// catalogGetDBVgList will handle dbFName == null.
|
||||
code = catalogGetDBVgList(pCtg, &conn, dbFName, &pVgList);
|
||||
if (code) {
|
||||
goto _return;
|
||||
}
|
||||
|
||||
if (NULL == taosArrayPush(pDbVgList, &pVgList)) {
|
||||
code = terrno;
|
||||
goto _return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
code = buildVnodePolicyNodeList(pRequest, pNodeList, pMnodeList, pDbVgList);
|
||||
|
@ -745,17 +788,12 @@ int32_t buildAsyncExecNodeList(SRequestObj* pRequest, SArray** pNodeList, SArray
|
|||
}
|
||||
|
||||
_return:
|
||||
taosArrayDestroy(pDbVgList);
|
||||
taosArrayDestroyEx(pDbVgList, fp);
|
||||
taosArrayDestroy(pQnodeList);
|
||||
|
||||
return code;
|
||||
}
|
||||
|
||||
void freeVgList(void* list) {
|
||||
SArray* pList = *(SArray**)list;
|
||||
taosArrayDestroy(pList);
|
||||
}
|
||||
|
||||
int32_t buildSyncExecNodeList(SRequestObj* pRequest, SArray** pNodeList, SArray* pMnodeList) {
|
||||
SArray* pDbVgList = NULL;
|
||||
SArray* pQnodeList = NULL;
|
||||
|
@ -1211,7 +1249,7 @@ void schedulerExecCb(SExecResult* pResult, void* param, int32_t code) {
|
|||
}
|
||||
}
|
||||
|
||||
SRequestObj* launchQueryImpl(SRequestObj* pRequest, SQuery* pQuery, bool keepQuery, void** res) {
|
||||
void launchQueryImpl(SRequestObj* pRequest, SQuery* pQuery, bool keepQuery, void** res) {
|
||||
int32_t code = 0;
|
||||
|
||||
if (pQuery->pRoot) {
|
||||
|
@ -1297,8 +1335,6 @@ SRequestObj* launchQueryImpl(SRequestObj* pRequest, SQuery* pQuery, bool keepQue
|
|||
*res = pRequest->body.resInfo.execRes.res;
|
||||
pRequest->body.resInfo.execRes.res = NULL;
|
||||
}
|
||||
|
||||
return pRequest;
|
||||
}
|
||||
|
||||
static int32_t asyncExecSchQuery(SRequestObj* pRequest, SQuery* pQuery, SMetaData* pResultMeta,
|
||||
|
@ -2405,10 +2441,9 @@ char* getDbOfConnection(STscObj* pObj) {
|
|||
(void)taosThreadMutexLock(&pObj->mutex);
|
||||
size_t len = strlen(pObj->db);
|
||||
if (len > 0) {
|
||||
p = strndup(pObj->db, tListLen(pObj->db));
|
||||
p = taosStrndup(pObj->db, tListLen(pObj->db));
|
||||
if (p == NULL) {
|
||||
tscError("failed to strndup db name");
|
||||
terrno = TSDB_CODE_OUT_OF_MEMORY;
|
||||
tscError("failed to taosStrndup db name");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2896,8 +2931,8 @@ TAOS_RES* taosQueryImpl(TAOS* taos, const char* sql, bool validateOnly, int8_t s
|
|||
return NULL;
|
||||
}
|
||||
code = tsem_destroy(¶m->sem);
|
||||
if(TSDB_CODE_SUCCESS != code) {
|
||||
tscError("failed to destroy semaphore since %s", tstrerror(code));
|
||||
if (TSDB_CODE_SUCCESS != code) {
|
||||
tscError("failed to destroy semaphore since %s", tstrerror(code));
|
||||
}
|
||||
|
||||
SRequestObj* pRequest = NULL;
|
||||
|
|
|
@ -1316,9 +1316,9 @@ void doAsyncQuery(SRequestObj *pRequest, bool updateMetaForce) {
|
|||
tscDebug("0x%" PRIx64 " client retry to handle the error, code:%d - %s, tryCount:%d,QID:0x%" PRIx64,
|
||||
pRequest->self, code, tstrerror(code), pRequest->retry, pRequest->requestId);
|
||||
code = refreshMeta(pRequest->pTscObj, pRequest);
|
||||
if (code != 0){
|
||||
tscWarn("0x%" PRIx64 " refresh meta failed, code:%d - %s,QID:0x%" PRIx64, pRequest->self, code,
|
||||
tstrerror(code), pRequest->requestId);
|
||||
if (code != 0) {
|
||||
tscWarn("0x%" PRIx64 " refresh meta failed, code:%d - %s,QID:0x%" PRIx64, pRequest->self, code, tstrerror(code),
|
||||
pRequest->requestId);
|
||||
}
|
||||
pRequest->prevCode = code;
|
||||
doAsyncQuery(pRequest, true);
|
||||
|
@ -1985,7 +1985,9 @@ int taos_stmt2_bind_param(TAOS_STMT2 *stmt, TAOS_STMT2_BINDV *bindv, int32_t col
|
|||
|
||||
STscStmt2 *pStmt = (STscStmt2 *)stmt;
|
||||
if (pStmt->options.asyncExecFn && !pStmt->semWaited) {
|
||||
(void)tsem_wait(&pStmt->asyncQuerySem);
|
||||
if (tsem_wait(&pStmt->asyncQuerySem) != 0) {
|
||||
tscError("wait async query sem failed");
|
||||
}
|
||||
pStmt->semWaited = true;
|
||||
}
|
||||
|
||||
|
|
|
@ -447,20 +447,19 @@ static char* readFile(TdFilePtr pFile, int64_t* offset, int64_t size) {
|
|||
char* pCont = NULL;
|
||||
int64_t totalSize = 0;
|
||||
if (size - *offset >= SLOW_LOG_SEND_SIZE_MAX) {
|
||||
pCont = taosMemoryCalloc(1, 4 + SLOW_LOG_SEND_SIZE_MAX); // 4 reserved for []
|
||||
totalSize = 4 + SLOW_LOG_SEND_SIZE_MAX;
|
||||
} else {
|
||||
pCont = taosMemoryCalloc(1, 4 + (size - *offset));
|
||||
totalSize = 4 + (size - *offset);
|
||||
}
|
||||
|
||||
pCont = taosMemoryCalloc(1, totalSize); // 4 reserved for []
|
||||
if (pCont == NULL) {
|
||||
tscError("failed to allocate memory for slow log, size:%" PRId64, totalSize);
|
||||
return NULL;
|
||||
}
|
||||
char* buf = pCont;
|
||||
(void)strcat(buf++, "[");
|
||||
int64_t readSize = taosReadFile(pFile, buf, SLOW_LOG_SEND_SIZE_MAX);
|
||||
int64_t readSize = taosReadFile(pFile, buf, totalSize - 4); // 4 reserved for []
|
||||
if (readSize <= 0) {
|
||||
if (readSize < 0) {
|
||||
tscError("failed to read len from file:%p since %s", pFile, terrstr());
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
#define RAW_NULL_CHECK(c) \
|
||||
do { \
|
||||
if (c == NULL) { \
|
||||
code = TSDB_CODE_OUT_OF_MEMORY; \
|
||||
code = terrno; \
|
||||
goto end; \
|
||||
} \
|
||||
} while (0)
|
||||
|
@ -394,7 +394,7 @@ static void buildChildElement(cJSON* json, SVCreateTbReq* pCreateReq) {
|
|||
uint8_t tagNum = pCreateReq->ctb.tagNum;
|
||||
int32_t code = 0;
|
||||
cJSON* tags = NULL;
|
||||
cJSON* tableName = cJSON_CreateString(name);
|
||||
cJSON* tableName = cJSON_CreateString(name);
|
||||
RAW_NULL_CHECK(tableName);
|
||||
RAW_FALSE_CHECK(cJSON_AddItemToObject(json, "tableName", tableName));
|
||||
cJSON* using = cJSON_CreateString(sname);
|
||||
|
@ -417,7 +417,7 @@ static void buildChildElement(cJSON* json, SVCreateTbReq* pCreateReq) {
|
|||
}
|
||||
char* pJson = NULL;
|
||||
parseTagDatatoJson(pTag, &pJson);
|
||||
if(pJson == NULL) {
|
||||
if (pJson == NULL) {
|
||||
uError("parseTagDatatoJson failed, pJson == NULL");
|
||||
goto end;
|
||||
}
|
||||
|
@ -731,7 +731,7 @@ static void processAlterTable(SMqMetaRsp* metaRsp, cJSON** pJson) {
|
|||
goto end;
|
||||
}
|
||||
parseTagDatatoJson(vAlterTbReq.pTagVal, &buf);
|
||||
if(buf == NULL) {
|
||||
if (buf == NULL) {
|
||||
uError("parseTagDatatoJson failed, buf == NULL");
|
||||
goto end;
|
||||
}
|
||||
|
@ -978,7 +978,7 @@ static int32_t taosCreateStb(TAOS* taos, void* meta, int32_t metaLen) {
|
|||
pQuery.msgType = pQuery.pCmdMsg->msgType;
|
||||
pQuery.stableQuery = true;
|
||||
|
||||
(void)launchQueryImpl(pRequest, &pQuery, true, NULL); // ignore, because return value is pRequest
|
||||
launchQueryImpl(pRequest, &pQuery, true, NULL); // ignore, because return value is pRequest
|
||||
|
||||
taosMemoryFree(pCmdMsg.pMsg);
|
||||
|
||||
|
@ -1082,7 +1082,7 @@ static int32_t taosDropStb(TAOS* taos, void* meta, int32_t metaLen) {
|
|||
pQuery.msgType = pQuery.pCmdMsg->msgType;
|
||||
pQuery.stableQuery = true;
|
||||
|
||||
(void)launchQueryImpl(pRequest, &pQuery, true, NULL); // ignore, because return value is pRequest
|
||||
launchQueryImpl(pRequest, &pQuery, true, NULL); // ignore, because return value is pRequest
|
||||
taosMemoryFree(pCmdMsg.pMsg);
|
||||
if (pRequest->code == TSDB_CODE_SUCCESS) {
|
||||
// ignore the error code
|
||||
|
@ -1120,7 +1120,8 @@ static int32_t taosCreateTable(TAOS* taos, void* meta, int32_t metaLen) {
|
|||
SRequestObj* pRequest = NULL;
|
||||
SQuery* pQuery = NULL;
|
||||
SHashObj* pVgroupHashmap = NULL;
|
||||
|
||||
SArray* pTagList = taosArrayInit(0, POINTER_BYTES);
|
||||
RAW_NULL_CHECK(pTagList);
|
||||
RAW_RETURN_CHECK(buildRequest(*(int64_t*)taos, "", 0, NULL, false, &pRequest, 0));
|
||||
uDebug(LOG_ID_TAG " create table, meta:%p, metaLen:%d", LOG_ID_VALUE, meta, metaLen);
|
||||
|
||||
|
@ -1186,6 +1187,14 @@ static int32_t taosCreateTable(TAOS* taos, void* meta, int32_t metaLen) {
|
|||
}
|
||||
pCreateReq->ctb.suid = pTableMeta->uid;
|
||||
|
||||
SArray* pTagVals = NULL;
|
||||
code = tTagToValArray((STag *)pCreateReq->ctb.pTag, &pTagVals);
|
||||
if (code != TSDB_CODE_SUCCESS) {
|
||||
taosMemoryFreeClear(pTableMeta);
|
||||
goto end;
|
||||
}
|
||||
|
||||
bool rebuildTag = false;
|
||||
for (int32_t i = 0; i < taosArrayGetSize(pCreateReq->ctb.tagName); i++) {
|
||||
char* tName = taosArrayGet(pCreateReq->ctb.tagName, i);
|
||||
if (tName == NULL) {
|
||||
|
@ -1195,11 +1204,34 @@ static int32_t taosCreateTable(TAOS* taos, void* meta, int32_t metaLen) {
|
|||
j < pTableMeta->tableInfo.numOfColumns + pTableMeta->tableInfo.numOfTags; j++) {
|
||||
SSchema* tag = &pTableMeta->schema[j];
|
||||
if (strcmp(tag->name, tName) == 0 && tag->type != TSDB_DATA_TYPE_JSON) {
|
||||
tTagSetCid((STag*)pCreateReq->ctb.pTag, i, tag->colId);
|
||||
STagVal* pTagVal = (STagVal*)taosArrayGet(pTagVals, i);
|
||||
if (pTagVal) {
|
||||
if (pTagVal->cid != tag->colId){
|
||||
pTagVal->cid = tag->colId;
|
||||
rebuildTag = true;
|
||||
}
|
||||
} else {
|
||||
uError("create tb invalid data %s, size:%d index:%d cid:%d", pCreateReq->name, (int)taosArrayGetSize(pTagVals), i, tag->colId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
taosMemoryFreeClear(pTableMeta);
|
||||
if (rebuildTag){
|
||||
STag* ppTag = NULL;
|
||||
code = tTagNew(pTagVals, 1, false, &ppTag);
|
||||
taosArrayDestroy(pTagVals);
|
||||
pTagVals = NULL;
|
||||
if (code != TSDB_CODE_SUCCESS) {
|
||||
goto end;
|
||||
}
|
||||
if (NULL == taosArrayPush(pTagList, &ppTag)) {
|
||||
tTagFree(ppTag);
|
||||
goto end;
|
||||
}
|
||||
pCreateReq->ctb.pTag = (uint8_t*)ppTag;
|
||||
}
|
||||
taosArrayDestroy(pTagVals);
|
||||
}
|
||||
RAW_NULL_CHECK(taosArrayPush(pRequest->tableList, &pName));
|
||||
|
||||
|
@ -1236,7 +1268,7 @@ static int32_t taosCreateTable(TAOS* taos, void* meta, int32_t metaLen) {
|
|||
|
||||
RAW_RETURN_CHECK(rewriteToVnodeModifyOpStmt(pQuery, pBufArray));
|
||||
|
||||
(void)launchQueryImpl(pRequest, pQuery, true, NULL);
|
||||
launchQueryImpl(pRequest, pQuery, true, NULL);
|
||||
if (pRequest->code == TSDB_CODE_SUCCESS) {
|
||||
RAW_RETURN_CHECK(removeMeta(pTscObj, pRequest->tableList, false));
|
||||
}
|
||||
|
@ -1251,6 +1283,7 @@ end:
|
|||
destroyRequest(pRequest);
|
||||
tDecoderClear(&coder);
|
||||
qDestroyQuery(pQuery);
|
||||
taosArrayDestroyP(pTagList, taosMemoryFree);
|
||||
return code;
|
||||
}
|
||||
|
||||
|
@ -1365,7 +1398,7 @@ static int32_t taosDropTable(TAOS* taos, void* meta, int32_t metaLen) {
|
|||
if (TSDB_CODE_SUCCESS != code) goto end;
|
||||
RAW_RETURN_CHECK(rewriteToVnodeModifyOpStmt(pQuery, pBufArray));
|
||||
|
||||
(void)launchQueryImpl(pRequest, pQuery, true, NULL);
|
||||
launchQueryImpl(pRequest, pQuery, true, NULL);
|
||||
if (pRequest->code == TSDB_CODE_SUCCESS) {
|
||||
RAW_RETURN_CHECK(removeMeta(pTscObj, pRequest->tableList, false));
|
||||
}
|
||||
|
@ -1510,7 +1543,7 @@ static int32_t taosAlterTable(TAOS* taos, void* meta, int32_t metaLen) {
|
|||
if (TSDB_CODE_SUCCESS != code) goto end;
|
||||
RAW_RETURN_CHECK(rewriteToVnodeModifyOpStmt(pQuery, pArray));
|
||||
|
||||
(void)launchQueryImpl(pRequest, pQuery, true, NULL);
|
||||
launchQueryImpl(pRequest, pQuery, true, NULL);
|
||||
|
||||
pVgData = NULL;
|
||||
pArray = NULL;
|
||||
|
@ -1587,7 +1620,7 @@ int taos_write_raw_block_with_fields_with_reqid(TAOS* taos, int rows, char* pDat
|
|||
RAW_RETURN_CHECK(rawBlockBindData(pQuery, pTableMeta, pData, NULL, fields, numFields, false, NULL, 0));
|
||||
RAW_RETURN_CHECK(smlBuildOutput(pQuery, pVgHash));
|
||||
|
||||
(void)launchQueryImpl(pRequest, pQuery, true, NULL);
|
||||
launchQueryImpl(pRequest, pQuery, true, NULL);
|
||||
code = pRequest->code;
|
||||
|
||||
end:
|
||||
|
@ -1647,7 +1680,7 @@ int taos_write_raw_block_with_reqid(TAOS* taos, int rows, char* pData, const cha
|
|||
RAW_RETURN_CHECK(rawBlockBindData(pQuery, pTableMeta, pData, NULL, NULL, 0, false, NULL, 0));
|
||||
RAW_RETURN_CHECK(smlBuildOutput(pQuery, pVgHash));
|
||||
|
||||
(void)launchQueryImpl(pRequest, pQuery, true, NULL);
|
||||
launchQueryImpl(pRequest, pQuery, true, NULL);
|
||||
code = pRequest->code;
|
||||
|
||||
end:
|
||||
|
@ -1766,7 +1799,7 @@ static int32_t tmqWriteRawDataImpl(TAOS* taos, void* data, int32_t dataLen) {
|
|||
|
||||
RAW_RETURN_CHECK(smlBuildOutput(pQuery, pVgHash));
|
||||
|
||||
(void)launchQueryImpl(pRequest, pQuery, true, NULL);
|
||||
launchQueryImpl(pRequest, pQuery, true, NULL);
|
||||
code = pRequest->code;
|
||||
|
||||
end:
|
||||
|
@ -1780,6 +1813,42 @@ end:
|
|||
return code;
|
||||
}
|
||||
|
||||
static int32_t buildCreateTbMap(STaosxRsp* rsp, SHashObj* pHashObj) {
|
||||
// find schema data info
|
||||
int32_t code = 0;
|
||||
SVCreateTbReq pCreateReq = {0};
|
||||
SDecoder decoderTmp = {0};
|
||||
|
||||
for (int j = 0; j < rsp->createTableNum; j++) {
|
||||
void** dataTmp = taosArrayGet(rsp->createTableReq, j);
|
||||
RAW_NULL_CHECK(dataTmp);
|
||||
int32_t* lenTmp = taosArrayGet(rsp->createTableLen, j);
|
||||
RAW_NULL_CHECK(lenTmp);
|
||||
|
||||
tDecoderInit(&decoderTmp, *dataTmp, *lenTmp);
|
||||
RAW_RETURN_CHECK (tDecodeSVCreateTbReq(&decoderTmp, &pCreateReq));
|
||||
|
||||
if (pCreateReq.type != TSDB_CHILD_TABLE) {
|
||||
code = TSDB_CODE_INVALID_MSG;
|
||||
goto end;
|
||||
}
|
||||
if (taosHashGet(pHashObj, pCreateReq.name, strlen(pCreateReq.name)) == NULL){
|
||||
RAW_RETURN_CHECK(taosHashPut(pHashObj, pCreateReq.name, strlen(pCreateReq.name), &pCreateReq, sizeof(SVCreateTbReq)));
|
||||
} else{
|
||||
tDestroySVCreateTbReq(&pCreateReq, TSDB_MSG_FLG_DECODE);
|
||||
pCreateReq = (SVCreateTbReq){0};
|
||||
}
|
||||
|
||||
tDecoderClear(&decoderTmp);
|
||||
}
|
||||
return 0;
|
||||
|
||||
end:
|
||||
tDecoderClear(&decoderTmp);
|
||||
tDestroySVCreateTbReq(&pCreateReq, TSDB_MSG_FLG_DECODE);
|
||||
return code;
|
||||
}
|
||||
|
||||
static int32_t tmqWriteRawMetaDataImpl(TAOS* taos, void* data, int32_t dataLen) {
|
||||
if (taos == NULL || data == NULL) {
|
||||
SET_ERROR_MSG("taos:%p or data:%p is NULL", taos, data);
|
||||
|
@ -1791,7 +1860,7 @@ static int32_t tmqWriteRawMetaDataImpl(TAOS* taos, void* data, int32_t dataLen)
|
|||
SMqTaosxRspObj rspObj = {0};
|
||||
SDecoder decoder = {0};
|
||||
STableMeta* pTableMeta = NULL;
|
||||
SVCreateTbReq* pCreateReqDst = NULL;
|
||||
SHashObj* pCreateTbHash = NULL;
|
||||
|
||||
SRequestObj* pRequest = NULL;
|
||||
RAW_RETURN_CHECK(createRequest(*(int64_t*)taos, TSDB_SQL_INSERT, 0, &pRequest));
|
||||
|
@ -1832,6 +1901,9 @@ static int32_t tmqWriteRawMetaDataImpl(TAOS* taos, void* data, int32_t dataLen)
|
|||
RAW_RETURN_CHECK(smlInitHandle(&pQuery));
|
||||
pVgHash = taosHashInit(16, taosGetDefaultHashFunction(TSDB_DATA_TYPE_INT), true, HASH_NO_LOCK);
|
||||
RAW_NULL_CHECK(pVgHash);
|
||||
pCreateTbHash = taosHashInit(16, taosGetDefaultHashFunction(TSDB_DATA_TYPE_BINARY), true, HASH_NO_LOCK);
|
||||
RAW_NULL_CHECK(pCreateTbHash);
|
||||
RAW_RETURN_CHECK(buildCreateTbMap(&rspObj.rsp, pCreateTbHash));
|
||||
|
||||
uDebug(LOG_ID_TAG " write raw metadata block num:%d", LOG_ID_VALUE, rspObj.rsp.common.blockNum);
|
||||
while (++rspObj.common.resIter < rspObj.rsp.common.blockNum) {
|
||||
|
@ -1854,40 +1926,7 @@ static int32_t tmqWriteRawMetaDataImpl(TAOS* taos, void* data, int32_t dataLen)
|
|||
(void)strcpy(pName.tname, tbName);
|
||||
|
||||
// find schema data info
|
||||
for (int j = 0; j < rspObj.rsp.createTableNum; j++) {
|
||||
void** dataTmp = taosArrayGet(rspObj.rsp.createTableReq, j);
|
||||
RAW_NULL_CHECK(dataTmp);
|
||||
int32_t* lenTmp = taosArrayGet(rspObj.rsp.createTableLen, j);
|
||||
RAW_NULL_CHECK(dataTmp);
|
||||
|
||||
SDecoder decoderTmp = {0};
|
||||
SVCreateTbReq pCreateReq = {0};
|
||||
tDecoderInit(&decoderTmp, *dataTmp, *lenTmp);
|
||||
if (tDecodeSVCreateTbReq(&decoderTmp, &pCreateReq) < 0) {
|
||||
tDecoderClear(&decoderTmp);
|
||||
tDestroySVCreateTbReq(&pCreateReq, TSDB_MSG_FLG_DECODE);
|
||||
code = TSDB_CODE_TMQ_INVALID_MSG;
|
||||
SET_ERROR_MSG("decode create table:%s req failed", tbName);
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (pCreateReq.type != TSDB_CHILD_TABLE) {
|
||||
code = TSDB_CODE_TSC_INVALID_VALUE;
|
||||
tDecoderClear(&decoderTmp);
|
||||
tDestroySVCreateTbReq(&pCreateReq, TSDB_MSG_FLG_DECODE);
|
||||
SET_ERROR_MSG("create table req type is not child table: %s, type: %d", tbName, pCreateReq.type);
|
||||
goto end;
|
||||
}
|
||||
if (strcmp(tbName, pCreateReq.name) == 0) {
|
||||
RAW_RETURN_CHECK(cloneSVreateTbReq(&pCreateReq, &pCreateReqDst));
|
||||
tDecoderClear(&decoderTmp);
|
||||
tDestroySVCreateTbReq(&pCreateReq, TSDB_MSG_FLG_DECODE);
|
||||
break;
|
||||
}
|
||||
tDecoderClear(&decoderTmp);
|
||||
tDestroySVCreateTbReq(&pCreateReq, TSDB_MSG_FLG_DECODE);
|
||||
}
|
||||
|
||||
SVCreateTbReq* pCreateReqDst = (SVCreateTbReq*)taosHashGet(pCreateTbHash, tbName, strlen(tbName));
|
||||
SVgroupInfo vg = {0};
|
||||
RAW_RETURN_CHECK(catalogGetTableHashVgroup(pCatalog, &conn, &pName, &vg));
|
||||
if (pCreateReqDst) { // change stable name to get meta
|
||||
|
@ -1920,13 +1959,17 @@ static int32_t tmqWriteRawMetaDataImpl(TAOS* taos, void* data, int32_t dataLen)
|
|||
}
|
||||
void* rawData = getRawDataFromRes(pRetrieve);
|
||||
char err[ERR_MSG_LEN] = {0};
|
||||
code = rawBlockBindData(pQuery, pTableMeta, rawData, &pCreateReqDst, fields, pSW->nCols, true, err, ERR_MSG_LEN);
|
||||
SVCreateTbReq* pCreateReqTmp = NULL;
|
||||
if (pCreateReqDst){
|
||||
RAW_RETURN_CHECK(cloneSVreateTbReq(pCreateReqDst, &pCreateReqTmp));
|
||||
}
|
||||
code = rawBlockBindData(pQuery, pTableMeta, rawData, &pCreateReqTmp, fields, pSW->nCols, true, err, ERR_MSG_LEN);
|
||||
if (pCreateReqTmp != NULL) {
|
||||
tdDestroySVCreateTbReq(pCreateReqTmp);
|
||||
taosMemoryFree(pCreateReqTmp);
|
||||
}
|
||||
taosMemoryFree(fields);
|
||||
taosMemoryFreeClear(pTableMeta);
|
||||
if (pCreateReqDst) {
|
||||
tdDestroySVCreateTbReq(pCreateReqDst);
|
||||
taosMemoryFreeClear(pCreateReqDst);
|
||||
}
|
||||
if (code != TSDB_CODE_SUCCESS) {
|
||||
SET_ERROR_MSG("table:%s, err:%s", tbName, err);
|
||||
goto end;
|
||||
|
@ -1935,21 +1978,23 @@ static int32_t tmqWriteRawMetaDataImpl(TAOS* taos, void* data, int32_t dataLen)
|
|||
|
||||
RAW_RETURN_CHECK(smlBuildOutput(pQuery, pVgHash));
|
||||
|
||||
(void)launchQueryImpl(pRequest, pQuery, true, NULL);
|
||||
launchQueryImpl(pRequest, pQuery, true, NULL);
|
||||
code = pRequest->code;
|
||||
|
||||
end:
|
||||
uDebug(LOG_ID_TAG " write raw metadata return, msg:%s", LOG_ID_VALUE, tstrerror(code));
|
||||
void* pIter = taosHashIterate(pCreateTbHash, NULL);
|
||||
while (pIter) {
|
||||
tDestroySVCreateTbReq(pIter, TSDB_MSG_FLG_DECODE);
|
||||
pIter = taosHashIterate(pCreateTbHash, pIter);
|
||||
}
|
||||
taosHashCleanup(pCreateTbHash);
|
||||
tDeleteSTaosxRsp(&rspObj.rsp);
|
||||
tDecoderClear(&decoder);
|
||||
qDestroyQuery(pQuery);
|
||||
destroyRequest(pRequest);
|
||||
taosHashCleanup(pVgHash);
|
||||
taosMemoryFreeClear(pTableMeta);
|
||||
if (pCreateReqDst) {
|
||||
tdDestroySVCreateTbReq(pCreateReqDst);
|
||||
taosMemoryFreeClear(pCreateReqDst);
|
||||
}
|
||||
return code;
|
||||
}
|
||||
|
||||
|
|
|
@ -112,7 +112,7 @@ static int32_t smlCheckAuth(SSmlHandle *info, SRequestConnInfo *conn, const char
|
|||
SUserAuthInfo pAuth = {0};
|
||||
(void)snprintf(pAuth.user, sizeof(pAuth.user), "%s", info->taos->user);
|
||||
if (NULL == pTabName) {
|
||||
if (tNameSetDbName(&pAuth.tbName, info->taos->acctId, info->pRequest->pDb, strlen(info->pRequest->pDb)) != 0){
|
||||
if (tNameSetDbName(&pAuth.tbName, info->taos->acctId, info->pRequest->pDb, strlen(info->pRequest->pDb)) != 0) {
|
||||
return TSDB_CODE_SML_INVALID_DATA;
|
||||
}
|
||||
} else {
|
||||
|
@ -165,7 +165,7 @@ int64_t smlGetTimeValue(const char *value, int32_t len, uint8_t fromPrecision, u
|
|||
return convertTimePrecision(tsInt64, fromPrecision, toPrecision);
|
||||
}
|
||||
|
||||
int32_t smlBuildTableInfo(int numRows, const char *measure, int32_t measureLen, SSmlTableInfo** tInfo) {
|
||||
int32_t smlBuildTableInfo(int numRows, const char *measure, int32_t measureLen, SSmlTableInfo **tInfo) {
|
||||
SSmlTableInfo *tag = (SSmlTableInfo *)taosMemoryCalloc(sizeof(SSmlTableInfo), 1);
|
||||
if (!tag) {
|
||||
return terrno;
|
||||
|
@ -203,13 +203,13 @@ static void smlDestroySTableMeta(void *para) {
|
|||
taosMemoryFree(meta);
|
||||
}
|
||||
|
||||
int32_t smlBuildSuperTableInfo(SSmlHandle *info, SSmlLineInfo *currElement, SSmlSTableMeta** sMeta) {
|
||||
int32_t code = TSDB_CODE_SUCCESS;
|
||||
char *measure = currElement->measure;
|
||||
int measureLen = currElement->measureLen;
|
||||
int32_t smlBuildSuperTableInfo(SSmlHandle *info, SSmlLineInfo *currElement, SSmlSTableMeta **sMeta) {
|
||||
int32_t code = TSDB_CODE_SUCCESS;
|
||||
char *measure = currElement->measure;
|
||||
int measureLen = currElement->measureLen;
|
||||
if (currElement->measureEscaped) {
|
||||
measure = (char *)taosMemoryMalloc(measureLen);
|
||||
if (measure == NULL){
|
||||
if (measure == NULL) {
|
||||
return terrno;
|
||||
}
|
||||
(void)memcpy(measure, currElement->measure, measureLen);
|
||||
|
@ -233,7 +233,7 @@ int32_t smlBuildSuperTableInfo(SSmlHandle *info, SSmlLineInfo *currElement, SSml
|
|||
}
|
||||
(*sMeta)->tableMeta = pTableMeta;
|
||||
code = taosHashPut(info->superTables, currElement->measure, currElement->measureLen, sMeta, POINTER_BYTES);
|
||||
if (code != TSDB_CODE_SUCCESS){
|
||||
if (code != TSDB_CODE_SUCCESS) {
|
||||
smlDestroySTableMeta(*sMeta);
|
||||
return code;
|
||||
}
|
||||
|
@ -250,11 +250,11 @@ int32_t smlBuildSuperTableInfo(SSmlHandle *info, SSmlLineInfo *currElement, SSml
|
|||
}
|
||||
|
||||
if (i < pTableMeta->tableInfo.numOfColumns) {
|
||||
if(taosArrayPush((*sMeta)->cols, &kv) == NULL){
|
||||
if (taosArrayPush((*sMeta)->cols, &kv) == NULL) {
|
||||
return terrno;
|
||||
}
|
||||
} else {
|
||||
if(taosArrayPush((*sMeta)->tags, &kv) == NULL){
|
||||
if (taosArrayPush((*sMeta)->tags, &kv) == NULL) {
|
||||
return terrno;
|
||||
}
|
||||
}
|
||||
|
@ -277,7 +277,7 @@ bool isSmlColAligned(SSmlHandle *info, int cnt, SSmlKv *kv) {
|
|||
goto END;
|
||||
}
|
||||
SSmlKv *maxKV = (SSmlKv *)taosArrayGet(info->maxColKVs, cnt);
|
||||
if (maxKV == NULL){
|
||||
if (maxKV == NULL) {
|
||||
goto END;
|
||||
}
|
||||
if (unlikely(!IS_SAME_KEY)) {
|
||||
|
@ -336,9 +336,9 @@ int32_t smlJoinMeasureTag(SSmlLineInfo *elements) {
|
|||
return TSDB_CODE_SUCCESS;
|
||||
}
|
||||
|
||||
static bool smlIsPKTable(STableMeta *pTableMeta){
|
||||
for(int i = 0; i < pTableMeta->tableInfo.numOfColumns; i++){
|
||||
if(pTableMeta->schema[i].flags & COL_IS_KEY){
|
||||
static bool smlIsPKTable(STableMeta *pTableMeta) {
|
||||
for (int i = 0; i < pTableMeta->tableInfo.numOfColumns; i++) {
|
||||
if (pTableMeta->schema[i].flags & COL_IS_KEY) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -368,14 +368,14 @@ int32_t smlProcessSuperTable(SSmlHandle *info, SSmlLineInfo *elements) {
|
|||
info->maxTagKVs = sMeta->tags;
|
||||
info->maxColKVs = sMeta->cols;
|
||||
|
||||
if(smlIsPKTable(sMeta->tableMeta)){
|
||||
if (smlIsPKTable(sMeta->tableMeta)) {
|
||||
return TSDB_CODE_SML_NOT_SUPPORT_PK;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t smlProcessChildTable(SSmlHandle *info, SSmlLineInfo *elements) {
|
||||
int32_t code = TSDB_CODE_SUCCESS;
|
||||
int32_t code = TSDB_CODE_SUCCESS;
|
||||
SSmlTableInfo **oneTable =
|
||||
(SSmlTableInfo **)taosHashGet(info->childTables, elements->measureTag, elements->measureTagsLen);
|
||||
SSmlTableInfo *tinfo = NULL;
|
||||
|
@ -385,19 +385,19 @@ int32_t smlProcessChildTable(SSmlHandle *info, SSmlLineInfo *elements) {
|
|||
return code;
|
||||
}
|
||||
code = taosHashPut(info->childTables, elements->measureTag, elements->measureTagsLen, &tinfo, POINTER_BYTES);
|
||||
if(code != 0){
|
||||
if (code != 0) {
|
||||
smlDestroyTableInfo(&tinfo);
|
||||
return code;
|
||||
}
|
||||
|
||||
tinfo->tags = taosArrayDup(info->preLineTagKV, NULL);
|
||||
if(tinfo->tags == NULL){
|
||||
if (tinfo->tags == NULL) {
|
||||
smlDestroyTableInfo(&tinfo);
|
||||
return TSDB_CODE_OUT_OF_MEMORY;
|
||||
}
|
||||
for (size_t i = 0; i < taosArrayGetSize(info->preLineTagKV); i++) {
|
||||
SSmlKv *kv = (SSmlKv *)taosArrayGet(info->preLineTagKV, i);
|
||||
if(kv == NULL){
|
||||
if (kv == NULL) {
|
||||
smlDestroyTableInfo(&tinfo);
|
||||
return TSDB_CODE_SML_INVALID_DATA;
|
||||
}
|
||||
|
@ -406,12 +406,12 @@ int32_t smlProcessChildTable(SSmlHandle *info, SSmlLineInfo *elements) {
|
|||
}
|
||||
|
||||
code = smlSetCTableName(tinfo, info->tbnameKey);
|
||||
if (code != TSDB_CODE_SUCCESS){
|
||||
if (code != TSDB_CODE_SUCCESS) {
|
||||
smlDestroyTableInfo(&tinfo);
|
||||
return code;
|
||||
}
|
||||
code = getTableUid(info, elements, tinfo);
|
||||
if (code != TSDB_CODE_SUCCESS){
|
||||
if (code != TSDB_CODE_SUCCESS) {
|
||||
smlDestroyTableInfo(&tinfo);
|
||||
return code;
|
||||
}
|
||||
|
@ -458,10 +458,10 @@ int32_t smlParseEndTelnetJson(SSmlHandle *info, SSmlLineInfo *elements, SSmlKv *
|
|||
return terrno;
|
||||
}
|
||||
}
|
||||
if (taosArrayPush(elements->colArray, kvTs) == NULL){
|
||||
if (taosArrayPush(elements->colArray, kvTs) == NULL) {
|
||||
return terrno;
|
||||
}
|
||||
if (taosArrayPush(elements->colArray, kv) == NULL){
|
||||
if (taosArrayPush(elements->colArray, kv) == NULL) {
|
||||
return terrno;
|
||||
}
|
||||
}
|
||||
|
@ -495,11 +495,11 @@ int32_t smlParseEndLine(SSmlHandle *info, SSmlLineInfo *elements, SSmlKv *kvTs)
|
|||
static int32_t smlParseTableName(SArray *tags, char *childTableName, char *tbnameKey) {
|
||||
bool autoChildName = false;
|
||||
size_t delimiter = strlen(tsSmlAutoChildTableNameDelimiter);
|
||||
if(delimiter > 0 && tbnameKey == NULL){
|
||||
if (delimiter > 0 && tbnameKey == NULL) {
|
||||
size_t totalNameLen = delimiter * (taosArrayGetSize(tags) - 1);
|
||||
for (int i = 0; i < taosArrayGetSize(tags); i++) {
|
||||
SSmlKv *tag = (SSmlKv *)taosArrayGet(tags, i);
|
||||
if(tag == NULL){
|
||||
if (tag == NULL) {
|
||||
return TSDB_CODE_SML_INVALID_DATA;
|
||||
}
|
||||
totalNameLen += tag->length;
|
||||
|
@ -512,7 +512,7 @@ static int32_t smlParseTableName(SArray *tags, char *childTableName, char *tbnam
|
|||
(void)memset(childTableName, 0, TSDB_TABLE_NAME_LEN);
|
||||
for (int i = 0; i < taosArrayGetSize(tags); i++) {
|
||||
SSmlKv *tag = (SSmlKv *)taosArrayGet(tags, i);
|
||||
if(tag == NULL){
|
||||
if (tag == NULL) {
|
||||
return TSDB_CODE_SML_INVALID_DATA;
|
||||
}
|
||||
(void)strncat(childTableName, tag->value, tag->length);
|
||||
|
@ -523,8 +523,8 @@ static int32_t smlParseTableName(SArray *tags, char *childTableName, char *tbnam
|
|||
if (tsSmlDot2Underline) {
|
||||
smlStrReplace(childTableName, strlen(childTableName));
|
||||
}
|
||||
}else{
|
||||
if (tbnameKey == NULL){
|
||||
} else {
|
||||
if (tbnameKey == NULL) {
|
||||
tbnameKey = tsSmlChildTableName;
|
||||
}
|
||||
size_t childTableNameLen = strlen(tbnameKey);
|
||||
|
@ -532,13 +532,14 @@ static int32_t smlParseTableName(SArray *tags, char *childTableName, char *tbnam
|
|||
|
||||
for (int i = 0; i < taosArrayGetSize(tags); i++) {
|
||||
SSmlKv *tag = (SSmlKv *)taosArrayGet(tags, i);
|
||||
if(tag == NULL){
|
||||
if (tag == NULL) {
|
||||
return TSDB_CODE_SML_INVALID_DATA;
|
||||
}
|
||||
// handle child table name
|
||||
if (childTableNameLen == tag->keyLen && strncmp(tag->key, tbnameKey, tag->keyLen) == 0) {
|
||||
(void)memset(childTableName, 0, TSDB_TABLE_NAME_LEN);
|
||||
(void)strncpy(childTableName, tag->value, (tag->length < TSDB_TABLE_NAME_LEN ? tag->length : TSDB_TABLE_NAME_LEN));
|
||||
(void)strncpy(childTableName, tag->value,
|
||||
(tag->length < TSDB_TABLE_NAME_LEN ? tag->length : TSDB_TABLE_NAME_LEN));
|
||||
if (tsSmlDot2Underline) {
|
||||
smlStrReplace(childTableName, strlen(childTableName));
|
||||
}
|
||||
|
@ -553,7 +554,7 @@ static int32_t smlParseTableName(SArray *tags, char *childTableName, char *tbnam
|
|||
|
||||
int32_t smlSetCTableName(SSmlTableInfo *oneTable, char *tbnameKey) {
|
||||
int32_t code = smlParseTableName(oneTable->tags, oneTable->childTableName, tbnameKey);
|
||||
if(code != TSDB_CODE_SUCCESS){
|
||||
if (code != TSDB_CODE_SUCCESS) {
|
||||
return code;
|
||||
}
|
||||
|
||||
|
@ -562,7 +563,7 @@ int32_t smlSetCTableName(SSmlTableInfo *oneTable, char *tbnameKey) {
|
|||
if (dst == NULL) {
|
||||
return TSDB_CODE_OUT_OF_MEMORY;
|
||||
}
|
||||
if(oneTable->sTableNameLen >= TSDB_TABLE_NAME_LEN){
|
||||
if (oneTable->sTableNameLen >= TSDB_TABLE_NAME_LEN) {
|
||||
uError("SML:smlSetCTableName super table name is too long");
|
||||
taosArrayDestroy(dst);
|
||||
return TSDB_CODE_SML_INTERNAL_ERROR;
|
||||
|
@ -578,7 +579,7 @@ int32_t smlSetCTableName(SSmlTableInfo *oneTable, char *tbnameKey) {
|
|||
}
|
||||
|
||||
code = buildChildTableName(&rName);
|
||||
if (code != TSDB_CODE_SUCCESS){
|
||||
if (code != TSDB_CODE_SUCCESS) {
|
||||
return code;
|
||||
}
|
||||
taosArrayDestroy(dst);
|
||||
|
@ -906,13 +907,13 @@ static int32_t smlFindNearestPowerOf2(int32_t length, uint8_t type) {
|
|||
return result;
|
||||
}
|
||||
|
||||
static int32_t smlProcessSchemaAction(SSmlHandle *info, SSchema *schemaField, SHashObj *schemaHash, SArray *cols, SArray *checkDumplicateCols,
|
||||
ESchemaAction *action, bool isTag) {
|
||||
static int32_t smlProcessSchemaAction(SSmlHandle *info, SSchema *schemaField, SHashObj *schemaHash, SArray *cols,
|
||||
SArray *checkDumplicateCols, ESchemaAction *action, bool isTag) {
|
||||
int32_t code = TSDB_CODE_SUCCESS;
|
||||
for (int j = 0; j < taosArrayGetSize(cols); ++j) {
|
||||
if (j == 0 && !isTag) continue;
|
||||
SSmlKv *kv = (SSmlKv *)taosArrayGet(cols, j);
|
||||
if (kv == NULL){
|
||||
if (kv == NULL) {
|
||||
return TSDB_CODE_SML_INVALID_DATA;
|
||||
}
|
||||
code = smlGenerateSchemaAction(schemaField, schemaHash, kv, isTag, action, info);
|
||||
|
@ -923,10 +924,10 @@ static int32_t smlProcessSchemaAction(SSmlHandle *info, SSchema *schemaField, SH
|
|||
|
||||
for (int j = 0; j < taosArrayGetSize(checkDumplicateCols); ++j) {
|
||||
SSmlKv *kv = (SSmlKv *)taosArrayGet(checkDumplicateCols, j);
|
||||
if (kv == NULL){
|
||||
if (kv == NULL) {
|
||||
return TSDB_CODE_SML_INVALID_DATA;
|
||||
}
|
||||
if(taosHashGet(schemaHash, kv->key, kv->keyLen) != NULL){
|
||||
if (taosHashGet(schemaHash, kv->key, kv->keyLen) != NULL) {
|
||||
return TSDB_CODE_PAR_DUPLICATED_COLUMN;
|
||||
}
|
||||
}
|
||||
|
@ -934,16 +935,16 @@ static int32_t smlProcessSchemaAction(SSmlHandle *info, SSchema *schemaField, SH
|
|||
}
|
||||
|
||||
static int32_t smlCheckMeta(SSchema *schema, int32_t length, SArray *cols, bool isTag) {
|
||||
int32_t code = TSDB_CODE_SUCCESS;
|
||||
int32_t code = TSDB_CODE_SUCCESS;
|
||||
SHashObj *hashTmp = taosHashInit(length, taosGetDefaultHashFunction(TSDB_DATA_TYPE_BINARY), true, HASH_NO_LOCK);
|
||||
if (hashTmp == NULL) {
|
||||
code = terrno;
|
||||
goto END;
|
||||
}
|
||||
int32_t i = 0;
|
||||
int32_t i = 0;
|
||||
for (; i < length; i++) {
|
||||
code = taosHashPut(hashTmp, schema[i].name, strlen(schema[i].name), &i, SHORT_BYTES);
|
||||
if (code != 0){
|
||||
if (code != 0) {
|
||||
goto END;
|
||||
}
|
||||
}
|
||||
|
@ -955,7 +956,7 @@ static int32_t smlCheckMeta(SSchema *schema, int32_t length, SArray *cols, bool
|
|||
}
|
||||
for (; i < taosArrayGetSize(cols); i++) {
|
||||
SSmlKv *kv = (SSmlKv *)taosArrayGet(cols, i);
|
||||
if (kv == NULL){
|
||||
if (kv == NULL) {
|
||||
code = TSDB_CODE_SML_INVALID_DATA;
|
||||
goto END;
|
||||
}
|
||||
|
@ -982,8 +983,8 @@ static int32_t getBytes(uint8_t type, int32_t length) {
|
|||
static int32_t smlBuildFieldsList(SSmlHandle *info, SSchema *schemaField, SHashObj *schemaHash, SArray *cols,
|
||||
SArray *results, int32_t numOfCols, bool isTag) {
|
||||
for (int j = 0; j < taosArrayGetSize(cols); ++j) {
|
||||
SSmlKv *kv = (SSmlKv *)taosArrayGet(cols, j);
|
||||
if (kv == NULL){
|
||||
SSmlKv *kv = (SSmlKv *)taosArrayGet(cols, j);
|
||||
if (kv == NULL) {
|
||||
return TSDB_CODE_SML_INVALID_DATA;
|
||||
}
|
||||
ESchemaAction action = SCHEMA_ACTION_NULL;
|
||||
|
@ -996,7 +997,7 @@ static int32_t smlBuildFieldsList(SSmlHandle *info, SSchema *schemaField, SHashO
|
|||
field.type = kv->type;
|
||||
field.bytes = getBytes(kv->type, kv->length);
|
||||
(void)memcpy(field.name, kv->key, kv->keyLen);
|
||||
if (taosArrayPush(results, &field) == NULL){
|
||||
if (taosArrayPush(results, &field) == NULL) {
|
||||
return terrno;
|
||||
}
|
||||
} else if (action == SCHEMA_ACTION_CHANGE_COLUMN_SIZE || action == SCHEMA_ACTION_CHANGE_TAG_SIZE) {
|
||||
|
@ -1008,7 +1009,7 @@ static int32_t smlBuildFieldsList(SSmlHandle *info, SSchema *schemaField, SHashO
|
|||
uint16_t newIndex = *index;
|
||||
if (isTag) newIndex -= numOfCols;
|
||||
SField *field = (SField *)taosArrayGet(results, newIndex);
|
||||
if (field == NULL){
|
||||
if (field == NULL) {
|
||||
return TSDB_CODE_SML_INVALID_DATA;
|
||||
}
|
||||
field->bytes = getBytes(kv->type, kv->length);
|
||||
|
@ -1019,7 +1020,7 @@ static int32_t smlBuildFieldsList(SSmlHandle *info, SSchema *schemaField, SHashO
|
|||
int32_t len = 0;
|
||||
for (int j = 0; j < taosArrayGetSize(results); ++j) {
|
||||
SField *field = taosArrayGet(results, j);
|
||||
if (field == NULL){
|
||||
if (field == NULL) {
|
||||
return TSDB_CODE_SML_INVALID_DATA;
|
||||
}
|
||||
len += field->bytes;
|
||||
|
@ -1051,14 +1052,14 @@ static int32_t smlSendMetaMsg(SSmlHandle *info, SName *pName, SArray *pColumns,
|
|||
}
|
||||
for (int32_t i = 0; i < pReq.numOfColumns; ++i) {
|
||||
SField *pField = taosArrayGet(pColumns, i);
|
||||
if (pField == NULL){
|
||||
if (pField == NULL) {
|
||||
code = TSDB_CODE_SML_INVALID_DATA;
|
||||
goto end;
|
||||
}
|
||||
SFieldWithOptions fieldWithOption = {0};
|
||||
setFieldWithOptions(&fieldWithOption, pField);
|
||||
setDefaultOptionsForField(&fieldWithOption);
|
||||
if (taosArrayPush(pReq.pColumns, &fieldWithOption) == NULL){
|
||||
if (taosArrayPush(pReq.pColumns, &fieldWithOption) == NULL) {
|
||||
code = terrno;
|
||||
goto end;
|
||||
}
|
||||
|
@ -1105,7 +1106,7 @@ static int32_t smlSendMetaMsg(SSmlHandle *info, SName *pName, SArray *pColumns,
|
|||
field.type = TSDB_DATA_TYPE_NCHAR;
|
||||
field.bytes = TSDB_NCHAR_SIZE + VARSTR_HEADER_SIZE;
|
||||
tstrncpy(field.name, tsSmlTagName, sizeof(field.name));
|
||||
if (taosArrayPush(pReq.pTags, &field) == NULL){
|
||||
if (taosArrayPush(pReq.pTags, &field) == NULL) {
|
||||
code = terrno;
|
||||
goto end;
|
||||
}
|
||||
|
@ -1121,7 +1122,7 @@ static int32_t smlSendMetaMsg(SSmlHandle *info, SName *pName, SArray *pColumns,
|
|||
pCmdMsg.epSet = getEpSet_s(&info->taos->pAppInfo->mgmtEp);
|
||||
pCmdMsg.msgType = TDMT_MND_CREATE_STB;
|
||||
pCmdMsg.msgLen = tSerializeSMCreateStbReq(NULL, 0, &pReq);
|
||||
if (pCmdMsg.msgLen < 0){
|
||||
if (pCmdMsg.msgLen < 0) {
|
||||
code = TSDB_CODE_OUT_OF_MEMORY;
|
||||
goto end;
|
||||
}
|
||||
|
@ -1131,7 +1132,7 @@ static int32_t smlSendMetaMsg(SSmlHandle *info, SName *pName, SArray *pColumns,
|
|||
goto end;
|
||||
}
|
||||
|
||||
if (tSerializeSMCreateStbReq(pCmdMsg.pMsg, pCmdMsg.msgLen, &pReq) < 0){
|
||||
if (tSerializeSMCreateStbReq(pCmdMsg.pMsg, pCmdMsg.msgLen, &pReq) < 0) {
|
||||
code = TSDB_CODE_OUT_OF_MEMORY;
|
||||
taosMemoryFree(pCmdMsg.pMsg);
|
||||
goto end;
|
||||
|
@ -1144,11 +1145,11 @@ static int32_t smlSendMetaMsg(SSmlHandle *info, SName *pName, SArray *pColumns,
|
|||
pQuery.msgType = pQuery.pCmdMsg->msgType;
|
||||
pQuery.stableQuery = true;
|
||||
|
||||
(void)launchQueryImpl(pRequest, &pQuery, true, NULL); // no need to check return value
|
||||
launchQueryImpl(pRequest, &pQuery, true, NULL); // no need to check return value
|
||||
|
||||
if (pRequest->code == TSDB_CODE_SUCCESS) {
|
||||
code = catalogRemoveTableMeta(info->pCatalog, pName);
|
||||
if (code != TSDB_CODE_SUCCESS){
|
||||
if (code != TSDB_CODE_SUCCESS) {
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
|
@ -1187,7 +1188,7 @@ static int32_t smlModifyDBSchemas(SSmlHandle *info) {
|
|||
size_t superTableLen = 0;
|
||||
void *superTable = taosHashGetKey(tmp, &superTableLen);
|
||||
char *measure = taosMemoryMalloc(superTableLen);
|
||||
if (measure == NULL){
|
||||
if (measure == NULL) {
|
||||
code = terrno;
|
||||
goto end;
|
||||
}
|
||||
|
@ -1246,28 +1247,28 @@ static int32_t smlModifyDBSchemas(SSmlHandle *info) {
|
|||
goto end;
|
||||
}
|
||||
} else if (code == TSDB_CODE_SUCCESS) {
|
||||
|
||||
if(smlIsPKTable(pTableMeta)){
|
||||
if (smlIsPKTable(pTableMeta)) {
|
||||
code = TSDB_CODE_SML_NOT_SUPPORT_PK;
|
||||
goto end;
|
||||
}
|
||||
|
||||
hashTmp = taosHashInit(pTableMeta->tableInfo.numOfTags, taosGetDefaultHashFunction(TSDB_DATA_TYPE_BINARY), true,
|
||||
HASH_NO_LOCK);
|
||||
if (hashTmp == NULL){
|
||||
if (hashTmp == NULL) {
|
||||
code = terrno;
|
||||
goto end;
|
||||
}
|
||||
for (uint16_t i = pTableMeta->tableInfo.numOfColumns;
|
||||
i < pTableMeta->tableInfo.numOfColumns + pTableMeta->tableInfo.numOfTags; i++) {
|
||||
code = taosHashPut(hashTmp, pTableMeta->schema[i].name, strlen(pTableMeta->schema[i].name), &i, SHORT_BYTES);
|
||||
if (code != 0){
|
||||
if (code != 0) {
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
|
||||
ESchemaAction action = SCHEMA_ACTION_NULL;
|
||||
code = smlProcessSchemaAction(info, pTableMeta->schema, hashTmp, sTableData->tags, sTableData->cols, &action, true);
|
||||
code =
|
||||
smlProcessSchemaAction(info, pTableMeta->schema, hashTmp, sTableData->tags, sTableData->cols, &action, true);
|
||||
if (code != TSDB_CODE_SUCCESS) {
|
||||
goto end;
|
||||
}
|
||||
|
@ -1280,13 +1281,13 @@ static int32_t smlModifyDBSchemas(SSmlHandle *info) {
|
|||
action);
|
||||
SArray *pColumns =
|
||||
taosArrayInit(taosArrayGetSize(sTableData->cols) + pTableMeta->tableInfo.numOfColumns, sizeof(SField));
|
||||
if (pColumns == NULL){
|
||||
if (pColumns == NULL) {
|
||||
code = terrno;
|
||||
goto end;
|
||||
}
|
||||
SArray *pTags =
|
||||
taosArrayInit(taosArrayGetSize(sTableData->tags) + pTableMeta->tableInfo.numOfTags, sizeof(SField));
|
||||
if (pTags == NULL){
|
||||
if (pTags == NULL) {
|
||||
taosArrayDestroy(pColumns);
|
||||
code = terrno;
|
||||
goto end;
|
||||
|
@ -1297,14 +1298,14 @@ static int32_t smlModifyDBSchemas(SSmlHandle *info) {
|
|||
field.bytes = pTableMeta->schema[i].bytes;
|
||||
tstrncpy(field.name, pTableMeta->schema[i].name, sizeof(field.name));
|
||||
if (i < pTableMeta->tableInfo.numOfColumns) {
|
||||
if (taosArrayPush(pColumns, &field) == NULL){
|
||||
if (taosArrayPush(pColumns, &field) == NULL) {
|
||||
taosArrayDestroy(pColumns);
|
||||
taosArrayDestroy(pTags);
|
||||
code = terrno;
|
||||
goto end;
|
||||
}
|
||||
} else {
|
||||
if (taosArrayPush(pTags, &field) == NULL){
|
||||
if (taosArrayPush(pTags, &field) == NULL) {
|
||||
taosArrayDestroy(pColumns);
|
||||
taosArrayDestroy(pTags);
|
||||
code = terrno;
|
||||
|
@ -1363,7 +1364,8 @@ static int32_t smlModifyDBSchemas(SSmlHandle *info) {
|
|||
}
|
||||
}
|
||||
action = SCHEMA_ACTION_NULL;
|
||||
code = smlProcessSchemaAction(info, pTableMeta->schema, hashTmp, sTableData->cols, sTableData->tags, &action, false);
|
||||
code =
|
||||
smlProcessSchemaAction(info, pTableMeta->schema, hashTmp, sTableData->cols, sTableData->tags, &action, false);
|
||||
if (code != TSDB_CODE_SUCCESS) {
|
||||
goto end;
|
||||
}
|
||||
|
@ -1376,13 +1378,13 @@ static int32_t smlModifyDBSchemas(SSmlHandle *info) {
|
|||
action);
|
||||
SArray *pColumns =
|
||||
taosArrayInit(taosArrayGetSize(sTableData->cols) + pTableMeta->tableInfo.numOfColumns, sizeof(SField));
|
||||
if (pColumns == NULL){
|
||||
if (pColumns == NULL) {
|
||||
code = terrno;
|
||||
goto end;
|
||||
}
|
||||
SArray *pTags =
|
||||
taosArrayInit(taosArrayGetSize(sTableData->tags) + pTableMeta->tableInfo.numOfTags, sizeof(SField));
|
||||
if (pTags == NULL){
|
||||
if (pTags == NULL) {
|
||||
taosArrayDestroy(pColumns);
|
||||
code = terrno;
|
||||
goto end;
|
||||
|
@ -1393,14 +1395,14 @@ static int32_t smlModifyDBSchemas(SSmlHandle *info) {
|
|||
field.bytes = pTableMeta->schema[i].bytes;
|
||||
tstrncpy(field.name, pTableMeta->schema[i].name, sizeof(field.name));
|
||||
if (i < pTableMeta->tableInfo.numOfColumns) {
|
||||
if (taosArrayPush(pColumns, &field) == NULL){
|
||||
if (taosArrayPush(pColumns, &field) == NULL) {
|
||||
taosArrayDestroy(pColumns);
|
||||
taosArrayDestroy(pTags);
|
||||
code = terrno;
|
||||
goto end;
|
||||
}
|
||||
} else {
|
||||
if (taosArrayPush(pTags, &field) == NULL){
|
||||
if (taosArrayPush(pTags, &field) == NULL) {
|
||||
taosArrayDestroy(pColumns);
|
||||
taosArrayDestroy(pTags);
|
||||
code = terrno;
|
||||
|
@ -1483,7 +1485,7 @@ end:
|
|||
taosHashCancelIterate(info->superTables, tmp);
|
||||
taosHashCleanup(hashTmp);
|
||||
taosMemoryFreeClear(pTableMeta);
|
||||
(void)catalogRefreshTableMeta(info->pCatalog, &conn, &pName, 1); // ignore refresh meta code if there is an error
|
||||
(void)catalogRefreshTableMeta(info->pCatalog, &conn, &pName, 1); // ignore refresh meta code if there is an error
|
||||
uError("SML:0x%" PRIx64 " smlModifyDBSchemas end failed:%d:%s, format:%d, needModifySchema:%d", info->id, code,
|
||||
tstrerror(code), info->dataFormat, info->needModifySchema);
|
||||
|
||||
|
@ -1494,34 +1496,35 @@ static int32_t smlInsertMeta(SHashObj *metaHash, SArray *metaArray, SArray *cols
|
|||
terrno = 0;
|
||||
for (int16_t i = 0; i < taosArrayGetSize(cols); ++i) {
|
||||
SSmlKv *kv = (SSmlKv *)taosArrayGet(cols, i);
|
||||
if (kv == NULL){
|
||||
if (kv == NULL) {
|
||||
return TSDB_CODE_SML_INVALID_DATA;
|
||||
}
|
||||
int ret = taosHashPut(metaHash, kv->key, kv->keyLen, &i, SHORT_BYTES);
|
||||
int ret = taosHashPut(metaHash, kv->key, kv->keyLen, &i, SHORT_BYTES);
|
||||
if (ret == 0) {
|
||||
if (taosArrayPush(metaArray, kv) == NULL){
|
||||
if (taosArrayPush(metaArray, kv) == NULL) {
|
||||
return terrno;
|
||||
}
|
||||
if(taosHashGet(checkDuplicate, kv->key, kv->keyLen) != NULL) {
|
||||
if (taosHashGet(checkDuplicate, kv->key, kv->keyLen) != NULL) {
|
||||
return TSDB_CODE_PAR_DUPLICATED_COLUMN;
|
||||
}
|
||||
}else if(terrno == TSDB_CODE_DUP_KEY){
|
||||
} else if (terrno == TSDB_CODE_DUP_KEY) {
|
||||
return TSDB_CODE_PAR_DUPLICATED_COLUMN;
|
||||
}
|
||||
}
|
||||
return TSDB_CODE_SUCCESS;
|
||||
}
|
||||
|
||||
static int32_t smlUpdateMeta(SHashObj *metaHash, SArray *metaArray, SArray *cols, bool isTag, SSmlMsgBuf *msg, SHashObj* checkDuplicate) {
|
||||
static int32_t smlUpdateMeta(SHashObj *metaHash, SArray *metaArray, SArray *cols, bool isTag, SSmlMsgBuf *msg,
|
||||
SHashObj *checkDuplicate) {
|
||||
for (int i = 0; i < taosArrayGetSize(cols); ++i) {
|
||||
SSmlKv *kv = (SSmlKv *)taosArrayGet(cols, i);
|
||||
if (kv == NULL){
|
||||
if (kv == NULL) {
|
||||
return TSDB_CODE_SML_INVALID_DATA;
|
||||
}
|
||||
int16_t *index = (int16_t *)taosHashGet(metaHash, kv->key, kv->keyLen);
|
||||
if (index) {
|
||||
SSmlKv *value = (SSmlKv *)taosArrayGet(metaArray, *index);
|
||||
if (value == NULL){
|
||||
if (value == NULL) {
|
||||
return TSDB_CODE_SML_INVALID_DATA;
|
||||
}
|
||||
|
||||
|
@ -1549,13 +1552,13 @@ static int32_t smlUpdateMeta(SHashObj *metaHash, SArray *metaArray, SArray *cols
|
|||
int16_t size = tmp;
|
||||
int ret = taosHashPut(metaHash, kv->key, kv->keyLen, &size, SHORT_BYTES);
|
||||
if (ret == 0) {
|
||||
if(taosArrayPush(metaArray, kv) == NULL){
|
||||
if (taosArrayPush(metaArray, kv) == NULL) {
|
||||
return terrno;
|
||||
}
|
||||
if(taosHashGet(checkDuplicate, kv->key, kv->keyLen) != NULL) {
|
||||
if (taosHashGet(checkDuplicate, kv->key, kv->keyLen) != NULL) {
|
||||
return TSDB_CODE_PAR_DUPLICATED_COLUMN;
|
||||
}
|
||||
}else{
|
||||
} else {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
@ -1586,7 +1589,7 @@ void freeSSmlKv(void *data) {
|
|||
|
||||
void smlDestroyInfo(SSmlHandle *info) {
|
||||
if (!info) return;
|
||||
// qDestroyQuery(info->pQuery);
|
||||
// qDestroyQuery(info->pQuery);
|
||||
|
||||
taosHashCleanup(info->pVgHash);
|
||||
taosHashCleanup(info->childTables);
|
||||
|
@ -1657,7 +1660,7 @@ int32_t smlBuildSmlInfo(TAOS *taos, SSmlHandle **handle) {
|
|||
|
||||
info->id = smlGenId();
|
||||
code = smlInitHandle(&info->pQuery);
|
||||
if (code != TSDB_CODE_SUCCESS){
|
||||
if (code != TSDB_CODE_SUCCESS) {
|
||||
goto FAILED;
|
||||
}
|
||||
info->dataFormat = true;
|
||||
|
@ -1688,7 +1691,7 @@ static int32_t smlPushCols(SArray *colsArray, SArray *cols) {
|
|||
}
|
||||
for (size_t i = 0; i < taosArrayGetSize(cols); i++) {
|
||||
SSmlKv *kv = (SSmlKv *)taosArrayGet(cols, i);
|
||||
if (kv == NULL){
|
||||
if (kv == NULL) {
|
||||
taosHashCleanup(kvHash);
|
||||
return TSDB_CODE_SML_INVALID_DATA;
|
||||
}
|
||||
|
@ -1698,7 +1701,7 @@ static int32_t smlPushCols(SArray *colsArray, SArray *cols) {
|
|||
taosHashCleanup(kvHash);
|
||||
return TSDB_CODE_PAR_DUPLICATED_COLUMN;
|
||||
}
|
||||
if (code != TSDB_CODE_SUCCESS){
|
||||
if (code != TSDB_CODE_SUCCESS) {
|
||||
taosHashCleanup(kvHash);
|
||||
return code;
|
||||
}
|
||||
|
@ -1759,9 +1762,11 @@ static int32_t smlParseLineBottom(SSmlHandle *info) {
|
|||
if (tableMeta) { // update meta
|
||||
uDebug("SML:0x%" PRIx64 " smlParseLineBottom update meta, format:%d, linenum:%d", info->id, info->dataFormat,
|
||||
info->lineNum);
|
||||
ret = smlUpdateMeta((*tableMeta)->colHash, (*tableMeta)->cols, elements->colArray, false, &info->msgBuf, (*tableMeta)->tagHash);
|
||||
ret = smlUpdateMeta((*tableMeta)->colHash, (*tableMeta)->cols, elements->colArray, false, &info->msgBuf,
|
||||
(*tableMeta)->tagHash);
|
||||
if (ret == TSDB_CODE_SUCCESS) {
|
||||
ret = smlUpdateMeta((*tableMeta)->tagHash, (*tableMeta)->tags, tinfo->tags, true, &info->msgBuf, (*tableMeta)->colHash);
|
||||
ret = smlUpdateMeta((*tableMeta)->tagHash, (*tableMeta)->tags, tinfo->tags, true, &info->msgBuf,
|
||||
(*tableMeta)->colHash);
|
||||
}
|
||||
if (ret != TSDB_CODE_SUCCESS) {
|
||||
uError("SML:0x%" PRIx64 " smlUpdateMeta failed, ret:%d", info->id, ret);
|
||||
|
@ -1801,17 +1806,17 @@ static int32_t smlInsertData(SSmlHandle *info) {
|
|||
|
||||
if (info->pRequest->dbList == NULL) {
|
||||
info->pRequest->dbList = taosArrayInit(1, TSDB_DB_FNAME_LEN);
|
||||
if (info->pRequest->dbList == NULL){
|
||||
if (info->pRequest->dbList == NULL) {
|
||||
return terrno;
|
||||
}
|
||||
}
|
||||
char *data = (char *)taosArrayReserve(info->pRequest->dbList, 1);
|
||||
if (data == NULL){
|
||||
if (data == NULL) {
|
||||
return terrno;
|
||||
}
|
||||
SName pName = {TSDB_TABLE_NAME_T, info->taos->acctId, {0}, {0}};
|
||||
tstrncpy(pName.dbname, info->pRequest->pDb, sizeof(pName.dbname));
|
||||
(void)tNameGetFullDbName(&pName, data); //ignore
|
||||
(void)tNameGetFullDbName(&pName, data); // ignore
|
||||
|
||||
SSmlTableInfo **oneTable = (SSmlTableInfo **)taosHashIterate(info->childTables, NULL);
|
||||
while (oneTable) {
|
||||
|
@ -1819,7 +1824,7 @@ static int32_t smlInsertData(SSmlHandle *info) {
|
|||
|
||||
int measureLen = tableData->sTableNameLen;
|
||||
char *measure = (char *)taosMemoryMalloc(tableData->sTableNameLen);
|
||||
if (measure == NULL){
|
||||
if (measure == NULL) {
|
||||
return terrno;
|
||||
}
|
||||
(void)memcpy(measure, tableData->sTableName, tableData->sTableNameLen);
|
||||
|
@ -1830,11 +1835,11 @@ static int32_t smlInsertData(SSmlHandle *info) {
|
|||
|
||||
if (info->pRequest->tableList == NULL) {
|
||||
info->pRequest->tableList = taosArrayInit(1, sizeof(SName));
|
||||
if (info->pRequest->tableList == NULL){
|
||||
if (info->pRequest->tableList == NULL) {
|
||||
return terrno;
|
||||
}
|
||||
}
|
||||
if (taosArrayPush(info->pRequest->tableList, &pName) == NULL){
|
||||
if (taosArrayPush(info->pRequest->tableList, &pName) == NULL) {
|
||||
return terrno;
|
||||
}
|
||||
|
||||
|
@ -1862,7 +1867,7 @@ static int32_t smlInsertData(SSmlHandle *info) {
|
|||
return code;
|
||||
}
|
||||
code = taosHashPut(info->pVgHash, (const char *)&vg.vgId, sizeof(vg.vgId), (char *)&vg, sizeof(vg));
|
||||
if (code != TSDB_CODE_SUCCESS){
|
||||
if (code != TSDB_CODE_SUCCESS) {
|
||||
uError("SML:0x%" PRIx64 " taosHashPut failed. table name: %s", info->id, tableData->childTableName);
|
||||
taosMemoryFree(measure);
|
||||
taosHashCancelIterate(info->childTables, oneTable);
|
||||
|
@ -1904,9 +1909,9 @@ static int32_t smlInsertData(SSmlHandle *info) {
|
|||
info->cost.insertRpcTime = taosGetTimestampUs();
|
||||
|
||||
SAppClusterSummary *pActivity = &info->taos->pAppInfo->summary;
|
||||
(void)atomic_add_fetch_64((int64_t *)&pActivity->numOfInsertsReq, 1); // no need to check return code
|
||||
(void)atomic_add_fetch_64((int64_t *)&pActivity->numOfInsertsReq, 1); // no need to check return code
|
||||
|
||||
(void)launchQueryImpl(info->pRequest, info->pQuery, true, NULL); // no need to check return code
|
||||
launchQueryImpl(info->pRequest, info->pQuery, true, NULL); // no need to check return code
|
||||
|
||||
uDebug("SML:0x%" PRIx64 " smlInsertData end, format:%d, code:%d,%s", info->id, info->dataFormat, info->pRequest->code,
|
||||
tstrerror(info->pRequest->code));
|
||||
|
@ -1975,12 +1980,12 @@ static bool getLine(SSmlHandle *info, char *lines[], char **rawLine, char *rawLi
|
|||
|
||||
if (*rawLine != NULL && (uDebugFlag & DEBUG_DEBUG)) {
|
||||
char *print = taosMemoryCalloc(*len + 1, 1);
|
||||
if (print != NULL){
|
||||
if (print != NULL) {
|
||||
(void)memcpy(print, *tmp, *len);
|
||||
uDebug("SML:0x%" PRIx64 " smlParseLine is raw, numLines:%d, protocol:%d, len:%d, data:%s", info->id, numLines,
|
||||
info->protocol, *len, print);
|
||||
taosMemoryFree(print);
|
||||
} else{
|
||||
} else {
|
||||
uError("SML:0x%" PRIx64 " smlParseLine taosMemoryCalloc failed", info->id);
|
||||
}
|
||||
} else {
|
||||
|
@ -2228,7 +2233,7 @@ TAOS_RES *taos_schemaless_insert_inner(TAOS *taos, char *lines[], char *rawLine,
|
|||
uInfo("SML:%" PRIx64 " retry:%d/10,ver is old retry or object is creating code:%d, msg:%s", info->id, cnt, code,
|
||||
tstrerror(code));
|
||||
code = refreshMeta(request->pTscObj, request);
|
||||
if (code != 0){
|
||||
if (code != 0) {
|
||||
uInfo("SML:%" PRIx64 " refresh meta error code:%d, msg:%s", info->id, code, tstrerror(code));
|
||||
}
|
||||
smlDestroyInfo(info);
|
||||
|
@ -2266,7 +2271,7 @@ end:
|
|||
*/
|
||||
|
||||
TAOS_RES *taos_schemaless_insert_ttl_with_reqid_tbname_key(TAOS *taos, char *lines[], int numLines, int protocol,
|
||||
int precision, int32_t ttl, int64_t reqid, char *tbnameKey){
|
||||
int precision, int32_t ttl, int64_t reqid, char *tbnameKey) {
|
||||
return taos_schemaless_insert_inner(taos, lines, NULL, NULL, numLines, protocol, precision, ttl, reqid, tbnameKey);
|
||||
}
|
||||
|
||||
|
@ -2306,14 +2311,17 @@ static void getRawLineLen(char *lines, int len, int32_t *totalRows, int protocol
|
|||
}
|
||||
|
||||
TAOS_RES *taos_schemaless_insert_raw_ttl_with_reqid_tbname_key(TAOS *taos, char *lines, int len, int32_t *totalRows,
|
||||
int protocol, int precision, int32_t ttl, int64_t reqid, char *tbnameKey){
|
||||
int protocol, int precision, int32_t ttl, int64_t reqid,
|
||||
char *tbnameKey) {
|
||||
getRawLineLen(lines, len, totalRows, protocol);
|
||||
return taos_schemaless_insert_inner(taos, NULL, lines, lines + len, *totalRows, protocol, precision, ttl, reqid, tbnameKey);
|
||||
return taos_schemaless_insert_inner(taos, NULL, lines, lines + len, *totalRows, protocol, precision, ttl, reqid,
|
||||
tbnameKey);
|
||||
}
|
||||
|
||||
TAOS_RES *taos_schemaless_insert_raw_ttl_with_reqid(TAOS *taos, char *lines, int len, int32_t *totalRows, int protocol,
|
||||
int precision, int32_t ttl, int64_t reqid) {
|
||||
return taos_schemaless_insert_raw_ttl_with_reqid_tbname_key(taos, lines, len, totalRows, protocol, precision, ttl, reqid, NULL);
|
||||
return taos_schemaless_insert_raw_ttl_with_reqid_tbname_key(taos, lines, len, totalRows, protocol, precision, ttl,
|
||||
reqid, NULL);
|
||||
}
|
||||
|
||||
TAOS_RES *taos_schemaless_insert_raw_with_reqid(TAOS *taos, char *lines, int len, int32_t *totalRows, int protocol,
|
||||
|
|
|
@ -25,7 +25,7 @@ static FORCE_INLINE int32_t stmtAllocQNodeFromBuf(STableBufInfo* pTblBuf, void**
|
|||
return terrno;
|
||||
}
|
||||
|
||||
if(taosArrayPush(pTblBuf->pBufList, &buff) == NULL){
|
||||
if (taosArrayPush(pTblBuf->pBufList, &buff) == NULL) {
|
||||
return terrno;
|
||||
}
|
||||
|
||||
|
@ -184,10 +184,16 @@ int32_t stmtBackupQueryFields(STscStmt* pStmt) {
|
|||
|
||||
int32_t size = pRes->numOfCols * sizeof(TAOS_FIELD);
|
||||
pRes->fields = taosMemoryMalloc(size);
|
||||
pRes->userFields = taosMemoryMalloc(size);
|
||||
if (NULL == pRes->fields || NULL == pRes->userFields) {
|
||||
if (pRes->fields == NULL) {
|
||||
STMT_ERR_RET(terrno);
|
||||
}
|
||||
|
||||
pRes->userFields = taosMemoryMalloc(size);
|
||||
if (pRes->userFields == NULL) {
|
||||
taosMemoryFreeClear(pRes->fields);
|
||||
STMT_ERR_RET(terrno);
|
||||
}
|
||||
|
||||
(void)memcpy(pRes->fields, pStmt->exec.pRequest->body.resInfo.fields, size);
|
||||
(void)memcpy(pRes->userFields, pStmt->exec.pRequest->body.resInfo.userFields, size);
|
||||
|
||||
|
@ -224,8 +230,8 @@ int32_t stmtUpdateBindInfo(TAOS_STMT* stmt, STableMeta* pTableMeta, void* tags,
|
|||
bool autoCreateTbl) {
|
||||
STscStmt* pStmt = (STscStmt*)stmt;
|
||||
char tbFName[TSDB_TABLE_FNAME_LEN];
|
||||
int32_t code = tNameExtractFullName(tbName, tbFName);
|
||||
if (code != 0){
|
||||
int32_t code = tNameExtractFullName(tbName, tbFName);
|
||||
if (code != 0) {
|
||||
return code;
|
||||
}
|
||||
|
||||
|
@ -772,7 +778,7 @@ void* stmtBindThreadFunc(void* param) {
|
|||
}
|
||||
|
||||
int ret = stmtAsyncOutput(pStmt, asyncParam);
|
||||
if (ret != 0){
|
||||
if (ret != 0) {
|
||||
qError("stmtAsyncOutput failed, reason:%s", tstrerror(ret));
|
||||
}
|
||||
}
|
||||
|
@ -821,7 +827,7 @@ int32_t stmtInitTableBuf(STableBufInfo* pTblBuf) {
|
|||
return terrno;
|
||||
}
|
||||
|
||||
if (taosArrayPush(pTblBuf->pBufList, &buff) == NULL){
|
||||
if (taosArrayPush(pTblBuf->pBufList, &buff) == NULL) {
|
||||
return terrno;
|
||||
}
|
||||
|
||||
|
@ -923,9 +929,9 @@ int stmtPrepare(TAOS_STMT* stmt, const char* sql, unsigned long length) {
|
|||
length = strlen(sql);
|
||||
}
|
||||
|
||||
pStmt->sql.sqlStr = strndup(sql, length);
|
||||
pStmt->sql.sqlStr = taosStrndup(sql, length);
|
||||
if (!pStmt->sql.sqlStr) {
|
||||
return TSDB_CODE_OUT_OF_MEMORY;
|
||||
return terrno;
|
||||
}
|
||||
pStmt->sql.sqlLen = length;
|
||||
pStmt->sql.stbInterlaceMode = pStmt->stbInterlaceMode;
|
||||
|
@ -967,7 +973,7 @@ int32_t stmtInitStbInterlaceTableInfo(STscStmt* pStmt) {
|
|||
}
|
||||
|
||||
int stmtSetDbName(TAOS_STMT* stmt, const char* dbName) {
|
||||
STscStmt *pStmt = (STscStmt *) stmt;
|
||||
STscStmt* pStmt = (STscStmt*)stmt;
|
||||
|
||||
STMT_DLOG("start to set dbName: %s", dbName);
|
||||
|
||||
|
@ -1045,7 +1051,7 @@ int stmtSetTbTags(TAOS_STMT* stmt, TAOS_MULTI_BIND* tags) {
|
|||
|
||||
STMT_ERR_RET(stmtSwitchStatus(pStmt, STMT_SETTAGS));
|
||||
|
||||
SBoundColInfo *tags_info = (SBoundColInfo*)pStmt->bInfo.boundTags;
|
||||
SBoundColInfo* tags_info = (SBoundColInfo*)pStmt->bInfo.boundTags;
|
||||
if (tags_info->numOfBound <= 0 || tags_info->numOfCols <= 0) {
|
||||
tscWarn("no tags bound in sql, will not bound tags");
|
||||
return TSDB_CODE_SUCCESS;
|
||||
|
@ -1192,7 +1198,7 @@ static FORCE_INLINE int32_t stmtGetTableColsFromCache(STscStmt* pStmt, SArray**
|
|||
return terrno;
|
||||
}
|
||||
|
||||
if (taosArrayPush(pStmt->sql.siInfo.pTableCols, &pTblCols) == NULL){
|
||||
if (taosArrayPush(pStmt->sql.siInfo.pTableCols, &pTblCols) == NULL) {
|
||||
return terrno;
|
||||
}
|
||||
}
|
||||
|
@ -1216,7 +1222,6 @@ int stmtBindBatch(TAOS_STMT* stmt, TAOS_MULTI_BIND* bind, int32_t colIdx) {
|
|||
|
||||
STMT_ERR_RET(stmtSwitchStatus(pStmt, STMT_BIND));
|
||||
|
||||
|
||||
if (pStmt->bInfo.needParse && pStmt->sql.runTimes && pStmt->sql.type > 0 &&
|
||||
STMT_TYPE_MULTI_INSERT != pStmt->sql.type) {
|
||||
pStmt->bInfo.needParse = false;
|
||||
|
@ -1256,7 +1261,7 @@ int stmtBindBatch(TAOS_STMT* stmt, TAOS_MULTI_BIND* bind, int32_t colIdx) {
|
|||
|
||||
if (pStmt->sql.pQuery->haveResultSet) {
|
||||
STMT_ERR_RET(setResSchemaInfo(&pStmt->exec.pRequest->body.resInfo, pStmt->sql.pQuery->pResSchema,
|
||||
pStmt->sql.pQuery->numOfResCols));
|
||||
pStmt->sql.pQuery->numOfResCols));
|
||||
taosMemoryFreeClear(pStmt->sql.pQuery->pResSchema);
|
||||
setResPrecision(&pStmt->exec.pRequest->body.resInfo, pStmt->sql.pQuery->precision);
|
||||
}
|
||||
|
@ -1549,7 +1554,7 @@ int stmtExec(TAOS_STMT* stmt) {
|
|||
STMT_ERR_RET(stmtSwitchStatus(pStmt, STMT_EXECUTE));
|
||||
|
||||
if (STMT_TYPE_QUERY == pStmt->sql.type) {
|
||||
(void)launchQueryImpl(pStmt->exec.pRequest, pStmt->sql.pQuery, true, NULL);
|
||||
launchQueryImpl(pStmt->exec.pRequest, pStmt->sql.pQuery, true, NULL);
|
||||
} else {
|
||||
if (pStmt->sql.stbInterlaceMode) {
|
||||
int64_t startTs = taosGetTimestampUs();
|
||||
|
@ -1571,7 +1576,7 @@ int stmtExec(TAOS_STMT* stmt) {
|
|||
STMT_ERR_RET(qBuildStmtOutput(pStmt->sql.pQuery, pStmt->sql.pVgHash, pStmt->exec.pBlockHash));
|
||||
}
|
||||
|
||||
(void)launchQueryImpl(pStmt->exec.pRequest, pStmt->sql.pQuery, true, NULL);
|
||||
launchQueryImpl(pStmt->exec.pRequest, pStmt->sql.pQuery, true, NULL);
|
||||
}
|
||||
|
||||
if (pStmt->exec.pRequest->code && NEED_CLIENT_HANDLE_ERROR(pStmt->exec.pRequest->code)) {
|
||||
|
|
|
@ -698,7 +698,9 @@ static void* stmtBindThreadFunc(void* param) {
|
|||
continue;
|
||||
}
|
||||
|
||||
(void)stmtAsyncOutput(pStmt, asyncParam);
|
||||
if (stmtAsyncOutput(pStmt, asyncParam) != 0) {
|
||||
qError("stmt async output failed");
|
||||
}
|
||||
}
|
||||
|
||||
qInfo("stmt bind thread stopped");
|
||||
|
@ -822,7 +824,11 @@ TAOS_STMT2* stmtInit2(STscObj* taos, TAOS_STMT2_OPTION* pOptions) {
|
|||
|
||||
pStmt->sql.siInfo.tableColsReady = true;
|
||||
if (pStmt->options.asyncExecFn) {
|
||||
(void)tsem_init(&pStmt->asyncQuerySem, 0, 1);
|
||||
if (tsem_init(&pStmt->asyncQuerySem, 0, 1) != 0) {
|
||||
terrno = TAOS_SYSTEM_ERROR(errno);
|
||||
(void)stmtClose(pStmt);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
pStmt->semWaited = false;
|
||||
|
||||
|
@ -868,9 +874,9 @@ int stmtPrepare2(TAOS_STMT2* stmt, const char* sql, unsigned long length) {
|
|||
length = strlen(sql);
|
||||
}
|
||||
|
||||
pStmt->sql.sqlStr = strndup(sql, length);
|
||||
pStmt->sql.sqlStr = taosStrndup(sql, length);
|
||||
if (!pStmt->sql.sqlStr) {
|
||||
return TSDB_CODE_OUT_OF_MEMORY;
|
||||
return terrno;
|
||||
}
|
||||
pStmt->sql.sqlLen = length;
|
||||
pStmt->sql.stbInterlaceMode = pStmt->stbInterlaceMode;
|
||||
|
@ -1603,7 +1609,9 @@ static void asyncQueryCb(void* userdata, TAOS_RES* res, int code) {
|
|||
(void)stmtCleanExecInfo(pStmt, (code ? false : true), false);
|
||||
++pStmt->sql.runTimes;
|
||||
|
||||
(void)tsem_post(&pStmt->asyncQuerySem);
|
||||
if (tsem_post(&pStmt->asyncQuerySem) != 0) {
|
||||
tscError("failed to post asyncQuerySem");
|
||||
}
|
||||
}
|
||||
|
||||
int stmtExec2(TAOS_STMT2* stmt, int* affected_rows) {
|
||||
|
@ -1645,7 +1653,7 @@ int stmtExec2(TAOS_STMT2* stmt, int* affected_rows) {
|
|||
__taos_async_fn_t fp = pStmt->options.asyncExecFn;
|
||||
|
||||
if (!fp) {
|
||||
(void)launchQueryImpl(pStmt->exec.pRequest, pStmt->sql.pQuery, true, NULL);
|
||||
launchQueryImpl(pStmt->exec.pRequest, pStmt->sql.pQuery, true, NULL);
|
||||
|
||||
if (pStmt->exec.pRequest->code && NEED_CLIENT_HANDLE_ERROR(pStmt->exec.pRequest->code)) {
|
||||
code = refreshMeta(pStmt->exec.pRequest->pTscObj, pStmt->exec.pRequest);
|
||||
|
@ -1710,7 +1718,9 @@ int stmtClose2(TAOS_STMT2* stmt) {
|
|||
}
|
||||
|
||||
if (pStmt->options.asyncExecFn && !pStmt->semWaited) {
|
||||
(void)tsem_wait(&pStmt->asyncQuerySem);
|
||||
if (tsem_wait(&pStmt->asyncQuerySem) != 0) {
|
||||
tscError("failed to wait asyncQuerySem");
|
||||
}
|
||||
}
|
||||
|
||||
STMT_DLOG("stmt %p closed, stbInterlaceMode: %d, statInfo: ctgGetTbMetaNum=>%" PRId64 ", getCacheTbInfo=>%" PRId64
|
||||
|
@ -1727,7 +1737,9 @@ int stmtClose2(TAOS_STMT2* stmt) {
|
|||
STMT_ERR_RET(stmtCleanSQLInfo(pStmt));
|
||||
|
||||
if (pStmt->options.asyncExecFn) {
|
||||
(void)tsem_destroy(&pStmt->asyncQuerySem);
|
||||
if (tsem_destroy(&pStmt->asyncQuerySem) != 0) {
|
||||
tscError("failed to destroy asyncQuerySem");
|
||||
}
|
||||
}
|
||||
taosMemoryFree(stmt);
|
||||
|
||||
|
@ -1873,6 +1885,8 @@ int stmtGetParamNum2(TAOS_STMT2* stmt, int* nums) {
|
|||
|
||||
int stmtGetParamTbName(TAOS_STMT2* stmt, int* nums) {
|
||||
STscStmt2* pStmt = (STscStmt2*)stmt;
|
||||
int32_t code = 0;
|
||||
int32_t preCode = pStmt->errCode;
|
||||
|
||||
STMT_DLOG_E("start to get param num");
|
||||
|
||||
|
@ -1895,17 +1909,19 @@ int stmtGetParamTbName(TAOS_STMT2* stmt, int* nums) {
|
|||
STMT_ERR_RET(stmtCreateRequest(pStmt));
|
||||
|
||||
if (pStmt->bInfo.needParse) {
|
||||
STMT_ERR_RET(stmtParseSql(pStmt));
|
||||
STMT_ERRI_JRET(stmtParseSql(pStmt));
|
||||
}
|
||||
|
||||
if (TSDB_CODE_TSC_STMT_TBNAME_ERROR == pStmt->errCode) {
|
||||
*nums = STMT_TYPE_MULTI_INSERT == pStmt->sql.type ? 1 : 0;
|
||||
|
||||
_return:
|
||||
if (TSDB_CODE_TSC_STMT_TBNAME_ERROR == code) {
|
||||
*nums = 1;
|
||||
pStmt->errCode = TSDB_CODE_SUCCESS;
|
||||
} else {
|
||||
*nums = STMT_TYPE_MULTI_INSERT == pStmt->sql.type ? 1 : 0;
|
||||
code = TSDB_CODE_SUCCESS;
|
||||
}
|
||||
|
||||
return TSDB_CODE_SUCCESS;
|
||||
pStmt->errCode = preCode;
|
||||
return code;
|
||||
}
|
||||
/*
|
||||
int stmtGetParam(TAOS_STMT* stmt, int idx, int* type, int* bytes) {
|
||||
|
|
|
@ -63,13 +63,10 @@ int32_t s3Begin() {
|
|||
TAOS_RETURN(TSDB_CODE_SUCCESS);
|
||||
}
|
||||
|
||||
void s3End() { (void)S3_deinitialize(); }
|
||||
void s3End() { S3_deinitialize(); }
|
||||
|
||||
int32_t s3Init() { TAOS_RETURN(TSDB_CODE_SUCCESS); /*s3Begin();*/ }
|
||||
|
||||
void s3CleanUp() { /*s3End();*/
|
||||
}
|
||||
|
||||
static int32_t s3ListBucket(char const *bucketname);
|
||||
|
||||
static void s3DumpCfgByEp(int8_t epIndex) {
|
||||
|
@ -506,7 +503,9 @@ S3Status initial_multipart_callback(const char *upload_id, void *callbackData) {
|
|||
}
|
||||
|
||||
S3Status MultipartResponseProperiesCallback(const S3ResponseProperties *properties, void *callbackData) {
|
||||
(void)responsePropertiesCallbackNull(properties, callbackData);
|
||||
if (S3StatusOK != responsePropertiesCallbackNull(properties, callbackData)) {
|
||||
uError("%s failed at line %d to process null callback.", __func__, __LINE__);
|
||||
}
|
||||
|
||||
MultipartPartData *data = (MultipartPartData *)callbackData;
|
||||
int seq = data->seq;
|
||||
|
@ -517,7 +516,9 @@ S3Status MultipartResponseProperiesCallback(const S3ResponseProperties *properti
|
|||
}
|
||||
|
||||
S3Status MultipartResponseProperiesCallbackWithCp(const S3ResponseProperties *properties, void *callbackData) {
|
||||
(void)responsePropertiesCallbackNull(properties, callbackData);
|
||||
if (S3StatusOK != responsePropertiesCallbackNull(properties, callbackData)) {
|
||||
uError("%s failed at line %d to process null callback.", __func__, __LINE__);
|
||||
}
|
||||
|
||||
MultipartPartData *data = (MultipartPartData *)callbackData;
|
||||
int seq = data->seq;
|
||||
|
@ -897,8 +898,6 @@ upload:
|
|||
if (partData.put_object_data.status != S3StatusOK) {
|
||||
s3PrintError(__FILE__, __LINE__, __func__, partData.put_object_data.status, partData.put_object_data.err_msg);
|
||||
TAOS_CHECK_GOTO(TAOS_SYSTEM_ERROR(EIO), &lino, _exit);
|
||||
|
||||
//(void)cos_cp_dump(&cp);
|
||||
}
|
||||
|
||||
if (!manager.etags[seq - 1]) {
|
||||
|
@ -952,7 +951,9 @@ _exit:
|
|||
}
|
||||
|
||||
if (cp.thefile) {
|
||||
(void)cos_cp_close(cp.thefile);
|
||||
if (cos_cp_close(cp.thefile)) {
|
||||
uError("%s failed at line %d to close cp file.", __func__, lino);
|
||||
}
|
||||
}
|
||||
if (cp.parts) {
|
||||
taosMemoryFree(cp.parts);
|
||||
|
@ -1292,7 +1293,10 @@ int32_t s3DeleteObjects(const char *object_name[], int nobject) {
|
|||
void s3DeleteObjectsByPrefix(const char *prefix) {
|
||||
SArray *objectArray = getListByPrefix(prefix);
|
||||
if (objectArray == NULL) return;
|
||||
(void)s3DeleteObjects(TARRAY_DATA(objectArray), TARRAY_SIZE(objectArray));
|
||||
int32_t code = s3DeleteObjects(TARRAY_DATA(objectArray), TARRAY_SIZE(objectArray));
|
||||
if (!code) {
|
||||
uError("%s failed at line %d since %s.", __func__, __LINE__, tstrerror(code));
|
||||
}
|
||||
taosArrayDestroyEx(objectArray, s3FreeObjectKey);
|
||||
}
|
||||
|
||||
|
@ -1539,7 +1543,7 @@ int32_t s3Init() {
|
|||
TAOS_RETURN(TSDB_CODE_SUCCESS);
|
||||
}
|
||||
|
||||
void s3CleanUp() { cos_http_io_deinitialize(); }
|
||||
// void s3CleanUp() { cos_http_io_deinitialize(); }
|
||||
|
||||
static void log_status(cos_status_t *s) {
|
||||
cos_warn_log("status->code: %d", s->code);
|
||||
|
@ -1745,20 +1749,20 @@ bool s3Get(const char *object_name, const char *path) {
|
|||
cos_table_t *headers = NULL;
|
||||
int traffic_limit = 0;
|
||||
|
||||
//创建内存池
|
||||
// 创建内存池
|
||||
cos_pool_create(&p, NULL);
|
||||
|
||||
//初始化请求选项
|
||||
// 初始化请求选项
|
||||
options = cos_request_options_create(p);
|
||||
s3InitRequestOptions(options, is_cname);
|
||||
cos_str_set(&bucket, tsS3BucketName);
|
||||
if (traffic_limit) {
|
||||
//限速值设置范围为819200 - 838860800,即100KB/s - 100MB/s,如果超出该范围将返回400错误
|
||||
// 限速值设置范围为819200 - 838860800,即100KB/s - 100MB/s,如果超出该范围将返回400错误
|
||||
headers = cos_table_make(p, 1);
|
||||
cos_table_add_int(headers, "x-cos-traffic-limit", 819200);
|
||||
}
|
||||
|
||||
//下载对象
|
||||
// 下载对象
|
||||
cos_str_set(&file, path);
|
||||
cos_str_set(&object, object_name);
|
||||
s = cos_get_object_to_file(options, &bucket, &object, headers, NULL, &file, &resp_headers);
|
||||
|
@ -1769,7 +1773,7 @@ bool s3Get(const char *object_name, const char *path) {
|
|||
cos_warn_log("get object failed\n");
|
||||
}
|
||||
|
||||
//销毁内存池
|
||||
// 销毁内存池
|
||||
cos_pool_destroy(p);
|
||||
|
||||
return ret;
|
||||
|
@ -1791,10 +1795,10 @@ int32_t s3GetObjectBlock(const char *object_name, int64_t offset, int64_t block_
|
|||
// int traffic_limit = 0;
|
||||
char range_buf[64];
|
||||
|
||||
//创建内存池
|
||||
// 创建内存池
|
||||
cos_pool_create(&p, NULL);
|
||||
|
||||
//初始化请求选项
|
||||
// 初始化请求选项
|
||||
options = cos_request_options_create(p);
|
||||
// init_test_request_options(options, is_cname);
|
||||
s3InitRequestOptions(options, is_cname);
|
||||
|
@ -1843,7 +1847,7 @@ int32_t s3GetObjectBlock(const char *object_name, int64_t offset, int64_t block_
|
|||
// cos_warn_log("Download data=%s", buf);
|
||||
|
||||
_exit:
|
||||
//销毁内存池
|
||||
// 销毁内存池
|
||||
cos_pool_destroy(p);
|
||||
|
||||
*ppBlock = buf;
|
||||
|
@ -1932,15 +1936,15 @@ long s3Size(const char *object_name) {
|
|||
cos_string_t object;
|
||||
cos_table_t *resp_headers = NULL;
|
||||
|
||||
//创建内存池
|
||||
// 创建内存池
|
||||
cos_pool_create(&p, NULL);
|
||||
|
||||
//初始化请求选项
|
||||
// 初始化请求选项
|
||||
options = cos_request_options_create(p);
|
||||
s3InitRequestOptions(options, is_cname);
|
||||
cos_str_set(&bucket, tsS3BucketName);
|
||||
|
||||
//获取对象元数据
|
||||
// 获取对象元数据
|
||||
cos_str_set(&object, object_name);
|
||||
s = cos_head_object(options, &bucket, &object, NULL, &resp_headers);
|
||||
// print_headers(resp_headers);
|
||||
|
@ -1954,7 +1958,7 @@ long s3Size(const char *object_name) {
|
|||
cos_warn_log("head object failed\n");
|
||||
}
|
||||
|
||||
//销毁内存池
|
||||
// 销毁内存池
|
||||
cos_pool_destroy(p);
|
||||
|
||||
return size;
|
||||
|
@ -1963,7 +1967,6 @@ long s3Size(const char *object_name) {
|
|||
#else
|
||||
|
||||
int32_t s3Init() { return 0; }
|
||||
void s3CleanUp() {}
|
||||
int32_t s3PutObjectFromFile(const char *file, const char *object) { return 0; }
|
||||
int32_t s3PutObjectFromFile2(const char *file, const char *object, int8_t withcp) { return 0; }
|
||||
int32_t s3PutObjectFromFileOffset(const char *file, const char *object_name, int64_t offset, int64_t size) { return 0; }
|
||||
|
|
|
@ -309,7 +309,7 @@ int32_t cos_cp_dump(SCheckpoint* cp) {
|
|||
if (!item) {
|
||||
TAOS_CHECK_GOTO(TSDB_CODE_OUT_OF_MEMORY, &lino, _exit);
|
||||
}
|
||||
(void)cJSON_AddItemToArray(ajson, item);
|
||||
if (!cJSON_AddItemToArray(ajson, item)) goto _exit;
|
||||
|
||||
if (NULL == cJSON_AddNumberToObject(item, "index", cp->parts[i].index)) {
|
||||
TAOS_CHECK_GOTO(TSDB_CODE_OUT_OF_MEMORY, &lino, _exit);
|
||||
|
|
|
@ -1771,26 +1771,6 @@ _err:
|
|||
return code;
|
||||
}
|
||||
|
||||
void tTagSetCid(const STag *pTag, int16_t iTag, int16_t cid) {
|
||||
uint8_t *p = NULL;
|
||||
int8_t isLarge = pTag->flags & TD_TAG_LARGE;
|
||||
int16_t offset = 0;
|
||||
|
||||
if (isLarge) {
|
||||
p = (uint8_t *)&((int16_t *)pTag->idx)[pTag->nTag];
|
||||
} else {
|
||||
p = (uint8_t *)&pTag->idx[pTag->nTag];
|
||||
}
|
||||
|
||||
if (isLarge) {
|
||||
offset = ((int16_t *)pTag->idx)[iTag];
|
||||
} else {
|
||||
offset = pTag->idx[iTag];
|
||||
}
|
||||
|
||||
int32_t nt = tPutI16v(p + offset, cid);
|
||||
}
|
||||
|
||||
// STSchema ========================================
|
||||
STSchema *tBuildTSchema(SSchema *aSchema, int32_t numOfCols, int32_t version) {
|
||||
STSchema *pTSchema = taosMemoryCalloc(1, sizeof(STSchema) + sizeof(STColumn) * numOfCols);
|
||||
|
|
|
@ -2299,11 +2299,14 @@ static int taosLogVarComp(void const *lp, void const *rp) {
|
|||
return strcasecmp(lpVar->name, rpVar->name);
|
||||
}
|
||||
|
||||
static int32_t taosCheckAndSetDebugFlag(int32_t *pFlagPtr, char *name, int32_t flag, SArray *noNeedToSetVars) {
|
||||
static void taosCheckAndSetDebugFlag(int32_t *pFlagPtr, char *name, int32_t flag, SArray *noNeedToSetVars) {
|
||||
if (noNeedToSetVars != NULL && taosArraySearch(noNeedToSetVars, name, taosLogVarComp, TD_EQ) != NULL) {
|
||||
TAOS_RETURN(TSDB_CODE_SUCCESS);
|
||||
return;
|
||||
}
|
||||
return taosSetDebugFlag(pFlagPtr, name, flag);
|
||||
if (taosSetDebugFlag(pFlagPtr, name, flag) != 0) {
|
||||
uError("failed to set flag %s to %d", name, flag);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
int32_t taosSetGlobalDebugFlag(int32_t flag) { return taosSetAllDebugFlag(tsCfg, flag); }
|
||||
|
@ -2320,29 +2323,29 @@ static int32_t taosSetAllDebugFlag(SConfig *pCfg, int32_t flag) {
|
|||
pItem->i32 = flag;
|
||||
noNeedToSetVars = pItem->array;
|
||||
|
||||
(void)taosCheckAndSetDebugFlag(&simDebugFlag, "simDebugFlag", flag, noNeedToSetVars);
|
||||
(void)taosCheckAndSetDebugFlag(&uDebugFlag, "uDebugFlag", flag, noNeedToSetVars);
|
||||
(void)taosCheckAndSetDebugFlag(&rpcDebugFlag, "rpcDebugFlag", flag, noNeedToSetVars);
|
||||
(void)taosCheckAndSetDebugFlag(&qDebugFlag, "qDebugFlag", flag, noNeedToSetVars);
|
||||
taosCheckAndSetDebugFlag(&simDebugFlag, "simDebugFlag", flag, noNeedToSetVars);
|
||||
taosCheckAndSetDebugFlag(&uDebugFlag, "uDebugFlag", flag, noNeedToSetVars);
|
||||
taosCheckAndSetDebugFlag(&rpcDebugFlag, "rpcDebugFlag", flag, noNeedToSetVars);
|
||||
taosCheckAndSetDebugFlag(&qDebugFlag, "qDebugFlag", flag, noNeedToSetVars);
|
||||
|
||||
(void)taosCheckAndSetDebugFlag(&jniDebugFlag, "jniDebugFlag", flag, noNeedToSetVars);
|
||||
(void)taosCheckAndSetDebugFlag(&cDebugFlag, "cDebugFlag", flag, noNeedToSetVars);
|
||||
taosCheckAndSetDebugFlag(&jniDebugFlag, "jniDebugFlag", flag, noNeedToSetVars);
|
||||
taosCheckAndSetDebugFlag(&cDebugFlag, "cDebugFlag", flag, noNeedToSetVars);
|
||||
|
||||
(void)taosCheckAndSetDebugFlag(&dDebugFlag, "dDebugFlag", flag, noNeedToSetVars);
|
||||
(void)taosCheckAndSetDebugFlag(&vDebugFlag, "vDebugFlag", flag, noNeedToSetVars);
|
||||
(void)taosCheckAndSetDebugFlag(&mDebugFlag, "mDebugFlag", flag, noNeedToSetVars);
|
||||
(void)taosCheckAndSetDebugFlag(&wDebugFlag, "wDebugFlag", flag, noNeedToSetVars);
|
||||
(void)taosCheckAndSetDebugFlag(&sDebugFlag, "sDebugFlag", flag, noNeedToSetVars);
|
||||
(void)taosCheckAndSetDebugFlag(&tsdbDebugFlag, "tsdbDebugFlag", flag, noNeedToSetVars);
|
||||
(void)taosCheckAndSetDebugFlag(&tqDebugFlag, "tqDebugFlag", flag, noNeedToSetVars);
|
||||
(void)taosCheckAndSetDebugFlag(&fsDebugFlag, "fsDebugFlag", flag, noNeedToSetVars);
|
||||
(void)taosCheckAndSetDebugFlag(&udfDebugFlag, "udfDebugFlag", flag, noNeedToSetVars);
|
||||
(void)taosCheckAndSetDebugFlag(&smaDebugFlag, "smaDebugFlag", flag, noNeedToSetVars);
|
||||
(void)taosCheckAndSetDebugFlag(&idxDebugFlag, "idxDebugFlag", flag, noNeedToSetVars);
|
||||
(void)taosCheckAndSetDebugFlag(&tdbDebugFlag, "tdbDebugFlag", flag, noNeedToSetVars);
|
||||
(void)taosCheckAndSetDebugFlag(&metaDebugFlag, "metaDebugFlag", flag, noNeedToSetVars);
|
||||
(void)taosCheckAndSetDebugFlag(&stDebugFlag, "stDebugFlag", flag, noNeedToSetVars);
|
||||
(void)taosCheckAndSetDebugFlag(&sndDebugFlag, "sndDebugFlag", flag, noNeedToSetVars);
|
||||
taosCheckAndSetDebugFlag(&dDebugFlag, "dDebugFlag", flag, noNeedToSetVars);
|
||||
taosCheckAndSetDebugFlag(&vDebugFlag, "vDebugFlag", flag, noNeedToSetVars);
|
||||
taosCheckAndSetDebugFlag(&mDebugFlag, "mDebugFlag", flag, noNeedToSetVars);
|
||||
taosCheckAndSetDebugFlag(&wDebugFlag, "wDebugFlag", flag, noNeedToSetVars);
|
||||
taosCheckAndSetDebugFlag(&sDebugFlag, "sDebugFlag", flag, noNeedToSetVars);
|
||||
taosCheckAndSetDebugFlag(&tsdbDebugFlag, "tsdbDebugFlag", flag, noNeedToSetVars);
|
||||
taosCheckAndSetDebugFlag(&tqDebugFlag, "tqDebugFlag", flag, noNeedToSetVars);
|
||||
taosCheckAndSetDebugFlag(&fsDebugFlag, "fsDebugFlag", flag, noNeedToSetVars);
|
||||
taosCheckAndSetDebugFlag(&udfDebugFlag, "udfDebugFlag", flag, noNeedToSetVars);
|
||||
taosCheckAndSetDebugFlag(&smaDebugFlag, "smaDebugFlag", flag, noNeedToSetVars);
|
||||
taosCheckAndSetDebugFlag(&idxDebugFlag, "idxDebugFlag", flag, noNeedToSetVars);
|
||||
taosCheckAndSetDebugFlag(&tdbDebugFlag, "tdbDebugFlag", flag, noNeedToSetVars);
|
||||
taosCheckAndSetDebugFlag(&metaDebugFlag, "metaDebugFlag", flag, noNeedToSetVars);
|
||||
taosCheckAndSetDebugFlag(&stDebugFlag, "stDebugFlag", flag, noNeedToSetVars);
|
||||
taosCheckAndSetDebugFlag(&sndDebugFlag, "sndDebugFlag", flag, noNeedToSetVars);
|
||||
|
||||
taosArrayClear(noNeedToSetVars); // reset array
|
||||
|
||||
|
|
|
@ -354,8 +354,10 @@ bool tdSKvRowGetVal(STSRow *pRow, col_id_t colId, col_id_t colIdx, SCellVal *pVa
|
|||
}
|
||||
|
||||
void *pBitmap = tdGetBitmapAddrKv(pRow, tdRowGetNCols(pRow));
|
||||
(void)tdGetKvRowValOfCol(pVal, pRow, pBitmap, pColIdx->offset,
|
||||
POINTER_DISTANCE(pColIdx, TD_ROW_COL_IDX(pRow)) / sizeof(SKvRowIdx));
|
||||
if (tdGetKvRowValOfCol(pVal, pRow, pBitmap, pColIdx->offset,
|
||||
POINTER_DISTANCE(pColIdx, TD_ROW_COL_IDX(pRow)) / sizeof(SKvRowIdx)) != TSDB_CODE_SUCCESS) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -30,7 +30,9 @@ static int64_t m_deltaUtc = 0;
|
|||
|
||||
void deltaToUtcInitOnce() {
|
||||
struct tm tm = {0};
|
||||
(void)taosStrpTime("1970-01-01 00:00:00", (const char*)("%Y-%m-%d %H:%M:%S"), &tm);
|
||||
if (taosStrpTime("1970-01-01 00:00:00", (const char*)("%Y-%m-%d %H:%M:%S"), &tm) != 0) {
|
||||
uError("failed to parse time string");
|
||||
}
|
||||
m_deltaUtc = (int64_t)taosMktime(&tm);
|
||||
// printf("====delta:%lld\n\n", seconds);
|
||||
}
|
||||
|
@ -689,10 +691,10 @@ int64_t taosTimeAdd(int64_t t, int64_t duration, char unit, int32_t precision) {
|
|||
int64_t numOfMonth = (unit == 'y') ? duration * 12 : duration;
|
||||
int64_t fraction = t % TSDB_TICK_PER_SECOND(precision);
|
||||
|
||||
struct tm tm;
|
||||
time_t tt = (time_t)(t / TSDB_TICK_PER_SECOND(precision));
|
||||
(void)taosLocalTime(&tt, &tm, NULL);
|
||||
int32_t mon = tm.tm_year * 12 + tm.tm_mon + (int32_t)numOfMonth;
|
||||
struct tm tm;
|
||||
time_t tt = (time_t)(t / TSDB_TICK_PER_SECOND(precision));
|
||||
struct tm* ptm = taosLocalTime(&tt, &tm, NULL);
|
||||
int32_t mon = tm.tm_year * 12 + tm.tm_mon + (int32_t)numOfMonth;
|
||||
tm.tm_year = mon / 12;
|
||||
tm.tm_mon = mon % 12;
|
||||
int daysOfMonth[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
|
||||
|
@ -750,13 +752,13 @@ int32_t taosTimeCountIntervalForFill(int64_t skey, int64_t ekey, int64_t interva
|
|||
skey /= (int64_t)(TSDB_TICK_PER_SECOND(precision));
|
||||
ekey /= (int64_t)(TSDB_TICK_PER_SECOND(precision));
|
||||
|
||||
struct tm tm;
|
||||
time_t t = (time_t)skey;
|
||||
(void)taosLocalTime(&t, &tm, NULL);
|
||||
int32_t smon = tm.tm_year * 12 + tm.tm_mon;
|
||||
struct tm tm;
|
||||
time_t t = (time_t)skey;
|
||||
struct tm* ptm = taosLocalTime(&t, &tm, NULL);
|
||||
int32_t smon = tm.tm_year * 12 + tm.tm_mon;
|
||||
|
||||
t = (time_t)ekey;
|
||||
(void)taosLocalTime(&t, &tm, NULL);
|
||||
ptm = taosLocalTime(&t, &tm, NULL);
|
||||
int32_t emon = tm.tm_year * 12 + tm.tm_mon;
|
||||
|
||||
if (unit == 'y') {
|
||||
|
@ -778,9 +780,9 @@ int64_t taosTimeTruncate(int64_t ts, const SInterval* pInterval) {
|
|||
|
||||
if (IS_CALENDAR_TIME_DURATION(pInterval->slidingUnit)) {
|
||||
start /= (int64_t)(TSDB_TICK_PER_SECOND(precision));
|
||||
struct tm tm;
|
||||
time_t tt = (time_t)start;
|
||||
(void)taosLocalTime(&tt, &tm, NULL);
|
||||
struct tm tm;
|
||||
time_t tt = (time_t)start;
|
||||
struct tm* ptm = taosLocalTime(&tt, &tm, NULL);
|
||||
tm.tm_sec = 0;
|
||||
tm.tm_min = 0;
|
||||
tm.tm_hour = 0;
|
||||
|
|
|
@ -81,11 +81,21 @@ static void dmSetAssert(int32_t signum, void *sigInfo, void *context) { tsAssert
|
|||
static void dmStopDnode(int signum, void *sigInfo, void *context) {
|
||||
// taosIgnSignal(SIGUSR1);
|
||||
// taosIgnSignal(SIGUSR2);
|
||||
(void)taosIgnSignal(SIGTERM);
|
||||
(void)taosIgnSignal(SIGHUP);
|
||||
(void)taosIgnSignal(SIGINT);
|
||||
(void)taosIgnSignal(SIGABRT);
|
||||
(void)taosIgnSignal(SIGBREAK);
|
||||
if (taosIgnSignal(SIGTERM) != 0) {
|
||||
dWarn("failed to ignore signal SIGTERM");
|
||||
}
|
||||
if (taosIgnSignal(SIGHUP) != 0) {
|
||||
dWarn("failed to ignore signal SIGHUP");
|
||||
}
|
||||
if (taosIgnSignal(SIGINT) != 0) {
|
||||
dWarn("failed to ignore signal SIGINT");
|
||||
}
|
||||
if (taosIgnSignal(SIGABRT) != 0) {
|
||||
dWarn("failed to ignore signal SIGABRT");
|
||||
}
|
||||
if (taosIgnSignal(SIGBREAK) != 0) {
|
||||
dWarn("failed to ignore signal SIGBREAK");
|
||||
}
|
||||
|
||||
dInfo("shut down signal is %d", signum);
|
||||
#ifndef WINDOWS
|
||||
|
@ -103,11 +113,19 @@ void dmLogCrash(int signum, void *sigInfo, void *context) {
|
|||
// taosIgnSignal(SIGBREAK);
|
||||
|
||||
#ifndef WINDOWS
|
||||
(void)taosIgnSignal(SIGBUS);
|
||||
if (taosIgnSignal(SIGBUS) != 0) {
|
||||
dWarn("failed to ignore signal SIGBUS");
|
||||
}
|
||||
#endif
|
||||
(void)taosIgnSignal(SIGABRT);
|
||||
(void)taosIgnSignal(SIGFPE);
|
||||
(void)taosIgnSignal(SIGSEGV);
|
||||
if (taosIgnSignal(SIGABRT) != 0) {
|
||||
dWarn("failed to ignore signal SIGABRT");
|
||||
}
|
||||
if (taosIgnSignal(SIGFPE) != 0) {
|
||||
dWarn("failed to ignore signal SIGABRT");
|
||||
}
|
||||
if (taosIgnSignal(SIGSEGV) != 0) {
|
||||
dWarn("failed to ignore signal SIGABRT");
|
||||
}
|
||||
|
||||
char *pMsg = NULL;
|
||||
const char *flags = "UTL FATAL ";
|
||||
|
@ -136,24 +154,31 @@ _return:
|
|||
}
|
||||
|
||||
static void dmSetSignalHandle() {
|
||||
(void)taosSetSignal(SIGUSR1, dmSetDebugFlag);
|
||||
(void)taosSetSignal(SIGUSR2, dmSetAssert);
|
||||
(void)taosSetSignal(SIGTERM, dmStopDnode);
|
||||
(void)taosSetSignal(SIGHUP, dmStopDnode);
|
||||
(void)taosSetSignal(SIGINT, dmStopDnode);
|
||||
(void)taosSetSignal(SIGBREAK, dmStopDnode);
|
||||
if (taosSetSignal(SIGUSR1, dmSetDebugFlag) != 0) {
|
||||
dWarn("failed to set signal SIGUSR1");
|
||||
}
|
||||
if (taosSetSignal(SIGUSR2, dmSetAssert) != 0) {
|
||||
dWarn("failed to set signal SIGUSR1");
|
||||
}
|
||||
if (taosSetSignal(SIGTERM, dmStopDnode) != 0) {
|
||||
dWarn("failed to set signal SIGUSR1");
|
||||
}
|
||||
if (taosSetSignal(SIGHUP, dmStopDnode) != 0) {
|
||||
dWarn("failed to set signal SIGUSR1");
|
||||
}
|
||||
if (taosSetSignal(SIGINT, dmStopDnode) != 0) {
|
||||
dWarn("failed to set signal SIGUSR1");
|
||||
}
|
||||
if (taosSetSignal(SIGBREAK, dmStopDnode) != 0) {
|
||||
dWarn("failed to set signal SIGUSR1");
|
||||
}
|
||||
#ifndef WINDOWS
|
||||
(void)taosSetSignal(SIGTSTP, dmStopDnode);
|
||||
(void)taosSetSignal(SIGQUIT, dmStopDnode);
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
#ifndef WINDOWS
|
||||
(void)taosSetSignal(SIGBUS, dmLogCrash);
|
||||
#endif
|
||||
(void)taosSetSignal(SIGABRT, dmLogCrash);
|
||||
(void)taosSetSignal(SIGFPE, dmLogCrash);
|
||||
(void)taosSetSignal(SIGSEGV, dmLogCrash);
|
||||
if (taosSetSignal(SIGTSTP, dmStopDnode) != 0) {
|
||||
dWarn("failed to set signal SIGUSR1");
|
||||
}
|
||||
if (taosSetSignal(SIGQUIT, dmStopDnode) != 0) {
|
||||
dWarn("failed to set signal SIGUSR1");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
@ -45,7 +45,9 @@ static void dmMayShouldUpdateIpWhiteList(SDnodeMgmt *pMgmt, int64_t ver) {
|
|||
if (pMgmt->pData->ipWhiteVer == ver) {
|
||||
if (ver == 0) {
|
||||
dDebug("disable ip-white-list on dnode ver: %" PRId64 ", status ver: %" PRId64 "", pMgmt->pData->ipWhiteVer, ver);
|
||||
(void)rpcSetIpWhite(pMgmt->msgCb.serverRpc, NULL);
|
||||
if (rpcSetIpWhite(pMgmt->msgCb.serverRpc, NULL) != 0) {
|
||||
dError("failed to disable ip white list on dnode");
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
@ -91,7 +93,9 @@ static void dmProcessStatusRsp(SDnodeMgmt *pMgmt, SRpcMsg *pRsp) {
|
|||
dGInfo("dnode:%d, set to dropped since not exist in mnode, statusSeq:%d", pMgmt->pData->dnodeId,
|
||||
pMgmt->statusSeq);
|
||||
pMgmt->pData->dropped = 1;
|
||||
(void)dmWriteEps(pMgmt->pData);
|
||||
if (dmWriteEps(pMgmt->pData) != 0) {
|
||||
dError("failed to write dnode file");
|
||||
}
|
||||
dInfo("dnode will exit since it is in the dropped state");
|
||||
(void)raise(SIGINT);
|
||||
}
|
||||
|
@ -147,7 +151,9 @@ void dmSendStatusReq(SDnodeMgmt *pMgmt) {
|
|||
req.clusterCfg.monitorParas.tsSlowLogThresholdTest = tsSlowLogThresholdTest;
|
||||
tstrncpy(req.clusterCfg.monitorParas.tsSlowLogExceptDb, tsSlowLogExceptDb, TSDB_DB_NAME_LEN);
|
||||
char timestr[32] = "1970-01-01 00:00:00.00";
|
||||
(void)taosParseTime(timestr, &req.clusterCfg.checkTime, (int32_t)strlen(timestr), TSDB_TIME_PRECISION_MILLI, 0);
|
||||
if (taosParseTime(timestr, &req.clusterCfg.checkTime, (int32_t)strlen(timestr), TSDB_TIME_PRECISION_MILLI, 0) != 0) {
|
||||
dError("failed to parse time since %s", tstrerror(code));
|
||||
}
|
||||
memcpy(req.clusterCfg.timezone, tsTimezoneStr, TD_TIMEZONE_LEN);
|
||||
memcpy(req.clusterCfg.locale, tsLocale, TD_LOCALE_LEN);
|
||||
memcpy(req.clusterCfg.charset, tsCharset, TD_LOCALE_LEN);
|
||||
|
@ -243,7 +249,9 @@ void dmSendNotifyReq(SDnodeMgmt *pMgmt, SNotifyReq *pReq) {
|
|||
|
||||
SEpSet epSet = {0};
|
||||
dmGetMnodeEpSet(pMgmt->pData, &epSet);
|
||||
(void)rpcSendRequest(pMgmt->msgCb.clientRpc, &epSet, &rpcMsg, NULL);
|
||||
if (rpcSendRequest(pMgmt->msgCb.clientRpc, &epSet, &rpcMsg, NULL) != 0) {
|
||||
dError("failed to send notify req");
|
||||
}
|
||||
}
|
||||
|
||||
int32_t dmProcessAuthRsp(SDnodeMgmt *pMgmt, SRpcMsg *pMsg) {
|
||||
|
|
|
@ -305,11 +305,16 @@ int32_t dmStartNotifyThread(SDnodeMgmt *pMgmt) {
|
|||
|
||||
void dmStopNotifyThread(SDnodeMgmt *pMgmt) {
|
||||
if (taosCheckPthreadValid(pMgmt->notifyThread)) {
|
||||
(void)tsem_post(&dmNotifyHdl.sem);
|
||||
if (tsem_post(&dmNotifyHdl.sem) != 0) {
|
||||
dError("failed to post notify sem");
|
||||
}
|
||||
|
||||
(void)taosThreadJoin(pMgmt->notifyThread, NULL);
|
||||
taosThreadClear(&pMgmt->notifyThread);
|
||||
}
|
||||
(void)tsem_destroy(&dmNotifyHdl.sem);
|
||||
if (tsem_destroy(&dmNotifyHdl.sem) != 0) {
|
||||
dError("failed to destroy notify sem");
|
||||
}
|
||||
}
|
||||
|
||||
int32_t dmStartMonitorThread(SDnodeMgmt *pMgmt) {
|
||||
|
|
|
@ -17,7 +17,9 @@
|
|||
#include "mmInt.h"
|
||||
|
||||
void mmGetMonitorInfo(SMnodeMgmt *pMgmt, SMonMmInfo *pInfo) {
|
||||
(void)mndGetMonitorInfo(pMgmt->pMnode, &pInfo->cluster, &pInfo->vgroup, &pInfo->stb, &pInfo->grant);
|
||||
if (mndGetMonitorInfo(pMgmt->pMnode, &pInfo->cluster, &pInfo->vgroup, &pInfo->stb, &pInfo->grant) != 0) {
|
||||
dError("failed to get monitor info");
|
||||
}
|
||||
}
|
||||
|
||||
void mmGetMnodeLoads(SMnodeMgmt *pMgmt, SMonMloadInfo *pInfo) {
|
||||
|
|
|
@ -23,7 +23,7 @@ static inline void qmSendRsp(SRpcMsg *pMsg, int32_t code) {
|
|||
.contLen = pMsg->info.rspLen,
|
||||
.info = pMsg->info,
|
||||
};
|
||||
(void)tmsgSendRsp(&rsp);
|
||||
tmsgSendRsp(&rsp);
|
||||
}
|
||||
|
||||
static void qmProcessQueue(SQueueInfo *pInfo, SRpcMsg *pMsg) {
|
||||
|
|
|
@ -23,15 +23,15 @@ static inline void smSendRsp(SRpcMsg *pMsg, int32_t code) {
|
|||
.contLen = pMsg->info.rspLen,
|
||||
.info = pMsg->info,
|
||||
};
|
||||
(void)tmsgSendRsp(&rsp);
|
||||
tmsgSendRsp(&rsp);
|
||||
}
|
||||
|
||||
static void smProcessWriteQueue(SQueueInfo *pInfo, STaosQall *qall, int32_t numOfMsgs) {
|
||||
SSnodeMgmt *pMgmt = pInfo->ahandle;
|
||||
|
||||
for (int32_t i = 0; i < numOfMsgs; i++) {
|
||||
SRpcMsg *pMsg = NULL;
|
||||
(void)taosGetQitem(qall, (void **)&pMsg);
|
||||
SRpcMsg *pMsg = NULL;
|
||||
int32_t num = taosGetQitem(qall, (void **)&pMsg);
|
||||
const STraceId *trace = &pMsg->info.traceId;
|
||||
|
||||
dTrace("msg:%p, get from snode-write queue", pMsg);
|
||||
|
|
|
@ -35,10 +35,14 @@ void vmGetVnodeLoads(SVnodeMgmt *pMgmt, SMonVloadInfo *pInfo, bool isReset) {
|
|||
SVnodeObj *pVnode = *ppVnode;
|
||||
SVnodeLoad vload = {.vgId = pVnode->vgId};
|
||||
if (!pVnode->failed) {
|
||||
(void)vnodeGetLoad(pVnode->pImpl, &vload);
|
||||
if (vnodeGetLoad(pVnode->pImpl, &vload) != 0) {
|
||||
dError("failed to get vnode load");
|
||||
}
|
||||
if (isReset) vnodeResetLoad(pVnode->pImpl, &vload);
|
||||
}
|
||||
(void)taosArrayPush(pInfo->pVloads, &vload);
|
||||
if (taosArrayPush(pInfo->pVloads, &vload) == NULL) {
|
||||
dError("failed to push vnode load");
|
||||
}
|
||||
pIter = taosHashIterate(pMgmt->hash, pIter);
|
||||
}
|
||||
|
||||
|
@ -116,7 +120,9 @@ void vmGetMonitorInfo(SVnodeMgmt *pMgmt, SMonVmInfo *pInfo) {
|
|||
pMgmt->state.numOfBatchInsertReqs = numOfBatchInsertReqs;
|
||||
pMgmt->state.numOfBatchInsertSuccessReqs = numOfBatchInsertSuccessReqs;
|
||||
|
||||
(void)tfsGetMonitorInfo(pMgmt->pTfs, &pInfo->tfs);
|
||||
if (tfsGetMonitorInfo(pMgmt->pTfs, &pInfo->tfs) != 0) {
|
||||
dError("failed to get tfs monitor info");
|
||||
}
|
||||
taosArrayDestroy(pVloads);
|
||||
}
|
||||
|
||||
|
@ -845,7 +851,9 @@ int32_t vmProcessDropVnodeReq(SVnodeMgmt *pMgmt, SRpcMsg *pMsg) {
|
|||
}
|
||||
|
||||
vmCloseVnode(pMgmt, pVnode, false);
|
||||
(void)vmWriteVnodeListToFile(pMgmt);
|
||||
if (vmWriteVnodeListToFile(pMgmt) != 0) {
|
||||
dError("vgId:%d, failed to write vnode list since %s", vgId, terrstr());
|
||||
}
|
||||
|
||||
dInfo("vgId:%d, is dropped", vgId);
|
||||
return 0;
|
||||
|
|
|
@ -24,7 +24,7 @@ int32_t vmGetPrimaryDisk(SVnodeMgmt *pMgmt, int32_t vgId) {
|
|||
SVnodeObj *pVnode = NULL;
|
||||
|
||||
(void)taosThreadRwlockRdlock(&pMgmt->lock);
|
||||
(void)taosHashGetDup(pMgmt->hash, &vgId, sizeof(int32_t), (void *)&pVnode);
|
||||
int32_t r = taosHashGetDup(pMgmt->hash, &vgId, sizeof(int32_t), (void *)&pVnode);
|
||||
if (pVnode != NULL) {
|
||||
diskId = pVnode->diskPrimary;
|
||||
}
|
||||
|
@ -97,7 +97,7 @@ SVnodeObj *vmAcquireVnodeImpl(SVnodeMgmt *pMgmt, int32_t vgId, bool strict) {
|
|||
SVnodeObj *pVnode = NULL;
|
||||
|
||||
(void)taosThreadRwlockRdlock(&pMgmt->lock);
|
||||
(void)taosHashGetDup(pMgmt->hash, &vgId, sizeof(int32_t), (void *)&pVnode);
|
||||
int32_t r = taosHashGetDup(pMgmt->hash, &vgId, sizeof(int32_t), (void *)&pVnode);
|
||||
if (pVnode == NULL || strict && (pVnode->dropped || pVnode->failed)) {
|
||||
terrno = TSDB_CODE_VND_INVALID_VGROUP_ID;
|
||||
pVnode = NULL;
|
||||
|
@ -165,7 +165,7 @@ int32_t vmOpenVnode(SVnodeMgmt *pMgmt, SWrapperCfg *pCfg, SVnode *pImpl) {
|
|||
|
||||
(void)taosThreadRwlockWrlock(&pMgmt->lock);
|
||||
SVnodeObj *pOld = NULL;
|
||||
(void)taosHashGetDup(pMgmt->hash, &pVnode->vgId, sizeof(int32_t), (void *)&pOld);
|
||||
int32_t r = taosHashGetDup(pMgmt->hash, &pVnode->vgId, sizeof(int32_t), (void *)&pOld);
|
||||
if (pOld) {
|
||||
vmFreeVnodeObj(&pOld);
|
||||
}
|
||||
|
@ -184,7 +184,7 @@ void vmCloseVnode(SVnodeMgmt *pMgmt, SVnodeObj *pVnode, bool commitAndRemoveWal)
|
|||
}
|
||||
|
||||
(void)taosThreadRwlockWrlock(&pMgmt->lock);
|
||||
(void)taosHashRemove(pMgmt->hash, &pVnode->vgId, sizeof(int32_t));
|
||||
int32_t r = taosHashRemove(pMgmt->hash, &pVnode->vgId, sizeof(int32_t));
|
||||
(void)taosThreadRwlockUnlock(&pMgmt->lock);
|
||||
vmReleaseVnode(pMgmt, pVnode);
|
||||
|
||||
|
@ -233,8 +233,12 @@ void vmCloseVnode(SVnodeMgmt *pMgmt, SVnodeObj *pVnode, bool commitAndRemoveWal)
|
|||
|
||||
if (commitAndRemoveWal) {
|
||||
dInfo("vgId:%d, commit data for vnode split", pVnode->vgId);
|
||||
(void)vnodeSyncCommit(pVnode->pImpl);
|
||||
(void)vnodeBegin(pVnode->pImpl);
|
||||
if (vnodeSyncCommit(pVnode->pImpl) != 0) {
|
||||
dError("vgId:%d, failed to commit data", pVnode->vgId);
|
||||
}
|
||||
if (vnodeBegin(pVnode->pImpl) != 0) {
|
||||
dError("vgId:%d, failed to begin", pVnode->vgId);
|
||||
}
|
||||
dInfo("vgId:%d, commit data finished", pVnode->vgId);
|
||||
}
|
||||
|
||||
|
@ -248,8 +252,12 @@ _closed:
|
|||
if (commitAndRemoveWal) {
|
||||
snprintf(path, TSDB_FILENAME_LEN, "vnode%svnode%d%swal", TD_DIRSEP, pVnode->vgId, TD_DIRSEP);
|
||||
dInfo("vgId:%d, remove all wals, path:%s", pVnode->vgId, path);
|
||||
(void)tfsRmdir(pMgmt->pTfs, path);
|
||||
(void)tfsMkdir(pMgmt->pTfs, path);
|
||||
if (tfsRmdir(pMgmt->pTfs, path) != 0) {
|
||||
dTrace("vgId:%d, failed to remove wals, path:%s", pVnode->vgId, path);
|
||||
}
|
||||
if (tfsMkdir(pMgmt->pTfs, path) != 0) {
|
||||
dTrace("vgId:%d, failed to create wals, path:%s", pVnode->vgId, path);
|
||||
}
|
||||
}
|
||||
|
||||
if (pVnode->dropped) {
|
||||
|
@ -289,11 +297,22 @@ static void *vmOpenVnodeInThread(void *param) {
|
|||
SVnodeMgmt *pMgmt = pThread->pMgmt;
|
||||
char path[TSDB_FILENAME_LEN];
|
||||
|
||||
dInfo("thread:%d, start to open %d vnodes", pThread->threadIndex, pThread->vnodeNum);
|
||||
dInfo("thread:%d, start to open or destroy %d vnodes", pThread->threadIndex, pThread->vnodeNum);
|
||||
setThreadName("open-vnodes");
|
||||
|
||||
for (int32_t v = 0; v < pThread->vnodeNum; ++v) {
|
||||
SWrapperCfg *pCfg = &pThread->pCfgs[v];
|
||||
if (pCfg->dropped) {
|
||||
char stepDesc[TSDB_STEP_DESC_LEN] = {0};
|
||||
snprintf(stepDesc, TSDB_STEP_DESC_LEN, "vgId:%d, start to destroy, %d of %d have been dropped", pCfg->vgId,
|
||||
pMgmt->state.openVnodes, pMgmt->state.totalVnodes);
|
||||
tmsgReportStartup("vnode-destroy", stepDesc);
|
||||
|
||||
snprintf(path, TSDB_FILENAME_LEN, "vnode%svnode%d", TD_DIRSEP, pCfg->vgId);
|
||||
vnodeDestroy(pCfg->vgId, path, pMgmt->pTfs, 0);
|
||||
pThread->updateVnodesList = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
char stepDesc[TSDB_STEP_DESC_LEN] = {0};
|
||||
snprintf(stepDesc, TSDB_STEP_DESC_LEN, "vgId:%d, start to restore, %d of %d have been opened", pCfg->vgId,
|
||||
|
|
|
@ -187,7 +187,9 @@ static void vmProcessSyncQueue(SQueueInfo *pInfo, STaosQall *qall, int32_t numOf
|
|||
static void vmSendResponse(SRpcMsg *pMsg) {
|
||||
if (pMsg->info.handle) {
|
||||
SRpcMsg rsp = {.info = pMsg->info, .code = terrno};
|
||||
(void)rpcSendResponse(&rsp);
|
||||
if (rpcSendResponse(&rsp) != 0) {
|
||||
dError("failed to send response since %s", terrstr());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -389,10 +391,28 @@ int32_t vmAllocQueue(SVnodeMgmt *pMgmt, SVnodeObj *pVnode) {
|
|||
SMultiWorkerCfg scfg = {.max = 1, .name = "vnode-sync", .fp = (FItems)vmProcessSyncQueue, .param = pVnode};
|
||||
SMultiWorkerCfg sccfg = {.max = 1, .name = "vnode-sync-rd", .fp = (FItems)vmProcessSyncQueue, .param = pVnode};
|
||||
SMultiWorkerCfg acfg = {.max = 1, .name = "vnode-apply", .fp = (FItems)vnodeApplyWriteMsg, .param = pVnode->pImpl};
|
||||
(void)tMultiWorkerInit(&pVnode->pWriteW, &wcfg);
|
||||
(void)tMultiWorkerInit(&pVnode->pSyncW, &scfg);
|
||||
(void)tMultiWorkerInit(&pVnode->pSyncRdW, &sccfg);
|
||||
(void)tMultiWorkerInit(&pVnode->pApplyW, &acfg);
|
||||
code = tMultiWorkerInit(&pVnode->pWriteW, &wcfg);
|
||||
if (code) {
|
||||
return code;
|
||||
}
|
||||
code = tMultiWorkerInit(&pVnode->pSyncW, &scfg);
|
||||
if (code) {
|
||||
tMultiWorkerCleanup(&pVnode->pWriteW);
|
||||
return code;
|
||||
}
|
||||
code = tMultiWorkerInit(&pVnode->pSyncRdW, &sccfg);
|
||||
if (code) {
|
||||
tMultiWorkerCleanup(&pVnode->pWriteW);
|
||||
tMultiWorkerCleanup(&pVnode->pSyncW);
|
||||
return code;
|
||||
}
|
||||
code = tMultiWorkerInit(&pVnode->pApplyW, &acfg);
|
||||
if (code) {
|
||||
tMultiWorkerCleanup(&pVnode->pWriteW);
|
||||
tMultiWorkerCleanup(&pVnode->pSyncW);
|
||||
tMultiWorkerCleanup(&pVnode->pSyncRdW);
|
||||
return code;
|
||||
}
|
||||
|
||||
pVnode->pQueryQ = tQueryAutoQWorkerAllocQueue(&pMgmt->queryPool, pVnode, (FItem)vmProcessQueryQueue);
|
||||
pVnode->pStreamQ = tAutoQWorkerAllocQueue(&pMgmt->streamPool, pVnode, (FItem)vmProcessStreamQueue);
|
||||
|
|
|
@ -47,8 +47,14 @@ static int32_t dmCheckRepeatInit(SDnode *pDnode) {
|
|||
}
|
||||
|
||||
static int32_t dmInitSystem() {
|
||||
(void)taosIgnSIGPIPE();
|
||||
(void)taosBlockSIGPIPE();
|
||||
if (taosIgnSIGPIPE() != 0) {
|
||||
dError("failed to ignore SIGPIPE");
|
||||
}
|
||||
|
||||
if (taosBlockSIGPIPE() != 0) {
|
||||
dError("failed to block SIGPIPE");
|
||||
}
|
||||
|
||||
taosResolveCRC();
|
||||
return 0;
|
||||
}
|
||||
|
@ -204,7 +210,9 @@ void dmCleanup() {
|
|||
auditCleanup();
|
||||
syncCleanUp();
|
||||
walCleanUp();
|
||||
(void)udfcClose();
|
||||
if (udfcClose() != 0) {
|
||||
dError("failed to close udfc");
|
||||
}
|
||||
udfStopUdfd();
|
||||
taosStopCacheRefreshWorker();
|
||||
(void)dmDiskClose();
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue