diff --git a/contrib/CMakeLists.txt b/contrib/CMakeLists.txt index ef7acb1f34..b1e85700a5 100644 --- a/contrib/CMakeLists.txt +++ b/contrib/CMakeLists.txt @@ -661,9 +661,10 @@ ELSEIF(TD_DARWIN) SET(TZ_OUTPUT_PATH /var/db/timezone/zoneinfo) ENDIF() -MESSAGE(STATUS "timezone file path: " ${TZ_OUTPUT_PATH}) if(NOT ${TD_WINDOWS}) + MESSAGE(STATUS "timezone file path: " ${TZ_OUTPUT_PATH}) + execute_process( COMMAND make TZDIR=${TZ_OUTPUT_PATH}/ tzdir.h WORKING_DIRECTORY "${TD_CONTRIB_DIR}/tz" diff --git a/docs/zh/14-reference/05-connector/10-cpp.mdx b/docs/zh/14-reference/05-connector/10-cpp.mdx index ac65403827..64163dcdca 100644 --- a/docs/zh/14-reference/05-connector/10-cpp.mdx +++ b/docs/zh/14-reference/05-connector/10-cpp.mdx @@ -687,12 +687,22 @@ TDengine 客户端驱动的版本号与 TDengine 服务端的版本号是一一 - **返回值**:`0`:成功,`-1`:失败。 - `int taos_options_connection(TAOS *taos, TSDB_OPTION_CONNECTION option, const void *arg, ...)` - - **接口说明**:设置客户端每个连接选项(不影响服务端的行为,特别对于 charset 和 timezone),目前支持字符集设置(`TSDB_OPTION_CONNECTION_CHARSET`)、时区设置(`TSDB_OPTION_CONNECTION_TIMEZONE`)、用户 IP 设置(`TSDB_OPTION_CONNECTION_USER_IP`)、用户 APP 设置(`TSDB_OPTION_CONNECTION_USER_APP`)。字符集、时区默认为操作系统当前设置,windows 不支持连接级别的时区设置,多次调用接口设置相同的配置,以后面的设置为准。 + - **接口说明**:设置客户端每个连接选项,目前支持字符集设置(`TSDB_OPTION_CONNECTION_CHARSET`)、时区设置(`TSDB_OPTION_CONNECTION_TIMEZONE`)、用户 IP 设置(`TSDB_OPTION_CONNECTION_USER_IP`)、用户 APP 设置(`TSDB_OPTION_CONNECTION_USER_APP`)。 - **参数说明**: - `taos`: [入参] taos_connect 返回的连接句柄。 - - `option`:[入参] 设置项类型,具体类型的使用方法及约束详见 taos.h 文件。 - - `arg`:[入参] 设置项值。为 NULL 时表示重置该选项。 -- **返回值**:`0`:成功,`非0`:失败。 + - `option`:[入参] 设置项类型。 + - `arg`:[入参] 设置项值。 + - **返回值**:`0`:成功,`非0`:失败。 + - **说明**: + - 字符集、时区默认为操作系统当前设置,windows 不支持连接级别的时区设置。 + - arg 为 NULL 时表示重置该选项。 + - 该接口只对当前连接有效,不会影响其他连接。 + - 同样参数多次调用该接口,以后面的为准,可以作为修改的方法。 + - TSDB_OPTION_CONNECTION_CLEAR 选项用于重置所有连接选项。 + - 时区和字符集重置后,使用操作系统的设置,user ip 和 user app 重置后为空。 + - 连接选项的值都是 string 类型,user app 参数值最大为 23,超过该值会被截断;其他参数非法时报错。 + - 时区参数设置为空或非法时,默认为 UTC。 + - 时区和字符集只在 client 侧起作用,对于在服务端的相关行为不起作用。 - `char *taos_get_client_info()` - **接口说明**:获取客户端版本信息。 diff --git a/include/client/taos.h b/include/client/taos.h index a00babb187..e59ea9d418 100644 --- a/include/client/taos.h +++ b/include/client/taos.h @@ -181,31 +181,14 @@ typedef struct TAOS_STMT_OPTIONS { bool singleTableBindOnce; } TAOS_STMT_OPTIONS; - -/* - description: - taos_options_connection use to set extra connect options and affect behavior for a connection. - This function may be called multiple times to set several options. - Call taos_options_connection() after taos_connect() or taos_connect_auth(). - The option argument is the option that you want to set; the arg argument is the value for the option. - If you want to reset the option, set arg to NULL. - input: - taos: returned by taos_connect - option: option name - arg: option value - output: - 0: success - others: fail, error msg can be got by taos_errstr(NULL) -*/ -DLL_EXPORT int taos_options_connection(TAOS *taos, TSDB_OPTION_CONNECTION option, const void *arg, ...); - DLL_EXPORT void taos_cleanup(void); DLL_EXPORT int taos_options(TSDB_OPTION option, const void *arg, ...); +DLL_EXPORT int taos_options_connection(TAOS *taos, TSDB_OPTION_CONNECTION option, const void *arg, ...); DLL_EXPORT setConfRet taos_set_config(const char *config); DLL_EXPORT int taos_init(void); DLL_EXPORT TAOS *taos_connect(const char *ip, const char *user, const char *pass, const char *db, uint16_t port); -DLL_EXPORT TAOS *taos_connect_auth(const char *ip, const char *user, const char *auth, const char *db, uint16_t port); -DLL_EXPORT void taos_close(TAOS *taos); +DLL_EXPORT TAOS *taos_connect_auth(const char *ip, const char *user, const char *auth, const char *db, uint16_t port); +DLL_EXPORT void taos_close(TAOS *taos); DLL_EXPORT const char *taos_data_type(int type); diff --git a/include/util/tencode.h b/include/util/tencode.h index 794844ed74..270d9e75df 100644 --- a/include/util/tencode.h +++ b/include/util/tencode.h @@ -413,18 +413,20 @@ static FORCE_INLINE int32_t tDecodeBinary(SDecoder* pCoder, uint8_t** val, uint3 static FORCE_INLINE int32_t tDecodeCStrAndLen(SDecoder* pCoder, char** val, uint32_t* len) { TAOS_CHECK_RETURN(tDecodeBinary(pCoder, (uint8_t**)val, len)); - (*len) -= 1; // *len = 0 - 1 + if (*len > 0) { // notice!!! *len maybe 0 + (*len) -= 1; + } return 0; } static FORCE_INLINE int32_t tDecodeCStr(SDecoder* pCoder, char** val) { - uint32_t len; + uint32_t len = 0; return tDecodeCStrAndLen(pCoder, val, &len); } static int32_t tDecodeCStrTo(SDecoder* pCoder, char* val) { - char* pStr; - uint32_t len; + char* pStr = NULL; + uint32_t len = 0; TAOS_CHECK_RETURN(tDecodeCStrAndLen(pCoder, &pStr, &len)); if (len < pCoder->size) { @@ -482,12 +484,14 @@ static FORCE_INLINE int32_t tDecodeBinaryAlloc32(SDecoder* pCoder, void** val, u static FORCE_INLINE int32_t tDecodeCStrAndLenAlloc(SDecoder* pCoder, char** val, uint64_t* len) { TAOS_CHECK_RETURN(tDecodeBinaryAlloc(pCoder, (void**)val, len)); - (*len) -= 1; + if (*len > 0){ + (*len) -= 1; + } return 0; } static FORCE_INLINE int32_t tDecodeCStrAlloc(SDecoder* pCoder, char** val) { - uint64_t len; + uint64_t len = 0; return tDecodeCStrAndLenAlloc(pCoder, val, &len); } diff --git a/source/client/test/clientTests.cpp b/source/client/test/clientTests.cpp index f4317f07f7..fa0871b812 100644 --- a/source/client/test/clientTests.cpp +++ b/source/client/test/clientTests.cpp @@ -1489,4 +1489,124 @@ TEST(clientCase, sub_tb_mt_test) { } } +TEST(clientCase, timezone_Test) { + { + // taos_options( TSDB_OPTION_TIMEZONE, "UTC-8"); + int code = taos_options(TSDB_OPTION_TIMEZONE, "UTC-8"); + ASSERT_TRUE(code == 0); + TAOS* pConn = taos_connect("localhost", "root", "taosdata", NULL, 0); + ASSERT_NE(pConn, nullptr); + + TAOS_RES* pRes = taos_query(pConn, "drop database if exists db1"); + ASSERT_EQ(taos_errno(pRes), TSDB_CODE_SUCCESS); + taos_free_result(pRes); + + pRes = taos_query(pConn, "create database db1"); + ASSERT_EQ(taos_errno(pRes), TSDB_CODE_SUCCESS); + taos_free_result(pRes); + + pRes = taos_query(pConn, "create table db1.t1 (ts timestamp, v int)"); + ASSERT_EQ(taos_errno(pRes), TSDB_CODE_SUCCESS); + taos_free_result(pRes); + + char sql[256] = {0}; + (void)sprintf(sql, "insert into db1.t1 values('2023-09-16 17:00:00', 1)"); + pRes = taos_query(pConn, sql); + ASSERT_EQ(taos_errno(pRes), TSDB_CODE_SUCCESS); + taos_free_result(pRes); + + pRes = taos_query(pConn, "select * from db1.t1 where ts == '2023-09-16 17:00:00'"); + ASSERT_EQ(taos_errno(pRes), TSDB_CODE_SUCCESS); + + TAOS_ROW pRow = NULL; + TAOS_FIELD* pFields = taos_fetch_fields(pRes); + int32_t numOfFields = taos_num_fields(pRes); + + char str[512] = {0}; + int rows = 0; + while ((pRow = taos_fetch_row(pRes)) != NULL) { + rows++; + } + ASSERT_TRUE(rows == 1); + + taos_free_result(pRes); + + taos_close(pConn); + } + + { + // taos_options( TSDB_OPTION_TIMEZONE, "UTC+8"); + int code = taos_options(TSDB_OPTION_TIMEZONE, "UTC+8"); + ASSERT_TRUE(code == 0); + TAOS* pConn = taos_connect("localhost", "root", "taosdata", NULL, 0); + ASSERT_NE(pConn, nullptr); + + TAOS_RES* pRes = taos_query(pConn, "select * from db1.t1 where ts == '2023-09-16 01:00:00'"); + ASSERT_EQ(taos_errno(pRes), TSDB_CODE_SUCCESS); + + TAOS_ROW pRow = NULL; + TAOS_FIELD* pFields = taos_fetch_fields(pRes); + int32_t numOfFields = taos_num_fields(pRes); + + int rows = 0; + char str[512] = {0}; + while ((pRow = taos_fetch_row(pRes)) != NULL) { + rows++; + } + ASSERT_TRUE(rows == 1); + + taos_free_result(pRes); + + char sql[256] = {0}; + (void)sprintf(sql, "insert into db1.t1 values('2023-09-16 17:00:01', 1)"); + pRes = taos_query(pConn, sql); + ASSERT_EQ(taos_errno(pRes), TSDB_CODE_SUCCESS); + + taos_free_result(pRes); + + taos_close(pConn); + } + + { + // taos_options( TSDB_OPTION_TIMEZONE, "UTC+0"); + int code = taos_options(TSDB_OPTION_TIMEZONE, "UTC+0"); + ASSERT_TRUE(code == 0); + TAOS* pConn = taos_connect("localhost", "root", "taosdata", NULL, 0); + ASSERT_NE(pConn, nullptr); + + TAOS_RES* pRes = taos_query(pConn, "select * from db1.t1 where ts == '2023-09-16 09:00:00'"); + ASSERT_EQ(taos_errno(pRes), TSDB_CODE_SUCCESS); + + TAOS_ROW pRow = NULL; + TAOS_FIELD* pFields = taos_fetch_fields(pRes); + int32_t numOfFields = taos_num_fields(pRes); + + int rows = 0; + char str[512] = {0}; + while ((pRow = taos_fetch_row(pRes)) != NULL) { + rows++; + } + ASSERT_TRUE(rows == 1); + taos_free_result(pRes); + + { + TAOS_RES* pRes = taos_query(pConn, "select * from db1.t1 where ts == '2023-09-17 01:00:01'"); + ASSERT_EQ(taos_errno(pRes), TSDB_CODE_SUCCESS); + + TAOS_ROW pRow = NULL; + TAOS_FIELD* pFields = taos_fetch_fields(pRes); + int32_t numOfFields = taos_num_fields(pRes); + + int rows = 0; + char str[512] = {0}; + while ((pRow = taos_fetch_row(pRes)) != NULL) { + rows++; + } + ASSERT_TRUE(rows == 1); + taos_free_result(pRes); + } + + taos_close(pConn); + } +} #pragma GCC diagnostic pop diff --git a/source/client/test/connectOptionsTest.cpp b/source/client/test/connectOptionsTest.cpp index c227a069ec..81213291e5 100644 --- a/source/client/test/connectOptionsTest.cpp +++ b/source/client/test/connectOptionsTest.cpp @@ -903,7 +903,7 @@ TEST(timezoneCase, localtime_performance_Test) { timezone_t sp = tzalloc("Asia/Shanghai"); ASSERT(sp); - int cnt = 10000000; + int cnt = 1000000; int times = 10; int64_t time_localtime = 0; int64_t time_localtime_rz = 0; diff --git a/source/common/src/tglobal.c b/source/common/src/tglobal.c index 64704bda66..e43bdc4687 100644 --- a/source/common/src/tglobal.c +++ b/source/common/src/tglobal.c @@ -2077,8 +2077,7 @@ static int32_t taosCfgDynamicOptionsForClient(SConfig *pCfg, const char *name) { int32_t code = TSDB_CODE_SUCCESS; int32_t lino = 0; - if (strcasecmp("locale", name) == 0 || strcasecmp("charset", name) == 0 - || strcasecmp("timezone", name) == 0) { + if (strcasecmp("charset", name) == 0 || strcasecmp("timezone", name) == 0) { goto _out; } cfgLock(pCfg); @@ -2169,6 +2168,22 @@ static int32_t taosCfgDynamicOptionsForClient(SConfig *pCfg, const char *name) { } break; } + case 'l': { + if (strcasecmp("locale", name) == 0) { + SConfigItem *pLocaleItem = cfgGetItem(pCfg, "locale"); + if (pLocaleItem == NULL) { + uError("failed to get locale from cfg"); + code = TSDB_CODE_CFG_NOT_FOUND; + goto _out; + } + + const char *locale = pLocaleItem->str; + TAOS_CHECK_GOTO(taosSetSystemLocale(locale), &lino, _out); + uInfo("locale set to '%s'", locale); + matched = true; + } + break; + } case 'm': { if (strcasecmp("metaCacheMaxSize", name) == 0) { atomic_store_32(&tsMetaCacheMaxSize, pItem->i32); diff --git a/source/util/test/encodeTest.cpp b/source/util/test/encodeTest.cpp index 974677d26c..074fee07ea 100644 --- a/source/util/test/encodeTest.cpp +++ b/source/util/test/encodeTest.cpp @@ -230,8 +230,8 @@ static int32_t tSStructA_v1_decode(SCoder *pCoder, SStructA_v1 *pSAV1) { if (tDecodeI32(pCoder, &pSAV1->A_a) < 0) return -1; if (tDecodeI64(pCoder, &pSAV1->A_b) < 0) return -1; - const char *tstr; - uint64_t len; + const char *tstr = NULL; + uint64_t len = 0; if (tDecodeCStrAndLen(pCoder, &tstr, &len) < 0) return -1; pSAV1->A_c = (char *)tCoderMalloc(pCoder, len + 1); memcpy(pSAV1->A_c, tstr, len + 1); @@ -269,8 +269,8 @@ static int32_t tSStructA_v2_decode(SCoder *pCoder, SStructA_v2 *pSAV2) { if (tDecodeI32(pCoder, &pSAV2->A_a) < 0) return -1; if (tDecodeI64(pCoder, &pSAV2->A_b) < 0) return -1; - const char *tstr; - uint64_t len; + const char *tstr = NULL; + uint64_t len = 0; if (tDecodeCStrAndLen(pCoder, &tstr, &len) < 0) return -1; pSAV2->A_c = (char *)tCoderMalloc(pCoder, len + 1); memcpy(pSAV2->A_c, tstr, len + 1);