From d69c5b1840cfdd707c2ac3886290ab0dceb468d3 Mon Sep 17 00:00:00 2001 From: xjzhou Date: Tue, 2 Jul 2024 10:18:56 +0800 Subject: [PATCH 1/7] isStmtBind --- source/libs/parser/src/parInsertSql.c | 16 ++- tests/taosc_test/taoscTest.cpp | 194 +++++++++++++++++++++++--- 2 files changed, 180 insertions(+), 30 deletions(-) diff --git a/source/libs/parser/src/parInsertSql.c b/source/libs/parser/src/parInsertSql.c index 9393a62e26..b053cd95a0 100644 --- a/source/libs/parser/src/parInsertSql.c +++ b/source/libs/parser/src/parInsertSql.c @@ -30,6 +30,7 @@ typedef struct SInsertParseContext { bool forceUpdate; bool needTableTagVal; bool needRequest; // whether or not request server + bool isStmtBind; // whether is stmt } SInsertParseContext; typedef int32_t (*_row_append_fn_t)(SMsgBuf* pMsgBuf, const void* value, int32_t len, void* param); @@ -1978,7 +1979,6 @@ static int32_t parseOneStbRow(SInsertParseContext* pCxt, SVnodeModifyOpStmt* pSt static int parseOneRow(SInsertParseContext* pCxt, const char** pSql, STableDataCxt* pTableCxt, bool* pGotRow, SToken* pToken) { SBoundColInfo* pCols = &pTableCxt->boundColsInfo; - bool isParseBindParam = false; SSchema* pSchemas = getTableColumnSchema(pTableCxt->pMeta); int32_t code = TSDB_CODE_SUCCESS; @@ -1996,7 +1996,7 @@ static int parseOneRow(SInsertParseContext* pCxt, const char** pSql, STableDataC SColVal* pVal = taosArrayGet(pTableCxt->pValues, pCols->pColIndex[i]); if (pToken->type == TK_NK_QUESTION) { - isParseBindParam = true; + pCxt->isStmtBind = true; if (NULL == pCxt->pComCxt->pStmtCb) { code = buildSyntaxErrMsg(&pCxt->msg, "? only used in stmt", pToken->z); break; @@ -2007,8 +2007,8 @@ static int parseOneRow(SInsertParseContext* pCxt, const char** pSql, STableDataC break; } - if (isParseBindParam) { - code = buildInvalidOperationMsg(&pCxt->msg, "no mix usage for ? and values"); + if (pCxt->isStmtBind) { + code = buildInvalidOperationMsg(&pCxt->msg, "stmt bind param does not support normal value in sql"); break; } @@ -2025,7 +2025,7 @@ static int parseOneRow(SInsertParseContext* pCxt, const char** pSql, STableDataC } } - if (TSDB_CODE_SUCCESS == code && !isParseBindParam) { + if (TSDB_CODE_SUCCESS == code && !pCxt->isStmtBind) { SRow** pRow = taosArrayReserve(pTableCxt->pData->aRowP, 1); code = tRowBuild(pTableCxt->pValues, pTableCxt->pSchema, pRow); if (TSDB_CODE_SUCCESS == code) { @@ -2035,7 +2035,7 @@ static int parseOneRow(SInsertParseContext* pCxt, const char** pSql, STableDataC } } - if (TSDB_CODE_SUCCESS == code && !isParseBindParam) { + if (TSDB_CODE_SUCCESS == code && !pCxt->isStmtBind) { *pGotRow = true; } @@ -2410,6 +2410,7 @@ static int32_t checkTableClauseFirstToken(SInsertParseContext* pCxt, SVnodeModif } if (TK_NK_QUESTION == pTbName->type) { + pCxt->isStmtBind = true; if (NULL == pCxt->pComCxt->pStmtCb) { return buildSyntaxErrMsg(&pCxt->msg, "? only used in stmt", pTbName->z); } @@ -2935,7 +2936,8 @@ int32_t parseInsertSql(SParseContext* pCxt, SQuery** pQuery, SCatalogReq* pCatal .missCache = false, .usingDuplicateTable = false, .needRequest = true, - .forceUpdate = (NULL != pCatalogReq ? pCatalogReq->forceUpdate : false)}; + .forceUpdate = (NULL != pCatalogReq ? pCatalogReq->forceUpdate : false), + .isStmtBind = false}; int32_t code = initInsertQuery(&context, pCatalogReq, pMetaData, pQuery); if (TSDB_CODE_SUCCESS == code) { diff --git a/tests/taosc_test/taoscTest.cpp b/tests/taosc_test/taoscTest.cpp index 3f49b11b70..d3f6f50547 100644 --- a/tests/taosc_test/taoscTest.cpp +++ b/tests/taosc_test/taoscTest.cpp @@ -32,29 +32,29 @@ class taoscTest : public ::testing::Test { protected: static void SetUpTestCase() { - printf("start test setup.\n"); - TAOS* taos = taos_connect("localhost", "root", "taosdata", NULL, 0); - ASSERT_TRUE(taos != nullptr); - - TAOS_RES* res = taos_query(taos, "drop database IF EXISTS taosc_test_db;"); - if (taos_errno(res) != 0) { - printf("error in drop database taosc_test_db, reason:%s\n", taos_errstr(res)); - return; - } - taosSsleep(5); - taos_free_result(res); - printf("drop database taosc_test_db,finished.\n"); - - res = taos_query(taos, "create database taosc_test_db;"); - if (taos_errno(res) != 0) { - printf("error in create database taosc_test_db, reason:%s\n", taos_errstr(res)); - return; - } - taosSsleep(5); - taos_free_result(res); - printf("create database taosc_test_db,finished.\n"); - - taos_close(taos); +// printf("start test setup.\n"); +// TAOS* taos = taos_connect("localhost", "root", "taosdata", NULL, 0); +// ASSERT_TRUE(taos != nullptr); +// +// TAOS_RES* res = taos_query(taos, "drop database IF EXISTS taosc_test_db;"); +// if (taos_errno(res) != 0) { +// printf("error in drop database taosc_test_db, reason:%s\n", taos_errstr(res)); +// return; +// } +// taosSsleep(5); +// taos_free_result(res); +// printf("drop database taosc_test_db,finished.\n"); +// +// res = taos_query(taos, "create database taosc_test_db;"); +// if (taos_errno(res) != 0) { +// printf("error in create database taosc_test_db, reason:%s\n", taos_errstr(res)); +// return; +// } +// taosSsleep(5); +// taos_free_result(res); +// printf("create database taosc_test_db,finished.\n"); +// +// taos_close(taos); } static void TearDownTestCase() {} @@ -99,6 +99,154 @@ void queryCallback(void* param, void* res, int32_t code) { taos_fetch_raw_block_a(res, fetchCallback, param); } +/** + * @brief execute sql only. + * + * @param taos + * @param sql + */ +void executeSQL(TAOS *taos, const char *sql) { + TAOS_RES *res = taos_query(taos, sql); + int code = taos_errno(res); + if (code != 0) { + printf("%s\n", taos_errstr(res)); + taos_free_result(res); + taos_close(taos); + exit(EXIT_FAILURE); + } + taos_free_result(res); +} + +/** + * @brief check return status and exit program when error occur. + * + * @param stmt + * @param code + * @param msg + */ +void checkErrorCode(TAOS_STMT *stmt, int code, const char* msg) { + if (code != 0) { + printf("%s. error: %s\n", msg, taos_stmt_errstr(stmt)); + taos_stmt_close(stmt); + exit(EXIT_FAILURE); + } +} + +typedef struct { + int64_t ts; + float current; + int voltage; + float phase; +} Row; + + +/** + * @brief insert data using stmt API + * + * @param taos + */ +void insertData(TAOS *taos) { + // init + TAOS_STMT *stmt = taos_stmt_init(taos); + // prepare +// const char *sql = "INSERT INTO ?.d1001 USING meters TAGS(?, ?) values(?, ?, ?, ?)"; +// const char *sql = "INSERT INTO ?.? USING meters TAGS(?, ?) values(?, ?, ?, ?)"; +// const char *sql = "INSERT INTO power.? USING meters TAGS(?, ?) values(?, ?, ?, ?)"; +// const char *sql = "INSERT INTO ? USING meters TAGS(?, ?) values(?, ?, ?, ?)"; +// const char *sql = "INSERT INTO ? USING meters TAGS(?, ?) values(?, ?, ?, ?)"; + const char *sql = "insert into huawei USING meters TAGS(?, ?) values(?, ?, ?, ?)"; + int code = taos_stmt_prepare(stmt, sql, 0); + checkErrorCode(stmt, code, "failed to execute taos_stmt_prepare"); + // bind table name and tags + TAOS_MULTI_BIND tags[2]; + char *location = "California.SanFrancisco"; + int groupId = 2; + tags[0].buffer_type = TSDB_DATA_TYPE_BINARY; + tags[0].buffer_length = strlen(location); + tags[0].length = (int32_t *)&tags[0].buffer_length; + tags[0].buffer = location; + tags[0].is_null = NULL; + + tags[1].buffer_type = TSDB_DATA_TYPE_INT; + tags[1].buffer_length = sizeof(int); + tags[1].length = (int32_t *)&tags[1].buffer_length; + tags[1].buffer = &groupId; + tags[1].is_null = NULL; + +// code = taos_stmt_set_tbname_tags(stmt, "duck", tags); +// checkErrorCode(stmt, code, "failed to execute taos_stmt_set_dbname_tbname_tags"); + + // insert two rows with multi binds + TAOS_MULTI_BIND params[4]; + // values to bind + int64_t ts[] = {1648432611250, 1648432611778}; + float current[] = {10.3, 12.6}; + int voltage[] = {219, 218}; + float phase[] = {0.31, 0.33}; + // is_null array + char is_null[2] = {0}; + // length array + int32_t int64Len[2] = {sizeof(int64_t)}; + int32_t floatLen[2] = {sizeof(float)}; + int32_t intLen[2] = {sizeof(int)}; + + params[0].buffer_type = TSDB_DATA_TYPE_TIMESTAMP; + params[0].buffer_length = sizeof(int64_t); + params[0].buffer = ts; + params[0].length = int64Len; + params[0].is_null = is_null; + params[0].num = 2; + + params[1].buffer_type = TSDB_DATA_TYPE_FLOAT; + params[1].buffer_length = sizeof(float); + params[1].buffer = current; + params[1].length = floatLen; + params[1].is_null = is_null; + params[1].num = 2; + + params[2].buffer_type = TSDB_DATA_TYPE_INT; + params[2].buffer_length = sizeof(int); + params[2].buffer = voltage; + params[2].length = intLen; + params[2].is_null = is_null; + params[2].num = 2; + + params[3].buffer_type = TSDB_DATA_TYPE_FLOAT; + params[3].buffer_length = sizeof(float); + params[3].buffer = phase; + params[3].length = floatLen; + params[3].is_null = is_null; + params[3].num = 2; + + code = taos_stmt_bind_param_batch(stmt, params); // bind batch + checkErrorCode(stmt, code, "failed to execute taos_stmt_bind_param_batch"); + code = taos_stmt_add_batch(stmt); // add batch + checkErrorCode(stmt, code, "failed to execute taos_stmt_add_batch"); + // execute + code = taos_stmt_execute(stmt); + checkErrorCode(stmt, code, "failed to execute taos_stmt_execute"); + int affectedRows = taos_stmt_affected_rows(stmt); + printf("successfully inserted %d rows\n", affectedRows); + + // close + taos_stmt_close(stmt); +} + +TEST_F(taoscTest, taos_stmt_test) { + TAOS *taos = taos_connect("localhost", "root", "taosdata", NULL, 6030); + if (taos == NULL) { + printf("failed to connect to server"); + exit(EXIT_FAILURE); + } +// executeSQL(taos, "drop database if exists power"); +// executeSQL(taos, "create database power"); + executeSQL(taos, "use power"); +// executeSQL(taos, "create stable meters (ts timestamp, current float, voltage int, phase float) tags (location binary(64), groupId int)"); + insertData(taos); + taos_close(taos); + taos_cleanup(); +} + TEST_F(taoscTest, taos_query_a_test) { char sql[1024] = {0}; int32_t code = 0; From 88aa15e944f88c9b44d148fcc2efc07520778f7b Mon Sep 17 00:00:00 2001 From: xjzhou Date: Tue, 2 Jul 2024 11:05:54 +0800 Subject: [PATCH 2/7] enh: Enhance error handling for stmt --- include/libs/parser/parser.h | 1 + source/client/inc/clientInt.h | 1 + source/client/src/clientImpl.c | 4 +++- source/client/src/clientStmt.c | 1 + source/libs/parser/src/parInsertSql.c | 2 +- 5 files changed, 7 insertions(+), 2 deletions(-) diff --git a/include/libs/parser/parser.h b/include/libs/parser/parser.h index ad41b9a542..3ac357055e 100644 --- a/include/libs/parser/parser.h +++ b/include/libs/parser/parser.h @@ -89,6 +89,7 @@ typedef struct SParseContext { bool isView; bool isAudit; bool nodeOffline; + bool isStmtBind; const char* svrVer; SArray* pTableMetaPos; // sql table pos => catalog data pos SArray* pTableVgroupPos; // sql table pos => catalog data pos diff --git a/source/client/inc/clientInt.h b/source/client/inc/clientInt.h index 7a84215e12..d05abb2051 100644 --- a/source/client/inc/clientInt.h +++ b/source/client/inc/clientInt.h @@ -283,6 +283,7 @@ typedef struct SRequestObj { bool inRetry; bool isSubReq; bool inCallback; + bool isStmtBind; // is statement bind parameter uint32_t prevCode; // previous error code: todo refactor, add update flag for catalog uint32_t retry; int64_t allocatorRefId; diff --git a/source/client/src/clientImpl.c b/source/client/src/clientImpl.c index 11d3797157..080e2dc32a 100644 --- a/source/client/src/clientImpl.c +++ b/source/client/src/clientImpl.c @@ -206,6 +206,7 @@ int32_t buildRequest(uint64_t connId, const char* sql, int sqlLen, void* param, (*pRequest)->sqlstr[sqlLen] = 0; (*pRequest)->sqlLen = sqlLen; (*pRequest)->validateOnly = validateSql; + (*pRequest)->isStmtBind = false; ((SSyncQueryParam*)(*pRequest)->body.interParam)->userParam = param; @@ -266,7 +267,8 @@ int32_t parseSql(SRequestObj* pRequest, bool topicQuery, SQuery** pQuery, SStmtC .isSuperUser = (0 == strcmp(pTscObj->user, TSDB_DEFAULT_USER)), .enableSysInfo = pTscObj->sysInfo, .svrVer = pTscObj->sVer, - .nodeOffline = (pTscObj->pAppInfo->onlineDnodes < pTscObj->pAppInfo->totalDnodes)}; + .nodeOffline = (pTscObj->pAppInfo->onlineDnodes < pTscObj->pAppInfo->totalDnodes), + .isStmtBind = pRequest->isStmtBind}; cxt.mgmtEpSet = getEpSet_s(&pTscObj->pAppInfo->mgmtEp); int32_t code = catalogGetHandle(pTscObj->pAppInfo->clusterId, &cxt.pCatalog); diff --git a/source/client/src/clientStmt.c b/source/client/src/clientStmt.c index e8b76d34c2..38a16d8fbd 100644 --- a/source/client/src/clientStmt.c +++ b/source/client/src/clientStmt.c @@ -72,6 +72,7 @@ static int32_t stmtCreateRequest(STscStmt* pStmt) { } if (TSDB_CODE_SUCCESS == code) { pStmt->exec.pRequest->syncQuery = true; + pStmt->exec.pRequest->isStmtBind = true; } } diff --git a/source/libs/parser/src/parInsertSql.c b/source/libs/parser/src/parInsertSql.c index b053cd95a0..7af376f21c 100644 --- a/source/libs/parser/src/parInsertSql.c +++ b/source/libs/parser/src/parInsertSql.c @@ -30,7 +30,7 @@ typedef struct SInsertParseContext { bool forceUpdate; bool needTableTagVal; bool needRequest; // whether or not request server - bool isStmtBind; // whether is stmt + bool isStmtBind; // whether is stmt bind } SInsertParseContext; typedef int32_t (*_row_append_fn_t)(SMsgBuf* pMsgBuf, const void* value, int32_t len, void* param); From 67217a9bed837cc1dcd05ab35e03a3823523845a Mon Sep 17 00:00:00 2001 From: xjzhou Date: Tue, 2 Jul 2024 18:01:54 +0800 Subject: [PATCH 3/7] Return an error early when an error has already occurred in stmt --- source/client/src/clientStmt.c | 50 ++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/source/client/src/clientStmt.c b/source/client/src/clientStmt.c index 38a16d8fbd..21d2cbf447 100644 --- a/source/client/src/clientStmt.c +++ b/source/client/src/clientStmt.c @@ -831,6 +831,7 @@ TAOS_STMT* stmtInit(STscObj* taos, int64_t reqid, TAOS_STMT_OPTIONS* pOptions) { pStmt->bInfo.needParse = true; pStmt->sql.status = STMT_INIT; pStmt->reqid = reqid; + pStmt->errCode = TSDB_CODE_SUCCESS; if (NULL != pOptions) { memcpy(&pStmt->options, pOptions, sizeof(pStmt->options)); @@ -883,6 +884,10 @@ int stmtPrepare(TAOS_STMT* stmt, const char* sql, unsigned long length) { STMT_DLOG_E("start to prepare"); + if (pStmt->errCode != TSDB_CODE_SUCCESS) { + return pStmt->errCode; + } + if (pStmt->sql.status >= STMT_PREPARE) { STMT_ERR_RET(stmtResetStmt(pStmt)); } @@ -954,6 +959,10 @@ int stmtSetTbName(TAOS_STMT* stmt, const char* tbName) { STMT_DLOG("start to set tbName: %s", tbName); + if (pStmt->errCode != TSDB_CODE_SUCCESS) { + return pStmt->errCode; + } + STMT_ERR_RET(stmtSwitchStatus(pStmt, STMT_SETTBNAME)); int32_t insert = 0; @@ -1000,6 +1009,10 @@ int stmtSetTbTags(TAOS_STMT* stmt, TAOS_MULTI_BIND* tags) { STMT_DLOG_E("start to set tbTags"); + if (pStmt->errCode != TSDB_CODE_SUCCESS) { + return pStmt->errCode; + } + STMT_ERR_RET(stmtSwitchStatus(pStmt, STMT_SETTAGS)); if (pStmt->bInfo.inExecCache) { @@ -1022,6 +1035,10 @@ int stmtSetTbTags(TAOS_STMT* stmt, TAOS_MULTI_BIND* tags) { } int stmtFetchTagFields(STscStmt* pStmt, int32_t* fieldNum, TAOS_FIELD_E** fields) { + if (pStmt->errCode != TSDB_CODE_SUCCESS) { + return pStmt->errCode; + } + if (STMT_TYPE_QUERY == pStmt->sql.type) { tscError("invalid operation to get query tag fileds"); STMT_ERR_RET(TSDB_CODE_TSC_STMT_API_ERROR); @@ -1040,6 +1057,10 @@ int stmtFetchTagFields(STscStmt* pStmt, int32_t* fieldNum, TAOS_FIELD_E** fields } int stmtFetchColFields(STscStmt* pStmt, int32_t* fieldNum, TAOS_FIELD_E** fields) { + if (pStmt->errCode != TSDB_CODE_SUCCESS) { + return pStmt->errCode; + } + if (STMT_TYPE_QUERY == pStmt->sql.type) { tscError("invalid operation to get query column fileds"); STMT_ERR_RET(TSDB_CODE_TSC_STMT_API_ERROR); @@ -1151,8 +1172,13 @@ int stmtBindBatch(TAOS_STMT* stmt, TAOS_MULTI_BIND* bind, int32_t colIdx) { STMT_DLOG("start to bind stmt data, colIdx: %d", colIdx); + if (pStmt->errCode != TSDB_CODE_SUCCESS) { + return pStmt->errCode; + } + 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; @@ -1308,6 +1334,10 @@ int stmtAddBatch(TAOS_STMT* stmt) { STMT_DLOG_E("start to add batch"); + if (pStmt->errCode != TSDB_CODE_SUCCESS) { + return pStmt->errCode; + } + STMT_ERR_RET(stmtSwitchStatus(pStmt, STMT_ADD_BATCH)); if (pStmt->sql.stbInterlaceMode) { @@ -1472,6 +1502,10 @@ int stmtExec(TAOS_STMT* stmt) { STMT_DLOG_E("start to exec"); + if (pStmt->errCode != TSDB_CODE_SUCCESS) { + return pStmt->errCode; + } + STMT_ERR_RET(stmtSwitchStatus(pStmt, STMT_EXECUTE)); if (STMT_TYPE_QUERY == pStmt->sql.type) { @@ -1600,6 +1634,10 @@ int stmtGetTagFields(TAOS_STMT* stmt, int* nums, TAOS_FIELD_E** fields) { STMT_DLOG_E("start to get tag fields"); + if (pStmt->errCode != TSDB_CODE_SUCCESS) { + return pStmt->errCode; + } + if (STMT_TYPE_QUERY == pStmt->sql.type) { STMT_ERRI_JRET(TSDB_CODE_TSC_STMT_API_ERROR); } @@ -1638,6 +1676,10 @@ int stmtGetColFields(TAOS_STMT* stmt, int* nums, TAOS_FIELD_E** fields) { STMT_DLOG_E("start to get col fields"); + if (pStmt->errCode != TSDB_CODE_SUCCESS) { + return pStmt->errCode; + } + if (STMT_TYPE_QUERY == pStmt->sql.type) { STMT_ERRI_JRET(TSDB_CODE_TSC_STMT_API_ERROR); } @@ -1675,6 +1717,10 @@ int stmtGetParamNum(TAOS_STMT* stmt, int* nums) { STMT_DLOG_E("start to get param num"); + if (pStmt->errCode != TSDB_CODE_SUCCESS) { + return pStmt->errCode; + } + STMT_ERR_RET(stmtSwitchStatus(pStmt, STMT_FETCH_FIELDS)); if (pStmt->bInfo.needParse && pStmt->sql.runTimes && pStmt->sql.type > 0 && @@ -1707,6 +1753,10 @@ int stmtGetParam(TAOS_STMT* stmt, int idx, int* type, int* bytes) { STMT_DLOG_E("start to get param"); + if (pStmt->errCode != TSDB_CODE_SUCCESS) { + return pStmt->errCode; + } + if (STMT_TYPE_QUERY == pStmt->sql.type) { STMT_RET(TSDB_CODE_TSC_STMT_API_ERROR); } From 3151d0663c87d9e5df89d0b9da9e4b5e3e704fcc Mon Sep 17 00:00:00 2001 From: xjzhou Date: Thu, 4 Jul 2024 16:45:10 +0800 Subject: [PATCH 4/7] update --- source/libs/parser/src/parInsertSql.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/libs/parser/src/parInsertSql.c b/source/libs/parser/src/parInsertSql.c index cd7288f1f5..d4b9f20f51 100644 --- a/source/libs/parser/src/parInsertSql.c +++ b/source/libs/parser/src/parInsertSql.c @@ -2938,7 +2938,7 @@ int32_t parseInsertSql(SParseContext* pCxt, SQuery** pQuery, SCatalogReq* pCatal .usingDuplicateTable = false, .needRequest = true, .forceUpdate = (NULL != pCatalogReq ? pCatalogReq->forceUpdate : false), - .isStmtBind = false}; + .isStmtBind = pCxt->isStmtBind}; int32_t code = initInsertQuery(&context, pCatalogReq, pMetaData, pQuery); if (TSDB_CODE_SUCCESS == code) { From b8012df90906dfb3702d7df1dfcccadf9539a182 Mon Sep 17 00:00:00 2001 From: xjzhou Date: Fri, 5 Jul 2024 14:18:51 +0800 Subject: [PATCH 5/7] handle fixed table name int sql --- source/client/src/clientStmt.c | 6 ++++++ source/libs/parser/src/parInsertSql.c | 7 +++++++ 2 files changed, 13 insertions(+) diff --git a/source/client/src/clientStmt.c b/source/client/src/clientStmt.c index 21d2cbf447..17b52521b8 100644 --- a/source/client/src/clientStmt.c +++ b/source/client/src/clientStmt.c @@ -1015,6 +1015,12 @@ int stmtSetTbTags(TAOS_STMT* stmt, TAOS_MULTI_BIND* tags) { STMT_ERR_RET(stmtSwitchStatus(pStmt, STMT_SETTAGS)); + 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; + } + if (pStmt->bInfo.inExecCache) { return TSDB_CODE_SUCCESS; } diff --git a/source/libs/parser/src/parInsertSql.c b/source/libs/parser/src/parInsertSql.c index d4b9f20f51..313d9449d2 100644 --- a/source/libs/parser/src/parInsertSql.c +++ b/source/libs/parser/src/parInsertSql.c @@ -2444,6 +2444,13 @@ static int32_t checkTableClauseFirstToken(SInsertParseContext* pCxt, SVnodeModif pTbName->n = strlen(tbName); } + if (pCxt->isStmtBind) { + if (TK_NK_ID == pTbName->type || (tbNameAfterDbName != NULL && *(tbNameAfterDbName + 1) != '?')) { + // In SQL statements, the table name has already been specified. + parserWarn("0x%" PRIx64 " table name is specified in sql, ignore the table name in bind param", pCxt->pComCxt->requestId); + } + } + *pHasData = true; return TSDB_CODE_SUCCESS; } From 48560ddf4332fc2c51646147b3b2133e97057e29 Mon Sep 17 00:00:00 2001 From: xjzhou Date: Fri, 5 Jul 2024 14:23:54 +0800 Subject: [PATCH 6/7] recover taoscTest.cpp --- tests/taosc_test/taoscTest.cpp | 201 +++++---------------------------- 1 file changed, 26 insertions(+), 175 deletions(-) diff --git a/tests/taosc_test/taoscTest.cpp b/tests/taosc_test/taoscTest.cpp index d3f6f50547..1b051f555e 100644 --- a/tests/taosc_test/taoscTest.cpp +++ b/tests/taosc_test/taoscTest.cpp @@ -30,31 +30,31 @@ #include "taos.h" class taoscTest : public ::testing::Test { - protected: +protected: static void SetUpTestCase() { -// printf("start test setup.\n"); -// TAOS* taos = taos_connect("localhost", "root", "taosdata", NULL, 0); -// ASSERT_TRUE(taos != nullptr); -// -// TAOS_RES* res = taos_query(taos, "drop database IF EXISTS taosc_test_db;"); -// if (taos_errno(res) != 0) { -// printf("error in drop database taosc_test_db, reason:%s\n", taos_errstr(res)); -// return; -// } -// taosSsleep(5); -// taos_free_result(res); -// printf("drop database taosc_test_db,finished.\n"); -// -// res = taos_query(taos, "create database taosc_test_db;"); -// if (taos_errno(res) != 0) { -// printf("error in create database taosc_test_db, reason:%s\n", taos_errstr(res)); -// return; -// } -// taosSsleep(5); -// taos_free_result(res); -// printf("create database taosc_test_db,finished.\n"); -// -// taos_close(taos); + printf("start test setup.\n"); + TAOS* taos = taos_connect("localhost", "root", "taosdata", NULL, 0); + ASSERT_TRUE(taos != nullptr); + + TAOS_RES* res = taos_query(taos, "drop database IF EXISTS taosc_test_db;"); + if (taos_errno(res) != 0) { + printf("error in drop database taosc_test_db, reason:%s\n", taos_errstr(res)); + return; + } + taosSsleep(5); + taos_free_result(res); + printf("drop database taosc_test_db,finished.\n"); + + res = taos_query(taos, "create database taosc_test_db;"); + if (taos_errno(res) != 0) { + printf("error in create database taosc_test_db, reason:%s\n", taos_errstr(res)); + return; + } + taosSsleep(5); + taos_free_result(res); + printf("create database taosc_test_db,finished.\n"); + + taos_close(taos); } static void TearDownTestCase() {} @@ -99,154 +99,6 @@ void queryCallback(void* param, void* res, int32_t code) { taos_fetch_raw_block_a(res, fetchCallback, param); } -/** - * @brief execute sql only. - * - * @param taos - * @param sql - */ -void executeSQL(TAOS *taos, const char *sql) { - TAOS_RES *res = taos_query(taos, sql); - int code = taos_errno(res); - if (code != 0) { - printf("%s\n", taos_errstr(res)); - taos_free_result(res); - taos_close(taos); - exit(EXIT_FAILURE); - } - taos_free_result(res); -} - -/** - * @brief check return status and exit program when error occur. - * - * @param stmt - * @param code - * @param msg - */ -void checkErrorCode(TAOS_STMT *stmt, int code, const char* msg) { - if (code != 0) { - printf("%s. error: %s\n", msg, taos_stmt_errstr(stmt)); - taos_stmt_close(stmt); - exit(EXIT_FAILURE); - } -} - -typedef struct { - int64_t ts; - float current; - int voltage; - float phase; -} Row; - - -/** - * @brief insert data using stmt API - * - * @param taos - */ -void insertData(TAOS *taos) { - // init - TAOS_STMT *stmt = taos_stmt_init(taos); - // prepare -// const char *sql = "INSERT INTO ?.d1001 USING meters TAGS(?, ?) values(?, ?, ?, ?)"; -// const char *sql = "INSERT INTO ?.? USING meters TAGS(?, ?) values(?, ?, ?, ?)"; -// const char *sql = "INSERT INTO power.? USING meters TAGS(?, ?) values(?, ?, ?, ?)"; -// const char *sql = "INSERT INTO ? USING meters TAGS(?, ?) values(?, ?, ?, ?)"; -// const char *sql = "INSERT INTO ? USING meters TAGS(?, ?) values(?, ?, ?, ?)"; - const char *sql = "insert into huawei USING meters TAGS(?, ?) values(?, ?, ?, ?)"; - int code = taos_stmt_prepare(stmt, sql, 0); - checkErrorCode(stmt, code, "failed to execute taos_stmt_prepare"); - // bind table name and tags - TAOS_MULTI_BIND tags[2]; - char *location = "California.SanFrancisco"; - int groupId = 2; - tags[0].buffer_type = TSDB_DATA_TYPE_BINARY; - tags[0].buffer_length = strlen(location); - tags[0].length = (int32_t *)&tags[0].buffer_length; - tags[0].buffer = location; - tags[0].is_null = NULL; - - tags[1].buffer_type = TSDB_DATA_TYPE_INT; - tags[1].buffer_length = sizeof(int); - tags[1].length = (int32_t *)&tags[1].buffer_length; - tags[1].buffer = &groupId; - tags[1].is_null = NULL; - -// code = taos_stmt_set_tbname_tags(stmt, "duck", tags); -// checkErrorCode(stmt, code, "failed to execute taos_stmt_set_dbname_tbname_tags"); - - // insert two rows with multi binds - TAOS_MULTI_BIND params[4]; - // values to bind - int64_t ts[] = {1648432611250, 1648432611778}; - float current[] = {10.3, 12.6}; - int voltage[] = {219, 218}; - float phase[] = {0.31, 0.33}; - // is_null array - char is_null[2] = {0}; - // length array - int32_t int64Len[2] = {sizeof(int64_t)}; - int32_t floatLen[2] = {sizeof(float)}; - int32_t intLen[2] = {sizeof(int)}; - - params[0].buffer_type = TSDB_DATA_TYPE_TIMESTAMP; - params[0].buffer_length = sizeof(int64_t); - params[0].buffer = ts; - params[0].length = int64Len; - params[0].is_null = is_null; - params[0].num = 2; - - params[1].buffer_type = TSDB_DATA_TYPE_FLOAT; - params[1].buffer_length = sizeof(float); - params[1].buffer = current; - params[1].length = floatLen; - params[1].is_null = is_null; - params[1].num = 2; - - params[2].buffer_type = TSDB_DATA_TYPE_INT; - params[2].buffer_length = sizeof(int); - params[2].buffer = voltage; - params[2].length = intLen; - params[2].is_null = is_null; - params[2].num = 2; - - params[3].buffer_type = TSDB_DATA_TYPE_FLOAT; - params[3].buffer_length = sizeof(float); - params[3].buffer = phase; - params[3].length = floatLen; - params[3].is_null = is_null; - params[3].num = 2; - - code = taos_stmt_bind_param_batch(stmt, params); // bind batch - checkErrorCode(stmt, code, "failed to execute taos_stmt_bind_param_batch"); - code = taos_stmt_add_batch(stmt); // add batch - checkErrorCode(stmt, code, "failed to execute taos_stmt_add_batch"); - // execute - code = taos_stmt_execute(stmt); - checkErrorCode(stmt, code, "failed to execute taos_stmt_execute"); - int affectedRows = taos_stmt_affected_rows(stmt); - printf("successfully inserted %d rows\n", affectedRows); - - // close - taos_stmt_close(stmt); -} - -TEST_F(taoscTest, taos_stmt_test) { - TAOS *taos = taos_connect("localhost", "root", "taosdata", NULL, 6030); - if (taos == NULL) { - printf("failed to connect to server"); - exit(EXIT_FAILURE); - } -// executeSQL(taos, "drop database if exists power"); -// executeSQL(taos, "create database power"); - executeSQL(taos, "use power"); -// executeSQL(taos, "create stable meters (ts timestamp, current float, voltage int, phase float) tags (location binary(64), groupId int)"); - insertData(taos); - taos_close(taos); - taos_cleanup(); -} - TEST_F(taoscTest, taos_query_a_test) { char sql[1024] = {0}; int32_t code = 0; @@ -336,7 +188,7 @@ TEST_F(taoscTest, taos_query_test) { void queryCallback2(void* param, void* res, int32_t code) { ASSERT_TRUE(code == 0); ASSERT_TRUE(param == pUserParam); - // After using taos_query_a to query, using taos_fetch_row in the callback will cause blocking. + // After using taos_query_a to query, using taos_fetch_row in the callback will cause blocking. // Reason: schProcessOnCbBegin SCH_LOCK_TASK(pTask) TAOS_ROW row; row = taos_fetch_row(res); @@ -402,7 +254,7 @@ TEST_F(taoscTest, taos_query_a_fetch_row) { printf("taos_query_a_fetch_row taos_fetch_row start...\n"); while ((row = taos_fetch_row(*pres))) { - getRecordCounts++; + getRecordCounts++; } printf("taos_query_a_fetch_row taos_fetch_row end. %p record count:%d.\n", *pres, getRecordCounts); taos_free_result(*pres); @@ -412,4 +264,3 @@ TEST_F(taoscTest, taos_query_a_fetch_row) { printf("taos_query_a_fetch_row test finished.\n"); } - From c9153b8176f31c55568518d1f6221b72f098c182 Mon Sep 17 00:00:00 2001 From: xjzhou Date: Fri, 5 Jul 2024 16:27:40 +0800 Subject: [PATCH 7/7] update CI test case stmt_error --- tests/system-test/1-insert/stmt_error.py | 70 +++++++++++++++++++++--- 1 file changed, 62 insertions(+), 8 deletions(-) diff --git a/tests/system-test/1-insert/stmt_error.py b/tests/system-test/1-insert/stmt_error.py index c6d747c317..0bfbedb9a1 100644 --- a/tests/system-test/1-insert/stmt_error.py +++ b/tests/system-test/1-insert/stmt_error.py @@ -24,7 +24,7 @@ class TDTestCase: case1 : [TD-11899] : this is an test case for check stmt error use . ''' return - + def init(self, conn, logSql, replicaVar=1): self.replicaVar = int(replicaVar) tdLog.debug("start to execute %s" % __file__) @@ -49,7 +49,7 @@ class TDTestCase: ff float, dd double, bb binary(65059), nn nchar(100), tt timestamp)", ) conn.load_table_info("log") - + stmt = conn.statement("insert into log values(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)") params = new_bind_params(16) @@ -123,7 +123,7 @@ class TDTestCase: ff float, dd double, bb binary(100), nn nchar(100), tt timestamp , error_data int )", ) conn.load_table_info("log") - + stmt = conn.statement("insert into log values(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,1000)") params = new_bind_params(16) @@ -195,20 +195,74 @@ class TDTestCase: except Exception as err: conn.close() raise err - + + def test_stmt_nornmal_value_error(self, conn): + # type: (TaosConnection) -> None + dbname = "pytest_taos_stmt_error" + try: + conn.execute("drop database if exists %s" % dbname) + conn.execute("create database if not exists %s" % dbname) + conn.select_db(dbname) + + conn.execute( + "create table if not exists log(ts timestamp, bo bool, nil tinyint, ti tinyint, si smallint, ii int,\ + bi bigint, tu tinyint unsigned, su smallint unsigned, iu int unsigned, bu bigint unsigned, \ + ff float, dd double, bb binary(100), nn nchar(100), tt timestamp , error_data int )", + ) + conn.load_table_info("log") + + + stmt = conn.statement("insert into log values(NOW(),?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)") + params = new_bind_params(16) + params[0].timestamp(1626861392589, PrecisionEnum.Milliseconds) + params[1].bool(True) + params[2].tinyint(None) + params[3].tinyint(2) + params[4].smallint(3) + params[5].int(4) + params[6].bigint(5) + params[7].tinyint_unsigned(6) + params[8].smallint_unsigned(7) + params[9].int_unsigned(8) + params[10].bigint_unsigned(9) + params[11].float(10.1) + params[12].double(10.11) + params[13].binary("hello") + params[14].nchar("stmt") + params[15].timestamp(1626861392589, PrecisionEnum.Milliseconds) + + stmt.bind_param(params) + stmt.execute() + + conn.close() + + except Exception as err: + conn.execute("drop database if exists %s" % dbname) + conn.close() + raise err + def run(self): - + self.test_stmt_insert(self.conn()) try: self.test_stmt_insert_error(self.conn()) except Exception as error : - - if str(error)=='[0x0200]: no mix usage for ? and values': + + if str(error)=='[0x0200]: stmt bind param does not support normal value in sql': tdLog.info('=========stmt error occured for bind part column ==============') else: tdLog.exit("expect error(%s) not occured" % str(error)) - try: + try: + self.test_stmt_nornmal_value_error(self.conn()) + except Exception as error : + + if str(error)=='[0x0200]: stmt bind param does not support normal value in sql': + tdLog.info('=========stmt error occured for bind part column ==============') + else: + tdLog.exit("expect error(%s) not occured" % str(error)) + + try: self.test_stmt_insert_error_null_timestamp(self.conn()) tdLog.exit("expect error not occured - 1") except Exception as error :