/* * Copyright (c) 2019 TAOS Data, Inc. * * This program is free software: you can use, redistribute, and/or modify * it under the terms of the GNU Affero General Public License, version 3 * or later ("AGPL"), as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ #include #include #include #include #include "clientSession.h" #include "taoserror.h" #include "tglobal.h" #include "thash.h" #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wwrite-strings" #pragma GCC diagnostic ignored "-Wunused-function" #pragma GCC diagnostic ignored "-Wunused-variable" #pragma GCC diagnostic ignored "-Wsign-compare" #include "clientInt.h" #include "executor.h" #include "taos.h" int main(int argc, char** argv) { testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); } TAOS* getConnWithGlobalOption(const char* tz) { int code = taos_options(TSDB_OPTION_TIMEZONE, tz); ASSERT(code == 0); TAOS* pConn = taos_connect("localhost", "root", "taosdata", NULL, 0); ASSERT(pConn != nullptr); return pConn; } TAOS* getConnWithOption(const char* tz) { TAOS* pConn = taos_connect("localhost", "root", "taosdata", NULL, 0); ASSERT(pConn != nullptr); if (tz != NULL) { int code = taos_options_connection(pConn, TSDB_OPTION_CONNECTION_TIMEZONE, tz); ASSERT(code == 0); } return pConn; } void execQuery(TAOS* pConn, const char* sql) { TAOS_RES* pRes = taos_query(pConn, sql); int code = taos_errno(pRes); while (code == TSDB_CODE_MND_DB_IN_CREATING || code == TSDB_CODE_MND_DB_IN_DROPPING) { taosMsleep(2000); TAOS_RES* pRes = taos_query(pConn, sql); code = taos_errno(pRes); } ASSERT(code == TSDB_CODE_SUCCESS); taos_free_result(pRes); } void execQueryFail(TAOS* pConn, const char* sql) { printf("execQueryFail: %s\n", sql); TAOS_RES* pRes = taos_query(pConn, sql); #ifndef WINDOWS ASSERT(taos_errno(pRes) != TSDB_CODE_SUCCESS); #endif taos_free_result(pRes); } void checkRows(TAOS* pConn, const char* sql, int32_t expectedRows) { printf("checkRows sql:%s,rows:%d\n", sql, expectedRows); TAOS_RES* pRes = taos_query(pConn, sql); ASSERT(taos_errno(pRes) == TSDB_CODE_SUCCESS); TAOS_ROW pRow = NULL; int rows = 0; while ((pRow = taos_fetch_row(pRes)) != NULL) { rows++; } ASSERT(rows == expectedRows); taos_free_result(pRes); } void check_timezone(TAOS* pConn, const char* sql, const char* tz) { TAOS_RES* pRes = taos_query(pConn, sql); ASSERT(taos_errno(pRes) == 0); TAOS_ROW row = NULL; while ((row = taos_fetch_row(pRes)) != NULL) { if (strcmp((const char*)row[0], "timezone") == 0) { ASSERT(strstr((const char*)row[1], tz) != NULL); } } taos_free_result(pRes); } void check_sql_result_partial(TAOS* pConn, const char* sql, const char* result) { TAOS_RES* pRes = taos_query(pConn, sql); ASSERT(taos_errno(pRes) == 0); TAOS_ROW row = NULL; while ((row = taos_fetch_row(pRes)) != NULL) { ASSERT(strstr((const char*)row[0], result) != NULL); } taos_free_result(pRes); } int64_t get_sql_result(TAOS* pConn, const char* sql) { int64_t ts = 0; TAOS_RES* pRes = taos_query(pConn, sql); ASSERT(taos_errno(pRes) == 0); TAOS_ROW row = NULL; while ((row = taos_fetch_row(pRes)) != NULL) { ts = *(int64_t*)row[0]; } taos_free_result(pRes); return ts; } void check_sql_result(TAOS* pConn, const char* sql, const char* result) { printf("check_sql_result sql:%s,result:%s\n", sql, result); TAOS_RES* pRes = taos_query(pConn, sql); ASSERT(taos_errno(pRes) == 0); TAOS_ROW row = NULL; while ((row = taos_fetch_row(pRes)) != NULL) { #ifndef WINDOWS ASSERT(memcmp((const char*)row[0], result, strlen(result)) == 0); #endif } taos_free_result(pRes); } void check_sql_result_integer(TAOS* pConn, const char* sql, int64_t result) { printf("check_sql_result_integer sql:%s,result:%ld\n", sql, result); TAOS_RES* pRes = taos_query(pConn, sql); ASSERT(taos_errno(pRes) == 0); TAOS_ROW row = NULL; while ((row = taos_fetch_row(pRes)) != NULL) { #ifndef WINDOWS ASSERT(*(int64_t*)row[0] == result); #endif } taos_free_result(pRes); } void check_set_timezone(TAOS* optionFunc(const char* tz)) { { TAOS* pConn = optionFunc("UTC-8"); // Asia/Shanghai timezone check_timezone(pConn, "show local variables", "UTC-8"); execQuery(pConn, "drop database if exists db1"); execQuery(pConn, "create database db1"); execQuery(pConn, "create table db1.t1 (ts timestamp, v int)"); execQuery(pConn, "insert into db1.t1 values('2023-09-16 17:00:00', 1)"); checkRows(pConn, "select * from db1.t1 where ts == '2023-09-16 17:00:00'", 1); taos_close(pConn); } { TAOS* pConn = optionFunc("UTC+8"); check_timezone(pConn, "show local variables", "UTC+8"); checkRows(pConn, "select * from db1.t1 where ts == '2023-09-16 01:00:00'", 1); execQuery(pConn, "insert into db1.t1 values('2023-09-16 17:00:01', 1)"); taos_close(pConn); } { TAOS* pConn = optionFunc("UTC+0"); check_timezone(pConn, "show local variables", "UTC+0"); checkRows(pConn, "select * from db1.t1 where ts == '2023-09-16 09:00:00'", 1); checkRows(pConn, "select * from db1.t1 where ts == '2023-09-17 01:00:01'", 1); taos_close(pConn); } } #define CHECK_TAOS_OPTION_POINTER(taos, option, isnull) \ { \ STscObj* pObj = acquireTscObj(*(int64_t*)taos); \ ASSERT(pObj != nullptr); \ if (isnull) { \ ASSERT(pObj->optionInfo.option == nullptr); \ } else { \ ASSERT(pObj->optionInfo.option != nullptr); \ } \ } #define CHECK_TAOS_OPTION_APP(taos, option, val) \ { \ STscObj* pObj = acquireTscObj(*(int64_t*)taos); \ ASSERT(pObj != nullptr); \ ASSERT(strcmp(pObj->optionInfo.option, val) == 0); \ } #define CHECK_TAOS_OPTION_IP_ERROR(taos, option, val) \ { \ STscObj* pObj = acquireTscObj(*(int64_t*)taos); \ ASSERT(pObj != nullptr); \ ASSERT(pObj->optionInfo.option == val); \ } #define CHECK_TAOS_OPTION_IP(taos, option, val) \ { \ STscObj* pObj = acquireTscObj(*(int64_t*)taos); \ ASSERT(pObj != nullptr); \ char ip[TD_IP_LEN] = {0}; \ taosInetNtoa(ip, pObj->optionInfo.option); \ ASSERT(strcmp(ip, val) == 0); \ } static int32_t checkUserIp(TAOS* taos, const char* ip) { TAOS_RES* pRes = taos_query(taos, "select user_ip from performance_schema.perf_connections"); ASSERT(taos_errno(pRes) == 0); TAOS_ROW row = NULL; bool found = false; while ((row = taos_fetch_row(pRes)) != NULL) { if (strcmp((const char*)row[0], ip) == 0) { found = true; break; } } if (found == false) { ASSERT(0); } taos_free_result(pRes); ASSERT(1); return 0; } TEST(connectionCase, setConnectionOption_Test) { int32_t code = taos_options_connection(NULL, TSDB_OPTION_CONNECTION_CHARSET, NULL); ASSERT(code != 0); TAOS* pConn = taos_connect("localhost", "root", "taosdata", NULL, 0); ASSERT_NE(pConn, nullptr); code = taos_options_connection(pConn, TSDB_MAX_OPTIONS_CONNECTION, NULL); ASSERT(code != 0); // test charset code = taos_options_connection(pConn, TSDB_OPTION_CONNECTION_CHARSET, ""); ASSERT(code != 0); code = taos_options_connection(pConn, TSDB_OPTION_CONNECTION_CHARSET, NULL); ASSERT(code == 0); CHECK_TAOS_OPTION_POINTER(pConn, charsetCxt, true); code = taos_options_connection(pConn, TSDB_OPTION_CONNECTION_CHARSET, "Asia/Shanghai"); ASSERT(code != 0); code = taos_options_connection(pConn, TSDB_OPTION_CONNECTION_CHARSET, "gbk"); ASSERT(code == 0); CHECK_TAOS_OPTION_POINTER(pConn, charsetCxt, false); #ifndef WINDOWS // test timezone code = taos_options_connection(pConn, TSDB_OPTION_CONNECTION_TIMEZONE, ""); ASSERT(code == 0); CHECK_TAOS_OPTION_POINTER(pConn, timezone, false); check_sql_result(pConn, "select timezone()", "UTC (UTC, +0000)"); code = taos_options_connection(pConn, TSDB_OPTION_CONNECTION_TIMEZONE, NULL); ASSERT(code == 0); CHECK_TAOS_OPTION_POINTER(pConn, timezone, true); check_sql_result(pConn, "select timezone()", "Asia/Shanghai (CST, +0800)"); code = taos_options_connection(pConn, TSDB_OPTION_CONNECTION_TIMEZONE, "UTC"); ASSERT(code == 0); CHECK_TAOS_OPTION_POINTER(pConn, timezone, false); check_sql_result(pConn, "select timezone()", "UTC (UTC, +0000)"); code = taos_options_connection(pConn, TSDB_OPTION_CONNECTION_TIMEZONE, "Asia/Kolkata"); ASSERT(code == 0); CHECK_TAOS_OPTION_POINTER(pConn, timezone, false); check_sql_result(pConn, "select timezone()", "Asia/Kolkata (IST, +0530)"); code = taos_options_connection(pConn, TSDB_OPTION_CONNECTION_TIMEZONE, "adbc"); ASSERT(code == 0); CHECK_TAOS_OPTION_POINTER(pConn, timezone, false); check_sql_result(pConn, "select timezone()", "adbc (UTC, +0000)"); #endif // test user APP code = taos_options_connection(pConn, TSDB_OPTION_CONNECTION_USER_APP, ""); ASSERT(code == 0); CHECK_TAOS_OPTION_APP(pConn, userApp, ""); code = taos_options_connection(pConn, TSDB_OPTION_CONNECTION_USER_APP, NULL); ASSERT(code == 0); CHECK_TAOS_OPTION_APP(pConn, userApp, ""); code = taos_options_connection(pConn, TSDB_OPTION_CONNECTION_USER_APP, "aaaaaaaaaaaaaaaaaaaaaabbbbbbb"); ASSERT(code == 0); CHECK_TAOS_OPTION_APP(pConn, userApp, "aaaaaaaaaaaaaaaaaaaaaab"); // test connector info code = taos_options_connection(pConn, TSDB_OPTION_CONNECTION_CONNECTOR_INFO, ""); ASSERT(code == 0); CHECK_TAOS_OPTION_APP(pConn, cInfo, ""); code = taos_options_connection(pConn, TSDB_OPTION_CONNECTION_CONNECTOR_INFO, NULL); ASSERT(code == 0); CHECK_TAOS_OPTION_APP(pConn, cInfo, ""); const char* str255 = "TDengine_ConnectOptionsTest_255_Character_String_ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz_" "This_is_a_test_string_for_connection_options_testing_in_TDengine_database_system_with_exactly_255_characters_" "including_alphanumeric_and_special"; const char* str258 = "TDengine_ConnectOptionsTest_255_Character_String_ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz_" "This_is_a_test_string_for_connection_options_testing_in_TDengine_database_system_with_exactly_255_characters_" "including_alphanumeric_and_specialaaa"; code = taos_options_connection(pConn, TSDB_OPTION_CONNECTION_CONNECTOR_INFO, str258); ASSERT(code == 0); CHECK_TAOS_OPTION_APP(pConn, cInfo, str255); // test user IP code = taos_options_connection(pConn, TSDB_OPTION_CONNECTION_USER_IP, ""); // ASSERT(code != 0); // add dual later CHECK_TAOS_OPTION_IP_ERROR(pConn, userIp, INADDR_NONE); checkUserIp(pConn, ""); code = taos_options_connection(pConn, TSDB_OPTION_CONNECTION_USER_IP, NULL); ASSERT(code == 0); CHECK_TAOS_OPTION_IP_ERROR(pConn, userIp, INADDR_NONE); checkUserIp(pConn, ""); code = taos_options_connection(pConn, TSDB_OPTION_CONNECTION_USER_IP, "aaaaaaaaaaaaaaaaaaaaaabbbbbbb"); // ASSERT(code != 0); // add dual later CHECK_TAOS_OPTION_IP_ERROR(pConn, userIp, INADDR_NONE); code = taos_options_connection(pConn, TSDB_OPTION_CONNECTION_USER_IP, "1292.168.0.2"); // ASSERT(code != 0); // add dual alter CHECK_TAOS_OPTION_IP_ERROR(pConn, userIp, INADDR_NONE); taosSsleep(6); checkUserIp(pConn, ""); code = taos_options_connection(pConn, TSDB_OPTION_CONNECTION_USER_IP, "192.168.0.2"); ASSERT(code == 0); CHECK_TAOS_OPTION_IP(pConn, userIp, "192.168.0.2"); taosSsleep(6); checkUserIp(pConn, "192.168.0.2"); taosMsleep(2 * HEARTBEAT_INTERVAL); // test user APP and user IP check_sql_result_integer( pConn, "select count(*) from performance_schema.perf_connections where user_app = 'aaaaaaaaaaaaaaaaaaaaaab'", 1); check_sql_result_integer(pConn, "select count(*) from performance_schema.perf_connections where user_ip = '192.168.0.2'", 1); code = taos_options_connection(pConn, TSDB_OPTION_CONNECTION_USER_IP, "192.168.1.2"); ASSERT(code == 0); CHECK_TAOS_OPTION_IP(pConn, userIp, "192.168.1.2"); code = taos_options_connection(pConn, TSDB_OPTION_CONNECTION_USER_IP, NULL); CHECK_TAOS_OPTION_IP_ERROR(pConn, userIp, INADDR_NONE); taosSsleep(6); checkUserIp(pConn, ""); code = taos_options_connection(pConn, TSDB_OPTION_CONNECTION_USER_IP, "192.168.1.2"); CHECK_TAOS_OPTION_IP(pConn, userIp, "192.168.1.2"); taosSsleep(6); checkUserIp(pConn, "192.168.1.2"); code = taos_options_connection(pConn, TSDB_OPTION_CONNECTION_USER_APP, "user"); ASSERT(code == 0); CHECK_TAOS_OPTION_APP(pConn, userApp, "user"); code = taos_options_connection(pConn, TSDB_OPTION_CONNECTION_CONNECTOR_INFO, "java-connector:3.23.3"); ASSERT(code == 0); CHECK_TAOS_OPTION_APP(pConn, cInfo, "java-connector:3.23.3"); taosMsleep(2 * HEARTBEAT_INTERVAL); check_sql_result_integer(pConn, "select count(*) from performance_schema.perf_connections where user_app = 'user'", 1); check_sql_result_integer( pConn, "select count(*) from performance_schema.perf_connections where connector_info = 'java-connector:3.23.3'", 1); check_sql_result_integer(pConn, "select count(*) from performance_schema.perf_connections where user_ip = '192.168.1.2'", 1); // test clear code = taos_options_connection(pConn, TSDB_OPTION_CONNECTION_CLEAR, "192.168.0.2"); ASSERT(code == 0); CHECK_TAOS_OPTION_POINTER(pConn, charsetCxt, true); #ifndef WINDOWS CHECK_TAOS_OPTION_POINTER(pConn, timezone, true); check_sql_result(pConn, "select timezone()", "Asia/Shanghai (CST, +0800)"); #endif CHECK_TAOS_OPTION_APP(pConn, userApp, ""); CHECK_TAOS_OPTION_IP_ERROR(pConn, userIp, INADDR_NONE); taos_close(pConn); } TEST(charsetCase, charset_Test) { // 1. build connection with different charset TAOS* pConnGbk = taos_connect("localhost", "root", "taosdata", NULL, 0); ASSERT(pConnGbk != nullptr); TAOS* pConnUTF8 = taos_connect("localhost", "root", "taosdata", NULL, 0); ASSERT(pConnUTF8 != nullptr); TAOS* pConnDefault = taos_connect("localhost", "root", "taosdata", NULL, 0); ASSERT(pConnDefault != nullptr); int32_t code = taos_options_connection(pConnGbk, TSDB_OPTION_CONNECTION_CHARSET, "gbk"); ASSERT(code == 0); CHECK_TAOS_OPTION_POINTER(pConnGbk, charsetCxt, false); code = taos_options_connection(pConnUTF8, TSDB_OPTION_CONNECTION_CHARSET, "UTF-8"); ASSERT(code == 0); CHECK_TAOS_OPTION_POINTER(pConnUTF8, charsetCxt, false); // 2. build test string char sqlTag[256] = {0}; char sqlCol[256] = {0}; // 芬 gbk encode is 0xB7D2, UTF-8 encode is 0xE88AAC // 中国 gbk encode is 0xD6D0B9FA, UTF-8 encode is 0xE4B8ADE59BBD char fenUtf8[32] = {0}; char fenGbk[32] = {0}; char zhongGbk[32] = {0}; char zhongguoUtf8[32] = {0}; char guoUtf8[32] = {0}; char zhongguoGbk[32] = {0}; snprintf(fenUtf8, sizeof(fenUtf8), "%c%c%c", 0xE8, 0x8A, 0xAC); snprintf(fenGbk, sizeof(fenGbk), "%c%c", 0xB7, 0xD2); snprintf(zhongguoUtf8, sizeof(zhongguoUtf8), "%c%c%c%c%c%c", 0xE4, 0xB8, 0xAD, 0xE5, 0x9B, 0xBD); snprintf(guoUtf8, sizeof(guoUtf8), "%c%c%c", 0xE5, 0x9B, 0xBD); snprintf(zhongguoGbk, sizeof(zhongguoGbk), "%c%c%c%c", 0xD6, 0xD0, 0xB9, 0xFA); snprintf(zhongGbk, sizeof(zhongGbk), "%c%c", 0xD6, 0xD0); // 3. create stable execQuery(pConnGbk, "drop database if exists db1"); execQuery(pConnGbk, "create database db1"); execQuery(pConnGbk, "create table db1.stb (ts timestamp, c1 nchar(32), c2 int) tags(t1 timestamp, t2 nchar(32), t3 int)"); // 4. test tag with different charset snprintf(sqlTag, sizeof(sqlTag), "create table db1.ctb1 using db1.stb tags('2023-09-16 17:00:00+05:00', '%s', 1)", fenUtf8); execQueryFail(pConnGbk, sqlTag); snprintf(sqlTag, sizeof(sqlTag), "create table db1.ctb1 using db1.stb tags('2023-09-16 17:00:00+05:00', '%s', 1)", fenGbk); execQuery(pConnGbk, sqlTag); // 5. test column with different charset snprintf(sqlCol, sizeof(sqlCol), "insert into db1.ctb1 values(1732178775133, '%s', 1)", zhongguoUtf8); execQueryFail(pConnGbk, sqlCol); snprintf(sqlCol, sizeof(sqlCol), "insert into db1.ctb1 values(1732178775133, '%s', 1)", zhongguoGbk); execQuery(pConnGbk, sqlCol); // 6. check result with different charset check_sql_result(pConnGbk, "select t2 from db1.ctb1", fenGbk); check_sql_result(pConnUTF8, "select t2 from db1.ctb1", fenUtf8); check_sql_result(pConnGbk, "select c1 from db1.ctb1", zhongguoGbk); check_sql_result(pConnUTF8, "select c1 from db1.ctb1", zhongguoUtf8); // 7. test function with different charset // 7.1 concat char zhongguofenGbk[32] = {0}; snprintf(zhongguofenGbk, sizeof(zhongguofenGbk), "%s%s", zhongguoGbk, fenGbk); char sql[256] = {0}; snprintf(sql, sizeof(sql), "select concat(c1, '%s') from db1.ctb1", fenGbk); execQueryFail(pConnGbk, sql); snprintf(sql, sizeof(sql), "select concat(c1, '%s') from db1.ctb1", fenUtf8); check_sql_result(pConnGbk, sql, zhongguofenGbk); // 7.2 trim snprintf(sql, sizeof(sql), "select trim(LEADING c1 from '%s') from db1.ctb1", zhongguofenGbk); check_sql_result(pConnGbk, sql, zhongguofenGbk); char zhongguofenUtf8[32] = {0}; snprintf(zhongguofenUtf8, sizeof(zhongguofenUtf8), "%s%s", zhongguoUtf8, fenUtf8); snprintf(sql, sizeof(sql), "select trim(LEADING c1 from '%s') from db1.ctb1", zhongguofenUtf8); check_sql_result(pConnGbk, sql, fenUtf8); check_sql_result(pConnGbk, "select char(c1) from db1.ctb1", ""); check_sql_result_integer(pConnGbk, "select ascii(c1) from db1.ctb1", 0xE4); check_sql_result_integer(pConnUTF8, "select ascii(c1) from db1.ctb1", 0xE4); check_sql_result_integer(pConnGbk, "select LENGTH(c1) from db1.ctb1", 8); check_sql_result_integer(pConnUTF8, "select LENGTH(c1) from db1.ctb1", 8); check_sql_result_integer(pConnGbk, "select CHAR_LENGTH(c1) from db1.ctb1", 2); check_sql_result_integer(pConnUTF8, "select CHAR_LENGTH(c1) from db1.ctb1", 2); execQuery(pConnGbk, "select LOWER(c1) from db1.ctb1"); execQuery(pConnGbk, "select UPPER(c1) from db1.ctb1"); snprintf(sql, sizeof(sql), "select position(c1 in '%s') from db1.ctb1", zhongguofenGbk); check_sql_result_integer(pConnGbk, sql, 0); snprintf(sql, sizeof(sql), "select position('%s' in c1) from db1.ctb1", guoUtf8); check_sql_result_integer(pConnUTF8, sql, 2); snprintf(sql, sizeof(sql), "select replace(c1, '%s', 'a') from db1.ctb1", zhongguoGbk); execQueryFail(pConnGbk, sql); snprintf(sql, sizeof(sql), "select replace(c1, '%s', 'a') from db1.ctb1", zhongguoUtf8); check_sql_result(pConnUTF8, sql, "a"); snprintf(sql, sizeof(sql), "%s%s", zhongguoGbk, zhongguoGbk); check_sql_result(pConnGbk, "select repeat(c1, 2) from db1.ctb1", sql); check_sql_result(pConnGbk, "select cast(c1 as binary(32)) from db1.ctb1", zhongguoUtf8); check_sql_result(pConnUTF8, "select substr(c1,2,1) from db1.ctb1", guoUtf8); snprintf(sql, sizeof(sql), "select SUBSTRING_INDEX(c1,'%s',1) from db1.ctb1", guoUtf8); check_sql_result(pConnGbk, sql, zhongGbk); // 8. test default charset snprintf(sqlCol, sizeof(sqlCol), "insert into db1.ctb1 values(1732178775134, '%s', 1)", zhongguoUtf8); execQuery(pConnDefault, sqlCol); check_sql_result(pConnDefault, "select c1 from db1.ctb1 where ts = 1732178775134", zhongguoUtf8); // 9. test json tag with different charset execQuery(pConnUTF8, "create table db1.jsta (ts timestamp, c1 nchar(32), c2 int) tags(t1 json)"); snprintf(sqlCol, sizeof(sqlCol), "create table db1.jsta1 using db1.jsta tags('{\"k\":\"%s\"}')", fenUtf8); execQuery(pConnUTF8, sqlCol); snprintf(sqlCol, sizeof(sqlCol), "insert into db1.jsta1 values(1732178775133, '%s', 1)", zhongguoUtf8); execQuery(pConnUTF8, sqlCol); char resJsonTag[32] = {0}; snprintf(resJsonTag, sizeof(resJsonTag), "{\"k\":\"%s\"}", fenGbk); check_sql_result(pConnGbk, "select t1 from db1.jsta1", resJsonTag); // 10. reset charset to default(utf-8 code = taos_options_connection(pConnGbk, TSDB_OPTION_CONNECTION_CHARSET, NULL); ASSERT(code == 0); CHECK_TAOS_OPTION_POINTER(pConnGbk, charsetCxt, true); check_sql_result(pConnGbk, "select t2 from db1.ctb1 where ts = 1732178775134", fenUtf8); check_sql_result(pConnGbk, "select c1 from db1.ctb1 where ts = 1732178775134", zhongguoUtf8); taos_close(pConnGbk); taos_close(pConnUTF8); taos_close(pConnDefault); } TEST(charsetCase, alter_charset_Test) { TAOS* pConn = taos_connect("localhost", "root", "taosdata", NULL, 0); ASSERT(pConn != nullptr); execQueryFail(pConn, "alter dnode 1 'charset gbk'"); execQueryFail(pConn, "local 'charset gbk'"); taos_close(pConn); } #ifndef WINDOWS TEST(timezoneCase, set_timezone_Test) { check_set_timezone(getConnWithGlobalOption); check_set_timezone(getConnWithOption); } TEST(timezoneCase, alter_timezone_Test) { TAOS* pConn = getConnWithGlobalOption("UTC-8"); check_timezone(pConn, "show local variables", "UTC-8"); execQuery(pConn, "alter local 'timezone Asia/Kolkata'"); check_timezone(pConn, "show local variables", "Asia/Kolkata"); execQuery(pConn, "alter local 'timezone Asia/Shanghai'"); check_timezone(pConn, "show local variables", "Asia/Shanghai"); execQueryFail(pConn, "alter dnode 1 'timezone Asia/Kolkata'"); taos_close(pConn); } char* tz_test[] = { "2023-09-16 17:00:00+", "2023-09-16 17:00:00+a", "2023-09-16 17:00:00+8", "2023-09-16 17:00:00+832", "2023-09-16 17:00:00+8323", "2023-09-16 17:00:00+:", "2023-09-16 17:00:00+8:", "2023-09-16 17:00:00++:", "2023-09-16 17:00:00+d:", "2023-09-16 17:00:00+09:", "2023-09-16 17:00:00+8f:", "2023-09-16 17:00:00+080:", "2023-09-16 17:00:00+:30", "2023-09-16 17:00:00+:3", "2023-09-16 17:00:00+:093", "2023-09-16 17:00:00+:-30", "2023-09-16 17:00:00++:-30", "2023-09-16 17:00:00+8:8", "2023-09-16 17:00:00+8:2a", "2023-09-16 17:00:00+8:08", "2023-09-16 17:00:00+8:038", "2023-09-16 17:00:00+08:8", "2023-09-16 17:00:00+09:3a", "2023-09-16 17:00:00+09:abc", "2023-09-16 17:00:00+09:001", }; void do_insert_failed() { TAOS* pConn = getConnWithGlobalOption("UTC-8"); for (unsigned int i = 0; i < sizeof(tz_test) / sizeof(tz_test[0]); ++i) { char sql[1024] = {0}; (void)snprintf(sql, sizeof(sql), "insert into db1.ctb1 values('%s', '%s', 1)", tz_test[i], tz_test[i]); execQueryFail(pConn, sql); } taos_close(pConn); } struct insert_params { const char* tz; const char* tbname; const char* t1; const char* t2; }; struct insert_params params1[] = { {"UTC", "ntb", "2023-09-16 17:00:00", "2023-09-16 17:00:00+08:00"}, {"UTC", "ctb1", "2023-09-16 17:00:00", "2023-09-16 17:00:00+08:00"}, }; struct insert_params params2[] = { {"UTC+9", "ntb", "2023-09-16 08:00:00", "2023-09-16 08:00:00-01:00"}, {"UTC+9", "ctb1", "2023-09-16 08:00:00", "2023-09-16 11:00:00+02:00"}, }; void do_insert(struct insert_params params) { TAOS* pConn = getConnWithOption(params.tz); char sql[1024] = {0}; (void)snprintf(sql, sizeof(sql), "insert into db1.%s values('%s', '%s', 1)", params.tbname, params.t1, params.t2); execQuery(pConn, sql); taos_close(pConn); } void do_select(struct insert_params params) { TAOS* pConn = getConnWithOption(params.tz); char sql[1024] = {0}; (void)snprintf(sql, sizeof(sql), "select * from db1.%s where ts == '%s' and c1 == '%s'", params.tbname, params.t1, params.t2); checkRows(pConn, sql, 1); taos_close(pConn); } // test insert string and integer to timestamp both normal table and child table(and tag) TEST(timezoneCase, insert_with_timezone_Test) { /* * 1. prepare data, create db and tables */ TAOS* pConn1 = getConnWithOption("UTC+2"); execQuery(pConn1, "drop database if exists db1"); execQuery(pConn1, "create database db1"); execQuery(pConn1, "create table db1.ntb (ts timestamp, c1 timestamp, c2 int)"); execQuery(pConn1, "create table db1.stb (ts timestamp, c1 timestamp, c2 int) tags(t1 timestamp, t2 timestamp, t3 int)"); execQuery(pConn1, "create table db1.ctb1 using db1.stb tags(\"2023-09-16 17:00:00+05:00\", \"2023-09-16 17:00:00\", 1)"); execQuery(pConn1, "create table db1.ctb2 using db1.stb tags(1732178775000, 1732178775000, 1)"); execQuery(pConn1, "insert into db1.ntb values(1732178775133, 1732178775133, 1)"); execQuery(pConn1, "insert into db1.ctb1 values(1732178775133, 1732178775133, 1)"); // 2024-11-21 10:46:15.133+02:00 execQuery(pConn1, "insert into db1.ctb2 values(1732178775133, 1732178775133, 1)"); /* * 2. test tag and timestamp with integer format */ TAOS* pConn2 = getConnWithOption("UTC-2"); checkRows(pConn2, "select * from db1.stb where t1 == '2023-09-16 17:00:00+05:00' and t2 == '2023-09-16 21:00:00'", 1); checkRows(pConn2, "select * from db1.stb where t1 == '2024-11-21 16:46:15+08:00' and t2 == '2024-11-21 09:46:15+01:00'", 1); checkRows(pConn2, "select * from db1.ntb where ts == '2024-11-21 09:46:15.133+01:00' and c1 == '2024-11-21 10:46:15.133'", 1); checkRows(pConn2, "select * from db1.ctb1 where ts == '2024-11-21 09:46:15.133+01:00' and c1 == '2024-11-21 10:46:15.133'", 1); check_sql_result(pConn2, "select TO_ISO8601(ts) from db1.ctb1", "2024-11-21T10:46:15.133+0200"); // 2024-01-01 23:00:00+0200 /* * 3. test timestamp with string format */ for (unsigned int i = 0; i < sizeof(params1) / sizeof(params1[0]); ++i) { do_insert(params1[i]); do_select(params1[i]); do_select(params2[i]); } do_insert_failed(); /* * 4. test NULL timezone, use default timezone UTC-8 */ TAOS* pConn3 = getConnWithOption(NULL); checkRows(pConn3, "select * from db1.stb where t1 == '2023-09-16 20:00:00' and t2 == '2023-09-17 03:00:00'", 2); checkRows(pConn3, "select * from db1.stb where t1 == 1732178775000 and t2 == 1732178775000", 1); checkRows(pConn3, "select * from db1.ntb where ts == '2024-11-21 16:46:15.133' and c1 == '2024-11-21 16:46:15.133'", 1); checkRows(pConn3, "select * from db1.ctb1 where ts == '2023-09-17 01:00:00' and c1 == '2023-09-16 17:00:00'", 1); /* * 5. test multi connection with different timezone */ checkRows(pConn2, "select * from db1.ctb1 where ts == '2024-11-21 09:46:15.133+01:00' and c1 == '2024-11-21 10:46:15.133'", 1); checkRows(pConn1, "select * from db1.ctb1 where ts == '2024-11-21 09:46:15.133+01:00' and c1 == '2024-11-21 06:46:15.133'", 1); taos_close(pConn1); taos_close(pConn2); taos_close(pConn3); } TEST(timezoneCase, func_timezone_Test) { TAOS* pConn = getConnWithGlobalOption("UTC+8"); check_sql_result(pConn, "select timezone()", "UTC+8 (UTC, -0800)"); taos_close(pConn); pConn = getConnWithOption("UTC-2"); execQuery(pConn, "drop database if exists db1"); execQuery(pConn, "create database db1"); execQuery(pConn, "create table db1.ntb (ts timestamp, c1 binary(32), c2 int)"); execQuery(pConn, "insert into db1.ntb values(1704142800000, '2024-01-01 23:00:00', 1)"); // 2024-01-01 23:00:00+0200 // test timezone check_sql_result(pConn, "select timezone()", "UTC-2 (UTC, +0200)"); // test timetruncate check_sql_result(pConn, "select TO_ISO8601(TIMETRUNCATE('2024-01-01 23:00:00', 1d, 0))", "2024-01-01T02:00:00.000+0200"); check_sql_result(pConn, "select TO_ISO8601(TIMETRUNCATE('2024-01-01 01:00:00', 1d, 0))", "2023-12-31T02:00:00.000+0200"); check_sql_result(pConn, "select TO_ISO8601(TIMETRUNCATE('2024-01-01 01:00:00+0300', 1d, 0))", "2023-12-31T02:00:00.000+0200"); check_sql_result(pConn, "select TO_ISO8601(TIMETRUNCATE('2024-01-01 01:00:00-0300', 1d, 0))", "2024-01-01T02:00:00.000+0200"); check_sql_result(pConn, "select TO_ISO8601(TIMETRUNCATE('2024-01-04 23:00:00', 1w, 0))", "2024-01-04T02:00:00.000+0200"); check_sql_result(pConn, "select TO_ISO8601(TIMETRUNCATE('2024-01-04 01:00:00', 1w, 0))", "2023-12-28T02:00:00.000+0200"); check_sql_result(pConn, "select TO_ISO8601(TIMETRUNCATE('2024-01-04 01:00:00+0300', 1w, 0))", "2023-12-28T02:00:00.000+0200"); check_sql_result(pConn, "select TO_ISO8601(TIMETRUNCATE('2024-01-04 01:00:00-0300', 1w, 0))", "2024-01-04T02:00:00.000+0200"); check_sql_result(pConn, "select TO_ISO8601(TIMETRUNCATE('2024-01-01 23:00:00', 1d, 1))", "2024-01-01T00:00:00.000+0200"); check_sql_result(pConn, "select TO_ISO8601(TIMETRUNCATE('2024-01-01 01:00:00', 1d, 1))", "2024-01-01T00:00:00.000+0200"); check_sql_result(pConn, "select TO_ISO8601(TIMETRUNCATE('2024-01-01 01:00:00+0500', 1d, 1))", "2023-12-31T00:00:00.000+0200"); check_sql_result(pConn, "select TO_ISO8601(TIMETRUNCATE('2024-01-01 01:00:00-0300', 1d, 1))", "2024-01-01T00:00:00.000+0200"); check_sql_result(pConn, "select TO_ISO8601(TIMETRUNCATE('2024-01-04 23:00:00', 1w, 1))", "2024-01-04T00:00:00.000+0200"); check_sql_result(pConn, "select TO_ISO8601(TIMETRUNCATE('2024-01-04 01:00:00', 1w, 1))", "2024-01-04T00:00:00.000+0200"); check_sql_result(pConn, "select TO_ISO8601(TIMETRUNCATE('2024-01-04 01:00:00+0500', 1w, 1))", "2023-12-28T00:00:00.000+0200"); check_sql_result(pConn, "select TO_ISO8601(TIMETRUNCATE('2024-01-04 01:00:00-0300', 1w, 1))", "2024-01-04T00:00:00.000+0200"); check_sql_result(pConn, "select TO_ISO8601(TIMETRUNCATE(1704142800000, 1d, 0))", "2024-01-01T02:00:00.000+0200"); // 2024-01-01 23:00:00+0200 check_sql_result(pConn, "select TO_ISO8601(TIMETRUNCATE(ts, 1w, 1)) from db1.ntb", "2023-12-28T00:00:00.000+0200"); // 2024-01-01 23:00:00+0200 // TODAY check_sql_result_partial(pConn, "select TO_ISO8601(today())", "T00:00:00.000+0200"); // NOW check_sql_result_partial(pConn, "select TO_ISO8601(now())", "+0200"); // WEEKDAY check_sql_result_integer(pConn, "select WEEKDAY('2024-01-01')", 0); check_sql_result_integer(pConn, "select WEEKDAY('2024-01-01 03:00:00')", 0); check_sql_result_integer(pConn, "select WEEKDAY('2024-01-01 23:00:00+0200')", 0); check_sql_result_integer(pConn, "select WEEKDAY('2024-01-01 23:00:00-1100')", 1); check_sql_result_integer(pConn, "select WEEKDAY(1704142800000)", 0); check_sql_result_integer(pConn, "select WEEKDAY(ts) from db1.ntb", 1); // DAYOFWEEK check_sql_result_integer(pConn, "select DAYOFWEEK('2024-01-01')", 2); check_sql_result_integer(pConn, "select DAYOFWEEK('2024-01-01 03:00:00')", 2); check_sql_result_integer(pConn, "select DAYOFWEEK('2024-01-01 23:00:00+0200')", 2); check_sql_result_integer(pConn, "select DAYOFWEEK('2024-01-01 23:00:00-1100')", 3); check_sql_result_integer(pConn, "select DAYOFWEEK(1704142800000)", 2); check_sql_result_integer(pConn, "select DAYOFWEEK(ts) from db1.ntb", 3); // WEEK check_sql_result_integer(pConn, "select WEEK('2024-01-07')", 1); check_sql_result_integer(pConn, "select WEEK('2024-01-07 02:00:00')", 1); check_sql_result_integer(pConn, "select WEEK('2024-01-07 02:00:00+0200')", 1); check_sql_result_integer(pConn, "select WEEK('2024-01-07 02:00:00+1100')", 0); check_sql_result_integer(pConn, "select WEEK(1704142800000)", 0); // 2024-01-01 23:00:00+0200 check_sql_result_integer(pConn, "select WEEK(ts) from db1.ntb", 0); // 2024-01-01 23:00:00+0200 check_sql_result_integer(pConn, "select WEEK('2024-01-07', 3)", 1); check_sql_result_integer(pConn, "select WEEK('2024-01-07 02:00:00', 3)", 1); check_sql_result_integer(pConn, "select WEEK('2024-01-07 02:00:00+0200', 3)", 1); check_sql_result_integer(pConn, "select WEEK('2024-01-01 02:00:00+1100', 3)", 52); check_sql_result_integer(pConn, "select WEEK(1704142800000, 3)", 1); // 2024-01-01 23:00:00+0200 check_sql_result_integer(pConn, "select WEEK(ts, 3) from db1.ntb", 1); // 2024-01-01 23:00:00+0200 // WEEKOFYEAR check_sql_result_integer(pConn, "select WEEKOFYEAR('2024-01-07')", 1); check_sql_result_integer(pConn, "select WEEKOFYEAR('2024-01-07 02:00:00')", 1); check_sql_result_integer(pConn, "select WEEKOFYEAR('2024-01-07 02:00:00+0200')", 1); check_sql_result_integer(pConn, "select WEEKOFYEAR('2024-01-01 02:00:00+1100')", 52); check_sql_result_integer(pConn, "select WEEKOFYEAR(1704142800000)", 1); // 2024-01-01 23:00:00+0200 check_sql_result_integer(pConn, "select WEEKOFYEAR(ts) from db1.ntb", 1); // 2024-01-01 23:00:00+0200 // TO_ISO8601 check_sql_result(pConn, "select TO_ISO8601(ts) from db1.ntb", "2024-01-01T23:00:00.000+0200"); check_sql_result(pConn, "select TO_ISO8601(ts,'-08') from db1.ntb", "2024-01-01T13:00:00.000-08"); check_sql_result(pConn, "select TO_ISO8601(1)", "1970-01-01T02:00:00.001+0200"); check_sql_result(pConn, "select TO_ISO8601(1,'+0800')", "1970-01-01T08:00:00.001+0800"); // TO_UNIXTIMESTAMP check_sql_result_integer(pConn, "select TO_UNIXTIMESTAMP(c1) from db1.ntb", 1704121200000); // use timezone in server UTC-8 check_sql_result_integer(pConn, "select TO_UNIXTIMESTAMP('2024-01-01T23:00:00.000+0200')", 1704142800000); check_sql_result_integer(pConn, "select TO_UNIXTIMESTAMP('2024-01-01T13:00:00.000-08')", 1704142800000); check_sql_result_integer(pConn, "select TO_UNIXTIMESTAMP('2024-01-01T23:00:00.001')", 1704142800001); // TO_TIMESTAMP check_sql_result_integer(pConn, "select TO_TIMESTAMP(c1,'yyyy-mm-dd hh24:mi:ss') from db1.ntb", 1704121200000); // use timezone in server UTC-8 check_sql_result_integer(pConn, "select TO_TIMESTAMP('2024-01-01 23:00:00+02:00', 'yyyy-mm-dd hh24:mi:ss tzh')", 1704142800000); check_sql_result_integer(pConn, "select TO_TIMESTAMP('2024-01-01T13:00:00-08', 'yyyy-mm-ddThh24:mi:ss tzh')", 1704142800000); check_sql_result_integer(pConn, "select TO_TIMESTAMP('2024/01/01 23:00:00', 'yyyy/mm/dd hh24:mi:ss')", 1704142800000); // TO_CHAR check_sql_result(pConn, "select TO_CHAR(ts,'yyyy-mm-dd hh24:mi:ss') from db1.ntb", "2024-01-02 05:00:00"); // use timezone in server UTC-8 check_sql_result(pConn, "select TO_CHAR(cast(1704142800000 as timestamp), 'yyyy-mm-dd hh24:mi:ss tzh')", "2024-01-01 23:00:00 +02"); check_sql_result(pConn, "select TO_CHAR(cast(1704142800000 as timestamp), 'yyyy-mm-dd hh24:mi:ss')", "2024-01-01 23:00:00"); // TIMEDIFF check_sql_result_integer(pConn, "select TIMEDIFF(c1, '2024-01-01T23:00:00.001+02') from db1.ntb", -21600001); // use timezone in server UTC-8 check_sql_result_integer(pConn, "select TIMEDIFF(c1, '2024-01-01T23:00:00.001') from db1.ntb", -1); // use timezone in server UTC-8 check_sql_result_integer(pConn, "select TIMEDIFF('2024-01-01T23:00:00.001', '2024-01-01T13:00:00.000-08')", 1); // CAST check_sql_result_integer(pConn, "select CAST(c1 as timestamp) from db1.ntb", 1704121200000); check_sql_result_integer(pConn, "select CAST('2024-01-01T23:00:00.000+02' as timestamp)", 1704142800000); check_sql_result_integer(pConn, "select CAST('2024-01-01T23:00:00.000' as timestamp)", 1704142800000); taos_close(pConn); // hash join pConn = getConnWithOption("UTC+1"); execQuery(pConn, "drop database if exists db1"); execQuery(pConn, "create database db1"); execQuery(pConn, "create table db1.ntb (ts timestamp, c1 binary(32), c2 int)"); execQuery(pConn, "create table db1.ntb1 (ts timestamp, c1 binary(32), c2 int)"); execQuery(pConn, "insert into db1.ntb values(1703987400000, '2023-12-31 00:50:00', 1)"); // 2023-12-31 00:50:00-0100 execQuery(pConn, "insert into db1.ntb1 values(1704070200000, '2023-12-31 23:50:00', 11)"); // 2023-12-31 23:50:00-0100 checkRows(pConn, "select a.ts,b.ts from db1.ntb a join db1.ntb1 b on timetruncate(a.ts, 1d) = timetruncate(b.ts, 1d)", 1); // operator +1n +1y check_sql_result(pConn, "select TO_ISO8601(CAST('2023-01-31T00:00:00.000-01' as timestamp) + 1n)", "2023-02-28T00:00:00.000-0100"); check_sql_result(pConn, "select TO_ISO8601(CAST('2024-01-31T00:00:00.000-01' as timestamp) + 1n)", "2024-02-29T00:00:00.000-0100"); check_sql_result(pConn, "select TO_ISO8601(CAST('2024-02-29T00:00:00.000-01' as timestamp) + 1y)", "2025-02-28T00:00:00.000-0100"); check_sql_result(pConn, "select TO_ISO8601(CAST('2024-01-31T00:00:00.000-01' as timestamp) + 1y)", "2025-01-31T00:00:00.000-0100"); check_sql_result(pConn, "select TO_ISO8601(CAST('2024-01-01T00:00:00.000+01' as timestamp) + 1n)", "2024-01-31T22:00:00.000-0100"); check_sql_result(pConn, "select TO_ISO8601(CAST('2024-01-01T00:00:00.000+01' as timestamp) + 1y)", "2024-12-31T22:00:00.000-0100"); // case when check_sql_result_integer( pConn, "select case CAST('2024-01-01T00:00:00.000+01' as timestamp) when 1704063600000 then 1 end", 1); check_sql_result_integer(pConn, "select case CAST('2024-01-01T00:00:00.000' as timestamp) when 1704070800000 then 1 end", 1); taos_close(pConn); } time_t time_winter = 1731323281; // 2024-11-11 19:08:01+0800 time_t time_summer = 1731323281 - 120 * 24 * 60 * 60; struct test_times { const char* name; time_t t; const char* timezone; } test_tz[] = {{"", time_winter, " (UTC, +0000)"}, {"America/New_York", time_winter, "America/New_York (EST, -0500)"}, // 2024-11-11 19:08:01+0800 {"America/New_York", time_summer, "America/New_York (EDT, -0400)"}, {"Asia/Kolkata", time_winter, "Asia/Kolkata (IST, +0530)"}, {"Asia/Shanghai", time_winter, "Asia/Shanghai (CST, +0800)"}, {"Europe/London", time_winter, "Europe/London (GMT, +0000)"}, {"Europe/London", time_summer, "Europe/London (BST, +0100)"}}; void timezone_str_test(const char* tz, time_t t, const char* tzStr) { int code = setenv("TZ", tz, 1); ASSERT(-1 != code); tzset(); char str1[TD_TIMEZONE_LEN] = {0}; ASSERT(taosFormatTimezoneStr(t, tz, NULL, str1) == 0); ASSERT_STREQ(str1, tzStr); } void timezone_rz_str_test(const char* tz, time_t t, const char* tzStr) { timezone_t sp = tzalloc(tz); ASSERT(sp); char str1[TD_TIMEZONE_LEN] = {0}; ASSERT(taosFormatTimezoneStr(t, tz, sp, str1) == 0); ASSERT_STREQ(str1, tzStr); tzfree(sp); } TEST(sessionTest, session1) { int32_t code = sessMgtInit(); ASSERT(code == 0); int32_t expect = 1000; char* users[] = {"test1", "test2", "test3", "test4", "test5"}; for (int32_t i = 0; i < sizeof(users) / sizeof(users[0]); i++) { code = sessMgtUpdataLimit(users[i], SESSION_PER_USER, expect); ASSERT(code == 0); code = sessMgtUpdataLimit(users[i], SESSION_CONN_TIME, expect); ASSERT(code == 0); code = sessMgtUpdataLimit(users[i], SESSION_CONN_IDLE_TIME, expect); ASSERT(code == 0); code = sessMgtUpdataLimit(users[i], SESSION_MAX_CONCURRENCY, expect); ASSERT(code == 0); code = sessMgtUpdataLimit(users[i], SESSION_MAX_CALL_VNODE_NUM, expect); ASSERT(code == 0); code = sessMgtUpdataLimit(users[i], SESSION_MAX_TYPE, 10); ASSERT(code != 0); } SSessParam para = {}; para.type = SESSION_PER_USER; para.value = 1; for (int32_t i = 0; i <= 1000; i++) { for (int32_t i = 0; i < sizeof(users) / sizeof(users[0]); i++) { code = sessMgtUpdateUserMetric(users[i], ¶); ASSERT(code == 0); } } for (int32_t i = 0; i < sizeof(users) / sizeof(users[0]); i++) { code = sessMgtUpdateUserMetric(users[i], ¶); ASSERT(code != 0); } sessMgtDestroy(); } #endif #pragma GCC diagnostic pop