From 298c4b48128cd9c3cc99a3f766eaf89c837a8f9b Mon Sep 17 00:00:00 2001 From: Minglei Jin Date: Thu, 15 Aug 2024 09:28:32 +0800 Subject: [PATCH 01/23] feat(stmt2): initial commit for stmt2 --- include/client/taos.h | 99 +- include/common/tdataformat.h | 12 + include/libs/parser/parser.h | 58 +- source/client/inc/clientStmt2.h | 233 +++ source/client/src/clientMain.c | 234 ++- source/client/src/clientStmt2.c | 1895 ++++++++++++++++++++++++ source/common/src/tdataformat.c | 137 ++ source/libs/parser/src/parInsertStmt.c | 347 ++++- source/libs/parser/src/parser.c | 116 +- 9 files changed, 3029 insertions(+), 102 deletions(-) create mode 100644 source/client/inc/clientStmt2.h create mode 100644 source/client/src/clientStmt2.c diff --git a/include/client/taos.h b/include/client/taos.h index 73ab52357a..9bd1517d38 100644 --- a/include/client/taos.h +++ b/include/client/taos.h @@ -51,7 +51,7 @@ typedef void TAOS_SUB; #define TSDB_DATA_TYPE_BLOB 18 // binary #define TSDB_DATA_TYPE_MEDIUMBLOB 19 #define TSDB_DATA_TYPE_BINARY TSDB_DATA_TYPE_VARCHAR // string -#define TSDB_DATA_TYPE_GEOMETRY 20 // geometry +#define TSDB_DATA_TYPE_GEOMETRY 20 // geometry #define TSDB_DATA_TYPE_MAX 21 typedef enum { @@ -168,7 +168,7 @@ DLL_EXPORT const char *taos_data_type(int type); DLL_EXPORT TAOS_STMT *taos_stmt_init(TAOS *taos); DLL_EXPORT TAOS_STMT *taos_stmt_init_with_reqid(TAOS *taos, int64_t reqid); -DLL_EXPORT TAOS_STMT *taos_stmt_init_with_options(TAOS *taos, TAOS_STMT_OPTIONS* options); +DLL_EXPORT TAOS_STMT *taos_stmt_init_with_options(TAOS *taos, TAOS_STMT_OPTIONS *options); DLL_EXPORT int taos_stmt_prepare(TAOS_STMT *stmt, const char *sql, unsigned long length); DLL_EXPORT int taos_stmt_set_tbname_tags(TAOS_STMT *stmt, const char *name, TAOS_MULTI_BIND *tags); DLL_EXPORT int taos_stmt_set_tbname(TAOS_STMT *stmt, const char *name); @@ -193,6 +193,49 @@ DLL_EXPORT char *taos_stmt_errstr(TAOS_STMT *stmt); DLL_EXPORT int taos_stmt_affected_rows(TAOS_STMT *stmt); DLL_EXPORT int taos_stmt_affected_rows_once(TAOS_STMT *stmt); +typedef void TAOS_STMT2; + +typedef enum { + TAOS_FIELD_COL = 1, + TAOS_FIELD_TAG, + TAOS_FIELD_QUERY, +} TAOS_FIELD_T; + +typedef struct { + int64_t reqid; + bool singleStbInsert; + bool singleTableBindOnce; + __taos_async_fn_t asyncExecFn; + void *userdata; +} TAOS_STMT2_OPTION; + +typedef struct { + int buffer_type; + void *buffer; + uintptr_t buffer_length; + int32_t *length; + char *is_null; + int num; +} TAOS_STMT2_BIND; + +typedef struct { + int count; + char **tbnames; + TAOS_STMT2_BIND **tags; + TAOS_STMT2_BIND **bind_cols; +} TAOS_STMT2_BINDV; + +DLL_EXPORT TAOS_STMT2 *taos_stmt2_init(TAOS *taos, TAOS_STMT2_OPTION *option); +DLL_EXPORT int taos_stmt2_prepare(TAOS_STMT2 *stmt, const char *sql, unsigned long length); +DLL_EXPORT int taos_stmt2_bind_param(TAOS_STMT2 *stmt, TAOS_STMT2_BINDV *bindv, int32_t col_idx); +DLL_EXPORT int taos_stmt2_exec(TAOS_STMT2 *stmt, int *affected_rows); +DLL_EXPORT int taos_stmt2_close(TAOS_STMT2 *stmt); +DLL_EXPORT int taos_stmt2_is_insert(TAOS_STMT2 *stmt, int *insert); +DLL_EXPORT int taos_stmt2_get_fields(TAOS_STMT2 *stmt, TAOS_FIELD_T field_type, int *count, TAOS_FIELD_E **fields); +DLL_EXPORT void taos_stmt2_free_fields(TAOS_STMT2 *stmt, TAOS_FIELD_E *fields); +DLL_EXPORT TAOS_RES *taos_stmt2_result(TAOS_STMT2 *stmt); +DLL_EXPORT char *taos_stmt2_error(TAOS_STMT2 *stmt); + DLL_EXPORT TAOS_RES *taos_query(TAOS *taos, const char *sql); DLL_EXPORT TAOS_RES *taos_query_with_reqid(TAOS *taos, const char *sql, int64_t reqId); @@ -245,14 +288,15 @@ DLL_EXPORT void taos_set_hb_quit(int8_t quitByKill); DLL_EXPORT int taos_set_notify_cb(TAOS *taos, __taos_notify_fn_t fp, void *param, int type); -typedef void (*__taos_async_whitelist_fn_t)(void *param, int code, TAOS *taos, int numOfWhiteLists, uint64_t* pWhiteLists); +typedef void (*__taos_async_whitelist_fn_t)(void *param, int code, TAOS *taos, int numOfWhiteLists, + uint64_t *pWhiteLists); DLL_EXPORT void taos_fetch_whitelist_a(TAOS *taos, __taos_async_whitelist_fn_t fp, void *param); typedef enum { TAOS_CONN_MODE_BI = 0, } TAOS_CONN_MODE; -DLL_EXPORT int taos_set_conn_mode(TAOS* taos, int mode, int value); +DLL_EXPORT int taos_set_conn_mode(TAOS *taos, int mode, int value); /* --------------------------schemaless INTERFACE------------------------------- */ DLL_EXPORT TAOS_RES *taos_schemaless_insert(TAOS *taos, char *lines[], int numLines, int protocol, int precision); @@ -270,10 +314,13 @@ DLL_EXPORT TAOS_RES *taos_schemaless_insert_raw_ttl(TAOS *taos, char *lines, int int precision, int32_t ttl); DLL_EXPORT 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); -DLL_EXPORT 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); -DLL_EXPORT 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); +DLL_EXPORT 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); +DLL_EXPORT 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); /* --------------------------TMQ INTERFACE------------------------------- */ typedef struct tmq_t tmq_t; @@ -319,14 +366,17 @@ DLL_EXPORT int32_t tmq_unsubscribe(tmq_t *tmq); DLL_EXPORT int32_t tmq_subscription(tmq_t *tmq, tmq_list_t **topics); DLL_EXPORT TAOS_RES *tmq_consumer_poll(tmq_t *tmq, int64_t timeout); DLL_EXPORT int32_t tmq_consumer_close(tmq_t *tmq); -DLL_EXPORT int32_t tmq_commit_sync(tmq_t *tmq, const TAOS_RES *msg); //Commit the msg’s offset + 1 +DLL_EXPORT int32_t tmq_commit_sync(tmq_t *tmq, const TAOS_RES *msg); // Commit the msg’s offset + 1 DLL_EXPORT void tmq_commit_async(tmq_t *tmq, const TAOS_RES *msg, tmq_commit_cb *cb, void *param); DLL_EXPORT int32_t tmq_commit_offset_sync(tmq_t *tmq, const char *pTopicName, int32_t vgId, int64_t offset); -DLL_EXPORT void tmq_commit_offset_async(tmq_t *tmq, const char *pTopicName, int32_t vgId, int64_t offset, tmq_commit_cb *cb, void *param); -DLL_EXPORT int32_t tmq_get_topic_assignment(tmq_t *tmq, const char *pTopicName, tmq_topic_assignment **assignment,int32_t *numOfAssignment); -DLL_EXPORT void tmq_free_assignment(tmq_topic_assignment* pAssignment); +DLL_EXPORT void tmq_commit_offset_async(tmq_t *tmq, const char *pTopicName, int32_t vgId, int64_t offset, + tmq_commit_cb *cb, void *param); +DLL_EXPORT int32_t tmq_get_topic_assignment(tmq_t *tmq, const char *pTopicName, tmq_topic_assignment **assignment, + int32_t *numOfAssignment); +DLL_EXPORT void tmq_free_assignment(tmq_topic_assignment *pAssignment); DLL_EXPORT int32_t tmq_offset_seek(tmq_t *tmq, const char *pTopicName, int32_t vgId, int64_t offset); -DLL_EXPORT int64_t tmq_position(tmq_t *tmq, const char *pTopicName, int32_t vgId); // The current offset is the offset of the last consumed message + 1 +DLL_EXPORT int64_t tmq_position(tmq_t *tmq, const char *pTopicName, + int32_t vgId); // The current offset is the offset of the last consumed message + 1 DLL_EXPORT int64_t tmq_committed(tmq_t *tmq, const char *pTopicName, int32_t vgId); DLL_EXPORT TAOS *tmq_get_connect(tmq_t *tmq); @@ -335,7 +385,7 @@ DLL_EXPORT tmq_res_t tmq_get_res_type(TAOS_RES *res); DLL_EXPORT const char *tmq_get_topic_name(TAOS_RES *res); DLL_EXPORT const char *tmq_get_db_name(TAOS_RES *res); DLL_EXPORT int32_t tmq_get_vgroup_id(TAOS_RES *res); -DLL_EXPORT int64_t tmq_get_vgroup_offset(TAOS_RES* res); +DLL_EXPORT int64_t tmq_get_vgroup_offset(TAOS_RES *res); DLL_EXPORT const char *tmq_err2str(int32_t code); /* ------------------------------ TAOSX -----------------------------------*/ @@ -345,15 +395,16 @@ typedef struct tmq_raw_data { uint16_t raw_type; } tmq_raw_data; -DLL_EXPORT int32_t tmq_get_raw(TAOS_RES *res, tmq_raw_data *raw); -DLL_EXPORT int32_t tmq_write_raw(TAOS *taos, tmq_raw_data raw); -DLL_EXPORT int taos_write_raw_block(TAOS *taos, int numOfRows, char *pData, const char *tbname); -DLL_EXPORT int taos_write_raw_block_with_reqid(TAOS *taos, int numOfRows, char *pData, const char *tbname, int64_t reqid); -DLL_EXPORT int taos_write_raw_block_with_fields(TAOS *taos, int rows, char *pData, const char *tbname, - TAOS_FIELD *fields, int numFields); -DLL_EXPORT int taos_write_raw_block_with_fields_with_reqid(TAOS *taos, int rows, char *pData, const char *tbname, - TAOS_FIELD *fields, int numFields, int64_t reqid); -DLL_EXPORT void tmq_free_raw(tmq_raw_data raw); +DLL_EXPORT int32_t tmq_get_raw(TAOS_RES *res, tmq_raw_data *raw); +DLL_EXPORT int32_t tmq_write_raw(TAOS *taos, tmq_raw_data raw); +DLL_EXPORT int taos_write_raw_block(TAOS *taos, int numOfRows, char *pData, const char *tbname); +DLL_EXPORT int taos_write_raw_block_with_reqid(TAOS *taos, int numOfRows, char *pData, const char *tbname, + int64_t reqid); +DLL_EXPORT int taos_write_raw_block_with_fields(TAOS *taos, int rows, char *pData, const char *tbname, + TAOS_FIELD *fields, int numFields); +DLL_EXPORT int taos_write_raw_block_with_fields_with_reqid(TAOS *taos, int rows, char *pData, const char *tbname, + TAOS_FIELD *fields, int numFields, int64_t reqid); +DLL_EXPORT void tmq_free_raw(tmq_raw_data raw); // Returning null means error. Returned result need to be freed by tmq_free_json_meta DLL_EXPORT char *tmq_get_json_meta(TAOS_RES *res); @@ -369,7 +420,7 @@ typedef enum { } TSDB_SERVER_STATUS; DLL_EXPORT TSDB_SERVER_STATUS taos_check_server_status(const char *fqdn, int port, char *details, int maxlen); -DLL_EXPORT char* getBuildInfo(); +DLL_EXPORT char *getBuildInfo(); #ifdef __cplusplus } #endif diff --git a/include/common/tdataformat.h b/include/common/tdataformat.h index 0acb28fabd..cb4f6972f0 100644 --- a/include/common/tdataformat.h +++ b/include/common/tdataformat.h @@ -378,6 +378,18 @@ typedef struct { int32_t tRowBuildFromBind(SBindInfo *infos, int32_t numOfInfos, bool infoSorted, const STSchema *pTSchema, SArray *rowArray); +// stmt2 binding +int32_t tColDataAddValueByBind2(SColData *pColData, TAOS_STMT2_BIND *pBind, int32_t buffMaxLen); + +typedef struct { + int32_t columnId; + int32_t type; + TAOS_STMT2_BIND *bind; +} SBindInfo2; + +int32_t tRowBuildFromBind2(SBindInfo2 *infos, int32_t numOfInfos, bool infoSorted, const STSchema *pTSchema, + SArray *rowArray); + #endif #ifdef __cplusplus diff --git a/include/libs/parser/parser.h b/include/libs/parser/parser.h index cefce8a9c0..5025da14d3 100644 --- a/include/libs/parser/parser.h +++ b/include/libs/parser/parser.h @@ -20,9 +20,9 @@ extern "C" { #endif +#include "catalog.h" #include "query.h" #include "querynodes.h" -#include "catalog.h" typedef struct SStmtCallback { TAOS_STMT* pStmt; @@ -37,15 +37,15 @@ typedef enum { } SParseResType; typedef struct SParseSchemaRes { - int8_t precision; - int32_t numOfCols; - SSchema* pSchema; + int8_t precision; + int32_t numOfCols; + SSchema* pSchema; } SParseSchemaRes; typedef struct SParseQueryRes { - SNode* pQuery; - SCatalogReq* pCatalogReq; - SMetaData meta; + SNode* pQuery; + SCatalogReq* pCatalogReq; + SMetaData meta; } SParseQueryRes; typedef struct SParseSqlRes { @@ -121,11 +121,13 @@ int32_t qSetSTableIdForRsma(SNode* pStmt, int64_t uid); int32_t qInitKeywordsTable(); void qCleanupKeywordsTable(); -int32_t qAppendStmtTableOutput(SQuery* pQuery, SHashObj* pAllVgHash, STableColsData* pTbData, STableDataCxt* pTbCtx, SStbInterlaceInfo* pBuildInfo); -int32_t qBuildStmtFinOutput(SQuery* pQuery, SHashObj* pAllVgHash, SArray* pVgDataBlocks); -//int32_t qBuildStmtOutputFromTbList(SQuery* pQuery, SHashObj* pVgHash, SArray* pBlockList, STableDataCxt* pTbCtx, int32_t tbNum); +int32_t qAppendStmtTableOutput(SQuery* pQuery, SHashObj* pAllVgHash, STableColsData* pTbData, STableDataCxt* pTbCtx, + SStbInterlaceInfo* pBuildInfo); +int32_t qBuildStmtFinOutput(SQuery* pQuery, SHashObj* pAllVgHash, SArray* pVgDataBlocks); +// int32_t qBuildStmtOutputFromTbList(SQuery* pQuery, SHashObj* pVgHash, SArray* pBlockList, STableDataCxt* pTbCtx, +// int32_t tbNum); int32_t qBuildStmtOutput(SQuery* pQuery, SHashObj* pVgHash, SHashObj* pBlockHash); -int32_t qResetStmtColumns(SArray* pCols, bool deepClear); +int32_t qResetStmtColumns(SArray* pCols, bool deepClear); int32_t qResetStmtDataBlock(STableDataCxt* block, bool keepBuf); int32_t qCloneStmtDataBlock(STableDataCxt** pDst, STableDataCxt* pSrc, bool reset); int32_t qRebuildStmtDataBlock(STableDataCxt** pDst, STableDataCxt* pSrc, uint64_t uid, uint64_t suid, int32_t vgId, @@ -136,39 +138,51 @@ int32_t qCloneCurrentTbData(STableDataCxt* pDataBlock, SSubmitTbData** pData int32_t qStmtBindParams(SQuery* pQuery, TAOS_MULTI_BIND* pParams, int32_t colIdx); int32_t qStmtParseQuerySql(SParseContext* pCxt, SQuery* pQuery); -int32_t qBindStmtStbColsValue(void* pBlock, SArray* pCols, TAOS_MULTI_BIND* bind, char* msgBuf, int32_t msgBufLen, STSchema** pTSchema, SBindInfo* pBindInfos); +int32_t qBindStmtStbColsValue(void* pBlock, SArray* pCols, TAOS_MULTI_BIND* bind, char* msgBuf, int32_t msgBufLen, + STSchema** pTSchema, SBindInfo* pBindInfos); int32_t qBindStmtColsValue(void* pBlock, SArray* pCols, TAOS_MULTI_BIND* bind, char* msgBuf, int32_t msgBufLen); -int32_t qBindStmtSingleColValue(void* pBlock, SArray* pCols, TAOS_MULTI_BIND* bind, char* msgBuf, int32_t msgBufLen, int32_t colIdx, - int32_t rowNum); +int32_t qBindStmtSingleColValue(void* pBlock, SArray* pCols, TAOS_MULTI_BIND* bind, char* msgBuf, int32_t msgBufLen, + int32_t colIdx, int32_t rowNum); int32_t qBuildStmtColFields(void* pDataBlock, int32_t* fieldNum, TAOS_FIELD_E** fields); int32_t qBuildStmtTagFields(void* pBlock, void* boundTags, int32_t* fieldNum, TAOS_FIELD_E** fields); int32_t qBindStmtTagsValue(void* pBlock, void* boundTags, int64_t suid, const char* sTableName, char* tName, TAOS_MULTI_BIND* bind, char* msgBuf, int32_t msgBufLen); + +int32_t qStmtBindParams2(SQuery* pQuery, TAOS_STMT2_BIND* pParams, int32_t colIdx); +int32_t qBindStmtStbColsValue2(void* pBlock, SArray* pCols, TAOS_STMT2_BIND* bind, char* msgBuf, int32_t msgBufLen, + STSchema** pTSchema, SBindInfo2* pBindInfos); +int32_t qBindStmtColsValue2(void* pBlock, SArray* pCols, TAOS_STMT2_BIND* bind, char* msgBuf, int32_t msgBufLen); +int32_t qBindStmtSingleColValue2(void* pBlock, SArray* pCols, TAOS_STMT2_BIND* bind, char* msgBuf, int32_t msgBufLen, + int32_t colIdx, int32_t rowNum); +int32_t qBindStmtTagsValue2(void* pBlock, void* boundTags, int64_t suid, const char* sTableName, char* tName, + TAOS_STMT2_BIND* bind, char* msgBuf, int32_t msgBufLen); + void destroyBoundColumnInfo(void* pBoundInfo); int32_t qCreateSName(SName* pName, const char* pTableName, int32_t acctId, char* dbName, char* msgBuf, int32_t msgBufLen); void qDestroyBoundColInfo(void* pInfo); -int32_t smlInitHandle(SQuery** query); -int32_t smlBuildRow(STableDataCxt* pTableCxt); -int32_t smlBuildCol(STableDataCxt* pTableCxt, SSchema* schema, void* kv, int32_t index); -int32_t smlInitTableDataCtx(SQuery* query, STableMeta* pTableMeta, STableDataCxt** cxt); +int32_t smlInitHandle(SQuery** query); +int32_t smlBuildRow(STableDataCxt* pTableCxt); +int32_t smlBuildCol(STableDataCxt* pTableCxt, SSchema* schema, void* kv, int32_t index); +int32_t smlInitTableDataCtx(SQuery* query, STableMeta* pTableMeta, STableDataCxt** cxt); void clearColValArraySml(SArray* pCols); int32_t smlBindData(SQuery* handle, bool dataFormat, SArray* tags, SArray* colsSchema, SArray* cols, STableMeta* pTableMeta, char* tableName, const char* sTableName, int32_t sTableNameLen, int32_t ttl, char* msgBuf, int32_t msgBufLen); int32_t smlBuildOutput(SQuery* handle, SHashObj* pVgHash); -int rawBlockBindData(SQuery *query, STableMeta* pTableMeta, void* data, SVCreateTbReq** pCreateTb, TAOS_FIELD *fields, - int numFields, bool needChangeLength, char* errstr, int32_t errstrLen); +int rawBlockBindData(SQuery* query, STableMeta* pTableMeta, void* data, SVCreateTbReq** pCreateTb, TAOS_FIELD* fields, + int numFields, bool needChangeLength, char* errstr, int32_t errstrLen); int32_t rewriteToVnodeModifyOpStmt(SQuery* pQuery, SArray* pBufArray); int32_t serializeVgroupsCreateTableBatch(SHashObj* pVgroupHashmap, SArray** pOut); int32_t serializeVgroupsDropTableBatch(SHashObj* pVgroupHashmap, SArray** pOut); -void destoryCatalogReq(SCatalogReq *pCatalogReq); +void destoryCatalogReq(SCatalogReq* pCatalogReq); bool isPrimaryKeyImpl(SNode* pExpr); -int32_t insAppendStmtTableDataCxt(SHashObj* pAllVgHash, STableColsData* pTbData, STableDataCxt* pTbCtx, SStbInterlaceInfo* pBuildInfo); +int32_t insAppendStmtTableDataCxt(SHashObj* pAllVgHash, STableColsData* pTbData, STableDataCxt* pTbCtx, + SStbInterlaceInfo* pBuildInfo); #ifdef __cplusplus } diff --git a/source/client/inc/clientStmt2.h b/source/client/inc/clientStmt2.h new file mode 100644 index 0000000000..e54ac03c55 --- /dev/null +++ b/source/client/inc/clientStmt2.h @@ -0,0 +1,233 @@ +/* + * 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 . + */ + +#ifndef TDENGINE_CLIENTSTMT2_H +#define TDENGINE_CLIENTSTMT2_H + +#ifdef __cplusplus +extern "C" { +#endif +#include "catalog.h" +/* +typedef enum { +STMT_TYPE_INSERT = 1, +STMT_TYPE_MULTI_INSERT, +STMT_TYPE_QUERY, +} STMT_TYPE; + +typedef enum { +STMT_INIT = 1, +STMT_PREPARE, +STMT_SETTBNAME, +STMT_SETTAGS, +STMT_FETCH_FIELDS, +STMT_BIND, +STMT_BIND_COL, +STMT_ADD_BATCH, +STMT_EXECUTE, +STMT_MAX, +} STMT_STATUS; + +#define STMT_TABLE_COLS_NUM 1000 + +typedef struct SStmtTableCache { +STableDataCxt *pDataCtx; +void *boundTags; +} SStmtTableCache; + +typedef struct SStmtQueryResInfo { +TAOS_FIELD *fields; +TAOS_FIELD *userFields; +uint32_t numOfCols; +int32_t precision; +} SStmtQueryResInfo; + +typedef struct SStmtBindInfo { +bool needParse; +bool inExecCache; +uint64_t tbUid; +uint64_t tbSuid; +int32_t tbVgId; +int32_t sBindRowNum; +int32_t sBindLastIdx; +int8_t tbType; +bool tagsCached; +void *boundTags; +char tbName[TSDB_TABLE_FNAME_LEN]; +char tbFName[TSDB_TABLE_FNAME_LEN]; +char stbFName[TSDB_TABLE_FNAME_LEN]; +SName sname; + +char statbName[TSDB_TABLE_FNAME_LEN]; +} SStmtBindInfo; + +typedef struct SStmtAsyncParam { +STableColsData *pTbData; +void* pStmt; +} SStmtAsyncParam; + +typedef struct SStmtExecInfo { +int32_t affectedRows; +SRequestObj *pRequest; +SHashObj *pBlockHash; +STableDataCxt *pCurrBlock; +SSubmitTbData *pCurrTbData; +} SStmtExecInfo; +*/ +typedef struct { + bool stbInterlaceMode; + STMT_TYPE type; + STMT_STATUS status; + uint64_t suid; + uint64_t runTimes; + SHashObj *pTableCache; // SHash + SQuery *pQuery; + char *sqlStr; + int32_t sqlLen; + SArray *nodeList; + SStmtQueryResInfo queryRes; + bool autoCreateTbl; + SHashObj *pVgHash; + SBindInfo2 *pBindInfo; + + SStbInterlaceInfo siInfo; +} SStmtSQLInfo2; +/* +typedef struct SStmtStatInfo { +int64_t ctgGetTbMetaNum; +int64_t getCacheTbInfo; +int64_t parseSqlNum; +int64_t bindDataNum; +int64_t setTbNameUs; +int64_t bindDataUs1; +int64_t bindDataUs2; +int64_t bindDataUs3; +int64_t bindDataUs4; +int64_t addBatchUs; +int64_t execWaitUs; +int64_t execUseUs; +} SStmtStatInfo; + +typedef struct SStmtQNode { +bool restoreTbCols; +STableColsData tblData; +struct SStmtQNode* next; +} SStmtQNode; + +typedef struct SStmtQueue { +bool stopQueue; +SStmtQNode* head; +SStmtQNode* tail; +uint64_t qRemainNum; +} SStmtQueue; +*/ + +typedef struct { + STscObj *taos; + SCatalog *pCatalog; + int32_t affectedRows; + uint32_t seqId; + uint32_t seqIds[STMT_MAX]; + bool bindThreadInUse; + TdThread bindThread; + TAOS_STMT2_OPTION options; + bool stbInterlaceMode; + SStmtQueue queue; + + SStmtSQLInfo2 sql; + SStmtExecInfo exec; + SStmtBindInfo bInfo; + + int64_t reqid; + int32_t errCode; + + SStmtStatInfo stat; +} STscStmt2; +/* +extern char *gStmtStatusStr[]; + +#define STMT_LOG_SEQ(n) \ +do { \ + (pStmt)->seqId++; \ + (pStmt)->seqIds[n]++; \ + STMT_DLOG("the %dth:%d %s", (pStmt)->seqIds[n], (pStmt)->seqId, gStmtStatusStr[n]); \ +} while (0) + +#define STMT_STATUS_NE(S) (pStmt->sql.status != STMT_##S) +#define STMT_STATUS_EQ(S) (pStmt->sql.status == STMT_##S) + +#define STMT_ERR_RET(c) \ +do { \ + int32_t _code = c; \ + if (_code != TSDB_CODE_SUCCESS) { \ + terrno = _code; \ + pStmt->errCode = _code; \ + return _code; \ + } \ +} while (0) +#define STMT_RET(c) \ +do { \ + int32_t _code = c; \ + if (_code != TSDB_CODE_SUCCESS) { \ + terrno = _code; \ + pStmt->errCode = _code; \ + } \ + return _code; \ +} while (0) +#define STMT_ERR_JRET(c) \ +do { \ + code = c; \ + if (code != TSDB_CODE_SUCCESS) { \ + terrno = code; \ + pStmt->errCode = code; \ + goto _return; \ + } \ +} while (0) +#define STMT_ERRI_JRET(c) \ +do { \ + code = c; \ + if (code != TSDB_CODE_SUCCESS) { \ + terrno = code; \ + goto _return; \ + } \ +} while (0) + + +#define STMT_FLOG(param, ...) qFatal("stmt:%p " param, pStmt, __VA_ARGS__) +#define STMT_ELOG(param, ...) qError("stmt:%p " param, pStmt, __VA_ARGS__) +#define STMT_DLOG(param, ...) qDebug("stmt:%p " param, pStmt, __VA_ARGS__) + +#define STMT_ELOG_E(param) qError("stmt:%p " param, pStmt) +#define STMT_DLOG_E(param) qDebug("stmt:%p " param, pStmt) +*/ +TAOS_STMT2 *stmtInit2(STscObj *taos, TAOS_STMT2_OPTION *pOptions); +int stmtClose2(TAOS_STMT2 *stmt); +int stmtExec2(TAOS_STMT2 *stmt, int *affected_rows); +int stmtPrepare2(TAOS_STMT2 *stmt, const char *sql, unsigned long length); +int stmtSetTbName2(TAOS_STMT2 *stmt, const char *tbName); +int stmtSetTbTags2(TAOS_STMT2 *stmt, TAOS_STMT2_BIND *tags); +int stmtGetTagFields2(TAOS_STMT2 *stmt, int *nums, TAOS_FIELD_E **fields); +int stmtGetColFields2(TAOS_STMT2 *stmt, int *nums, TAOS_FIELD_E **fields); +int stmtIsInsert2(TAOS_STMT2 *stmt, int *insert); +int stmtGetParamNum2(TAOS_STMT2 *stmt, int *nums); +TAOS_RES *stmtUseResult2(TAOS_STMT2 *stmt); +int stmtBindBatch2(TAOS_STMT2 *stmt, TAOS_STMT2_BIND *bind, int32_t colIdx); +const char *stmtErrstr2(TAOS_STMT2 *stmt); + +#ifdef __cplusplus +} +#endif + +#endif // TDENGINE_CLIENTSTMT2_H diff --git a/source/client/src/clientMain.c b/source/client/src/clientMain.c index 12702a93f3..52895bb24b 100644 --- a/source/client/src/clientMain.c +++ b/source/client/src/clientMain.c @@ -16,19 +16,20 @@ #include "catalog.h" #include "clientInt.h" #include "clientLog.h" -#include "clientStmt.h" #include "clientMonitor.h" +#include "clientStmt.h" +#include "clientStmt2.h" #include "functionMgt.h" #include "os.h" #include "query.h" #include "scheduler.h" +#include "tcompare.h" #include "tdatablock.h" #include "tglobal.h" #include "tmsg.h" #include "tref.h" #include "trpc.h" #include "version.h" -#include "tcompare.h" #define TSC_VAR_NOT_RELEASE 1 #define TSC_VAR_RELEASED 0 @@ -124,7 +125,7 @@ TAOS *taos_connect(const char *ip, const char *user, const char *pass, const cha } STscObj *pObj = NULL; - int32_t code = taos_connect_internal(ip, user, pass, NULL, db, port, CONN_TYPE__QUERY, &pObj); + int32_t code = taos_connect_internal(ip, user, pass, NULL, db, port, CONN_TYPE__QUERY, &pObj); if (TSDB_CODE_SUCCESS == code) { int64_t *rid = taosMemoryCalloc(1, sizeof(int64_t)); if (NULL == rid) { @@ -187,15 +188,15 @@ int taos_set_notify_cb(TAOS *taos, __taos_notify_fn_t fp, void *param, int type) return 0; } -typedef struct SFetchWhiteListInfo{ - int64_t connId; +typedef struct SFetchWhiteListInfo { + int64_t connId; __taos_async_whitelist_fn_t userCbFn; - void* userParam; + void *userParam; } SFetchWhiteListInfo; -int32_t fetchWhiteListCallbackFn(void* param, SDataBuf* pMsg, int32_t code) { - SFetchWhiteListInfo* pInfo = (SFetchWhiteListInfo*)param; - TAOS* taos = &pInfo->connId; +int32_t fetchWhiteListCallbackFn(void *param, SDataBuf *pMsg, int32_t code) { + SFetchWhiteListInfo *pInfo = (SFetchWhiteListInfo *)param; + TAOS *taos = &pInfo->connId; if (code != TSDB_CODE_SUCCESS) { pInfo->userCbFn(pInfo->userParam, code, taos, 0, NULL); taosMemoryFree(pMsg->pData); @@ -213,7 +214,7 @@ int32_t fetchWhiteListCallbackFn(void* param, SDataBuf* pMsg, int32_t code) { return terrno; } - uint64_t* pWhiteLists = taosMemoryMalloc(wlRsp.numWhiteLists * sizeof(uint64_t)); + uint64_t *pWhiteLists = taosMemoryMalloc(wlRsp.numWhiteLists * sizeof(uint64_t)); if (pWhiteLists == NULL) { taosMemoryFree(pMsg->pData); taosMemoryFree(pMsg->pEpSet); @@ -242,7 +243,7 @@ void taos_fetch_whitelist_a(TAOS *taos, __taos_async_whitelist_fn_t fp, void *pa return; } - int64_t connId = *(int64_t*)taos; + int64_t connId = *(int64_t *)taos; STscObj *pTsc = acquireTscObj(connId); if (NULL == pTsc) { @@ -259,7 +260,7 @@ void taos_fetch_whitelist_a(TAOS *taos, __taos_async_whitelist_fn_t fp, void *pa return; } - void* pReq = taosMemoryMalloc(msgLen); + void *pReq = taosMemoryMalloc(msgLen); if (pReq == NULL) { fp(param, TSDB_CODE_OUT_OF_MEMORY, taos, 0, NULL); releaseTscObj(connId); @@ -273,7 +274,7 @@ void taos_fetch_whitelist_a(TAOS *taos, __taos_async_whitelist_fn_t fp, void *pa return; } - SFetchWhiteListInfo* pParam = taosMemoryMalloc(sizeof(SFetchWhiteListInfo)); + SFetchWhiteListInfo *pParam = taosMemoryMalloc(sizeof(SFetchWhiteListInfo)); if (pParam == NULL) { fp(param, TSDB_CODE_OUT_OF_MEMORY, taos, 0, NULL); taosMemoryFree(pReq); @@ -284,9 +285,9 @@ void taos_fetch_whitelist_a(TAOS *taos, __taos_async_whitelist_fn_t fp, void *pa pParam->connId = connId; pParam->userCbFn = fp; pParam->userParam = param; - SMsgSendInfo* pSendInfo = taosMemoryCalloc(1, sizeof(SMsgSendInfo)); + SMsgSendInfo *pSendInfo = taosMemoryCalloc(1, sizeof(SMsgSendInfo)); if (pSendInfo == NULL) { - fp(param, TSDB_CODE_OUT_OF_MEMORY, taos, 0, NULL); + fp(param, TSDB_CODE_OUT_OF_MEMORY, taos, 0, NULL); taosMemoryFree(pParam); taosMemoryFree(pReq); releaseTscObj(connId); @@ -301,7 +302,7 @@ void taos_fetch_whitelist_a(TAOS *taos, __taos_async_whitelist_fn_t fp, void *pa pSendInfo->msgType = TDMT_MND_GET_USER_WHITELIST; int64_t transportId = 0; - SEpSet epSet = getEpSet_s(&pTsc->pAppInfo->mgmtEp); + SEpSet epSet = getEpSet_s(&pTsc->pAppInfo->mgmtEp); if (TSDB_CODE_SUCCESS != asyncSendMsgToServer(pTsc->pAppInfo->pTransporter, &epSet, &transportId, pSendInfo)) { tscWarn("failed to async send msg to server"); } @@ -447,7 +448,7 @@ TAOS_ROW taos_fetch_row(TAOS_RES *res) { return NULL; } - if(pRequest->inCallback) { + if (pRequest->inCallback) { tscError("can not call taos_fetch_row before query callback ends."); terrno = TSDB_CODE_TSC_INVALID_OPERATION; return NULL; @@ -458,7 +459,7 @@ TAOS_ROW taos_fetch_row(TAOS_RES *res) { SMqRspObj *msg = ((SMqRspObj *)res); SReqResultInfo *pResultInfo = NULL; if (msg->common.resIter == -1) { - if(tmqGetNextResInfo(res, true, &pResultInfo) != 0){ + if (tmqGetNextResInfo(res, true, &pResultInfo) != 0) { return NULL; } } else { @@ -470,7 +471,7 @@ TAOS_ROW taos_fetch_row(TAOS_RES *res) { pResultInfo->current += 1; return pResultInfo->row; } else { - if (tmqGetNextResInfo(res, true, &pResultInfo) != 0){ + if (tmqGetNextResInfo(res, true, &pResultInfo) != 0) { return NULL; } @@ -545,22 +546,23 @@ int taos_print_row(char *str, TAOS_ROW row, TAOS_FIELD *fields, int num_fields) len += sprintf(str + len, "%lf", dv); } break; - case TSDB_DATA_TYPE_VARBINARY:{ - void* data = NULL; + case TSDB_DATA_TYPE_VARBINARY: { + void *data = NULL; uint32_t size = 0; - int32_t charLen = varDataLen((char *)row[i] - VARSTR_HEADER_SIZE); - if(taosAscii2Hex(row[i], charLen, &data, &size) < 0){ + int32_t charLen = varDataLen((char *)row[i] - VARSTR_HEADER_SIZE); + if (taosAscii2Hex(row[i], charLen, &data, &size) < 0) { break; } (void)memcpy(str + len, data, size); len += size; taosMemoryFree(data); - }break; + } break; case TSDB_DATA_TYPE_BINARY: case TSDB_DATA_TYPE_NCHAR: case TSDB_DATA_TYPE_GEOMETRY: { int32_t charLen = varDataLen((char *)row[i] - VARSTR_HEADER_SIZE); - if (fields[i].type == TSDB_DATA_TYPE_BINARY || fields[i].type == TSDB_DATA_TYPE_VARBINARY || fields[i].type == TSDB_DATA_TYPE_GEOMETRY) { + if (fields[i].type == TSDB_DATA_TYPE_BINARY || fields[i].type == TSDB_DATA_TYPE_VARBINARY || + fields[i].type == TSDB_DATA_TYPE_GEOMETRY) { if (ASSERT(charLen <= fields[i].bytes && charLen >= 0)) { tscError("taos_print_row error binary. charLen:%d, fields[i].bytes:%d", charLen, fields[i].bytes); } @@ -667,7 +669,8 @@ const char *taos_get_client_info() { return version; } // return int32_t int taos_affected_rows(TAOS_RES *res) { - if (res == NULL || TD_RES_TMQ(res) || TD_RES_TMQ_META(res) || TD_RES_TMQ_METADATA(res) || TD_RES_TMQ_BATCH_META(res)) { + if (res == NULL || TD_RES_TMQ(res) || TD_RES_TMQ_META(res) || TD_RES_TMQ_METADATA(res) || + TD_RES_TMQ_BATCH_META(res)) { return 0; } @@ -678,7 +681,8 @@ int taos_affected_rows(TAOS_RES *res) { // return int64_t int64_t taos_affected_rows64(TAOS_RES *res) { - if (res == NULL || TD_RES_TMQ(res) || TD_RES_TMQ_META(res) || TD_RES_TMQ_METADATA(res) || TD_RES_TMQ_BATCH_META(res)) { + if (res == NULL || TD_RES_TMQ(res) || TD_RES_TMQ_META(res) || TD_RES_TMQ_METADATA(res) || + TD_RES_TMQ_BATCH_META(res)) { return 0; } @@ -728,7 +732,8 @@ int taos_select_db(TAOS *taos, const char *db) { } void taos_stop_query(TAOS_RES *res) { - if (res == NULL || TD_RES_TMQ(res) || TD_RES_TMQ_META(res) || TD_RES_TMQ_METADATA(res) || TD_RES_TMQ_BATCH_META(res)) { + if (res == NULL || TD_RES_TMQ(res) || TD_RES_TMQ_META(res) || TD_RES_TMQ_METADATA(res) || + TD_RES_TMQ_BATCH_META(res)) { return; } @@ -787,7 +792,7 @@ int taos_fetch_block_s(TAOS_RES *res, int *numOfRows, TAOS_ROW *rows) { return pRequest->code; } else if (TD_RES_TMQ(res) || TD_RES_TMQ_METADATA(res)) { SReqResultInfo *pResultInfo = NULL; - int32_t code = tmqGetNextResInfo(res, true, &pResultInfo); + int32_t code = tmqGetNextResInfo(res, true, &pResultInfo); if (code != 0) return code; pResultInfo->current = pResultInfo->numOfRows; @@ -810,7 +815,7 @@ int taos_fetch_raw_block(TAOS_RES *res, int *numOfRows, void **pData) { if (TD_RES_TMQ(res) || TD_RES_TMQ_METADATA(res)) { SReqResultInfo *pResultInfo = NULL; - int32_t code = tmqGetNextResInfo(res, false, &pResultInfo); + int32_t code = tmqGetNextResInfo(res, false, &pResultInfo); if (code != 0) { (*numOfRows) = 0; return 0; @@ -956,7 +961,7 @@ static void doAsyncQueryFromAnalyse(SMetaData *pResultMeta, void *param, int32_t (void)memcpy(&pRequest->parseMeta, pResultMeta, sizeof(*pResultMeta)); (void)memset(pResultMeta, 0, sizeof(*pResultMeta)); } - + handleQueryAnslyseRes(pWrapper, pResultMeta, code); } @@ -1002,7 +1007,7 @@ void handleSubQueryFromAnalyse(SSqlCallbackWrapper *pWrapper, SMetaData *pResult } pNewRequest->pQuery = NULL; - code = nodesMakeNode(QUERY_NODE_QUERY, (SNode**)&pNewRequest->pQuery); + code = nodesMakeNode(QUERY_NODE_QUERY, (SNode **)&pNewRequest->pQuery); if (pNewRequest->pQuery) { pNewRequest->pQuery->pRoot = pRoot; pRoot = NULL; @@ -1274,7 +1279,7 @@ void doAsyncQuery(SRequestObj *pRequest, bool updateMetaForce) { if (NEED_CLIENT_HANDLE_ERROR(code)) { tscDebug("0x%" PRIx64 " client retry to handle the error, code:%d - %s, tryCount:%d, reqId:0x%" PRIx64, pRequest->self, code, tstrerror(code), pRequest->retry, pRequest->requestId); - (void)refreshMeta(pRequest->pTscObj, pRequest); //ignore return code,try again + (void)refreshMeta(pRequest->pTscObj, pRequest); // ignore return code,try again pRequest->prevCode = code; doAsyncQuery(pRequest, true); return; @@ -1288,7 +1293,7 @@ void doAsyncQuery(SRequestObj *pRequest, bool updateMetaForce) { void restartAsyncQuery(SRequestObj *pRequest, int32_t code) { tscInfo("restart request: %s p: %p", pRequest->sqlstr, pRequest); - SRequestObj* pUserReq = pRequest; + SRequestObj *pUserReq = pRequest; (void)acquireRequest(pRequest->self); while (pUserReq) { if (pUserReq->self == pUserReq->relation.userRefId || pUserReq->relation.userRefId == 0) { @@ -1634,7 +1639,6 @@ TAOS_STMT *taos_stmt_init_with_options(TAOS *taos, TAOS_STMT_OPTIONS *options) { return pStmt; } - int taos_stmt_prepare(TAOS_STMT *stmt, const char *sql, unsigned long length) { if (stmt == NULL || sql == NULL) { tscError("NULL parameter for %s", __FUNCTION__); @@ -1877,7 +1881,161 @@ int taos_stmt_close(TAOS_STMT *stmt) { return stmtClose(stmt); } -int taos_set_conn_mode(TAOS* taos, int mode, int value) { +TAOS_STMT2 *taos_stmt2_init(TAOS *taos, TAOS_STMT2_OPTION *option) { + STscObj *pObj = acquireTscObj(*(int64_t *)taos); + if (NULL == pObj) { + tscError("invalid parameter for %s", __FUNCTION__); + terrno = TSDB_CODE_TSC_DISCONNECTED; + return NULL; + } + + TAOS_STMT2 *pStmt = stmtInit2(pObj, option); + + releaseTscObj(*(int64_t *)taos); + + return pStmt; +} + +int taos_stmt2_prepare(TAOS_STMT2 *stmt, const char *sql, unsigned long length) { + if (stmt == NULL || sql == NULL) { + tscError("NULL parameter for %s", __FUNCTION__); + terrno = TSDB_CODE_INVALID_PARA; + return terrno; + } + + return stmtPrepare2(stmt, sql, length); +} + +int taos_stmt2_bind_param(TAOS_STMT2 *stmt, TAOS_STMT2_BINDV *bindv, int32_t col_idx) { + if (stmt == NULL) { + tscError("NULL parameter for %s", __FUNCTION__); + terrno = TSDB_CODE_INVALID_PARA; + return terrno; + } + + int32_t code = 0; + for (int i = 0; i < bindv->count; ++i) { + char *tbname = bindv->tbnames[i]; + TAOS_STMT2_BIND *tags = bindv->tags[i]; + TAOS_STMT2_BIND *bind = bindv->bind_cols[i]; + + if (tbname) { + code = stmtSetTbName2(stmt, tbname); + if (code) { + return code; + } + } + + if (tags) { + code = stmtSetTbTags2(stmt, tags); + if (code) { + return code; + } + } + + if (bind) { + if (bind->num <= 0 || bind->num > INT16_MAX) { + tscError("invalid bind num %d", bind->num); + terrno = TSDB_CODE_INVALID_PARA; + return terrno; + } + + int32_t insert = 0; + (void)stmtIsInsert(stmt, &insert); + if (0 == insert && bind->num > 1) { + tscError("only one row data allowed for query"); + terrno = TSDB_CODE_INVALID_PARA; + return terrno; + } + + code = stmtBindBatch2(stmt, bind, col_idx); + if (TSDB_CODE_SUCCESS != code) { + return code; + } + } + } + + return TSDB_CODE_SUCCESS; +} + +int taos_stmt2_exec(TAOS_STMT2 *stmt, int *affected_rows) { + if (stmt == NULL) { + tscError("NULL parameter for %s", __FUNCTION__); + terrno = TSDB_CODE_INVALID_PARA; + return terrno; + } + + return stmtExec2(stmt, affected_rows); +} + +int taos_stmt2_close(TAOS_STMT2 *stmt) { + if (stmt == NULL) { + tscError("NULL parameter for %s", __FUNCTION__); + terrno = TSDB_CODE_INVALID_PARA; + return terrno; + } + + return stmtClose2(stmt); +} +/* +int taos_stmt2_param_count(TAOS_STMT2 *stmt, int *nums) { + if (stmt == NULL || nums == NULL) { + tscError("NULL parameter for %s", __FUNCTION__); + terrno = TSDB_CODE_INVALID_PARA; + return terrno; + } + return stmtGetParamNum2(stmt, nums); +} +*/ +int taos_stmt2_is_insert(TAOS_STMT2 *stmt, int *insert) { + if (stmt == NULL || insert == NULL) { + tscError("NULL parameter for %s", __FUNCTION__); + terrno = TSDB_CODE_INVALID_PARA; + return terrno; + } + + return stmtIsInsert2(stmt, insert); +} + +int taos_stmt2_get_fields(TAOS_STMT2 *stmt, TAOS_FIELD_T field_type, int *count, TAOS_FIELD_E **fields) { + if (stmt == NULL || NULL == count) { + tscError("NULL parameter for %s", __FUNCTION__); + terrno = TSDB_CODE_INVALID_PARA; + return terrno; + } + + if (field_type == TAOS_FIELD_COL) { + return stmtGetColFields2(stmt, count, fields); + } else if (field_type == TAOS_FIELD_TAG) { + return stmtGetTagFields2(stmt, count, fields); + } else if (field_type == TAOS_FIELD_QUERY) { + return stmtGetParamNum2(stmt, count); + } else { + tscError("invalid parameter for %s", __FUNCTION__); + terrno = TSDB_CODE_INVALID_PARA; + return terrno; + } +} + +void taos_stmt2_free_fields(TAOS_STMT2 *stmt, TAOS_FIELD_E *fields) { + (void)stmt; + if (!fields) return; + taosMemoryFree(fields); +} + +TAOS_RES *taos_stmt2_result(TAOS_STMT2 *stmt) { + if (stmt == NULL) { + tscError("NULL parameter for %s", __FUNCTION__); + terrno = TSDB_CODE_INVALID_PARA; + return NULL; + } + + return stmtUseResult2(stmt); +} + +char *taos_stmt2_error(TAOS_STMT2 *stmt) { return (char *)stmtErrstr2(stmt); } + +int taos_set_conn_mode(TAOS *taos, int mode, int value) { if (taos == NULL) { terrno = TSDB_CODE_INVALID_PARA; return terrno; @@ -1900,6 +2058,4 @@ int taos_set_conn_mode(TAOS* taos, int mode, int value) { return 0; } -char* getBuildInfo(){ - return buildinfo; -} +char *getBuildInfo() { return buildinfo; } diff --git a/source/client/src/clientStmt2.c b/source/client/src/clientStmt2.c new file mode 100644 index 0000000000..5f7abefa85 --- /dev/null +++ b/source/client/src/clientStmt2.c @@ -0,0 +1,1895 @@ +#include "clientInt.h" +#include "clientLog.h" +#include "tdef.h" + +#include "clientStmt.h" +#include "clientStmt2.h" +/* +char* gStmtStatusStr[] = {"unknown", "init", "prepare", "settbname", "settags", + "fetchFields", "bind", "bindCol", "addBatch", "exec"}; +*/ +static FORCE_INLINE int32_t stmtAllocQNodeFromBuf(STableBufInfo* pTblBuf, void** pBuf) { + if (pTblBuf->buffOffset < pTblBuf->buffSize) { + *pBuf = (char*)pTblBuf->pCurBuff + pTblBuf->buffOffset; + pTblBuf->buffOffset += pTblBuf->buffUnit; + } else if (pTblBuf->buffIdx < taosArrayGetSize(pTblBuf->pBufList)) { + pTblBuf->pCurBuff = taosArrayGetP(pTblBuf->pBufList, pTblBuf->buffIdx++); + if (NULL == pTblBuf->pCurBuff) { + return TAOS_GET_TERRNO(TSDB_CODE_OUT_OF_MEMORY); + } + *pBuf = pTblBuf->pCurBuff; + pTblBuf->buffOffset = pTblBuf->buffUnit; + } else { + void* buff = taosMemoryMalloc(pTblBuf->buffSize); + if (NULL == buff) { + return terrno; + } + + if (taosArrayPush(pTblBuf->pBufList, &buff) == NULL) { + return terrno; + } + + pTblBuf->buffIdx++; + pTblBuf->pCurBuff = buff; + *pBuf = buff; + pTblBuf->buffOffset = pTblBuf->buffUnit; + } + + return TSDB_CODE_SUCCESS; +} + +static bool stmtDequeue(STscStmt2* pStmt, SStmtQNode** param) { + while (0 == atomic_load_64(&pStmt->queue.qRemainNum)) { + taosUsleep(1); + return false; + } + + SStmtQNode* orig = pStmt->queue.head; + + SStmtQNode* node = pStmt->queue.head->next; + pStmt->queue.head = pStmt->queue.head->next; + + // taosMemoryFreeClear(orig); + + *param = node; + + (void)atomic_sub_fetch_64(&pStmt->queue.qRemainNum, 1); + + return true; +} + +static void stmtEnqueue(STscStmt2* pStmt, SStmtQNode* param) { + pStmt->queue.tail->next = param; + pStmt->queue.tail = param; + + pStmt->stat.bindDataNum++; + (void)atomic_add_fetch_64(&pStmt->queue.qRemainNum, 1); +} + +static int32_t stmtCreateRequest(STscStmt2* pStmt) { + int32_t code = 0; + + if (pStmt->exec.pRequest == NULL) { + code = buildRequest(pStmt->taos->id, pStmt->sql.sqlStr, pStmt->sql.sqlLen, NULL, false, &pStmt->exec.pRequest, + pStmt->reqid); + if (pStmt->reqid != 0) { + pStmt->reqid++; + } + if (TSDB_CODE_SUCCESS == code) { + pStmt->exec.pRequest->syncQuery = true; + pStmt->exec.pRequest->isStmtBind = true; + } + } + + return code; +} + +static int32_t stmtSwitchStatus(STscStmt2* pStmt, STMT_STATUS newStatus) { + int32_t code = 0; + + if (newStatus >= STMT_INIT && newStatus < STMT_MAX) { + STMT_LOG_SEQ(newStatus); + } + + if (pStmt->errCode && newStatus != STMT_PREPARE) { + STMT_DLOG("stmt already failed with err: %s", tstrerror(pStmt->errCode)); + return pStmt->errCode; + } + + switch (newStatus) { + case STMT_PREPARE: + pStmt->errCode = 0; + break; + case STMT_SETTBNAME: + if (STMT_STATUS_EQ(INIT)) { + code = TSDB_CODE_TSC_STMT_API_ERROR; + } + if (!pStmt->sql.stbInterlaceMode && (STMT_STATUS_EQ(BIND) || STMT_STATUS_EQ(BIND_COL))) { + code = TSDB_CODE_TSC_STMT_API_ERROR; + } + break; + case STMT_SETTAGS: + if (STMT_STATUS_NE(SETTBNAME) && STMT_STATUS_NE(FETCH_FIELDS)) { + code = TSDB_CODE_TSC_STMT_API_ERROR; + } + break; + case STMT_FETCH_FIELDS: + if (STMT_STATUS_EQ(INIT)) { + code = TSDB_CODE_TSC_STMT_API_ERROR; + } + break; + case STMT_BIND: + if (STMT_STATUS_EQ(INIT) || STMT_STATUS_EQ(BIND_COL)) { + code = TSDB_CODE_TSC_STMT_API_ERROR; + } + /* + if ((pStmt->sql.type == STMT_TYPE_MULTI_INSERT) && ()) { + code = TSDB_CODE_TSC_STMT_API_ERROR; + } + */ + break; + case STMT_BIND_COL: + if (STMT_STATUS_EQ(INIT) || STMT_STATUS_EQ(BIND)) { + code = TSDB_CODE_TSC_STMT_API_ERROR; + } + break; + case STMT_ADD_BATCH: + if (STMT_STATUS_NE(BIND) && STMT_STATUS_NE(BIND_COL) && STMT_STATUS_NE(FETCH_FIELDS)) { + code = TSDB_CODE_TSC_STMT_API_ERROR; + } + break; + case STMT_EXECUTE: + if (STMT_TYPE_QUERY == pStmt->sql.type) { + if (STMT_STATUS_NE(ADD_BATCH) && STMT_STATUS_NE(FETCH_FIELDS) && STMT_STATUS_NE(BIND) && + STMT_STATUS_NE(BIND_COL)) { + code = TSDB_CODE_TSC_STMT_API_ERROR; + } + } else { + if (STMT_STATUS_NE(ADD_BATCH) && STMT_STATUS_NE(FETCH_FIELDS)) { + code = TSDB_CODE_TSC_STMT_API_ERROR; + } + } + break; + default: + code = TSDB_CODE_APP_ERROR; + break; + } + + STMT_ERR_RET(code); + + pStmt->sql.status = newStatus; + + return TSDB_CODE_SUCCESS; +} + +static int32_t stmtGetTbName(TAOS_STMT2* stmt, char** tbName) { + STscStmt2* pStmt = (STscStmt2*)stmt; + + pStmt->sql.type = STMT_TYPE_MULTI_INSERT; + + if ('\0' == pStmt->bInfo.tbName[0]) { + tscError("no table name set"); + STMT_ERR_RET(TSDB_CODE_TSC_STMT_TBNAME_ERROR); + } + + *tbName = pStmt->bInfo.tbName; + + return TSDB_CODE_SUCCESS; +} + +static int32_t stmtBackupQueryFields(STscStmt2* pStmt) { + SStmtQueryResInfo* pRes = &pStmt->sql.queryRes; + pRes->numOfCols = pStmt->exec.pRequest->body.resInfo.numOfCols; + pRes->precision = pStmt->exec.pRequest->body.resInfo.precision; + + int32_t size = pRes->numOfCols * sizeof(TAOS_FIELD); + pRes->fields = taosMemoryMalloc(size); + pRes->userFields = taosMemoryMalloc(size); + if (NULL == pRes->fields || NULL == pRes->userFields) { + STMT_ERR_RET(TSDB_CODE_OUT_OF_MEMORY); + } + (void)memcpy(pRes->fields, pStmt->exec.pRequest->body.resInfo.fields, size); + (void)memcpy(pRes->userFields, pStmt->exec.pRequest->body.resInfo.userFields, size); + + return TSDB_CODE_SUCCESS; +} + +static int32_t stmtRestoreQueryFields(STscStmt2* pStmt) { + SStmtQueryResInfo* pRes = &pStmt->sql.queryRes; + int32_t size = pRes->numOfCols * sizeof(TAOS_FIELD); + + pStmt->exec.pRequest->body.resInfo.numOfCols = pRes->numOfCols; + pStmt->exec.pRequest->body.resInfo.precision = pRes->precision; + + if (NULL == pStmt->exec.pRequest->body.resInfo.fields) { + pStmt->exec.pRequest->body.resInfo.fields = taosMemoryMalloc(size); + if (NULL == pStmt->exec.pRequest->body.resInfo.fields) { + STMT_ERR_RET(TSDB_CODE_OUT_OF_MEMORY); + } + (void)memcpy(pStmt->exec.pRequest->body.resInfo.fields, pRes->fields, size); + } + + if (NULL == pStmt->exec.pRequest->body.resInfo.userFields) { + pStmt->exec.pRequest->body.resInfo.userFields = taosMemoryMalloc(size); + if (NULL == pStmt->exec.pRequest->body.resInfo.userFields) { + STMT_ERR_RET(TSDB_CODE_OUT_OF_MEMORY); + } + (void)memcpy(pStmt->exec.pRequest->body.resInfo.userFields, pRes->userFields, size); + } + + return TSDB_CODE_SUCCESS; +} + +static int32_t stmtUpdateBindInfo(TAOS_STMT2* stmt, STableMeta* pTableMeta, void* tags, SName* tbName, + const char* sTableName, bool autoCreateTbl) { + STscStmt2* pStmt = (STscStmt2*)stmt; + char tbFName[TSDB_TABLE_FNAME_LEN]; + int32_t code = tNameExtractFullName(tbName, tbFName); + if (code != 0) { + return code; + } + + (void)memcpy(&pStmt->bInfo.sname, tbName, sizeof(*tbName)); + (void)strncpy(pStmt->bInfo.tbFName, tbFName, sizeof(pStmt->bInfo.tbFName) - 1); + pStmt->bInfo.tbFName[sizeof(pStmt->bInfo.tbFName) - 1] = 0; + + pStmt->bInfo.tbUid = autoCreateTbl ? 0 : pTableMeta->uid; + pStmt->bInfo.tbSuid = pTableMeta->suid; + pStmt->bInfo.tbVgId = pTableMeta->vgId; + pStmt->bInfo.tbType = pTableMeta->tableType; + pStmt->bInfo.boundTags = tags; + pStmt->bInfo.tagsCached = false; + tstrncpy(pStmt->bInfo.stbFName, sTableName, sizeof(pStmt->bInfo.stbFName)); + + return TSDB_CODE_SUCCESS; +} + +static int32_t stmtUpdateExecInfo(TAOS_STMT2* stmt, SHashObj* pVgHash, SHashObj* pBlockHash) { + STscStmt2* pStmt = (STscStmt2*)stmt; + + pStmt->sql.pVgHash = pVgHash; + pStmt->exec.pBlockHash = pBlockHash; + + return TSDB_CODE_SUCCESS; +} + +static int32_t stmtUpdateInfo(TAOS_STMT2* stmt, STableMeta* pTableMeta, void* tags, SName* tbName, bool autoCreateTbl, + SHashObj* pVgHash, SHashObj* pBlockHash, const char* sTableName) { + STscStmt2* pStmt = (STscStmt2*)stmt; + + STMT_ERR_RET(stmtUpdateBindInfo(stmt, pTableMeta, tags, tbName, sTableName, autoCreateTbl)); + STMT_ERR_RET(stmtUpdateExecInfo(stmt, pVgHash, pBlockHash)); + + pStmt->sql.autoCreateTbl = autoCreateTbl; + if (pStmt->sql.autoCreateTbl) { + pStmt->sql.stbInterlaceMode = false; + } + + return TSDB_CODE_SUCCESS; +} + +static int32_t stmtGetExecInfo(TAOS_STMT2* stmt, SHashObj** pVgHash, SHashObj** pBlockHash) { + STscStmt2* pStmt = (STscStmt2*)stmt; + + *pVgHash = pStmt->sql.pVgHash; + pStmt->sql.pVgHash = NULL; + + *pBlockHash = pStmt->exec.pBlockHash; + pStmt->exec.pBlockHash = NULL; + + return TSDB_CODE_SUCCESS; +} + +static int32_t stmtCacheBlock(STscStmt2* pStmt) { + if (pStmt->sql.type != STMT_TYPE_MULTI_INSERT) { + return TSDB_CODE_SUCCESS; + } + + uint64_t uid = pStmt->bInfo.tbUid; + uint64_t cacheUid = (TSDB_CHILD_TABLE == pStmt->bInfo.tbType) ? pStmt->bInfo.tbSuid : uid; + + if (taosHashGet(pStmt->sql.pTableCache, &cacheUid, sizeof(cacheUid))) { + return TSDB_CODE_SUCCESS; + } + + STableDataCxt** pSrc = taosHashGet(pStmt->exec.pBlockHash, pStmt->bInfo.tbFName, strlen(pStmt->bInfo.tbFName)); + if (!pSrc) { + return TSDB_CODE_OUT_OF_MEMORY; + } + STableDataCxt* pDst = NULL; + + STMT_ERR_RET(qCloneStmtDataBlock(&pDst, *pSrc, true)); + + SStmtTableCache cache = { + .pDataCtx = pDst, + .boundTags = pStmt->bInfo.boundTags, + }; + + if (taosHashPut(pStmt->sql.pTableCache, &cacheUid, sizeof(cacheUid), &cache, sizeof(cache))) { + return TSDB_CODE_OUT_OF_MEMORY; + } + + if (pStmt->sql.autoCreateTbl) { + pStmt->bInfo.tagsCached = true; + } else { + pStmt->bInfo.boundTags = NULL; + } + + return TSDB_CODE_SUCCESS; +} + +static int32_t stmtParseSql(STscStmt2* pStmt) { + pStmt->exec.pCurrBlock = NULL; + + SStmtCallback stmtCb = { + .pStmt = pStmt, + .getTbNameFn = stmtGetTbName, + .setInfoFn = stmtUpdateInfo, + .getExecInfoFn = stmtGetExecInfo, + }; + + STMT_ERR_RET(stmtCreateRequest(pStmt)); + + pStmt->stat.parseSqlNum++; + STMT_ERR_RET(parseSql(pStmt->exec.pRequest, false, &pStmt->sql.pQuery, &stmtCb)); + pStmt->sql.siInfo.pQuery = pStmt->sql.pQuery; + + pStmt->bInfo.needParse = false; + + if (pStmt->sql.pQuery->pRoot && 0 == pStmt->sql.type) { + pStmt->sql.type = STMT_TYPE_INSERT; + pStmt->sql.stbInterlaceMode = false; + } else if (pStmt->sql.pQuery->pPrepareRoot) { + pStmt->sql.type = STMT_TYPE_QUERY; + pStmt->sql.stbInterlaceMode = false; + + return TSDB_CODE_SUCCESS; + } + + STableDataCxt** pSrc = + (STableDataCxt**)taosHashGet(pStmt->exec.pBlockHash, pStmt->bInfo.tbFName, strlen(pStmt->bInfo.tbFName)); + if (NULL == pSrc || NULL == *pSrc) { + return TSDB_CODE_OUT_OF_MEMORY; + } + + STableDataCxt* pTableCtx = *pSrc; + if (pStmt->sql.stbInterlaceMode) { + int16_t lastIdx = -1; + + for (int32_t i = 0; i < pTableCtx->boundColsInfo.numOfBound; ++i) { + if (pTableCtx->boundColsInfo.pColIndex[i] < lastIdx) { + pStmt->sql.stbInterlaceMode = false; + break; + } + + lastIdx = pTableCtx->boundColsInfo.pColIndex[i]; + } + } + + if (NULL == pStmt->sql.pBindInfo) { + pStmt->sql.pBindInfo = taosMemoryMalloc(pTableCtx->boundColsInfo.numOfBound * sizeof(*pStmt->sql.pBindInfo)); + if (NULL == pStmt->sql.pBindInfo) { + return TSDB_CODE_OUT_OF_MEMORY; + } + } + + return TSDB_CODE_SUCCESS; +} + +static int32_t stmtCleanBindInfo(STscStmt2* pStmt) { + pStmt->bInfo.tbUid = 0; + pStmt->bInfo.tbSuid = 0; + pStmt->bInfo.tbVgId = -1; + pStmt->bInfo.tbType = 0; + pStmt->bInfo.needParse = true; + pStmt->bInfo.inExecCache = false; + + pStmt->bInfo.tbName[0] = 0; + pStmt->bInfo.tbFName[0] = 0; + if (!pStmt->bInfo.tagsCached) { + qDestroyBoundColInfo(pStmt->bInfo.boundTags); + taosMemoryFreeClear(pStmt->bInfo.boundTags); + } + pStmt->bInfo.stbFName[0] = 0; + + return TSDB_CODE_SUCCESS; +} + +static void stmtFreeTableBlkList(STableColsData* pTb) { + (void)qResetStmtColumns(pTb->aCol, true); + taosArrayDestroy(pTb->aCol); +} + +static void stmtResetQueueTableBuf(STableBufInfo* pTblBuf, SStmtQueue* pQueue) { + pTblBuf->pCurBuff = taosArrayGetP(pTblBuf->pBufList, 0); + if (NULL == pTblBuf->pCurBuff) { + tscError("QInfo:%p, failed to get buffer from list", pTblBuf); + return; + } + pTblBuf->buffIdx = 1; + pTblBuf->buffOffset = sizeof(*pQueue->head); + + pQueue->head = pQueue->tail = pTblBuf->pCurBuff; + pQueue->qRemainNum = 0; + pQueue->head->next = NULL; +} + +static int32_t stmtCleanExecInfo(STscStmt2* pStmt, bool keepTable, bool deepClean) { + if (pStmt->sql.stbInterlaceMode) { + if (deepClean) { + taosHashCleanup(pStmt->exec.pBlockHash); + pStmt->exec.pBlockHash = NULL; + + if (NULL != pStmt->exec.pCurrBlock) { + taosMemoryFreeClear(pStmt->exec.pCurrBlock->pData); + qDestroyStmtDataBlock(pStmt->exec.pCurrBlock); + } + } else { + pStmt->sql.siInfo.pTableColsIdx = 0; + stmtResetQueueTableBuf(&pStmt->sql.siInfo.tbBuf, &pStmt->queue); + } + } else { + if (STMT_TYPE_QUERY != pStmt->sql.type || deepClean) { + taos_free_result(pStmt->exec.pRequest); + pStmt->exec.pRequest = NULL; + } + + size_t keyLen = 0; + void* pIter = taosHashIterate(pStmt->exec.pBlockHash, NULL); + while (pIter) { + STableDataCxt* pBlocks = *(STableDataCxt**)pIter; + char* key = taosHashGetKey(pIter, &keyLen); + STableMeta* pMeta = qGetTableMetaInDataBlock(pBlocks); + + if (keepTable && pBlocks == pStmt->exec.pCurrBlock) { + TSWAP(pBlocks->pData, pStmt->exec.pCurrTbData); + STMT_ERR_RET(qResetStmtDataBlock(pBlocks, false)); + + pIter = taosHashIterate(pStmt->exec.pBlockHash, pIter); + continue; + } + + qDestroyStmtDataBlock(pBlocks); + STMT_ERR_RET(taosHashRemove(pStmt->exec.pBlockHash, key, keyLen)); + + pIter = taosHashIterate(pStmt->exec.pBlockHash, pIter); + } + + if (keepTable) { + return TSDB_CODE_SUCCESS; + } + + taosHashCleanup(pStmt->exec.pBlockHash); + pStmt->exec.pBlockHash = NULL; + + tDestroySubmitTbData(pStmt->exec.pCurrTbData, TSDB_MSG_FLG_ENCODE); + taosMemoryFreeClear(pStmt->exec.pCurrTbData); + } + + STMT_ERR_RET(stmtCleanBindInfo(pStmt)); + + return TSDB_CODE_SUCCESS; +} + +static void stmtFreeTbBuf(void* buf) { + void* pBuf = *(void**)buf; + taosMemoryFree(pBuf); +} + +static void stmtFreeTbCols(void* buf) { + SArray* pCols = *(SArray**)buf; + taosArrayDestroy(pCols); +} + +static int32_t stmtCleanSQLInfo(STscStmt2* pStmt) { + STMT_DLOG_E("start to free SQL info"); + + taosMemoryFree(pStmt->sql.pBindInfo); + taosMemoryFree(pStmt->sql.queryRes.fields); + taosMemoryFree(pStmt->sql.queryRes.userFields); + taosMemoryFree(pStmt->sql.sqlStr); + qDestroyQuery(pStmt->sql.pQuery); + taosArrayDestroy(pStmt->sql.nodeList); + taosHashCleanup(pStmt->sql.pVgHash); + pStmt->sql.pVgHash = NULL; + + void* pIter = taosHashIterate(pStmt->sql.pTableCache, NULL); + while (pIter) { + SStmtTableCache* pCache = (SStmtTableCache*)pIter; + + qDestroyStmtDataBlock(pCache->pDataCtx); + qDestroyBoundColInfo(pCache->boundTags); + taosMemoryFreeClear(pCache->boundTags); + + pIter = taosHashIterate(pStmt->sql.pTableCache, pIter); + } + taosHashCleanup(pStmt->sql.pTableCache); + pStmt->sql.pTableCache = NULL; + + STMT_ERR_RET(stmtCleanExecInfo(pStmt, false, true)); + STMT_ERR_RET(stmtCleanBindInfo(pStmt)); + + taos_free_result(pStmt->sql.siInfo.pRequest); + taosHashCleanup(pStmt->sql.siInfo.pVgroupHash); + tSimpleHashCleanup(pStmt->sql.siInfo.pTableHash); + taosArrayDestroyEx(pStmt->sql.siInfo.tbBuf.pBufList, stmtFreeTbBuf); + taosMemoryFree(pStmt->sql.siInfo.pTSchema); + qDestroyStmtDataBlock(pStmt->sql.siInfo.pDataCtx); + taosArrayDestroyEx(pStmt->sql.siInfo.pTableCols, stmtFreeTbCols); + + (void)memset(&pStmt->sql, 0, sizeof(pStmt->sql)); + pStmt->sql.siInfo.tableColsReady = true; + + STMT_DLOG_E("end to free SQL info"); + + return TSDB_CODE_SUCCESS; +} + +static int32_t stmtTryAddTableVgroupInfo(STscStmt2* pStmt, int32_t* vgId) { + if (*vgId >= 0 && taosHashGet(pStmt->sql.pVgHash, (const char*)vgId, sizeof(*vgId))) { + return TSDB_CODE_SUCCESS; + } + + SVgroupInfo vgInfo = {0}; + SRequestConnInfo conn = {.pTrans = pStmt->taos->pAppInfo->pTransporter, + .requestId = pStmt->exec.pRequest->requestId, + .requestObjRefId = pStmt->exec.pRequest->self, + .mgmtEps = getEpSet_s(&pStmt->taos->pAppInfo->mgmtEp)}; + + int32_t code = catalogGetTableHashVgroup(pStmt->pCatalog, &conn, &pStmt->bInfo.sname, &vgInfo); + if (TSDB_CODE_SUCCESS != code) { + return code; + } + + code = + taosHashPut(pStmt->sql.pVgHash, (const char*)&vgInfo.vgId, sizeof(vgInfo.vgId), (char*)&vgInfo, sizeof(vgInfo)); + if (TSDB_CODE_SUCCESS != code) { + return code; + } + + *vgId = vgInfo.vgId; + + return TSDB_CODE_SUCCESS; +} + +static int32_t stmtRebuildDataBlock(STscStmt2* pStmt, STableDataCxt* pDataBlock, STableDataCxt** newBlock, uint64_t uid, + uint64_t suid, int32_t vgId) { + STMT_ERR_RET(stmtTryAddTableVgroupInfo(pStmt, &vgId)); + STMT_ERR_RET(qRebuildStmtDataBlock(newBlock, pDataBlock, uid, suid, vgId, pStmt->sql.autoCreateTbl)); + + STMT_DLOG("tableDataCxt rebuilt, uid:%" PRId64 ", vgId:%d", uid, vgId); + + return TSDB_CODE_SUCCESS; +} + +static int32_t stmtGetFromCache(STscStmt2* pStmt) { + if (pStmt->sql.stbInterlaceMode && pStmt->sql.siInfo.pDataCtx) { + pStmt->bInfo.needParse = false; + pStmt->bInfo.inExecCache = false; + return TSDB_CODE_SUCCESS; + } + + pStmt->bInfo.needParse = true; + pStmt->bInfo.inExecCache = false; + + STableDataCxt** pCxtInExec = taosHashGet(pStmt->exec.pBlockHash, pStmt->bInfo.tbFName, strlen(pStmt->bInfo.tbFName)); + if (pCxtInExec) { + pStmt->bInfo.needParse = false; + pStmt->bInfo.inExecCache = true; + + pStmt->exec.pCurrBlock = *pCxtInExec; + + if (pStmt->sql.autoCreateTbl) { + tscDebug("reuse stmt block for tb %s in execBlock", pStmt->bInfo.tbFName); + return TSDB_CODE_SUCCESS; + } + } + + if (NULL == pStmt->pCatalog) { + STMT_ERR_RET(catalogGetHandle(pStmt->taos->pAppInfo->clusterId, &pStmt->pCatalog)); + pStmt->sql.siInfo.pCatalog = pStmt->pCatalog; + } + + if (NULL == pStmt->sql.pTableCache || taosHashGetSize(pStmt->sql.pTableCache) <= 0) { + if (pStmt->bInfo.inExecCache) { + pStmt->bInfo.needParse = false; + tscDebug("reuse stmt block for tb %s in execBlock", pStmt->bInfo.tbFName); + return TSDB_CODE_SUCCESS; + } + + tscDebug("no stmt block cache for tb %s", pStmt->bInfo.tbFName); + return TSDB_CODE_SUCCESS; + } + + if (pStmt->sql.autoCreateTbl) { + SStmtTableCache* pCache = taosHashGet(pStmt->sql.pTableCache, &pStmt->bInfo.tbSuid, sizeof(pStmt->bInfo.tbSuid)); + if (pCache) { + pStmt->bInfo.needParse = false; + pStmt->bInfo.tbUid = 0; + + STableDataCxt* pNewBlock = NULL; + STMT_ERR_RET(stmtRebuildDataBlock(pStmt, pCache->pDataCtx, &pNewBlock, 0, pStmt->bInfo.tbSuid, -1)); + + if (taosHashPut(pStmt->exec.pBlockHash, pStmt->bInfo.tbFName, strlen(pStmt->bInfo.tbFName), &pNewBlock, + POINTER_BYTES)) { + STMT_ERR_RET(TSDB_CODE_OUT_OF_MEMORY); + } + + pStmt->exec.pCurrBlock = pNewBlock; + + tscDebug("reuse stmt block for tb %s in sqlBlock, suid:0x%" PRIx64, pStmt->bInfo.tbFName, pStmt->bInfo.tbSuid); + + return TSDB_CODE_SUCCESS; + } + + STMT_RET(stmtCleanBindInfo(pStmt)); + } + + uint64_t uid, suid; + int32_t vgId; + int8_t tableType; + + STableMeta* pTableMeta = NULL; + SRequestConnInfo conn = {.pTrans = pStmt->taos->pAppInfo->pTransporter, + .requestId = pStmt->exec.pRequest->requestId, + .requestObjRefId = pStmt->exec.pRequest->self, + .mgmtEps = getEpSet_s(&pStmt->taos->pAppInfo->mgmtEp)}; + int32_t code = catalogGetTableMeta(pStmt->pCatalog, &conn, &pStmt->bInfo.sname, &pTableMeta); + + pStmt->stat.ctgGetTbMetaNum++; + + if (TSDB_CODE_PAR_TABLE_NOT_EXIST == code) { + tscDebug("tb %s not exist", pStmt->bInfo.tbFName); + STMT_ERR_RET(stmtCleanBindInfo(pStmt)); + + STMT_ERR_RET(code); + } + + STMT_ERR_RET(code); + + uid = pTableMeta->uid; + suid = pTableMeta->suid; + tableType = pTableMeta->tableType; + pStmt->bInfo.tbVgId = pTableMeta->vgId; + vgId = pTableMeta->vgId; + + taosMemoryFree(pTableMeta); + + uint64_t cacheUid = (TSDB_CHILD_TABLE == tableType) ? suid : uid; + + if (uid == pStmt->bInfo.tbUid) { + pStmt->bInfo.needParse = false; + + tscDebug("tb %s is current table", pStmt->bInfo.tbFName); + + return TSDB_CODE_SUCCESS; + } + + if (pStmt->bInfo.inExecCache) { + SStmtTableCache* pCache = taosHashGet(pStmt->sql.pTableCache, &cacheUid, sizeof(cacheUid)); + if (NULL == pCache) { + tscError("table [%s, %" PRIx64 ", %" PRIx64 "] found in exec blockHash, but not in sql blockHash", + pStmt->bInfo.tbFName, uid, cacheUid); + + STMT_ERR_RET(TSDB_CODE_APP_ERROR); + } + + pStmt->bInfo.needParse = false; + + pStmt->bInfo.tbUid = uid; + pStmt->bInfo.tbSuid = suid; + pStmt->bInfo.tbType = tableType; + pStmt->bInfo.boundTags = pCache->boundTags; + pStmt->bInfo.tagsCached = true; + + tscDebug("tb %s in execBlock list, set to current", pStmt->bInfo.tbFName); + + return TSDB_CODE_SUCCESS; + } + + SStmtTableCache* pCache = taosHashGet(pStmt->sql.pTableCache, &cacheUid, sizeof(cacheUid)); + if (pCache) { + pStmt->bInfo.needParse = false; + + pStmt->bInfo.tbUid = uid; + pStmt->bInfo.tbSuid = suid; + pStmt->bInfo.tbType = tableType; + pStmt->bInfo.boundTags = pCache->boundTags; + pStmt->bInfo.tagsCached = true; + + STableDataCxt* pNewBlock = NULL; + STMT_ERR_RET(stmtRebuildDataBlock(pStmt, pCache->pDataCtx, &pNewBlock, uid, suid, vgId)); + + if (taosHashPut(pStmt->exec.pBlockHash, pStmt->bInfo.tbFName, strlen(pStmt->bInfo.tbFName), &pNewBlock, + POINTER_BYTES)) { + STMT_ERR_RET(TSDB_CODE_OUT_OF_MEMORY); + } + + pStmt->exec.pCurrBlock = pNewBlock; + + tscDebug("tb %s in sqlBlock list, set to current", pStmt->bInfo.tbFName); + + return TSDB_CODE_SUCCESS; + } + + STMT_ERR_RET(stmtCleanBindInfo(pStmt)); + + return TSDB_CODE_SUCCESS; +} + +static int32_t stmtResetStmt(STscStmt2* pStmt) { + STMT_ERR_RET(stmtCleanSQLInfo(pStmt)); + + pStmt->sql.pTableCache = taosHashInit(100, taosGetDefaultHashFunction(TSDB_DATA_TYPE_BIGINT), false, HASH_NO_LOCK); + if (NULL == pStmt->sql.pTableCache) { + terrno = TSDB_CODE_OUT_OF_MEMORY; + STMT_ERR_RET(terrno); + } + + pStmt->sql.status = STMT_INIT; + + return TSDB_CODE_SUCCESS; +} + +static int32_t stmtAsyncOutput(STscStmt2* pStmt, void* param) { + SStmtQNode* pParam = (SStmtQNode*)param; + + if (pParam->restoreTbCols) { + for (int32_t i = 0; i < pStmt->sql.siInfo.pTableColsIdx; ++i) { + SArray** p = (SArray**)TARRAY_GET_ELEM(pStmt->sql.siInfo.pTableCols, i); + *p = taosArrayInit(20, POINTER_BYTES); + if (*p == NULL) { + STMT_ERR_RET(TSDB_CODE_OUT_OF_MEMORY); + } + } + + atomic_store_8((int8_t*)&pStmt->sql.siInfo.tableColsReady, true); + } else { + STMT_ERR_RET(qAppendStmtTableOutput(pStmt->sql.pQuery, pStmt->sql.pVgHash, &pParam->tblData, pStmt->exec.pCurrBlock, + &pStmt->sql.siInfo)); + + // taosMemoryFree(pParam->pTbData); + + (void)atomic_sub_fetch_64(&pStmt->sql.siInfo.tbRemainNum, 1); + } + return TSDB_CODE_SUCCESS; +} + +static void* stmtBindThreadFunc(void* param) { + setThreadName("stmtBind"); + + qInfo("stmt bind thread started"); + + STscStmt2* pStmt = (STscStmt2*)param; + + while (true) { + if (atomic_load_8((int8_t*)&pStmt->queue.stopQueue)) { + break; + } + + SStmtQNode* asyncParam = NULL; + if (!stmtDequeue(pStmt, &asyncParam)) { + continue; + } + + (void)stmtAsyncOutput(pStmt, asyncParam); + } + + qInfo("stmt bind thread stopped"); + + return NULL; +} + +static int32_t stmtStartBindThread(STscStmt2* pStmt) { + TdThreadAttr thAttr; + if (taosThreadAttrInit(&thAttr) != 0) { + return TSDB_CODE_TSC_INTERNAL_ERROR; + } + if (taosThreadAttrSetDetachState(&thAttr, PTHREAD_CREATE_JOINABLE) != 0) { + return TSDB_CODE_TSC_INTERNAL_ERROR; + } + + if (taosThreadCreate(&pStmt->bindThread, &thAttr, stmtBindThreadFunc, pStmt) != 0) { + terrno = TAOS_SYSTEM_ERROR(errno); + STMT_ERR_RET(terrno); + } + + pStmt->bindThreadInUse = true; + + (void)taosThreadAttrDestroy(&thAttr); + return TSDB_CODE_SUCCESS; +} + +static int32_t stmtInitQueue(STscStmt2* pStmt) { + STMT_ERR_RET(stmtAllocQNodeFromBuf(&pStmt->sql.siInfo.tbBuf, (void**)&pStmt->queue.head)); + pStmt->queue.tail = pStmt->queue.head; + + return TSDB_CODE_SUCCESS; +} + +static int32_t stmtInitTableBuf(STableBufInfo* pTblBuf) { + pTblBuf->buffUnit = sizeof(SStmtQNode); + pTblBuf->buffSize = pTblBuf->buffUnit * 1000; + pTblBuf->pBufList = taosArrayInit(100, POINTER_BYTES); + if (NULL == pTblBuf->pBufList) { + return TSDB_CODE_OUT_OF_MEMORY; + } + void* buff = taosMemoryMalloc(pTblBuf->buffSize); + if (NULL == buff) { + return TSDB_CODE_OUT_OF_MEMORY; + } + + if (taosArrayPush(pTblBuf->pBufList, &buff) == NULL) { + return TSDB_CODE_OUT_OF_MEMORY; + } + + pTblBuf->pCurBuff = buff; + pTblBuf->buffIdx = 1; + pTblBuf->buffOffset = 0; + + return TSDB_CODE_SUCCESS; +} + +TAOS_STMT2* stmtInit2(STscObj* taos, TAOS_STMT2_OPTION* pOptions) { + STscObj* pObj = (STscObj*)taos; + STscStmt2* pStmt = NULL; + int32_t code = 0; + + pStmt = taosMemoryCalloc(1, sizeof(STscStmt2)); + if (NULL == pStmt) { + terrno = TSDB_CODE_OUT_OF_MEMORY; + return NULL; + } + + pStmt->sql.pTableCache = taosHashInit(100, taosGetDefaultHashFunction(TSDB_DATA_TYPE_BIGINT), false, HASH_NO_LOCK); + if (NULL == pStmt->sql.pTableCache) { + terrno = TSDB_CODE_OUT_OF_MEMORY; + taosMemoryFree(pStmt); + return NULL; + } + + pStmt->taos = pObj; + pStmt->bInfo.needParse = true; + pStmt->sql.status = STMT_INIT; + pStmt->errCode = TSDB_CODE_SUCCESS; + + if (NULL != pOptions) { + (void)memcpy(&pStmt->options, pOptions, sizeof(pStmt->options)); + if (pOptions->singleStbInsert && pOptions->singleTableBindOnce) { + pStmt->stbInterlaceMode = true; + } + + pStmt->reqid = pOptions->reqid; + } + + if (pStmt->stbInterlaceMode) { + pStmt->sql.siInfo.transport = taos->pAppInfo->pTransporter; + pStmt->sql.siInfo.acctId = taos->acctId; + pStmt->sql.siInfo.dbname = taos->db; + pStmt->sql.siInfo.mgmtEpSet = getEpSet_s(&pStmt->taos->pAppInfo->mgmtEp); + pStmt->sql.siInfo.pTableHash = tSimpleHashInit(100, taosGetDefaultHashFunction(TSDB_DATA_TYPE_BINARY)); + if (NULL == pStmt->sql.siInfo.pTableHash) { + terrno = TSDB_CODE_OUT_OF_MEMORY; + (void)stmtClose(pStmt); + return NULL; + } + pStmt->sql.siInfo.pTableCols = taosArrayInit(STMT_TABLE_COLS_NUM, POINTER_BYTES); + if (NULL == pStmt->sql.siInfo.pTableCols) { + terrno = TSDB_CODE_OUT_OF_MEMORY; + (void)stmtClose(pStmt); + return NULL; + } + + code = stmtInitTableBuf(&pStmt->sql.siInfo.tbBuf); + if (TSDB_CODE_SUCCESS == code) { + code = stmtInitQueue(pStmt); + } + if (TSDB_CODE_SUCCESS == code) { + code = stmtStartBindThread(pStmt); + } + if (TSDB_CODE_SUCCESS != code) { + terrno = code; + (void)stmtClose(pStmt); + return NULL; + } + } + + pStmt->sql.siInfo.tableColsReady = true; + + STMT_LOG_SEQ(STMT_INIT); + + tscDebug("stmt:%p initialized", pStmt); + + return pStmt; +} + +static int stmtSetDbName2(TAOS_STMT2* stmt, const char* dbName) { + STscStmt2* pStmt = (STscStmt2*)stmt; + + STMT_DLOG("start to set dbName: %s", dbName); + + STMT_ERR_RET(stmtCreateRequest(pStmt)); + + // The SQL statement specifies a database name, overriding the previously specified database + taosMemoryFreeClear(pStmt->exec.pRequest->pDb); + pStmt->exec.pRequest->pDb = taosStrdup(dbName); + if (pStmt->exec.pRequest->pDb == NULL) { + return TSDB_CODE_OUT_OF_MEMORY; + } + return TSDB_CODE_SUCCESS; +} + +int stmtPrepare2(TAOS_STMT2* stmt, const char* sql, unsigned long length) { + STscStmt2* pStmt = (STscStmt2*)stmt; + + 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)); + } + + STMT_ERR_RET(stmtSwitchStatus(pStmt, STMT_PREPARE)); + + if (length <= 0) { + length = strlen(sql); + } + + pStmt->sql.sqlStr = strndup(sql, length); + pStmt->sql.sqlLen = length; + pStmt->sql.stbInterlaceMode = pStmt->stbInterlaceMode; + + char* dbName = NULL; + if (qParseDbName(sql, length, &dbName)) { + STMT_ERR_RET(stmtSetDbName2(stmt, dbName)); + taosMemoryFreeClear(dbName); + } + + return TSDB_CODE_SUCCESS; +} + +static int32_t stmtInitStbInterlaceTableInfo(STscStmt2* pStmt) { + STableDataCxt** pSrc = taosHashGet(pStmt->exec.pBlockHash, pStmt->bInfo.tbFName, strlen(pStmt->bInfo.tbFName)); + if (!pSrc) { + return TSDB_CODE_OUT_OF_MEMORY; + } + STableDataCxt* pDst = NULL; + + STMT_ERR_RET(qCloneStmtDataBlock(&pDst, *pSrc, true)); + pStmt->sql.siInfo.pDataCtx = pDst; + + SArray* pTblCols = NULL; + for (int32_t i = 0; i < STMT_TABLE_COLS_NUM; i++) { + pTblCols = taosArrayInit(20, POINTER_BYTES); + if (NULL == pTblCols) { + return TSDB_CODE_OUT_OF_MEMORY; + } + + if (taosArrayPush(pStmt->sql.siInfo.pTableCols, &pTblCols) == NULL) { + return TSDB_CODE_OUT_OF_MEMORY; + } + } + + pStmt->sql.siInfo.boundTags = pStmt->bInfo.boundTags; + + return TSDB_CODE_SUCCESS; +} + +int stmtSetTbName2(TAOS_STMT2* stmt, const char* tbName) { + STscStmt2* pStmt = (STscStmt2*)stmt; + + int64_t startUs = taosGetTimestampUs(); + + 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; + STMT_ERR_RET(stmtIsInsert(stmt, &insert)); + if (0 == insert) { + tscError("set tb name not available for none insert statement"); + STMT_ERR_RET(TSDB_CODE_TSC_STMT_API_ERROR); + } + + if (!pStmt->sql.stbInterlaceMode || NULL == pStmt->sql.siInfo.pDataCtx) { + STMT_ERR_RET(stmtCreateRequest(pStmt)); + + STMT_ERR_RET(qCreateSName(&pStmt->bInfo.sname, tbName, pStmt->taos->acctId, pStmt->exec.pRequest->pDb, + pStmt->exec.pRequest->msgBuf, pStmt->exec.pRequest->msgBufLen)); + STMT_ERR_RET(tNameExtractFullName(&pStmt->bInfo.sname, pStmt->bInfo.tbFName)); + + STMT_ERR_RET(stmtGetFromCache(pStmt)); + + if (pStmt->bInfo.needParse) { + (void)strncpy(pStmt->bInfo.tbName, tbName, sizeof(pStmt->bInfo.tbName) - 1); + pStmt->bInfo.tbName[sizeof(pStmt->bInfo.tbName) - 1] = 0; + + STMT_ERR_RET(stmtParseSql(pStmt)); + } + } else { + (void)strncpy(pStmt->bInfo.tbName, tbName, sizeof(pStmt->bInfo.tbName) - 1); + pStmt->bInfo.tbName[sizeof(pStmt->bInfo.tbName) - 1] = 0; + pStmt->exec.pRequest->requestId++; + pStmt->bInfo.needParse = false; + } + + if (pStmt->sql.stbInterlaceMode && NULL == pStmt->sql.siInfo.pDataCtx) { + STMT_ERR_RET(stmtInitStbInterlaceTableInfo(pStmt)); + } + + int64_t startUs2 = taosGetTimestampUs(); + pStmt->stat.setTbNameUs += startUs2 - startUs; + + return TSDB_CODE_SUCCESS; +} + +int stmtSetTbTags2(TAOS_STMT2* stmt, TAOS_STMT2_BIND* tags) { + STscStmt2* pStmt = (STscStmt2*)stmt; + + STMT_DLOG_E("start to set tbTags"); + + if (pStmt->errCode != TSDB_CODE_SUCCESS) { + return pStmt->errCode; + } + + 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; + } + + STableDataCxt** pDataBlock = + (STableDataCxt**)taosHashGet(pStmt->exec.pBlockHash, pStmt->bInfo.tbFName, strlen(pStmt->bInfo.tbFName)); + if (NULL == pDataBlock) { + tscError("table %s not found in exec blockHash", pStmt->bInfo.tbFName); + STMT_ERR_RET(TSDB_CODE_APP_ERROR); + } + + tscDebug("start to bind stmt tag values"); + STMT_ERR_RET(qBindStmtTagsValue2(*pDataBlock, pStmt->bInfo.boundTags, pStmt->bInfo.tbSuid, pStmt->bInfo.stbFName, + pStmt->bInfo.sname.tname, tags, pStmt->exec.pRequest->msgBuf, + pStmt->exec.pRequest->msgBufLen)); + + return TSDB_CODE_SUCCESS; +} + +int stmtFetchTagFields2(STscStmt2* 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); + } + + STableDataCxt** pDataBlock = + (STableDataCxt**)taosHashGet(pStmt->exec.pBlockHash, pStmt->bInfo.tbFName, strlen(pStmt->bInfo.tbFName)); + if (NULL == pDataBlock) { + tscError("table %s not found in exec blockHash", pStmt->bInfo.tbFName); + STMT_ERR_RET(TSDB_CODE_APP_ERROR); + } + + STMT_ERR_RET(qBuildStmtTagFields(*pDataBlock, pStmt->bInfo.boundTags, fieldNum, fields)); + + return TSDB_CODE_SUCCESS; +} + +int stmtFetchColFields2(STscStmt2* 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); + } + + STableDataCxt** pDataBlock = NULL; + + if (pStmt->sql.stbInterlaceMode) { + pDataBlock = &pStmt->sql.siInfo.pDataCtx; + } else { + pDataBlock = + (STableDataCxt**)taosHashGet(pStmt->exec.pBlockHash, pStmt->bInfo.tbFName, strlen(pStmt->bInfo.tbFName)); + if (NULL == pDataBlock) { + tscError("table %s not found in exec blockHash", pStmt->bInfo.tbFName); + STMT_ERR_RET(TSDB_CODE_APP_ERROR); + } + } + + STMT_ERR_RET(qBuildStmtColFields(*pDataBlock, fieldNum, fields)); + + return TSDB_CODE_SUCCESS; +} + +/* +SArray* stmtGetFreeCol(STscStmt2* pStmt, int32_t* idx) { + while (true) { + if (pStmt->exec.smInfo.pColIdx >= STMT_COL_BUF_SIZE) { + pStmt->exec.smInfo.pColIdx = 0; + } + + if ((pStmt->exec.smInfo.pColIdx + 1) == atomic_load_32(&pStmt->exec.smInfo.pColFreeIdx)) { + taosUsleep(1); + continue; + } + + *idx = pStmt->exec.smInfo.pColIdx; + return pStmt->exec.smInfo.pCols[pStmt->exec.smInfo.pColIdx++]; + } +} +*/ + +static int32_t stmtAppendTablePostHandle(STscStmt2* pStmt, SStmtQNode* param) { + if (NULL == pStmt->sql.siInfo.pVgroupHash) { + pStmt->sql.siInfo.pVgroupHash = + taosHashInit(64, taosGetDefaultHashFunction(TSDB_DATA_TYPE_INT), true, HASH_ENTRY_LOCK); + } + if (NULL == pStmt->sql.siInfo.pVgroupList) { + pStmt->sql.siInfo.pVgroupList = taosArrayInit(64, POINTER_BYTES); + } + + if (NULL == pStmt->sql.siInfo.pRequest) { + STMT_ERR_RET(buildRequest(pStmt->taos->id, pStmt->sql.sqlStr, pStmt->sql.sqlLen, NULL, false, + (SRequestObj**)&pStmt->sql.siInfo.pRequest, pStmt->reqid)); + + if (pStmt->reqid != 0) { + pStmt->reqid++; + } + pStmt->exec.pRequest->syncQuery = true; + + pStmt->sql.siInfo.requestId = ((SRequestObj*)pStmt->sql.siInfo.pRequest)->requestId; + pStmt->sql.siInfo.requestSelf = ((SRequestObj*)pStmt->sql.siInfo.pRequest)->self; + } + + if (!pStmt->sql.siInfo.tbFromHash && pStmt->sql.siInfo.firstName[0] && + 0 == strcmp(pStmt->sql.siInfo.firstName, pStmt->bInfo.tbName)) { + pStmt->sql.siInfo.tbFromHash = true; + } + + if (0 == pStmt->sql.siInfo.firstName[0]) { + (void)strcpy(pStmt->sql.siInfo.firstName, pStmt->bInfo.tbName); + } + + param->tblData.getFromHash = pStmt->sql.siInfo.tbFromHash; + param->next = NULL; + + (void)atomic_add_fetch_64(&pStmt->sql.siInfo.tbRemainNum, 1); + + stmtEnqueue(pStmt, param); + + return TSDB_CODE_SUCCESS; +} + +static FORCE_INLINE int32_t stmtGetTableColsFromCache(STscStmt2* pStmt, SArray** pTableCols) { + while (true) { + if (pStmt->sql.siInfo.pTableColsIdx < taosArrayGetSize(pStmt->sql.siInfo.pTableCols)) { + *pTableCols = (SArray*)taosArrayGetP(pStmt->sql.siInfo.pTableCols, pStmt->sql.siInfo.pTableColsIdx++); + break; + } else { + SArray* pTblCols = NULL; + for (int32_t i = 0; i < 100; i++) { + pTblCols = taosArrayInit(20, POINTER_BYTES); + if (NULL == pTblCols) { + return TSDB_CODE_OUT_OF_MEMORY; + } + + if (taosArrayPush(pStmt->sql.siInfo.pTableCols, &pTblCols) == NULL) { + return TSDB_CODE_OUT_OF_MEMORY; + } + } + } + } + + return TSDB_CODE_SUCCESS; +} + +static int stmtAddBatch2(TAOS_STMT2* stmt) { + STscStmt2* pStmt = (STscStmt2*)stmt; + + int64_t startUs = taosGetTimestampUs(); + + 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) { + int64_t startUs2 = taosGetTimestampUs(); + pStmt->stat.addBatchUs += startUs2 - startUs; + + pStmt->sql.siInfo.tableColsReady = false; + + SStmtQNode* param = NULL; + STMT_ERR_RET(stmtAllocQNodeFromBuf(&pStmt->sql.siInfo.tbBuf, (void**)¶m)); + param->restoreTbCols = true; + param->next = NULL; + + stmtEnqueue(pStmt, param); + + return TSDB_CODE_SUCCESS; + } + + STMT_ERR_RET(stmtCacheBlock(pStmt)); + + return TSDB_CODE_SUCCESS; +} + +int stmtBindBatch2(TAOS_STMT2* stmt, TAOS_STMT2_BIND* bind, int32_t colIdx) { + STscStmt2* pStmt = (STscStmt2*)stmt; + int32_t code = 0; + + int64_t startUs = taosGetTimestampUs(); + + 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; + } + + if (pStmt->exec.pRequest && STMT_TYPE_QUERY == pStmt->sql.type && pStmt->sql.runTimes) { + taos_free_result(pStmt->exec.pRequest); + pStmt->exec.pRequest = NULL; + } + + STMT_ERR_RET(stmtCreateRequest(pStmt)); + + if (pStmt->bInfo.needParse) { + STMT_ERR_RET(stmtParseSql(pStmt)); + } + + if (STMT_TYPE_QUERY == pStmt->sql.type) { + STMT_ERR_RET(qStmtBindParams2(pStmt->sql.pQuery, bind, colIdx)); + + SParseContext ctx = {.requestId = pStmt->exec.pRequest->requestId, + .acctId = pStmt->taos->acctId, + .db = pStmt->exec.pRequest->pDb, + .topicQuery = false, + .pSql = pStmt->sql.sqlStr, + .sqlLen = pStmt->sql.sqlLen, + .pMsg = pStmt->exec.pRequest->msgBuf, + .msgLen = ERROR_MSG_BUF_DEFAULT_SIZE, + .pTransporter = pStmt->taos->pAppInfo->pTransporter, + .pStmtCb = NULL, + .pUser = pStmt->taos->user}; + ctx.mgmtEpSet = getEpSet_s(&pStmt->taos->pAppInfo->mgmtEp); + STMT_ERR_RET(catalogGetHandle(pStmt->taos->pAppInfo->clusterId, &ctx.pCatalog)); + + STMT_ERR_RET(qStmtParseQuerySql(&ctx, pStmt->sql.pQuery)); + + if (pStmt->sql.pQuery->haveResultSet) { + STMT_ERR_RET(setResSchemaInfo(&pStmt->exec.pRequest->body.resInfo, pStmt->sql.pQuery->pResSchema, + pStmt->sql.pQuery->numOfResCols)); + taosMemoryFreeClear(pStmt->sql.pQuery->pResSchema); + setResPrecision(&pStmt->exec.pRequest->body.resInfo, pStmt->sql.pQuery->precision); + } + + TSWAP(pStmt->exec.pRequest->dbList, pStmt->sql.pQuery->pDbList); + TSWAP(pStmt->exec.pRequest->tableList, pStmt->sql.pQuery->pTableList); + TSWAP(pStmt->exec.pRequest->targetTableList, pStmt->sql.pQuery->pTargetTableList); + + // if (STMT_TYPE_QUERY == pStmt->sql.queryRes) { + // STMT_ERR_RET(stmtRestoreQueryFields(pStmt)); + // } + + // STMT_ERR_RET(stmtBackupQueryFields(pStmt)); + + return TSDB_CODE_SUCCESS; + } + + if (pStmt->sql.stbInterlaceMode && NULL == pStmt->sql.siInfo.pDataCtx) { + STMT_ERR_RET(stmtInitStbInterlaceTableInfo(pStmt)); + } + + STableDataCxt** pDataBlock = NULL; + + if (pStmt->exec.pCurrBlock) { + pDataBlock = &pStmt->exec.pCurrBlock; + } else { + pDataBlock = + (STableDataCxt**)taosHashGet(pStmt->exec.pBlockHash, pStmt->bInfo.tbFName, strlen(pStmt->bInfo.tbFName)); + if (NULL == pDataBlock) { + tscError("table %s not found in exec blockHash", pStmt->bInfo.tbFName); + STMT_ERR_RET(TSDB_CODE_TSC_STMT_CACHE_ERROR); + } + pStmt->exec.pCurrBlock = *pDataBlock; + if (pStmt->sql.stbInterlaceMode) { + taosArrayDestroy(pStmt->exec.pCurrBlock->pData->aCol); + pStmt->exec.pCurrBlock->pData->aCol = NULL; + } + } + + int64_t startUs2 = taosGetTimestampUs(); + pStmt->stat.bindDataUs1 += startUs2 - startUs; + + SStmtQNode* param = NULL; + if (pStmt->sql.stbInterlaceMode) { + STMT_ERR_RET(stmtAllocQNodeFromBuf(&pStmt->sql.siInfo.tbBuf, (void**)¶m)); + STMT_ERR_RET(stmtGetTableColsFromCache(pStmt, ¶m->tblData.aCol)); + taosArrayClear(param->tblData.aCol); + + // param->tblData.aCol = taosArrayInit(20, POINTER_BYTES); + + param->restoreTbCols = false; + (void)strcpy(param->tblData.tbName, pStmt->bInfo.tbName); + } + + int64_t startUs3 = taosGetTimestampUs(); + pStmt->stat.bindDataUs2 += startUs3 - startUs2; + + SArray* pCols = pStmt->sql.stbInterlaceMode ? param->tblData.aCol : (*pDataBlock)->pData->aCol; + + if (colIdx < 0) { + if (pStmt->sql.stbInterlaceMode) { + (*pDataBlock)->pData->flags = 0; + code = qBindStmtStbColsValue2(*pDataBlock, pCols, bind, pStmt->exec.pRequest->msgBuf, + pStmt->exec.pRequest->msgBufLen, &pStmt->sql.siInfo.pTSchema, pStmt->sql.pBindInfo); + } else { + code = + qBindStmtColsValue2(*pDataBlock, pCols, bind, pStmt->exec.pRequest->msgBuf, pStmt->exec.pRequest->msgBufLen); + } + + if (code) { + tscError("qBindStmtColsValue failed, error:%s", tstrerror(code)); + STMT_ERR_RET(code); + } + } else { + if (pStmt->sql.stbInterlaceMode) { + tscError("bind single column not allowed in stb insert mode"); + STMT_ERR_RET(TSDB_CODE_TSC_STMT_API_ERROR); + } + + if (colIdx != (pStmt->bInfo.sBindLastIdx + 1) && colIdx != 0) { + tscError("bind column index not in sequence"); + STMT_ERR_RET(TSDB_CODE_APP_ERROR); + } + + pStmt->bInfo.sBindLastIdx = colIdx; + + if (0 == colIdx) { + pStmt->bInfo.sBindRowNum = bind->num; + } + + code = qBindStmtSingleColValue2(*pDataBlock, pCols, bind, pStmt->exec.pRequest->msgBuf, + pStmt->exec.pRequest->msgBufLen, colIdx, pStmt->bInfo.sBindRowNum); + if (code) { + tscError("qBindStmtSingleColValue failed, error:%s", tstrerror(code)); + STMT_ERR_RET(code); + } + } + + int64_t startUs4 = taosGetTimestampUs(); + pStmt->stat.bindDataUs3 += startUs4 - startUs3; + + if (pStmt->sql.stbInterlaceMode) { + STMT_ERR_RET(stmtAppendTablePostHandle(pStmt, param)); + } + + STMT_ERR_RET(stmtAddBatch2(pStmt)); + + pStmt->stat.bindDataUs4 += taosGetTimestampUs() - startUs4; + + return TSDB_CODE_SUCCESS; +} +/* +int stmtUpdateTableUid(STscStmt2* pStmt, SSubmitRsp* pRsp) { + tscDebug("stmt start to update tbUid, blockNum: %d", pRsp->nBlocks); + + int32_t code = 0; + int32_t finalCode = 0; + size_t keyLen = 0; + void* pIter = taosHashIterate(pStmt->exec.pBlockHash, NULL); + while (pIter) { + STableDataCxt* pBlock = *(STableDataCxt**)pIter; + char* key = taosHashGetKey(pIter, &keyLen); + + STableMeta* pMeta = qGetTableMetaInDataBlock(pBlock); + if (pMeta->uid) { + pIter = taosHashIterate(pStmt->exec.pBlockHash, pIter); + continue; + } + + SSubmitBlkRsp* blkRsp = NULL; + int32_t i = 0; + for (; i < pRsp->nBlocks; ++i) { + blkRsp = pRsp->pBlocks + i; + if (strlen(blkRsp->tblFName) != keyLen) { + continue; + } + + if (strncmp(blkRsp->tblFName, key, keyLen)) { + continue; + } + + break; + } + + if (i < pRsp->nBlocks) { + tscDebug("auto created table %s uid updated from %" PRIx64 " to %" PRIx64, blkRsp->tblFName, pMeta->uid, + blkRsp->uid); + + pMeta->uid = blkRsp->uid; + pStmt->bInfo.tbUid = blkRsp->uid; + } else { + tscDebug("table %s not found in submit rsp, will update from catalog", pStmt->bInfo.tbFName); + if (NULL == pStmt->pCatalog) { + code = catalogGetHandle(pStmt->taos->pAppInfo->clusterId, &pStmt->pCatalog); + if (code) { + pIter = taosHashIterate(pStmt->exec.pBlockHash, pIter); + finalCode = code; + continue; + } + } + + code = stmtCreateRequest(pStmt); + if (code) { + pIter = taosHashIterate(pStmt->exec.pBlockHash, pIter); + finalCode = code; + continue; + } + + STableMeta* pTableMeta = NULL; + SRequestConnInfo conn = {.pTrans = pStmt->taos->pAppInfo->pTransporter, + .requestId = pStmt->exec.pRequest->requestId, + .requestObjRefId = pStmt->exec.pRequest->self, + .mgmtEps = getEpSet_s(&pStmt->taos->pAppInfo->mgmtEp)}; + code = catalogGetTableMeta(pStmt->pCatalog, &conn, &pStmt->bInfo.sname, &pTableMeta); + + pStmt->stat.ctgGetTbMetaNum++; + + taos_free_result(pStmt->exec.pRequest); + pStmt->exec.pRequest = NULL; + + if (code || NULL == pTableMeta) { + pIter = taosHashIterate(pStmt->exec.pBlockHash, pIter); + finalCode = code; + taosMemoryFree(pTableMeta); + continue; + } + + pMeta->uid = pTableMeta->uid; + pStmt->bInfo.tbUid = pTableMeta->uid; + taosMemoryFree(pTableMeta); + } + + pIter = taosHashIterate(pStmt->exec.pBlockHash, pIter); + } + + return finalCode; +} +*/ +/* +int stmtStaticModeExec(TAOS_STMT* stmt) { + STscStmt2* pStmt = (STscStmt2*)stmt; + int32_t code = 0; + SSubmitRsp* pRsp = NULL; + if (pStmt->sql.staticMode) { + return TSDB_CODE_TSC_STMT_API_ERROR; + } + + STMT_DLOG_E("start to exec"); + + STMT_ERR_RET(stmtSwitchStatus(pStmt, STMT_EXECUTE)); + + STMT_ERR_RET(qBuildStmtOutputFromTbList(pStmt->sql.pQuery, pStmt->sql.pVgHash, pStmt->exec.pTbBlkList, +pStmt->exec.pCurrBlock, pStmt->exec.tbBlkNum)); + + 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); + if (code) { + pStmt->exec.pRequest->code = code; + } else { + tFreeSSubmitRsp(pRsp); + STMT_ERR_RET(stmtResetStmt(pStmt)); + STMT_ERR_RET(TSDB_CODE_NEED_RETRY); + } + } + + STMT_ERR_JRET(pStmt->exec.pRequest->code); + + pStmt->exec.affectedRows = taos_affected_rows(pStmt->exec.pRequest); + pStmt->affectedRows += pStmt->exec.affectedRows; + +_return: + + stmtCleanExecInfo(pStmt, (code ? false : true), false); + + tFreeSSubmitRsp(pRsp); + + ++pStmt->sql.runTimes; + + STMT_RET(code); +} +*/ + +static int32_t createParseContext(const SRequestObj* pRequest, SParseContext** pCxt, SSqlCallbackWrapper* pWrapper) { + const STscObj* pTscObj = pRequest->pTscObj; + + *pCxt = taosMemoryCalloc(1, sizeof(SParseContext)); + if (*pCxt == NULL) { + return TSDB_CODE_OUT_OF_MEMORY; + } + + **pCxt = (SParseContext){.requestId = pRequest->requestId, + .requestRid = pRequest->self, + .acctId = pTscObj->acctId, + .db = pRequest->pDb, + .topicQuery = false, + .pSql = pRequest->sqlstr, + .sqlLen = pRequest->sqlLen, + .pMsg = pRequest->msgBuf, + .msgLen = ERROR_MSG_BUF_DEFAULT_SIZE, + .pTransporter = pTscObj->pAppInfo->pTransporter, + .pStmtCb = NULL, + .pUser = pTscObj->user, + .pEffectiveUser = pRequest->effectiveUser, + .isSuperUser = (0 == strcmp(pTscObj->user, TSDB_DEFAULT_USER)), + .enableSysInfo = pTscObj->sysInfo, + .async = true, + .svrVer = pTscObj->sVer, + .nodeOffline = (pTscObj->pAppInfo->onlineDnodes < pTscObj->pAppInfo->totalDnodes), + .allocatorId = pRequest->allocatorRefId, + .parseSqlFp = clientParseSql, + .parseSqlParam = pWrapper}; + int8_t biMode = atomic_load_8(&((STscObj*)pTscObj)->biMode); + (*pCxt)->biMode = biMode; + return TSDB_CODE_SUCCESS; +} + +int stmtExec2(TAOS_STMT2* stmt, int* affected_rows) { + STscStmt2* pStmt = (STscStmt2*)stmt; + int32_t code = 0; + SSubmitRsp* pRsp = NULL; + + int64_t startUs = taosGetTimestampUs(); + + 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) { + if (pStmt->sql.stbInterlaceMode) { + int64_t startTs = taosGetTimestampUs(); + while (atomic_load_64(&pStmt->sql.siInfo.tbRemainNum)) { + taosUsleep(1); + } + pStmt->stat.execWaitUs += taosGetTimestampUs() - startTs; + + STMT_ERR_RET(qBuildStmtFinOutput(pStmt->sql.pQuery, pStmt->sql.pVgHash, pStmt->sql.siInfo.pVgroupList)); + taosHashCleanup(pStmt->sql.siInfo.pVgroupHash); + pStmt->sql.siInfo.pVgroupHash = NULL; + pStmt->sql.siInfo.pVgroupList = NULL; + } else { + tDestroySubmitTbData(pStmt->exec.pCurrTbData, TSDB_MSG_FLG_ENCODE); + taosMemoryFreeClear(pStmt->exec.pCurrTbData); + + STMT_ERR_RET(qCloneCurrentTbData(pStmt->exec.pCurrBlock, &pStmt->exec.pCurrTbData)); + + STMT_ERR_RET(qBuildStmtOutput(pStmt->sql.pQuery, pStmt->sql.pVgHash, pStmt->exec.pBlockHash)); + } + } + + (void)launchQueryImpl(pStmt->exec.pRequest, pStmt->sql.pQuery, true, NULL); + + /* + SSqlCallbackWrapper* pWrapper = taosMemoryCalloc(1, sizeof(SSqlCallbackWrapper)); + if (pWrapper == NULL) { + code = TSDB_CODE_OUT_OF_MEMORY; + } else { + pWrapper->pRequest = pStmt->exec.pRequest; + pStmt->exec.pRequest->pWrapper = pWrapper; + //*ppWrapper = pWrapper; + } + if (TSDB_CODE_SUCCESS == code) { + code = createParseContext(pStmt->exec.pRequest, &pWrapper->pParseCtx, pWrapper); + } + pStmt->exec.pRequest->syncQuery = false; + pStmt->exec.pRequest->body.queryFp = fp; + ((SSyncQueryParam*)(pStmt->exec.pRequest)->body.interParam)->userParam = param; + launchAsyncQuery(pStmt->exec.pRequest, pStmt->sql.pQuery, NULL, pWrapper); + */ + + if (pStmt->exec.pRequest->code && NEED_CLIENT_HANDLE_ERROR(pStmt->exec.pRequest->code)) { + code = refreshMeta(pStmt->exec.pRequest->pTscObj, pStmt->exec.pRequest); + if (code) { + pStmt->exec.pRequest->code = code; + } else { + tFreeSSubmitRsp(pRsp); + STMT_ERR_RET(stmtResetStmt(pStmt)); + STMT_ERR_RET(TSDB_CODE_NEED_RETRY); + } + } + + STMT_ERR_JRET(pStmt->exec.pRequest->code); + + pStmt->exec.affectedRows = taos_affected_rows(pStmt->exec.pRequest); + pStmt->affectedRows += pStmt->exec.affectedRows; + +_return: + + while (0 == atomic_load_8((int8_t*)&pStmt->sql.siInfo.tableColsReady)) { + taosUsleep(1); + } + + STMT_ERR_RET(stmtCleanExecInfo(pStmt, (code ? false : true), false)); + + tFreeSSubmitRsp(pRsp); + + ++pStmt->sql.runTimes; + + int64_t startUs2 = taosGetTimestampUs(); + pStmt->stat.execUseUs += startUs2 - startUs; + + STMT_RET(code); +} + +int stmtClose2(TAOS_STMT2* stmt) { + STscStmt2* pStmt = (STscStmt2*)stmt; + + STMT_DLOG_E("start to free stmt"); + + pStmt->queue.stopQueue = true; + + if (pStmt->bindThreadInUse) { + (void)taosThreadJoin(pStmt->bindThread, NULL); + pStmt->bindThreadInUse = false; + } + + STMT_DLOG("stmt %p closed, stbInterlaceMode: %d, statInfo: ctgGetTbMetaNum=>%" PRId64 ", getCacheTbInfo=>%" PRId64 + ", parseSqlNum=>%" PRId64 ", pStmt->stat.bindDataNum=>%" PRId64 + ", settbnameAPI:%u, bindAPI:%u, addbatchAPI:%u, execAPI:%u" + ", setTbNameUs:%" PRId64 ", bindDataUs:%" PRId64 ",%" PRId64 ",%" PRId64 ",%" PRId64 " addBatchUs:%" PRId64 + ", execWaitUs:%" PRId64 ", execUseUs:%" PRId64, + pStmt, pStmt->sql.stbInterlaceMode, pStmt->stat.ctgGetTbMetaNum, pStmt->stat.getCacheTbInfo, + pStmt->stat.parseSqlNum, pStmt->stat.bindDataNum, pStmt->seqIds[STMT_SETTBNAME], pStmt->seqIds[STMT_BIND], + pStmt->seqIds[STMT_ADD_BATCH], pStmt->seqIds[STMT_EXECUTE], pStmt->stat.setTbNameUs, + pStmt->stat.bindDataUs1, pStmt->stat.bindDataUs2, pStmt->stat.bindDataUs3, pStmt->stat.bindDataUs4, + pStmt->stat.addBatchUs, pStmt->stat.execWaitUs, pStmt->stat.execUseUs); + + STMT_ERR_RET(stmtCleanSQLInfo(pStmt)); + taosMemoryFree(stmt); + + return TSDB_CODE_SUCCESS; +} + +const char* stmtErrstr2(TAOS_STMT2* stmt) { + STscStmt2* pStmt = (STscStmt2*)stmt; + + if (stmt == NULL || NULL == pStmt->exec.pRequest) { + return (char*)tstrerror(terrno); + } + + pStmt->exec.pRequest->code = terrno; + + return taos_errstr(pStmt->exec.pRequest); +} +/* +int stmtAffectedRows(TAOS_STMT* stmt) { return ((STscStmt2*)stmt)->affectedRows; } + +int stmtAffectedRowsOnce(TAOS_STMT* stmt) { return ((STscStmt2*)stmt)->exec.affectedRows; } +*/ +int stmtIsInsert2(TAOS_STMT2* stmt, int* insert) { + STscStmt2* pStmt = (STscStmt2*)stmt; + + STMT_DLOG_E("start is insert"); + + if (pStmt->sql.type) { + *insert = (STMT_TYPE_INSERT == pStmt->sql.type || STMT_TYPE_MULTI_INSERT == pStmt->sql.type); + } else { + *insert = qIsInsertValuesSql(pStmt->sql.sqlStr, pStmt->sql.sqlLen); + } + + return TSDB_CODE_SUCCESS; +} + +int stmtGetTagFields2(TAOS_STMT2* stmt, int* nums, TAOS_FIELD_E** fields) { + int32_t code = 0; + STscStmt2* pStmt = (STscStmt2*)stmt; + int32_t preCode = pStmt->errCode; + + 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); + } + + STMT_ERRI_JRET(stmtSwitchStatus(pStmt, STMT_FETCH_FIELDS)); + + if (pStmt->bInfo.needParse && pStmt->sql.runTimes && pStmt->sql.type > 0 && + STMT_TYPE_MULTI_INSERT != pStmt->sql.type) { + pStmt->bInfo.needParse = false; + } + + if (pStmt->exec.pRequest && STMT_TYPE_QUERY == pStmt->sql.type && pStmt->sql.runTimes) { + taos_free_result(pStmt->exec.pRequest); + pStmt->exec.pRequest = NULL; + } + + STMT_ERRI_JRET(stmtCreateRequest(pStmt)); + + if (pStmt->bInfo.needParse) { + STMT_ERRI_JRET(stmtParseSql(pStmt)); + } + + STMT_ERRI_JRET(stmtFetchTagFields2(stmt, nums, fields)); + +_return: + + pStmt->errCode = preCode; + + return code; +} + +int stmtGetColFields2(TAOS_STMT2* stmt, int* nums, TAOS_FIELD_E** fields) { + int32_t code = 0; + STscStmt2* pStmt = (STscStmt2*)stmt; + int32_t preCode = pStmt->errCode; + + 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); + } + + STMT_ERRI_JRET(stmtSwitchStatus(pStmt, STMT_FETCH_FIELDS)); + + if (pStmt->bInfo.needParse && pStmt->sql.runTimes && pStmt->sql.type > 0 && + STMT_TYPE_MULTI_INSERT != pStmt->sql.type) { + pStmt->bInfo.needParse = false; + } + + if (pStmt->exec.pRequest && STMT_TYPE_QUERY == pStmt->sql.type && pStmt->sql.runTimes) { + taos_free_result(pStmt->exec.pRequest); + pStmt->exec.pRequest = NULL; + STMT_ERR_RET(stmtCreateRequest(pStmt)); + } + + STMT_ERRI_JRET(stmtCreateRequest(pStmt)); + + if (pStmt->bInfo.needParse) { + STMT_ERRI_JRET(stmtParseSql(pStmt)); + } + + STMT_ERRI_JRET(stmtFetchColFields2(stmt, nums, fields)); + +_return: + + pStmt->errCode = preCode; + + return code; +} + +int stmtGetParamNum2(TAOS_STMT2* stmt, int* nums) { + STscStmt2* pStmt = (STscStmt2*)stmt; + + 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 && + STMT_TYPE_MULTI_INSERT != pStmt->sql.type) { + pStmt->bInfo.needParse = false; + } + + if (pStmt->exec.pRequest && STMT_TYPE_QUERY == pStmt->sql.type && pStmt->sql.runTimes) { + taos_free_result(pStmt->exec.pRequest); + pStmt->exec.pRequest = NULL; + } + + STMT_ERR_RET(stmtCreateRequest(pStmt)); + + if (pStmt->bInfo.needParse) { + STMT_ERR_RET(stmtParseSql(pStmt)); + } + + if (STMT_TYPE_QUERY == pStmt->sql.type) { + *nums = taosArrayGetSize(pStmt->sql.pQuery->pPlaceholderValues); + } else { + STMT_ERR_RET(stmtFetchColFields2(stmt, nums, NULL)); + } + + return TSDB_CODE_SUCCESS; +} +/* +int stmtGetParam(TAOS_STMT* stmt, int idx, int* type, int* bytes) { + STscStmt2* pStmt = (STscStmt2*)stmt; + + 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); + } + + STMT_ERR_RET(stmtSwitchStatus(pStmt, STMT_FETCH_FIELDS)); + + if (pStmt->bInfo.needParse && pStmt->sql.runTimes && pStmt->sql.type > 0 && + STMT_TYPE_MULTI_INSERT != pStmt->sql.type) { + pStmt->bInfo.needParse = false; + } + + if (pStmt->exec.pRequest && STMT_TYPE_QUERY == pStmt->sql.type && pStmt->sql.runTimes) { + taos_free_result(pStmt->exec.pRequest); + pStmt->exec.pRequest = NULL; + } + + STMT_ERR_RET(stmtCreateRequest(pStmt)); + + if (pStmt->bInfo.needParse) { + STMT_ERR_RET(stmtParseSql(pStmt)); + } + + int32_t nums = 0; + TAOS_FIELD_E* pField = NULL; + STMT_ERR_RET(stmtFetchColFields(stmt, &nums, &pField)); + if (idx >= nums) { + tscError("idx %d is too big", idx); + taosMemoryFree(pField); + STMT_ERR_RET(TSDB_CODE_INVALID_PARA); + } + + *type = pField[idx].type; + *bytes = pField[idx].bytes; + + taosMemoryFree(pField); + + return TSDB_CODE_SUCCESS; +} +*/ +TAOS_RES* stmtUseResult2(TAOS_STMT2* stmt) { + STscStmt2* pStmt = (STscStmt2*)stmt; + + STMT_DLOG_E("start to use result"); + + if (STMT_TYPE_QUERY != pStmt->sql.type) { + tscError("useResult only for query statement"); + return NULL; + } + + return pStmt->exec.pRequest; +} diff --git a/source/common/src/tdataformat.c b/source/common/src/tdataformat.c index 5caf93de65..02279ff06f 100644 --- a/source/common/src/tdataformat.c +++ b/source/common/src/tdataformat.c @@ -3119,6 +3119,143 @@ _exit: return code; } +int32_t tColDataAddValueByBind2(SColData *pColData, TAOS_STMT2_BIND *pBind, int32_t buffMaxLen) { + int32_t code = 0; + + if (!(pBind->num == 1 && pBind->is_null && *pBind->is_null)) { + ASSERT(pColData->type == pBind->buffer_type); + } + + if (IS_VAR_DATA_TYPE(pColData->type)) { // var-length data type + for (int32_t i = 0; i < pBind->num; ++i) { + if (pBind->is_null && pBind->is_null[i]) { + if (pColData->cflag & COL_IS_KEY) { + code = TSDB_CODE_PAR_PRIMARY_KEY_IS_NULL; + goto _exit; + } + code = tColDataAppendValueImpl[pColData->flag][CV_FLAG_NULL](pColData, NULL, 0); + if (code) goto _exit; + } else if (pBind->length[i] > buffMaxLen) { + uError("var data length too big, len:%d, max:%d", pBind->length[i], buffMaxLen); + return TSDB_CODE_INVALID_PARA; + } else { + code = tColDataAppendValueImpl[pColData->flag][CV_FLAG_VALUE]( + pColData, (uint8_t *)pBind->buffer + pBind->buffer_length * i, pBind->length[i]); + } + } + } else { // fixed-length data type + bool allValue; + bool allNull; + if (pBind->is_null) { + bool same = (memcmp(pBind->is_null, pBind->is_null + 1, pBind->num - 1) == 0); + allNull = (same && pBind->is_null[0] != 0); + allValue = (same && pBind->is_null[0] == 0); + } else { + allNull = false; + allValue = true; + } + + if ((pColData->cflag & COL_IS_KEY) && !allValue) { + code = TSDB_CODE_PAR_PRIMARY_KEY_IS_NULL; + goto _exit; + } + + if (allValue) { + // optimize (todo) + for (int32_t i = 0; i < pBind->num; ++i) { + code = tColDataAppendValueImpl[pColData->flag][CV_FLAG_VALUE]( + pColData, (uint8_t *)pBind->buffer + TYPE_BYTES[pColData->type] * i, pBind->buffer_length); + } + } else if (allNull) { + // optimize (todo) + for (int32_t i = 0; i < pBind->num; ++i) { + code = tColDataAppendValueImpl[pColData->flag][CV_FLAG_NULL](pColData, NULL, 0); + if (code) goto _exit; + } + } else { + for (int32_t i = 0; i < pBind->num; ++i) { + if (pBind->is_null[i]) { + code = tColDataAppendValueImpl[pColData->flag][CV_FLAG_NULL](pColData, NULL, 0); + if (code) goto _exit; + } else { + code = tColDataAppendValueImpl[pColData->flag][CV_FLAG_VALUE]( + pColData, (uint8_t *)pBind->buffer + TYPE_BYTES[pColData->type] * i, pBind->buffer_length); + } + } + } + } + +_exit: + return code; +} + +/* build rows to `rowArray` from bind + * `infos` is the bind information array + * `numOfInfos` is the number of bind information + * `infoSorted` is whether the bind information is sorted by column id + * `pTSchema` is the schema of the table + * `rowArray` is the array to store the rows + */ +int32_t tRowBuildFromBind2(SBindInfo2 *infos, int32_t numOfInfos, bool infoSorted, const STSchema *pTSchema, + SArray *rowArray) { + if (infos == NULL || numOfInfos <= 0 || numOfInfos > pTSchema->numOfCols || pTSchema == NULL || rowArray == NULL) { + return TSDB_CODE_INVALID_PARA; + } + + if (!infoSorted) { + taosqsort_r(infos, numOfInfos, sizeof(SBindInfo), NULL, tBindInfoCompare); + } + + int32_t code = 0; + int32_t numOfRows = infos[0].bind->num; + SArray *colValArray; + SColVal colVal; + + if ((colValArray = taosArrayInit(numOfInfos, sizeof(SColVal))) == NULL) { + return terrno; + } + + for (int32_t iRow = 0; iRow < numOfRows; iRow++) { + taosArrayClear(colValArray); + + for (int32_t iInfo = 0; iInfo < numOfInfos; iInfo++) { + if (infos[iInfo].bind->is_null && infos[iInfo].bind->is_null[iRow]) { + colVal = COL_VAL_NULL(infos[iInfo].columnId, infos[iInfo].type); + } else { + SValue value = { + .type = infos[iInfo].type, + }; + if (IS_VAR_DATA_TYPE(infos[iInfo].type)) { + value.nData = infos[iInfo].bind->length[iRow]; + value.pData = (uint8_t *)infos[iInfo].bind->buffer + infos[iInfo].bind->buffer_length * iRow; + } else { + (void)memcpy(&value.val, (uint8_t *)infos[iInfo].bind->buffer + infos[iInfo].bind->buffer_length * iRow, + infos[iInfo].bind->buffer_length); + } + colVal = COL_VAL_VALUE(infos[iInfo].columnId, value); + } + if (taosArrayPush(colValArray, &colVal) == NULL) { + code = TSDB_CODE_OUT_OF_MEMORY; + goto _exit; + } + } + + SRow *row; + if ((code = tRowBuild(colValArray, pTSchema, &row))) { + goto _exit; + } + + if ((taosArrayPush(rowArray, &row)) == NULL) { + code = TSDB_CODE_OUT_OF_MEMORY; + goto _exit; + } + } + +_exit: + taosArrayDestroy(colValArray); + return code; +} + static int32_t tColDataCopyRowCell(SColData *pFromColData, int32_t iFromRow, SColData *pToColData, int32_t iToRow) { int32_t code = TSDB_CODE_SUCCESS; diff --git a/source/libs/parser/src/parInsertStmt.c b/source/libs/parser/src/parInsertStmt.c index 025459a8c9..62a52f522f 100644 --- a/source/libs/parser/src/parInsertStmt.c +++ b/source/libs/parser/src/parInsertStmt.c @@ -448,7 +448,348 @@ int32_t qBindStmtSingleColValue(void* pBlock, SArray* pCols, TAOS_MULTI_BIND* bi pBind = bind; } - code = tColDataAddValueByBind(pCol, pBind, IS_VAR_DATA_TYPE(pColSchema->type) ? pColSchema->bytes - VARSTR_HEADER_SIZE : -1); + code = tColDataAddValueByBind(pCol, pBind, + IS_VAR_DATA_TYPE(pColSchema->type) ? pColSchema->bytes - VARSTR_HEADER_SIZE : -1); + + qDebug("stmt col %d bind %d rows data", colIdx, rowNum); + +_return: + + taosMemoryFree(ncharBind.buffer); + taosMemoryFree(ncharBind.length); + + return code; +} + +static int32_t convertStmtNcharCol2(SMsgBuf* pMsgBuf, SSchema* pSchema, TAOS_STMT2_BIND* src, TAOS_STMT2_BIND* dst) { + int32_t output = 0; + int32_t newBuflen = (pSchema->bytes - VARSTR_HEADER_SIZE) * src->num; + if (dst->buffer_length < newBuflen) { + dst->buffer = taosMemoryRealloc(dst->buffer, newBuflen); + if (NULL == dst->buffer) { + return TSDB_CODE_OUT_OF_MEMORY; + } + } + + if (NULL == dst->length) { + dst->length = taosMemoryRealloc(dst->length, sizeof(int32_t) * src->num); + if (NULL == dst->length) { + taosMemoryFreeClear(dst->buffer); + return TSDB_CODE_OUT_OF_MEMORY; + } + } + + dst->buffer_length = pSchema->bytes - VARSTR_HEADER_SIZE; + + for (int32_t i = 0; i < src->num; ++i) { + if (src->is_null && src->is_null[i]) { + continue; + } + + if (!taosMbsToUcs4(((char*)src->buffer) + src->buffer_length * i, src->length[i], + (TdUcs4*)(((char*)dst->buffer) + dst->buffer_length * i), dst->buffer_length, &output)) { + if (errno == E2BIG) { + return generateSyntaxErrMsg(pMsgBuf, TSDB_CODE_PAR_VALUE_TOO_LONG, pSchema->name); + } + char buf[512] = {0}; + snprintf(buf, tListLen(buf), "%s", strerror(errno)); + return buildSyntaxErrMsg(pMsgBuf, buf, NULL); + } + + dst->length[i] = output; + } + + dst->buffer_type = src->buffer_type; + dst->is_null = src->is_null; + dst->num = src->num; + + return TSDB_CODE_SUCCESS; +} + +int32_t qBindStmtStbColsValue2(void* pBlock, SArray* pCols, TAOS_STMT2_BIND* bind, char* msgBuf, int32_t msgBufLen, + STSchema** pTSchema, SBindInfo2* pBindInfos) { + STableDataCxt* pDataBlock = (STableDataCxt*)pBlock; + SSchema* pSchema = getTableColumnSchema(pDataBlock->pMeta); + SBoundColInfo* boundInfo = &pDataBlock->boundColsInfo; + SMsgBuf pBuf = {.buf = msgBuf, .len = msgBufLen}; + int32_t rowNum = bind->num; + TAOS_STMT2_BIND ncharBind = {0}; + TAOS_STMT2_BIND* pBind = NULL; + int32_t code = 0; + int16_t lastColId = -1; + bool colInOrder = true; + + if (NULL == *pTSchema) { + *pTSchema = tBuildTSchema(pSchema, pDataBlock->pMeta->tableInfo.numOfColumns, pDataBlock->pMeta->sversion); + } + + for (int c = 0; c < boundInfo->numOfBound; ++c) { + SSchema* pColSchema = &pSchema[boundInfo->pColIndex[c]]; + if (pColSchema->colId <= lastColId) { + colInOrder = false; + } else { + lastColId = pColSchema->colId; + } + // SColData* pCol = taosArrayGet(pCols, c); + + if (bind[c].num != rowNum) { + code = buildInvalidOperationMsg(&pBuf, "row number in each bind param should be the same"); + goto _return; + } + + if ((!(rowNum == 1 && bind[c].is_null && *bind[c].is_null)) && + bind[c].buffer_type != pColSchema->type) { // for rowNum ==1 , connector may not set buffer_type + code = buildInvalidOperationMsg(&pBuf, "column type mis-match with buffer type"); + goto _return; + } + + if (TSDB_DATA_TYPE_NCHAR == pColSchema->type) { + code = convertStmtNcharCol2(&pBuf, pColSchema, bind + c, &ncharBind); + if (code) { + goto _return; + } + pBind = &ncharBind; + } else { + pBind = bind + c; + } + + pBindInfos[c].columnId = pColSchema->colId; + pBindInfos[c].bind = pBind; + pBindInfos[c].type = pColSchema->type; + + // code = tColDataAddValueByBind(pCol, pBind, IS_VAR_DATA_TYPE(pColSchema->type) ? pColSchema->bytes - + // VARSTR_HEADER_SIZE: -1); if (code) { + // goto _return; + // } + } + + code = tRowBuildFromBind2(pBindInfos, boundInfo->numOfBound, colInOrder, *pTSchema, pCols); + + qDebug("stmt all %d columns bind %d rows data", boundInfo->numOfBound, rowNum); + +_return: + + taosMemoryFree(ncharBind.buffer); + taosMemoryFree(ncharBind.length); + + return code; +} + +int32_t qBindStmtTagsValue2(void* pBlock, void* boundTags, int64_t suid, const char* sTableName, char* tName, + TAOS_STMT2_BIND* bind, char* msgBuf, int32_t msgBufLen) { + STableDataCxt* pDataBlock = (STableDataCxt*)pBlock; + SMsgBuf pBuf = {.buf = msgBuf, .len = msgBufLen}; + int32_t code = TSDB_CODE_SUCCESS; + SBoundColInfo* tags = (SBoundColInfo*)boundTags; + if (NULL == tags) { + return TSDB_CODE_APP_ERROR; + } + + SArray* pTagArray = taosArrayInit(tags->numOfBound, sizeof(STagVal)); + if (!pTagArray) { + return buildInvalidOperationMsg(&pBuf, "out of memory"); + } + + SArray* tagName = taosArrayInit(8, TSDB_COL_NAME_LEN); + if (!tagName) { + code = buildInvalidOperationMsg(&pBuf, "out of memory"); + goto end; + } + + SSchema* pSchema = getTableTagSchema(pDataBlock->pMeta); + + bool isJson = false; + STag* pTag = NULL; + + for (int c = 0; c < tags->numOfBound; ++c) { + if (bind[c].is_null && bind[c].is_null[0]) { + continue; + } + + SSchema* pTagSchema = &pSchema[tags->pColIndex[c]]; + int32_t colLen = pTagSchema->bytes; + if (IS_VAR_DATA_TYPE(pTagSchema->type)) { + colLen = bind[c].length[0]; + if ((colLen + VARSTR_HEADER_SIZE) > pTagSchema->bytes) { + code = buildInvalidOperationMsg(&pBuf, "tag length is too big"); + goto end; + } + } + if (NULL == taosArrayPush(tagName, pTagSchema->name)) { + code = TSDB_CODE_OUT_OF_MEMORY; + goto end; + } + if (pTagSchema->type == TSDB_DATA_TYPE_JSON) { + if (colLen > (TSDB_MAX_JSON_TAG_LEN - VARSTR_HEADER_SIZE) / TSDB_NCHAR_SIZE) { + code = buildSyntaxErrMsg(&pBuf, "json string too long than 4095", bind[c].buffer); + goto end; + } + + isJson = true; + char* tmp = taosMemoryCalloc(1, colLen + 1); + memcpy(tmp, bind[c].buffer, colLen); + code = parseJsontoTagData(tmp, pTagArray, &pTag, &pBuf); + taosMemoryFree(tmp); + if (code != TSDB_CODE_SUCCESS) { + goto end; + } + } else { + STagVal val = {.cid = pTagSchema->colId, .type = pTagSchema->type}; + // strcpy(val.colName, pTagSchema->name); + if (pTagSchema->type == TSDB_DATA_TYPE_BINARY || pTagSchema->type == TSDB_DATA_TYPE_VARBINARY || + pTagSchema->type == TSDB_DATA_TYPE_GEOMETRY) { + val.pData = (uint8_t*)bind[c].buffer; + val.nData = colLen; + } else if (pTagSchema->type == TSDB_DATA_TYPE_NCHAR) { + int32_t output = 0; + void* p = taosMemoryCalloc(1, colLen * TSDB_NCHAR_SIZE); + if (p == NULL) { + code = TSDB_CODE_OUT_OF_MEMORY; + goto end; + } + if (!taosMbsToUcs4(bind[c].buffer, colLen, (TdUcs4*)(p), colLen * TSDB_NCHAR_SIZE, &output)) { + if (errno == E2BIG) { + taosMemoryFree(p); + code = generateSyntaxErrMsg(&pBuf, TSDB_CODE_PAR_VALUE_TOO_LONG, pTagSchema->name); + goto end; + } + char buf[512] = {0}; + snprintf(buf, tListLen(buf), " taosMbsToUcs4 error:%s", strerror(errno)); + taosMemoryFree(p); + code = buildSyntaxErrMsg(&pBuf, buf, bind[c].buffer); + goto end; + } + val.pData = p; + val.nData = output; + } else { + memcpy(&val.i64, bind[c].buffer, colLen); + } + if (NULL == taosArrayPush(pTagArray, &val)) { + code = TSDB_CODE_OUT_OF_MEMORY; + goto end; + } + } + } + + if (!isJson && (code = tTagNew(pTagArray, 1, false, &pTag)) != TSDB_CODE_SUCCESS) { + goto end; + } + + if (NULL == pDataBlock->pData->pCreateTbReq) { + pDataBlock->pData->pCreateTbReq = taosMemoryCalloc(1, sizeof(SVCreateTbReq)); + if (NULL == pDataBlock->pData->pCreateTbReq) { + code = TSDB_CODE_OUT_OF_MEMORY; + goto end; + } + } + + insBuildCreateTbReq(pDataBlock->pData->pCreateTbReq, tName, pTag, suid, sTableName, tagName, + pDataBlock->pMeta->tableInfo.numOfTags, TSDB_DEFAULT_TABLE_TTL); + pTag = NULL; + +end: + for (int i = 0; i < taosArrayGetSize(pTagArray); ++i) { + STagVal* p = (STagVal*)taosArrayGet(pTagArray, i); + if (p->type == TSDB_DATA_TYPE_NCHAR) { + taosMemoryFreeClear(p->pData); + } + } + taosArrayDestroy(pTagArray); + taosArrayDestroy(tagName); + taosMemoryFree(pTag); + + return code; +} + +int32_t qBindStmtColsValue2(void* pBlock, SArray* pCols, TAOS_STMT2_BIND* bind, char* msgBuf, int32_t msgBufLen) { + STableDataCxt* pDataBlock = (STableDataCxt*)pBlock; + SSchema* pSchema = getTableColumnSchema(pDataBlock->pMeta); + SBoundColInfo* boundInfo = &pDataBlock->boundColsInfo; + SMsgBuf pBuf = {.buf = msgBuf, .len = msgBufLen}; + int32_t rowNum = bind->num; + TAOS_STMT2_BIND ncharBind = {0}; + TAOS_STMT2_BIND* pBind = NULL; + int32_t code = 0; + + for (int c = 0; c < boundInfo->numOfBound; ++c) { + SSchema* pColSchema = &pSchema[boundInfo->pColIndex[c]]; + SColData* pCol = taosArrayGet(pCols, c); + + if (bind[c].num != rowNum) { + code = buildInvalidOperationMsg(&pBuf, "row number in each bind param should be the same"); + goto _return; + } + + if ((!(rowNum == 1 && bind[c].is_null && *bind[c].is_null)) && + bind[c].buffer_type != pColSchema->type) { // for rowNum ==1 , connector may not set buffer_type + code = buildInvalidOperationMsg(&pBuf, "column type mis-match with buffer type"); + goto _return; + } + + if (TSDB_DATA_TYPE_NCHAR == pColSchema->type) { + code = convertStmtNcharCol2(&pBuf, pColSchema, bind + c, &ncharBind); + if (code) { + goto _return; + } + pBind = &ncharBind; + } else { + pBind = bind + c; + } + + code = tColDataAddValueByBind2(pCol, pBind, + IS_VAR_DATA_TYPE(pColSchema->type) ? pColSchema->bytes - VARSTR_HEADER_SIZE : -1); + if (code) { + goto _return; + } + } + + qDebug("stmt all %d columns bind %d rows data", boundInfo->numOfBound, rowNum); + +_return: + + taosMemoryFree(ncharBind.buffer); + taosMemoryFree(ncharBind.length); + + return code; +} + +int32_t qBindStmtSingleColValue2(void* pBlock, SArray* pCols, TAOS_STMT2_BIND* bind, char* msgBuf, int32_t msgBufLen, + int32_t colIdx, int32_t rowNum) { + STableDataCxt* pDataBlock = (STableDataCxt*)pBlock; + SSchema* pSchema = getTableColumnSchema(pDataBlock->pMeta); + SBoundColInfo* boundInfo = &pDataBlock->boundColsInfo; + SMsgBuf pBuf = {.buf = msgBuf, .len = msgBufLen}; + SSchema* pColSchema = &pSchema[boundInfo->pColIndex[colIdx]]; + SColData* pCol = taosArrayGet(pCols, colIdx); + TAOS_STMT2_BIND ncharBind = {0}; + TAOS_STMT2_BIND* pBind = NULL; + int32_t code = 0; + + if (bind->num != rowNum) { + return buildInvalidOperationMsg(&pBuf, "row number in each bind param should be the same"); + } + + // Column index exceeds the number of columns + if (colIdx >= pCols->size && pCol == NULL) { + return buildInvalidOperationMsg(&pBuf, "column index exceeds the number of columns"); + } + + if (bind->buffer_type != pColSchema->type) { + return buildInvalidOperationMsg(&pBuf, "column type mis-match with buffer type"); + } + + if (TSDB_DATA_TYPE_NCHAR == pColSchema->type) { + code = convertStmtNcharCol2(&pBuf, pColSchema, bind, &ncharBind); + if (code) { + goto _return; + } + pBind = &ncharBind; + } else { + pBind = bind; + } + + code = tColDataAddValueByBind2(pCol, pBind, + IS_VAR_DATA_TYPE(pColSchema->type) ? pColSchema->bytes - VARSTR_HEADER_SIZE : -1); qDebug("stmt col %d bind %d rows data", colIdx, rowNum); @@ -533,7 +874,7 @@ int32_t qResetStmtColumns(SArray* pCols, bool deepClear) { for (int32_t i = 0; i < colNum; ++i) { SColData* pCol = (SColData*)taosArrayGet(pCols, i); - if (pCol == NULL){ + if (pCol == NULL) { qError("qResetStmtColumns column is NULL"); return TSDB_CODE_OUT_OF_MEMORY; } @@ -553,7 +894,7 @@ int32_t qResetStmtDataBlock(STableDataCxt* block, bool deepClear) { for (int32_t i = 0; i < colNum; ++i) { SColData* pCol = (SColData*)taosArrayGet(pBlock->pData->aCol, i); - if (pCol == NULL){ + if (pCol == NULL) { qError("qResetStmtDataBlock column is NULL"); return TSDB_CODE_OUT_OF_MEMORY; } diff --git a/source/libs/parser/src/parser.c b/source/libs/parser/src/parser.c index e96aaf52ed..b78cd36f0e 100644 --- a/source/libs/parser/src/parser.c +++ b/source/libs/parser/src/parser.c @@ -76,33 +76,33 @@ bool qIsCreateTbFromFileSql(const char* pStr, size_t length) { } bool qParseDbName(const char* pStr, size_t length, char** pDbName) { - (void) length; + (void)length; int32_t index = 0; - SToken t; + SToken t; if (NULL == pStr) { *pDbName = NULL; return false; } - t = tStrGetToken((char *) pStr, &index, false, NULL); + t = tStrGetToken((char*)pStr, &index, false, NULL); if (TK_INSERT != t.type && TK_IMPORT != t.type) { *pDbName = NULL; return false; } - t = tStrGetToken((char *) pStr, &index, false, NULL); + t = tStrGetToken((char*)pStr, &index, false, NULL); if (TK_INTO != t.type) { *pDbName = NULL; return false; } - t = tStrGetToken((char *) pStr, &index, false, NULL); + t = tStrGetToken((char*)pStr, &index, false, NULL); if (t.n == 0 || t.z == NULL) { *pDbName = NULL; return false; } - char *dotPos = strnchr(t.z, '.', t.n, true); + char* dotPos = strnchr(t.z, '.', t.n, true); if (dotPos != NULL) { int dbNameLen = dotPos - t.z; *pDbName = taosMemoryMalloc(dbNameLen + 1); @@ -331,13 +331,12 @@ int32_t qContinueParsePostQuery(SParseContext* pCxt, SQuery* pQuery, SSDataBlock return code; } - -static void destoryTablesReq(void *p) { - STablesReq *pRes = (STablesReq *)p; +static void destoryTablesReq(void* p) { + STablesReq* pRes = (STablesReq*)p; taosArrayDestroy(pRes->pTables); } -void destoryCatalogReq(SCatalogReq *pCatalogReq) { +void destoryCatalogReq(SCatalogReq* pCatalogReq) { if (NULL == pCatalogReq) { return; } @@ -369,7 +368,6 @@ void destoryCatalogReq(SCatalogReq *pCatalogReq) { taosArrayDestroy(pCatalogReq->pTableTag); } - void tfreeSParseQueryRes(void* p) { if (NULL == p) { return; @@ -410,9 +408,7 @@ int32_t qSetSTableIdForRsma(SNode* pStmt, int64_t uid) { return TSDB_CODE_FAILED; } -int32_t qInitKeywordsTable() { - return taosInitKeywordsTable(); -} +int32_t qInitKeywordsTable() { return taosInitKeywordsTable(); } void qCleanupKeywordsTable() { taosCleanupKeywordsTable(); } @@ -445,6 +441,98 @@ int32_t qStmtBindParams(SQuery* pQuery, TAOS_MULTI_BIND* pParams, int32_t colIdx return code; } +static int32_t setValueByBindParam2(SValueNode* pVal, TAOS_STMT2_BIND* pParam) { + if (IS_VAR_DATA_TYPE(pVal->node.resType.type)) { + taosMemoryFreeClear(pVal->datum.p); + } + + if (pParam->is_null && 1 == *(pParam->is_null)) { + pVal->node.resType.type = TSDB_DATA_TYPE_NULL; + pVal->node.resType.bytes = tDataTypes[TSDB_DATA_TYPE_NULL].bytes; + return TSDB_CODE_SUCCESS; + } + + int32_t inputSize = (NULL != pParam->length ? *(pParam->length) : tDataTypes[pParam->buffer_type].bytes); + pVal->node.resType.type = pParam->buffer_type; + pVal->node.resType.bytes = inputSize; + + switch (pParam->buffer_type) { + case TSDB_DATA_TYPE_VARBINARY: + pVal->datum.p = taosMemoryCalloc(1, pVal->node.resType.bytes + VARSTR_HEADER_SIZE + 1); + if (NULL == pVal->datum.p) { + return TSDB_CODE_OUT_OF_MEMORY; + } + varDataSetLen(pVal->datum.p, pVal->node.resType.bytes); + memcpy(varDataVal(pVal->datum.p), pParam->buffer, pVal->node.resType.bytes); + pVal->node.resType.bytes += VARSTR_HEADER_SIZE; + break; + case TSDB_DATA_TYPE_VARCHAR: + case TSDB_DATA_TYPE_GEOMETRY: + pVal->datum.p = taosMemoryCalloc(1, pVal->node.resType.bytes + VARSTR_HEADER_SIZE + 1); + if (NULL == pVal->datum.p) { + return TSDB_CODE_OUT_OF_MEMORY; + } + varDataSetLen(pVal->datum.p, pVal->node.resType.bytes); + strncpy(varDataVal(pVal->datum.p), (const char*)pParam->buffer, pVal->node.resType.bytes); + pVal->node.resType.bytes += VARSTR_HEADER_SIZE; + break; + case TSDB_DATA_TYPE_NCHAR: { + pVal->node.resType.bytes *= TSDB_NCHAR_SIZE; + pVal->datum.p = taosMemoryCalloc(1, pVal->node.resType.bytes + VARSTR_HEADER_SIZE + 1); + if (NULL == pVal->datum.p) { + return TSDB_CODE_OUT_OF_MEMORY; + } + + int32_t output = 0; + if (!taosMbsToUcs4(pParam->buffer, inputSize, (TdUcs4*)varDataVal(pVal->datum.p), pVal->node.resType.bytes, + &output)) { + return errno; + } + varDataSetLen(pVal->datum.p, output); + pVal->node.resType.bytes = output + VARSTR_HEADER_SIZE; + break; + } + default: { + int32_t code = nodesSetValueNodeValue(pVal, pParam->buffer); + if (code) { + return code; + } + break; + } + } + pVal->translate = true; + return TSDB_CODE_SUCCESS; +} + +int32_t qStmtBindParams2(SQuery* pQuery, TAOS_STMT2_BIND* pParams, int32_t colIdx) { + int32_t code = TSDB_CODE_SUCCESS; + + if (colIdx < 0) { + int32_t size = taosArrayGetSize(pQuery->pPlaceholderValues); + for (int32_t i = 0; i < size; ++i) { + code = setValueByBindParam2((SValueNode*)taosArrayGetP(pQuery->pPlaceholderValues, i), pParams + i); + if (TSDB_CODE_SUCCESS != code) { + return code; + } + } + } else { + code = setValueByBindParam2((SValueNode*)taosArrayGetP(pQuery->pPlaceholderValues, colIdx), pParams); + } + + if (TSDB_CODE_SUCCESS == code && (colIdx < 0 || colIdx + 1 == pQuery->placeholderNum)) { + nodesDestroyNode(pQuery->pRoot); + pQuery->pRoot = NULL; + code = nodesCloneNode(pQuery->pPrepareRoot, &pQuery->pRoot); + if (NULL == pQuery->pRoot) { + code = code; + } + } + if (TSDB_CODE_SUCCESS == code) { + rewriteExprAlias(pQuery->pRoot); + } + return code; +} + int32_t qStmtParseQuerySql(SParseContext* pCxt, SQuery* pQuery) { int32_t code = translate(pCxt, pQuery, NULL); if (TSDB_CODE_SUCCESS == code) { From 0630b7d7aedcdb62480f8ac837b75c413fa6a679 Mon Sep 17 00:00:00 2001 From: Minglei Jin Date: Thu, 15 Aug 2024 10:34:23 +0800 Subject: [PATCH 02/23] fix the first commit's stmtIsInsert2 --- source/client/src/clientMain.c | 2 +- source/client/src/clientStmt2.c | 35 ++++++++++++++++----------------- 2 files changed, 18 insertions(+), 19 deletions(-) diff --git a/source/client/src/clientMain.c b/source/client/src/clientMain.c index 52895bb24b..67ccfe3637 100644 --- a/source/client/src/clientMain.c +++ b/source/client/src/clientMain.c @@ -1941,7 +1941,7 @@ int taos_stmt2_bind_param(TAOS_STMT2 *stmt, TAOS_STMT2_BINDV *bindv, int32_t col } int32_t insert = 0; - (void)stmtIsInsert(stmt, &insert); + (void)stmtIsInsert2(stmt, &insert); if (0 == insert && bind->num > 1) { tscError("only one row data allowed for query"); terrno = TSDB_CODE_INVALID_PARA; diff --git a/source/client/src/clientStmt2.c b/source/client/src/clientStmt2.c index 5f7abefa85..e8b8514460 100644 --- a/source/client/src/clientStmt2.c +++ b/source/client/src/clientStmt2.c @@ -978,6 +978,20 @@ static int32_t stmtInitStbInterlaceTableInfo(STscStmt2* pStmt) { return TSDB_CODE_SUCCESS; } +int stmtIsInsert2(TAOS_STMT2* stmt, int* insert) { + STscStmt2* pStmt = (STscStmt2*)stmt; + + STMT_DLOG_E("start is insert"); + + if (pStmt->sql.type) { + *insert = (STMT_TYPE_INSERT == pStmt->sql.type || STMT_TYPE_MULTI_INSERT == pStmt->sql.type); + } else { + *insert = qIsInsertValuesSql(pStmt->sql.sqlStr, pStmt->sql.sqlLen); + } + + return TSDB_CODE_SUCCESS; +} + int stmtSetTbName2(TAOS_STMT2* stmt, const char* tbName) { STscStmt2* pStmt = (STscStmt2*)stmt; @@ -992,7 +1006,7 @@ int stmtSetTbName2(TAOS_STMT2* stmt, const char* tbName) { STMT_ERR_RET(stmtSwitchStatus(pStmt, STMT_SETTBNAME)); int32_t insert = 0; - STMT_ERR_RET(stmtIsInsert(stmt, &insert)); + STMT_ERR_RET(stmtIsInsert2(stmt, &insert)); if (0 == insert) { tscError("set tb name not available for none insert statement"); STMT_ERR_RET(TSDB_CODE_TSC_STMT_API_ERROR); @@ -1066,7 +1080,7 @@ int stmtSetTbTags2(TAOS_STMT2* stmt, TAOS_STMT2_BIND* tags) { return TSDB_CODE_SUCCESS; } -int stmtFetchTagFields2(STscStmt2* pStmt, int32_t* fieldNum, TAOS_FIELD_E** fields) { +static int stmtFetchTagFields2(STscStmt2* pStmt, int32_t* fieldNum, TAOS_FIELD_E** fields) { if (pStmt->errCode != TSDB_CODE_SUCCESS) { return pStmt->errCode; } @@ -1088,7 +1102,7 @@ int stmtFetchTagFields2(STscStmt2* pStmt, int32_t* fieldNum, TAOS_FIELD_E** fiel return TSDB_CODE_SUCCESS; } -int stmtFetchColFields2(STscStmt2* pStmt, int32_t* fieldNum, TAOS_FIELD_E** fields) { +static int stmtFetchColFields2(STscStmt2* pStmt, int32_t* fieldNum, TAOS_FIELD_E** fields) { if (pStmt->errCode != TSDB_CODE_SUCCESS) { return pStmt->errCode; } @@ -1608,7 +1622,6 @@ int stmtExec2(TAOS_STMT2* stmt, int* affected_rows) { } else { pWrapper->pRequest = pStmt->exec.pRequest; pStmt->exec.pRequest->pWrapper = pWrapper; - //*ppWrapper = pWrapper; } if (TSDB_CODE_SUCCESS == code) { code = createParseContext(pStmt->exec.pRequest, &pWrapper->pParseCtx, pWrapper); @@ -1698,20 +1711,6 @@ int stmtAffectedRows(TAOS_STMT* stmt) { return ((STscStmt2*)stmt)->affectedRows; int stmtAffectedRowsOnce(TAOS_STMT* stmt) { return ((STscStmt2*)stmt)->exec.affectedRows; } */ -int stmtIsInsert2(TAOS_STMT2* stmt, int* insert) { - STscStmt2* pStmt = (STscStmt2*)stmt; - - STMT_DLOG_E("start is insert"); - - if (pStmt->sql.type) { - *insert = (STMT_TYPE_INSERT == pStmt->sql.type || STMT_TYPE_MULTI_INSERT == pStmt->sql.type); - } else { - *insert = qIsInsertValuesSql(pStmt->sql.sqlStr, pStmt->sql.sqlLen); - } - - return TSDB_CODE_SUCCESS; -} - int stmtGetTagFields2(TAOS_STMT2* stmt, int* nums, TAOS_FIELD_E** fields) { int32_t code = 0; STscStmt2* pStmt = (STscStmt2*)stmt; From bf4f0bc3770d3c4d8c515c2d3cee7265e7895ab3 Mon Sep 17 00:00:00 2001 From: Minglei Jin Date: Thu, 15 Aug 2024 16:06:16 +0800 Subject: [PATCH 03/23] move tag binding out of cols binding --- source/client/src/clientStmt2.c | 2 +- source/libs/parser/src/parInsertStmt.c | 228 ++++++++++++------------- 2 files changed, 115 insertions(+), 115 deletions(-) diff --git a/source/client/src/clientStmt2.c b/source/client/src/clientStmt2.c index e8b8514460..e938e27cc8 100644 --- a/source/client/src/clientStmt2.c +++ b/source/client/src/clientStmt2.c @@ -1057,7 +1057,7 @@ int stmtSetTbTags2(TAOS_STMT2* stmt, TAOS_STMT2_BIND* tags) { 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"); + tscWarn("no tags or cols bound in sql, will not bound tags"); return TSDB_CODE_SUCCESS; } diff --git a/source/libs/parser/src/parInsertStmt.c b/source/libs/parser/src/parInsertStmt.c index 62a52f522f..01719b699a 100644 --- a/source/libs/parser/src/parInsertStmt.c +++ b/source/libs/parser/src/parInsertStmt.c @@ -461,120 +461,6 @@ _return: return code; } -static int32_t convertStmtNcharCol2(SMsgBuf* pMsgBuf, SSchema* pSchema, TAOS_STMT2_BIND* src, TAOS_STMT2_BIND* dst) { - int32_t output = 0; - int32_t newBuflen = (pSchema->bytes - VARSTR_HEADER_SIZE) * src->num; - if (dst->buffer_length < newBuflen) { - dst->buffer = taosMemoryRealloc(dst->buffer, newBuflen); - if (NULL == dst->buffer) { - return TSDB_CODE_OUT_OF_MEMORY; - } - } - - if (NULL == dst->length) { - dst->length = taosMemoryRealloc(dst->length, sizeof(int32_t) * src->num); - if (NULL == dst->length) { - taosMemoryFreeClear(dst->buffer); - return TSDB_CODE_OUT_OF_MEMORY; - } - } - - dst->buffer_length = pSchema->bytes - VARSTR_HEADER_SIZE; - - for (int32_t i = 0; i < src->num; ++i) { - if (src->is_null && src->is_null[i]) { - continue; - } - - if (!taosMbsToUcs4(((char*)src->buffer) + src->buffer_length * i, src->length[i], - (TdUcs4*)(((char*)dst->buffer) + dst->buffer_length * i), dst->buffer_length, &output)) { - if (errno == E2BIG) { - return generateSyntaxErrMsg(pMsgBuf, TSDB_CODE_PAR_VALUE_TOO_LONG, pSchema->name); - } - char buf[512] = {0}; - snprintf(buf, tListLen(buf), "%s", strerror(errno)); - return buildSyntaxErrMsg(pMsgBuf, buf, NULL); - } - - dst->length[i] = output; - } - - dst->buffer_type = src->buffer_type; - dst->is_null = src->is_null; - dst->num = src->num; - - return TSDB_CODE_SUCCESS; -} - -int32_t qBindStmtStbColsValue2(void* pBlock, SArray* pCols, TAOS_STMT2_BIND* bind, char* msgBuf, int32_t msgBufLen, - STSchema** pTSchema, SBindInfo2* pBindInfos) { - STableDataCxt* pDataBlock = (STableDataCxt*)pBlock; - SSchema* pSchema = getTableColumnSchema(pDataBlock->pMeta); - SBoundColInfo* boundInfo = &pDataBlock->boundColsInfo; - SMsgBuf pBuf = {.buf = msgBuf, .len = msgBufLen}; - int32_t rowNum = bind->num; - TAOS_STMT2_BIND ncharBind = {0}; - TAOS_STMT2_BIND* pBind = NULL; - int32_t code = 0; - int16_t lastColId = -1; - bool colInOrder = true; - - if (NULL == *pTSchema) { - *pTSchema = tBuildTSchema(pSchema, pDataBlock->pMeta->tableInfo.numOfColumns, pDataBlock->pMeta->sversion); - } - - for (int c = 0; c < boundInfo->numOfBound; ++c) { - SSchema* pColSchema = &pSchema[boundInfo->pColIndex[c]]; - if (pColSchema->colId <= lastColId) { - colInOrder = false; - } else { - lastColId = pColSchema->colId; - } - // SColData* pCol = taosArrayGet(pCols, c); - - if (bind[c].num != rowNum) { - code = buildInvalidOperationMsg(&pBuf, "row number in each bind param should be the same"); - goto _return; - } - - if ((!(rowNum == 1 && bind[c].is_null && *bind[c].is_null)) && - bind[c].buffer_type != pColSchema->type) { // for rowNum ==1 , connector may not set buffer_type - code = buildInvalidOperationMsg(&pBuf, "column type mis-match with buffer type"); - goto _return; - } - - if (TSDB_DATA_TYPE_NCHAR == pColSchema->type) { - code = convertStmtNcharCol2(&pBuf, pColSchema, bind + c, &ncharBind); - if (code) { - goto _return; - } - pBind = &ncharBind; - } else { - pBind = bind + c; - } - - pBindInfos[c].columnId = pColSchema->colId; - pBindInfos[c].bind = pBind; - pBindInfos[c].type = pColSchema->type; - - // code = tColDataAddValueByBind(pCol, pBind, IS_VAR_DATA_TYPE(pColSchema->type) ? pColSchema->bytes - - // VARSTR_HEADER_SIZE: -1); if (code) { - // goto _return; - // } - } - - code = tRowBuildFromBind2(pBindInfos, boundInfo->numOfBound, colInOrder, *pTSchema, pCols); - - qDebug("stmt all %d columns bind %d rows data", boundInfo->numOfBound, rowNum); - -_return: - - taosMemoryFree(ncharBind.buffer); - taosMemoryFree(ncharBind.length); - - return code; -} - int32_t qBindStmtTagsValue2(void* pBlock, void* boundTags, int64_t suid, const char* sTableName, char* tName, TAOS_STMT2_BIND* bind, char* msgBuf, int32_t msgBufLen) { STableDataCxt* pDataBlock = (STableDataCxt*)pBlock; @@ -701,6 +587,120 @@ end: return code; } +static int32_t convertStmtNcharCol2(SMsgBuf* pMsgBuf, SSchema* pSchema, TAOS_STMT2_BIND* src, TAOS_STMT2_BIND* dst) { + int32_t output = 0; + int32_t newBuflen = (pSchema->bytes - VARSTR_HEADER_SIZE) * src->num; + if (dst->buffer_length < newBuflen) { + dst->buffer = taosMemoryRealloc(dst->buffer, newBuflen); + if (NULL == dst->buffer) { + return TSDB_CODE_OUT_OF_MEMORY; + } + } + + if (NULL == dst->length) { + dst->length = taosMemoryRealloc(dst->length, sizeof(int32_t) * src->num); + if (NULL == dst->length) { + taosMemoryFreeClear(dst->buffer); + return TSDB_CODE_OUT_OF_MEMORY; + } + } + + dst->buffer_length = pSchema->bytes - VARSTR_HEADER_SIZE; + + for (int32_t i = 0; i < src->num; ++i) { + if (src->is_null && src->is_null[i]) { + continue; + } + + if (!taosMbsToUcs4(((char*)src->buffer) + src->buffer_length * i, src->length[i], + (TdUcs4*)(((char*)dst->buffer) + dst->buffer_length * i), dst->buffer_length, &output)) { + if (errno == E2BIG) { + return generateSyntaxErrMsg(pMsgBuf, TSDB_CODE_PAR_VALUE_TOO_LONG, pSchema->name); + } + char buf[512] = {0}; + snprintf(buf, tListLen(buf), "%s", strerror(errno)); + return buildSyntaxErrMsg(pMsgBuf, buf, NULL); + } + + dst->length[i] = output; + } + + dst->buffer_type = src->buffer_type; + dst->is_null = src->is_null; + dst->num = src->num; + + return TSDB_CODE_SUCCESS; +} + +int32_t qBindStmtStbColsValue2(void* pBlock, SArray* pCols, TAOS_STMT2_BIND* bind, char* msgBuf, int32_t msgBufLen, + STSchema** pTSchema, SBindInfo2* pBindInfos) { + STableDataCxt* pDataBlock = (STableDataCxt*)pBlock; + SSchema* pSchema = getTableColumnSchema(pDataBlock->pMeta); + SBoundColInfo* boundInfo = &pDataBlock->boundColsInfo; + SMsgBuf pBuf = {.buf = msgBuf, .len = msgBufLen}; + int32_t rowNum = bind->num; + TAOS_STMT2_BIND ncharBind = {0}; + TAOS_STMT2_BIND* pBind = NULL; + int32_t code = 0; + int16_t lastColId = -1; + bool colInOrder = true; + + if (NULL == *pTSchema) { + *pTSchema = tBuildTSchema(pSchema, pDataBlock->pMeta->tableInfo.numOfColumns, pDataBlock->pMeta->sversion); + } + + for (int c = 0; c < boundInfo->numOfBound; ++c) { + SSchema* pColSchema = &pSchema[boundInfo->pColIndex[c]]; + if (pColSchema->colId <= lastColId) { + colInOrder = false; + } else { + lastColId = pColSchema->colId; + } + // SColData* pCol = taosArrayGet(pCols, c); + + if (bind[c].num != rowNum) { + code = buildInvalidOperationMsg(&pBuf, "row number in each bind param should be the same"); + goto _return; + } + + if ((!(rowNum == 1 && bind[c].is_null && *bind[c].is_null)) && + bind[c].buffer_type != pColSchema->type) { // for rowNum ==1 , connector may not set buffer_type + code = buildInvalidOperationMsg(&pBuf, "column type mis-match with buffer type"); + goto _return; + } + + if (TSDB_DATA_TYPE_NCHAR == pColSchema->type) { + code = convertStmtNcharCol2(&pBuf, pColSchema, bind + c, &ncharBind); + if (code) { + goto _return; + } + pBind = &ncharBind; + } else { + pBind = bind + c; + } + + pBindInfos[c].columnId = pColSchema->colId; + pBindInfos[c].bind = pBind; + pBindInfos[c].type = pColSchema->type; + + // code = tColDataAddValueByBind(pCol, pBind, IS_VAR_DATA_TYPE(pColSchema->type) ? pColSchema->bytes - + // VARSTR_HEADER_SIZE: -1); if (code) { + // goto _return; + // } + } + + code = tRowBuildFromBind2(pBindInfos, boundInfo->numOfBound, colInOrder, *pTSchema, pCols); + + qDebug("stmt all %d columns bind %d rows data", boundInfo->numOfBound, rowNum); + +_return: + + taosMemoryFree(ncharBind.buffer); + taosMemoryFree(ncharBind.length); + + return code; +} + int32_t qBindStmtColsValue2(void* pBlock, SArray* pCols, TAOS_STMT2_BIND* bind, char* msgBuf, int32_t msgBufLen) { STableDataCxt* pDataBlock = (STableDataCxt*)pBlock; SSchema* pSchema = getTableColumnSchema(pDataBlock->pMeta); From b9303b0ed4b5e5eb78853130b12aef91dc99c4e2 Mon Sep 17 00:00:00 2001 From: Minglei Jin Date: Tue, 20 Aug 2024 13:55:02 +0800 Subject: [PATCH 04/23] fix multi nchar writing --- source/client/src/clientMain.c | 16 +- source/libs/parser/src/parInsertStmt.c | 204 ++++++++++++++++--------- 2 files changed, 142 insertions(+), 78 deletions(-) diff --git a/source/client/src/clientMain.c b/source/client/src/clientMain.c index 67ccfe3637..d2559baea5 100644 --- a/source/client/src/clientMain.c +++ b/source/client/src/clientMain.c @@ -1915,25 +1915,23 @@ int taos_stmt2_bind_param(TAOS_STMT2 *stmt, TAOS_STMT2_BINDV *bindv, int32_t col int32_t code = 0; for (int i = 0; i < bindv->count; ++i) { - char *tbname = bindv->tbnames[i]; - TAOS_STMT2_BIND *tags = bindv->tags[i]; - TAOS_STMT2_BIND *bind = bindv->bind_cols[i]; - - if (tbname) { - code = stmtSetTbName2(stmt, tbname); + if (bindv->tbnames && bindv->tbnames[i]) { + code = stmtSetTbName2(stmt, bindv->tbnames[i]); if (code) { return code; } } - if (tags) { - code = stmtSetTbTags2(stmt, tags); + if (bindv->tags && bindv->tags[i]) { + code = stmtSetTbTags2(stmt, bindv->tags[i]); if (code) { return code; } } - if (bind) { + if (bindv->bind_cols && bindv->bind_cols[i]) { + TAOS_STMT2_BIND *bind = bindv->bind_cols[i]; + if (bind->num <= 0 || bind->num > INT16_MAX) { tscError("invalid bind num %d", bind->num); terrno = TSDB_CODE_INVALID_PARA; diff --git a/source/libs/parser/src/parInsertStmt.c b/source/libs/parser/src/parInsertStmt.c index 01719b699a..cc36afe7f9 100644 --- a/source/libs/parser/src/parInsertStmt.c +++ b/source/libs/parser/src/parInsertStmt.c @@ -587,6 +587,141 @@ end: return code; } +static int32_t convertStmtStbNcharCol2(SMsgBuf* pMsgBuf, SSchema* pSchema, TAOS_STMT2_BIND* src, TAOS_STMT2_BIND* dst) { + int32_t output = 0; + int32_t newBuflen = (pSchema->bytes - VARSTR_HEADER_SIZE) * src->num; + // if (dst->buffer_length < newBuflen) { + // dst->buffer = taosMemoryRealloc(dst->buffer, newBuflen); + dst->buffer = taosMemoryCalloc(1, newBuflen); + if (NULL == dst->buffer) { + return TSDB_CODE_OUT_OF_MEMORY; + } + //} + + // if (NULL == dst->length) { + // dst->length = taosMemoryRealloc(dst->length, sizeof(int32_t) * src->num); + dst->length = taosMemoryCalloc(1, sizeof(int32_t) * src->num); + if (NULL == dst->length) { + taosMemoryFreeClear(dst->buffer); + return TSDB_CODE_OUT_OF_MEMORY; + } + //} + + dst->buffer_length = pSchema->bytes - VARSTR_HEADER_SIZE; + + for (int32_t i = 0; i < src->num; ++i) { + if (src->is_null && src->is_null[i]) { + continue; + } + + if (!taosMbsToUcs4(((char*)src->buffer) + src->buffer_length * i, src->length[i], + (TdUcs4*)(((char*)dst->buffer) + dst->buffer_length * i), dst->buffer_length, &output)) { + if (errno == E2BIG) { + return generateSyntaxErrMsg(pMsgBuf, TSDB_CODE_PAR_VALUE_TOO_LONG, pSchema->name); + } + char buf[512] = {0}; + snprintf(buf, tListLen(buf), "%s", strerror(errno)); + return buildSyntaxErrMsg(pMsgBuf, buf, NULL); + } + + dst->length[i] = output; + } + + dst->buffer_type = src->buffer_type; + dst->is_null = src->is_null; + dst->num = src->num; + + return TSDB_CODE_SUCCESS; +} + +int32_t qBindStmtStbColsValue2(void* pBlock, SArray* pCols, TAOS_STMT2_BIND* bind, char* msgBuf, int32_t msgBufLen, + STSchema** pTSchema, SBindInfo2* pBindInfos) { + STableDataCxt* pDataBlock = (STableDataCxt*)pBlock; + SSchema* pSchema = getTableColumnSchema(pDataBlock->pMeta); + SBoundColInfo* boundInfo = &pDataBlock->boundColsInfo; + SMsgBuf pBuf = {.buf = msgBuf, .len = msgBufLen}; + int32_t rowNum = bind->num; + SArray* ncharBinds = NULL; + TAOS_STMT2_BIND ncharBind = {0}; + TAOS_STMT2_BIND* pBind = NULL; + int32_t code = 0; + int16_t lastColId = -1; + bool colInOrder = true; + + if (NULL == *pTSchema) { + *pTSchema = tBuildTSchema(pSchema, pDataBlock->pMeta->tableInfo.numOfColumns, pDataBlock->pMeta->sversion); + } + + for (int c = 0; c < boundInfo->numOfBound; ++c) { + SSchema* pColSchema = &pSchema[boundInfo->pColIndex[c]]; + if (pColSchema->colId <= lastColId) { + colInOrder = false; + } else { + lastColId = pColSchema->colId; + } + // SColData* pCol = taosArrayGet(pCols, c); + + if (bind[c].num != rowNum) { + code = buildInvalidOperationMsg(&pBuf, "row number in each bind param should be the same"); + goto _return; + } + + if ((!(rowNum == 1 && bind[c].is_null && *bind[c].is_null)) && + bind[c].buffer_type != pColSchema->type) { // for rowNum ==1 , connector may not set buffer_type + code = buildInvalidOperationMsg(&pBuf, "column type mis-match with buffer type"); + goto _return; + } + + if (TSDB_DATA_TYPE_NCHAR == pColSchema->type) { + code = convertStmtStbNcharCol2(&pBuf, pColSchema, bind + c, &ncharBind); + if (code) { + goto _return; + } + if (!ncharBinds) { + ncharBinds = taosArrayInit(1, sizeof(ncharBind)); + if (!ncharBinds) { + code = TSDB_CODE_OUT_OF_MEMORY; + goto _return; + } + } + if (!taosArrayPush(ncharBinds, &ncharBind)) { + code = TSDB_CODE_OUT_OF_MEMORY; + goto _return; + } + // pBind = &ncharBind; + pBind = taosArrayGetLast(ncharBinds); + } else { + pBind = bind + c; + } + + pBindInfos[c].columnId = pColSchema->colId; + pBindInfos[c].bind = pBind; + pBindInfos[c].type = pColSchema->type; + + // code = tColDataAddValueByBind(pCol, pBind, IS_VAR_DATA_TYPE(pColSchema->type) ? pColSchema->bytes - + // VARSTR_HEADER_SIZE: -1); if (code) { + // goto _return; + // } + } + + code = tRowBuildFromBind2(pBindInfos, boundInfo->numOfBound, colInOrder, *pTSchema, pCols); + + qDebug("stmt all %d columns bind %d rows data", boundInfo->numOfBound, rowNum); + +_return: + + for (int i = 0; i < TARRAY_SIZE(ncharBinds); ++i) { + TAOS_STMT2_BIND* ncharBind = TARRAY_DATA(ncharBinds); + taosMemoryFree(ncharBind[i].buffer); + taosMemoryFree(ncharBind[i].length); + } + taosArrayDestroy(ncharBinds); + // taosMemoryFree(ncharBind.buffer); + // taosMemoryFree(ncharBind.length); + + return code; +} + static int32_t convertStmtNcharCol2(SMsgBuf* pMsgBuf, SSchema* pSchema, TAOS_STMT2_BIND* src, TAOS_STMT2_BIND* dst) { int32_t output = 0; int32_t newBuflen = (pSchema->bytes - VARSTR_HEADER_SIZE) * src->num; @@ -632,75 +767,6 @@ static int32_t convertStmtNcharCol2(SMsgBuf* pMsgBuf, SSchema* pSchema, TAOS_STM return TSDB_CODE_SUCCESS; } -int32_t qBindStmtStbColsValue2(void* pBlock, SArray* pCols, TAOS_STMT2_BIND* bind, char* msgBuf, int32_t msgBufLen, - STSchema** pTSchema, SBindInfo2* pBindInfos) { - STableDataCxt* pDataBlock = (STableDataCxt*)pBlock; - SSchema* pSchema = getTableColumnSchema(pDataBlock->pMeta); - SBoundColInfo* boundInfo = &pDataBlock->boundColsInfo; - SMsgBuf pBuf = {.buf = msgBuf, .len = msgBufLen}; - int32_t rowNum = bind->num; - TAOS_STMT2_BIND ncharBind = {0}; - TAOS_STMT2_BIND* pBind = NULL; - int32_t code = 0; - int16_t lastColId = -1; - bool colInOrder = true; - - if (NULL == *pTSchema) { - *pTSchema = tBuildTSchema(pSchema, pDataBlock->pMeta->tableInfo.numOfColumns, pDataBlock->pMeta->sversion); - } - - for (int c = 0; c < boundInfo->numOfBound; ++c) { - SSchema* pColSchema = &pSchema[boundInfo->pColIndex[c]]; - if (pColSchema->colId <= lastColId) { - colInOrder = false; - } else { - lastColId = pColSchema->colId; - } - // SColData* pCol = taosArrayGet(pCols, c); - - if (bind[c].num != rowNum) { - code = buildInvalidOperationMsg(&pBuf, "row number in each bind param should be the same"); - goto _return; - } - - if ((!(rowNum == 1 && bind[c].is_null && *bind[c].is_null)) && - bind[c].buffer_type != pColSchema->type) { // for rowNum ==1 , connector may not set buffer_type - code = buildInvalidOperationMsg(&pBuf, "column type mis-match with buffer type"); - goto _return; - } - - if (TSDB_DATA_TYPE_NCHAR == pColSchema->type) { - code = convertStmtNcharCol2(&pBuf, pColSchema, bind + c, &ncharBind); - if (code) { - goto _return; - } - pBind = &ncharBind; - } else { - pBind = bind + c; - } - - pBindInfos[c].columnId = pColSchema->colId; - pBindInfos[c].bind = pBind; - pBindInfos[c].type = pColSchema->type; - - // code = tColDataAddValueByBind(pCol, pBind, IS_VAR_DATA_TYPE(pColSchema->type) ? pColSchema->bytes - - // VARSTR_HEADER_SIZE: -1); if (code) { - // goto _return; - // } - } - - code = tRowBuildFromBind2(pBindInfos, boundInfo->numOfBound, colInOrder, *pTSchema, pCols); - - qDebug("stmt all %d columns bind %d rows data", boundInfo->numOfBound, rowNum); - -_return: - - taosMemoryFree(ncharBind.buffer); - taosMemoryFree(ncharBind.length); - - return code; -} - int32_t qBindStmtColsValue2(void* pBlock, SArray* pCols, TAOS_STMT2_BIND* bind, char* msgBuf, int32_t msgBufLen) { STableDataCxt* pDataBlock = (STableDataCxt*)pBlock; SSchema* pSchema = getTableColumnSchema(pDataBlock->pMeta); From 921b7e495ee8b59bd4740bb611cda5fcd74be0c3 Mon Sep 17 00:00:00 2001 From: Minglei Jin Date: Wed, 21 Aug 2024 12:33:19 +0800 Subject: [PATCH 05/23] stmt2/stb: no hole in bind for stb binding --- include/common/tdataformat.h | 1 + source/common/src/tdataformat.c | 24 +- source/libs/parser/src/parInsertStmt.c | 71 +++--- tests/script/api/makefile | 11 + tests/script/api/stmt2-nohole.c | 335 +++++++++++++++++++++++++ 5 files changed, 396 insertions(+), 46 deletions(-) create mode 100644 tests/script/api/stmt2-nohole.c diff --git a/include/common/tdataformat.h b/include/common/tdataformat.h index cb4f6972f0..9c51bb2b8f 100644 --- a/include/common/tdataformat.h +++ b/include/common/tdataformat.h @@ -384,6 +384,7 @@ int32_t tColDataAddValueByBind2(SColData *pColData, TAOS_STMT2_BIND *pBind, int3 typedef struct { int32_t columnId; int32_t type; + int32_t bytes; TAOS_STMT2_BIND *bind; } SBindInfo2; diff --git a/source/common/src/tdataformat.c b/source/common/src/tdataformat.c index 02279ff06f..d12b44a093 100644 --- a/source/common/src/tdataformat.c +++ b/source/common/src/tdataformat.c @@ -3208,12 +3208,23 @@ int32_t tRowBuildFromBind2(SBindInfo2 *infos, int32_t numOfInfos, bool infoSorte int32_t code = 0; int32_t numOfRows = infos[0].bind->num; - SArray *colValArray; + SArray *colValArray, *bufArray; SColVal colVal; if ((colValArray = taosArrayInit(numOfInfos, sizeof(SColVal))) == NULL) { return terrno; } + if ((bufArray = taosArrayInit(numOfInfos, sizeof(uint8_t *))) == NULL) { + taosArrayDestroy(colValArray); + return TSDB_CODE_OUT_OF_MEMORY; + } + for (int i = 0; i < numOfInfos; ++i) { + if (!taosArrayPush(bufArray, &infos[i].bind->buffer)) { + taosArrayDestroy(colValArray); + taosArrayDestroy(bufArray); + return TSDB_CODE_OUT_OF_MEMORY; + } + } for (int32_t iRow = 0; iRow < numOfRows; iRow++) { taosArrayClear(colValArray); @@ -3226,11 +3237,15 @@ int32_t tRowBuildFromBind2(SBindInfo2 *infos, int32_t numOfInfos, bool infoSorte .type = infos[iInfo].type, }; if (IS_VAR_DATA_TYPE(infos[iInfo].type)) { - value.nData = infos[iInfo].bind->length[iRow]; - value.pData = (uint8_t *)infos[iInfo].bind->buffer + infos[iInfo].bind->buffer_length * iRow; + int32_t length = infos[iInfo].bind->length[iRow]; + uint8_t **data = &((uint8_t **)TARRAY_DATA(bufArray))[iInfo]; + value.nData = length; + value.pData = *data; + *data += length; + // value.pData = (uint8_t *)infos[iInfo].bind->buffer + infos[iInfo].bind->buffer_length * iRow; } else { (void)memcpy(&value.val, (uint8_t *)infos[iInfo].bind->buffer + infos[iInfo].bind->buffer_length * iRow, - infos[iInfo].bind->buffer_length); + infos[iInfo].bytes /*bind->buffer_length*/); } colVal = COL_VAL_VALUE(infos[iInfo].columnId, value); } @@ -3253,6 +3268,7 @@ int32_t tRowBuildFromBind2(SBindInfo2 *infos, int32_t numOfInfos, bool infoSorte _exit: taosArrayDestroy(colValArray); + taosArrayDestroy(bufArray); return code; } diff --git a/source/libs/parser/src/parInsertStmt.c b/source/libs/parser/src/parInsertStmt.c index cc36afe7f9..51373f0828 100644 --- a/source/libs/parser/src/parInsertStmt.c +++ b/source/libs/parser/src/parInsertStmt.c @@ -589,33 +589,27 @@ end: static int32_t convertStmtStbNcharCol2(SMsgBuf* pMsgBuf, SSchema* pSchema, TAOS_STMT2_BIND* src, TAOS_STMT2_BIND* dst) { int32_t output = 0; - int32_t newBuflen = (pSchema->bytes - VARSTR_HEADER_SIZE) * src->num; - // if (dst->buffer_length < newBuflen) { - // dst->buffer = taosMemoryRealloc(dst->buffer, newBuflen); - dst->buffer = taosMemoryCalloc(1, newBuflen); + int32_t max_buf_len = pSchema->bytes - VARSTR_HEADER_SIZE; + + dst->buffer = taosMemoryCalloc(src->num, max_buf_len); if (NULL == dst->buffer) { return TSDB_CODE_OUT_OF_MEMORY; } - //} - // if (NULL == dst->length) { - // dst->length = taosMemoryRealloc(dst->length, sizeof(int32_t) * src->num); - dst->length = taosMemoryCalloc(1, sizeof(int32_t) * src->num); + dst->length = taosMemoryCalloc(src->num, sizeof(int32_t)); if (NULL == dst->length) { taosMemoryFreeClear(dst->buffer); return TSDB_CODE_OUT_OF_MEMORY; } - //} - - dst->buffer_length = pSchema->bytes - VARSTR_HEADER_SIZE; + char* src_buf = src->buffer; + char* dst_buf = dst->buffer; for (int32_t i = 0; i < src->num; ++i) { if (src->is_null && src->is_null[i]) { continue; } - if (!taosMbsToUcs4(((char*)src->buffer) + src->buffer_length * i, src->length[i], - (TdUcs4*)(((char*)dst->buffer) + dst->buffer_length * i), dst->buffer_length, &output)) { + if (!taosMbsToUcs4(src_buf, src->length[i], (TdUcs4*)dst_buf, max_buf_len, &output)) { if (errno == E2BIG) { return generateSyntaxErrMsg(pMsgBuf, TSDB_CODE_PAR_VALUE_TOO_LONG, pSchema->name); } @@ -625,6 +619,8 @@ static int32_t convertStmtStbNcharCol2(SMsgBuf* pMsgBuf, SSchema* pSchema, TAOS_ } dst->length[i] = output; + src_buf += src->length[i]; + dst_buf += output; } dst->buffer_type = src->buffer_type; @@ -636,17 +632,16 @@ static int32_t convertStmtStbNcharCol2(SMsgBuf* pMsgBuf, SSchema* pSchema, TAOS_ int32_t qBindStmtStbColsValue2(void* pBlock, SArray* pCols, TAOS_STMT2_BIND* bind, char* msgBuf, int32_t msgBufLen, STSchema** pTSchema, SBindInfo2* pBindInfos) { - STableDataCxt* pDataBlock = (STableDataCxt*)pBlock; - SSchema* pSchema = getTableColumnSchema(pDataBlock->pMeta); - SBoundColInfo* boundInfo = &pDataBlock->boundColsInfo; - SMsgBuf pBuf = {.buf = msgBuf, .len = msgBufLen}; - int32_t rowNum = bind->num; - SArray* ncharBinds = NULL; - TAOS_STMT2_BIND ncharBind = {0}; - TAOS_STMT2_BIND* pBind = NULL; - int32_t code = 0; - int16_t lastColId = -1; - bool colInOrder = true; + STableDataCxt* pDataBlock = (STableDataCxt*)pBlock; + SSchema* pSchema = getTableColumnSchema(pDataBlock->pMeta); + SBoundColInfo* boundInfo = &pDataBlock->boundColsInfo; + SMsgBuf pBuf = {.buf = msgBuf, .len = msgBufLen}; + int32_t rowNum = bind->num; + SArray* ncharBinds = NULL; + TAOS_STMT2_BIND ncharBind = {0}; + int32_t code = 0; + int16_t lastColId = -1; + bool colInOrder = true; if (NULL == *pTSchema) { *pTSchema = tBuildTSchema(pSchema, pDataBlock->pMeta->tableInfo.numOfColumns, pDataBlock->pMeta->sversion); @@ -659,7 +654,6 @@ int32_t qBindStmtStbColsValue2(void* pBlock, SArray* pCols, TAOS_STMT2_BIND* bin } else { lastColId = pColSchema->colId; } - // SColData* pCol = taosArrayGet(pCols, c); if (bind[c].num != rowNum) { code = buildInvalidOperationMsg(&pBuf, "row number in each bind param should be the same"); @@ -688,20 +682,14 @@ int32_t qBindStmtStbColsValue2(void* pBlock, SArray* pCols, TAOS_STMT2_BIND* bin code = TSDB_CODE_OUT_OF_MEMORY; goto _return; } - // pBind = &ncharBind; - pBind = taosArrayGetLast(ncharBinds); + pBindInfos[c].bind = taosArrayGetLast(ncharBinds); } else { - pBind = bind + c; + pBindInfos[c].bind = bind + c; } pBindInfos[c].columnId = pColSchema->colId; - pBindInfos[c].bind = pBind; pBindInfos[c].type = pColSchema->type; - - // code = tColDataAddValueByBind(pCol, pBind, IS_VAR_DATA_TYPE(pColSchema->type) ? pColSchema->bytes - - // VARSTR_HEADER_SIZE: -1); if (code) { - // goto _return; - // } + pBindInfos[c].bytes = pColSchema->bytes; } code = tRowBuildFromBind2(pBindInfos, boundInfo->numOfBound, colInOrder, *pTSchema, pCols); @@ -709,15 +697,14 @@ int32_t qBindStmtStbColsValue2(void* pBlock, SArray* pCols, TAOS_STMT2_BIND* bin qDebug("stmt all %d columns bind %d rows data", boundInfo->numOfBound, rowNum); _return: - - for (int i = 0; i < TARRAY_SIZE(ncharBinds); ++i) { - TAOS_STMT2_BIND* ncharBind = TARRAY_DATA(ncharBinds); - taosMemoryFree(ncharBind[i].buffer); - taosMemoryFree(ncharBind[i].length); + if (ncharBinds) { + for (int i = 0; i < TARRAY_SIZE(ncharBinds); ++i) { + TAOS_STMT2_BIND* ncBind = TARRAY_DATA(ncharBinds); + taosMemoryFree(ncBind[i].buffer); + taosMemoryFree(ncBind[i].length); + } + taosArrayDestroy(ncharBinds); } - taosArrayDestroy(ncharBinds); - // taosMemoryFree(ncharBind.buffer); - // taosMemoryFree(ncharBind.length); return code; } diff --git a/tests/script/api/makefile b/tests/script/api/makefile index d848dca194..4457445cdf 100644 --- a/tests/script/api/makefile +++ b/tests/script/api/makefile @@ -7,6 +7,7 @@ LFLAGS = '-Wl,-rpath,/usr/local/taos/driver/' -ltaos -lpthread -lm -lrt CFLAGS = -O0 -g -Wno-deprecated -fPIC -Wno-unused-result -Wconversion \ -Wno-char-subscripts -D_REENTRANT -Wno-format -D_REENTRANT -DLINUX \ -Wno-unused-function -D_M_X64 -I/usr/local/taos/include -std=gnu99 -Wno-sign-conversion +CFLAGS += -fsanitize=address -fsanitize=undefined -fsanitize-recover=all -fsanitize=float-divide-by-zero -fsanitize=float-cast-overflow -fno-sanitize=shift-base -fno-sanitize=alignment all: $(TARGET) @@ -20,6 +21,11 @@ exe: gcc $(CFLAGS) ./insert_stb.c -o $(ROOT)insert_stb $(LFLAGS) gcc $(CFLAGS) ./tmqViewTest.c -o $(ROOT)tmqViewTest $(LFLAGS) gcc $(CFLAGS) ./stmtQuery.c -o $(ROOT)stmtQuery $(LFLAGS) + gcc $(CFLAGS) ./stmt.c -o $(ROOT)stmt $(LFLAGS) + gcc $(CFLAGS) ./stmt2.c -o $(ROOT)stmt2 $(LFLAGS) + gcc $(CFLAGS) ./stmt2-example.c -o $(ROOT)stmt2-example $(LFLAGS) + gcc $(CFLAGS) ./stmt2-nohole.c -o $(ROOT)stmt2-nohole $(LFLAGS) + gcc $(CFLAGS) ./stmt-crash.c -o $(ROOT)stmt-crash $(LFLAGS) clean: rm $(ROOT)batchprepare @@ -31,3 +37,8 @@ clean: rm $(ROOT)insert_stb rm $(ROOT)tmqViewTest rm $(ROOT)stmtQuery + rm $(ROOT)stmt + rm $(ROOT)stmt2 + rm $(ROOT)stmt2-example + rm $(ROOT)stmt2-nohole + rm $(ROOT)stmt-crash diff --git a/tests/script/api/stmt2-nohole.c b/tests/script/api/stmt2-nohole.c new file mode 100644 index 0000000000..8ec5136631 --- /dev/null +++ b/tests/script/api/stmt2-nohole.c @@ -0,0 +1,335 @@ +// sample code to verify all TDengine API +// to compile: gcc -o apitest apitest.c -ltaos + +#include +#include +#include +#include +#include "taos.h" +static int64_t count = 10000; + +int64_t genReqid() { + count += 100; + return count; +} + +void stmtAsyncQueryCb(void* param, TAOS_RES* pRes, int code) { + int affected_rows = taos_affected_rows(pRes); + return; + /* + SSP_CB_PARAM* qParam = (SSP_CB_PARAM*)param; + if (code == 0 && pRes) { + if (qParam->fetch) { + taos_fetch_rows_a(pRes, sqAsyncFetchCb, param); + } else { + if (qParam->free) { + taos_free_result(pRes); + } + *qParam->end = 1; + } + } else { + sqError("select", taos_errstr(pRes)); + *qParam->end = 1; + taos_free_result(pRes); + } + */ +} + +void veriry_stmt(TAOS* taos) { + TAOS_RES* result = taos_query(taos, "drop database if exists test;"); + taos_free_result(result); + usleep(100000); + result = taos_query(taos, "create database test;"); + + int code = taos_errno(result); + if (code != 0) { + printf("\033[31mfailed to create database, reason:%s\033[0m\n", taos_errstr(result)); + taos_free_result(result); + return; + } + taos_free_result(result); + + usleep(100000); + taos_select_db(taos, "test"); + + // create table + /* + const char* sql = + "create table m1 (ts timestamp, b bool, v1 tinyint, v2 smallint, v4 int, v8 bigint, f4 float, f8 double, bin " + "binary(40), blob nchar(10))"; + */ + const char* sql = + "create table m1 (ts timestamp, b bool, v1 tinyint, v2 smallint, v4 int, v8 bigint, f4 float, f8 double, blob2 " + "nchar(10), blob nchar(10))"; + result = taos_query(taos, sql); + code = taos_errno(result); + if (code != 0) { + printf("\033[31mfailed to create table, reason:%s\033[0m\n", taos_errstr(result)); + taos_free_result(result); + return; + } + taos_free_result(result); + + // insert 10 records + struct { + int64_t ts[10]; + int8_t b[10]; + int8_t v1[10]; + int16_t v2[10]; + int32_t v4[10]; + int64_t v8[10]; + float f4[10]; + double f8[10]; + char bin[10][40]; + // char blob[10][80]; + // char blob2[10][80]; + char blob[1024]; + char blob2[1024]; + } v; + + int32_t* t8_len = malloc(sizeof(int32_t) * 10); + int32_t* t16_len = malloc(sizeof(int32_t) * 10); + int32_t* t32_len = malloc(sizeof(int32_t) * 10); + int32_t* t64_len = malloc(sizeof(int32_t) * 10); + int32_t* float_len = malloc(sizeof(int32_t) * 10); + int32_t* double_len = malloc(sizeof(int32_t) * 10); + int32_t* bin_len = malloc(sizeof(int32_t) * 10); + int32_t* blob_len = malloc(sizeof(int32_t) * 10); + int32_t* blob_len2 = malloc(sizeof(int32_t) * 10); + +#include "time.h" + clock_t start, end; + TAOS_STMT2_OPTION option = {0, true, true, stmtAsyncQueryCb, NULL}; + + start = clock(); + TAOS_STMT2* stmt = taos_stmt2_init(taos, &option); + end = clock(); + printf("init time:%f\n", (double)(end - start) / CLOCKS_PER_SEC); + // TAOS_MULTI_BIND params[10]; + TAOS_STMT2_BIND params[10]; + char is_null[10] = {0}; + + params[0].buffer_type = TSDB_DATA_TYPE_TIMESTAMP; + params[0].buffer_length = sizeof(v.ts[0]); + params[0].buffer = v.ts; + params[0].length = t64_len; + params[0].is_null = is_null; + params[0].num = 10; + + params[1].buffer_type = TSDB_DATA_TYPE_BOOL; + params[1].buffer_length = sizeof(v.b[0]); + params[1].buffer = v.b; + params[1].length = t8_len; + params[1].is_null = is_null; + params[1].num = 10; + + params[2].buffer_type = TSDB_DATA_TYPE_TINYINT; + params[2].buffer_length = sizeof(v.v1[0]); + params[2].buffer = v.v1; + params[2].length = t8_len; + params[2].is_null = is_null; + params[2].num = 10; + + params[3].buffer_type = TSDB_DATA_TYPE_SMALLINT; + params[3].buffer_length = sizeof(v.v2[0]); + params[3].buffer = v.v2; + params[3].length = t16_len; + params[3].is_null = is_null; + params[3].num = 10; + + params[4].buffer_type = TSDB_DATA_TYPE_INT; + params[4].buffer_length = sizeof(v.v4[0]); + params[4].buffer = v.v4; + params[4].length = t32_len; + params[4].is_null = is_null; + params[4].num = 10; + + params[5].buffer_type = TSDB_DATA_TYPE_BIGINT; + params[5].buffer_length = sizeof(v.v8[0]); + params[5].buffer = v.v8; + params[5].length = t64_len; + params[5].is_null = is_null; + params[5].num = 10; + + params[6].buffer_type = TSDB_DATA_TYPE_FLOAT; + params[6].buffer_length = sizeof(v.f4[0]); + params[6].buffer = v.f4; + params[6].length = float_len; + params[6].is_null = is_null; + params[6].num = 10; + + params[7].buffer_type = TSDB_DATA_TYPE_DOUBLE; + params[7].buffer_length = sizeof(v.f8[0]); + params[7].buffer = v.f8; + params[7].length = double_len; + params[7].is_null = is_null; + params[7].num = 10; + /* + params[8].buffer_type = TSDB_DATA_TYPE_BINARY; + params[8].buffer_length = sizeof(v.bin[0]); + params[8].buffer = v.bin; + params[8].length = bin_len; + params[8].is_null = is_null; + params[8].num = 10; + */ + params[8].buffer_type = TSDB_DATA_TYPE_NCHAR; + // params[8].buffer_length = sizeof(v.blob2[0]); + params[8].buffer = v.blob2; + params[8].length = blob_len2; + params[8].is_null = is_null; + params[8].num = 10; + + params[9].buffer_type = TSDB_DATA_TYPE_NCHAR; + params[9].buffer_length = sizeof(v.blob[0]); + params[9].buffer = v.blob; + params[9].length = blob_len; + params[9].is_null = is_null; + params[9].num = 10; + + sql = "insert into ? (ts, b, v1, v2, v4, v8, f4, f8, blob2, blob) values(?,?,?,?,?,?,?,?,?,?)"; + start = clock(); + code = taos_stmt2_prepare(stmt, sql, 0); + end = clock(); + printf("prepare time:%f\n", (double)(end - start) / CLOCKS_PER_SEC); + if (code != 0) { + printf("\033[31mfailed to execute taos_stmt_prepare. error:%s\033[0m\n", taos_stmt_errstr(stmt)); + taos_stmt_close(stmt); + return; + } + /* + code = taos_stmt_set_tbname(stmt, "m1"); + if (code != 0) { + printf("\033[31mfailed to execute taos_stmt_prepare. error:%s\033[0m\n", taos_stmt_errstr(stmt)); + taos_stmt_close(stmt); + return; + } + */ + + int64_t ts = 1591060628000; + char* blob2_buffer = v.blob2; + char* blob_buffer = v.blob; + for (int i = 0; i < 10; ++i) { + is_null[i] = 0; + + v.ts[i] = ts++; + v.b[i] = (int8_t)i % 2; + v.v1[i] = (int8_t)i; + v.v2[i] = (int16_t)(i * 2); + v.v4[i] = (int32_t)(i * 4); + v.v8[i] = (int64_t)(i * 8); + v.f4[i] = (float)(i * 40); + v.f8[i] = (double)(i * 80); + for (int j = 0; j < sizeof(v.bin[0]); ++j) { + v.bin[i][j] = (char)(i + '0'); + } + // strcpy(v.blob2[i], "一二三四五六七十九八"); + // strcpy(v.blob[i], "一二三四五六七八九十"); + const char* blob2_str = "一二三四五六七十九八"; + const char* blob_str = "一二三四五六七八九十"; + strcpy(blob2_buffer, blob2_str); + strcpy(blob_buffer, blob_str); + + t8_len[i] = sizeof(int8_t); + t16_len[i] = sizeof(int16_t); + t32_len[i] = sizeof(int32_t); + t64_len[i] = sizeof(int64_t); + float_len[i] = sizeof(float); + double_len[i] = sizeof(double); + bin_len[i] = sizeof(v.bin[0]); + // blob_len[i] = (int32_t)strlen(v.blob[i]); + // blob_len2[i] = (int32_t)strlen(v.blob2[i]); + blob_len[i] = (int32_t)strlen(blob_str); + blob_len2[i] = (int32_t)strlen(blob2_str); + blob_buffer += blob_len[i]; + blob2_buffer += blob_len2[i]; + } + + char* tbname = "m1"; + TAOS_STMT2_BIND* bind_cols[1] = {¶ms[0]}; + TAOS_STMT2_BINDV bindv = {1, &tbname, NULL, &bind_cols[0]}; + start = clock(); + // taos_stmt2_bind_param(stmt, "m1", NULL, params, -1); + taos_stmt2_bind_param(stmt, &bindv, -1); + end = clock(); + printf("bind time:%f\n", (double)(end - start) / CLOCKS_PER_SEC); + // taos_stmt_bind_param_batch(stmt, params); + // taos_stmt_add_batch(stmt); + /* + int param_count = -1; + code = taos_stmt2_param_count(stmt, ¶m_count); + if (code != 0) { + printf("\033[31mfailed to execute taos_stmt_param_count. error:%s\033[0m\n", taos_stmt_errstr(stmt)); + taos_stmt_close(stmt); + return; + } + printf("param_count: %d\n", param_count); + */ + TAOS_FIELD_E* fields = NULL; + int field_count = -1; + start = clock(); + code = taos_stmt2_get_fields(stmt, TAOS_FIELD_COL, &field_count, NULL); + end = clock(); + printf("get fields time:%f\n", (double)(end - start) / CLOCKS_PER_SEC); + if (code != 0) { + printf("\033[31mfailed to execute taos_stmt_param_count. error:%s\033[0m\n", taos_stmt2_error(stmt)); + taos_stmt2_close(stmt); + return; + } + printf("col field_count: %d\n", field_count); + start = clock(); + taos_stmt2_free_fields(stmt, fields); + end = clock(); + printf("free time:%f\n", (double)(end - start) / CLOCKS_PER_SEC); + /* + code = taos_stmt2_get_fields(stmt, TAOS_FIELD_TAG, &field_count, &fields); + if (code != 0) { + printf("\033[31mfailed to execute taos_stmt_param_count. error:%s\033[0m\n", taos_stmt_errstr(stmt)); + taos_stmt_close(stmt); + return; + } + printf("tag field_count: %d\n", field_count); + taos_stmt2_free_fields(stmt, fields); + */ + // if (taos_stmt_execute(stmt) != 0) { + start = clock(); + // if (taos_stmt2_exec(stmt, NULL, stmtAsyncQueryCb, NULL) != 0) { + if (taos_stmt2_exec(stmt, NULL) != 0) { + printf("\033[31mfailed to execute insert statement.error:%s\033[0m\n", taos_stmt_errstr(stmt)); + taos_stmt2_close(stmt); + return; + } + end = clock(); + printf("exec time:%f\n", (double)(end - start) / CLOCKS_PER_SEC); + + taos_stmt2_close(stmt); + + free(t8_len); + free(t16_len); + free(t32_len); + free(t64_len); + free(float_len); + free(double_len); + free(bin_len); + free(blob_len); + free(blob_len2); +} + +int main(int argc, char* argv[]) { + const char* host = "127.0.0.1"; + const char* user = "root"; + const char* passwd = "taosdata"; + + taos_options(TSDB_OPTION_TIMEZONE, "GMT-8"); + TAOS* taos = taos_connect(host, user, passwd, "", 0); + if (taos == NULL) { + printf("\033[31mfailed to connect to db, reason:%s\033[0m\n", taos_errstr(taos)); + exit(1); + } + + printf("********* verify stmt query **********\n"); + veriry_stmt(taos); + + printf("done\n"); + taos_close(taos); + taos_cleanup(); +} From 68bd8d28f09845ab64193409c736f138e7e906a5 Mon Sep 17 00:00:00 2001 From: Minglei Jin Date: Wed, 21 Aug 2024 15:30:21 +0800 Subject: [PATCH 06/23] stmt2/binding: no hole for cols binding --- include/client/taos.h | 11 +++--- source/common/src/tdataformat.c | 15 ++++---- source/libs/parser/src/parInsertStmt.c | 30 +++++++++------- tests/script/api/stmt2-nohole.c | 48 +++++++++++++++----------- 4 files changed, 60 insertions(+), 44 deletions(-) diff --git a/include/client/taos.h b/include/client/taos.h index 9bd1517d38..90d6712d6e 100644 --- a/include/client/taos.h +++ b/include/client/taos.h @@ -210,12 +210,11 @@ typedef struct { } TAOS_STMT2_OPTION; typedef struct { - int buffer_type; - void *buffer; - uintptr_t buffer_length; - int32_t *length; - char *is_null; - int num; + int buffer_type; + void *buffer; + int32_t *length; + char *is_null; + int num; } TAOS_STMT2_BIND; typedef struct { diff --git a/source/common/src/tdataformat.c b/source/common/src/tdataformat.c index d12b44a093..6e5e614481 100644 --- a/source/common/src/tdataformat.c +++ b/source/common/src/tdataformat.c @@ -3127,6 +3127,7 @@ int32_t tColDataAddValueByBind2(SColData *pColData, TAOS_STMT2_BIND *pBind, int3 } if (IS_VAR_DATA_TYPE(pColData->type)) { // var-length data type + uint8_t *buf = pBind->buffer; for (int32_t i = 0; i < pBind->num; ++i) { if (pBind->is_null && pBind->is_null[i]) { if (pColData->cflag & COL_IS_KEY) { @@ -3139,8 +3140,8 @@ int32_t tColDataAddValueByBind2(SColData *pColData, TAOS_STMT2_BIND *pBind, int3 uError("var data length too big, len:%d, max:%d", pBind->length[i], buffMaxLen); return TSDB_CODE_INVALID_PARA; } else { - code = tColDataAppendValueImpl[pColData->flag][CV_FLAG_VALUE]( - pColData, (uint8_t *)pBind->buffer + pBind->buffer_length * i, pBind->length[i]); + code = tColDataAppendValueImpl[pColData->flag][CV_FLAG_VALUE](pColData, buf, pBind->length[i]); + buf += pBind->length[i]; } } } else { // fixed-length data type @@ -3164,7 +3165,7 @@ int32_t tColDataAddValueByBind2(SColData *pColData, TAOS_STMT2_BIND *pBind, int3 // optimize (todo) for (int32_t i = 0; i < pBind->num; ++i) { code = tColDataAppendValueImpl[pColData->flag][CV_FLAG_VALUE]( - pColData, (uint8_t *)pBind->buffer + TYPE_BYTES[pColData->type] * i, pBind->buffer_length); + pColData, (uint8_t *)pBind->buffer + TYPE_BYTES[pColData->type] * i, TYPE_BYTES[pColData->type]); } } else if (allNull) { // optimize (todo) @@ -3179,7 +3180,7 @@ int32_t tColDataAddValueByBind2(SColData *pColData, TAOS_STMT2_BIND *pBind, int3 if (code) goto _exit; } else { code = tColDataAppendValueImpl[pColData->flag][CV_FLAG_VALUE]( - pColData, (uint8_t *)pBind->buffer + TYPE_BYTES[pColData->type] * i, pBind->buffer_length); + pColData, (uint8_t *)pBind->buffer + TYPE_BYTES[pColData->type] * i, TYPE_BYTES[pColData->type]); } } } @@ -3244,8 +3245,10 @@ int32_t tRowBuildFromBind2(SBindInfo2 *infos, int32_t numOfInfos, bool infoSorte *data += length; // value.pData = (uint8_t *)infos[iInfo].bind->buffer + infos[iInfo].bind->buffer_length * iRow; } else { - (void)memcpy(&value.val, (uint8_t *)infos[iInfo].bind->buffer + infos[iInfo].bind->buffer_length * iRow, - infos[iInfo].bytes /*bind->buffer_length*/); + (void)memcpy( + &value.val, + (uint8_t *)infos[iInfo].bind->buffer + infos[iInfo].bytes /*infos[iInfo].bind->buffer_length*/ * iRow, + infos[iInfo].bytes /*bind->buffer_length*/); } colVal = COL_VAL_VALUE(infos[iInfo].columnId, value); } diff --git a/source/libs/parser/src/parInsertStmt.c b/source/libs/parser/src/parInsertStmt.c index 51373f0828..5b459243a4 100644 --- a/source/libs/parser/src/parInsertStmt.c +++ b/source/libs/parser/src/parInsertStmt.c @@ -588,8 +588,8 @@ end: } static int32_t convertStmtStbNcharCol2(SMsgBuf* pMsgBuf, SSchema* pSchema, TAOS_STMT2_BIND* src, TAOS_STMT2_BIND* dst) { - int32_t output = 0; - int32_t max_buf_len = pSchema->bytes - VARSTR_HEADER_SIZE; + int32_t output = 0; + const int32_t max_buf_len = pSchema->bytes - VARSTR_HEADER_SIZE; dst->buffer = taosMemoryCalloc(src->num, max_buf_len); if (NULL == dst->buffer) { @@ -710,14 +710,16 @@ _return: } static int32_t convertStmtNcharCol2(SMsgBuf* pMsgBuf, SSchema* pSchema, TAOS_STMT2_BIND* src, TAOS_STMT2_BIND* dst) { - int32_t output = 0; + int32_t output = 0; + const int32_t max_buf_len = pSchema->bytes - VARSTR_HEADER_SIZE; + int32_t newBuflen = (pSchema->bytes - VARSTR_HEADER_SIZE) * src->num; - if (dst->buffer_length < newBuflen) { - dst->buffer = taosMemoryRealloc(dst->buffer, newBuflen); - if (NULL == dst->buffer) { - return TSDB_CODE_OUT_OF_MEMORY; - } + // if (dst->buffer_length < newBuflen) { + dst->buffer = taosMemoryRealloc(dst->buffer, newBuflen); + if (NULL == dst->buffer) { + return TSDB_CODE_OUT_OF_MEMORY; } + //} if (NULL == dst->length) { dst->length = taosMemoryRealloc(dst->length, sizeof(int32_t) * src->num); @@ -727,15 +729,17 @@ static int32_t convertStmtNcharCol2(SMsgBuf* pMsgBuf, SSchema* pSchema, TAOS_STM } } - dst->buffer_length = pSchema->bytes - VARSTR_HEADER_SIZE; - + // dst->buffer_length = pSchema->bytes - VARSTR_HEADER_SIZE; + char* src_buf = src->buffer; + char* dst_buf = dst->buffer; for (int32_t i = 0; i < src->num; ++i) { if (src->is_null && src->is_null[i]) { continue; } - if (!taosMbsToUcs4(((char*)src->buffer) + src->buffer_length * i, src->length[i], - (TdUcs4*)(((char*)dst->buffer) + dst->buffer_length * i), dst->buffer_length, &output)) { + /*if (!taosMbsToUcs4(((char*)src->buffer) + src->buffer_length * i, src->length[i], + (TdUcs4*)(((char*)dst->buffer) + dst->buffer_length * i), dst->buffer_length, &output)) {*/ + if (!taosMbsToUcs4(src_buf, src->length[i], (TdUcs4*)dst_buf, max_buf_len, &output)) { if (errno == E2BIG) { return generateSyntaxErrMsg(pMsgBuf, TSDB_CODE_PAR_VALUE_TOO_LONG, pSchema->name); } @@ -745,6 +749,8 @@ static int32_t convertStmtNcharCol2(SMsgBuf* pMsgBuf, SSchema* pSchema, TAOS_STM } dst->length[i] = output; + src_buf += src->length[i]; + dst_buf += output; } dst->buffer_type = src->buffer_type; diff --git a/tests/script/api/stmt2-nohole.c b/tests/script/api/stmt2-nohole.c index 8ec5136631..9e6b94778c 100644 --- a/tests/script/api/stmt2-nohole.c +++ b/tests/script/api/stmt2-nohole.c @@ -99,7 +99,7 @@ void veriry_stmt(TAOS* taos) { #include "time.h" clock_t start, end; - TAOS_STMT2_OPTION option = {0, true, true, stmtAsyncQueryCb, NULL}; + TAOS_STMT2_OPTION option = {0, true, false, stmtAsyncQueryCb, NULL}; start = clock(); TAOS_STMT2* stmt = taos_stmt2_init(taos, &option); @@ -110,63 +110,63 @@ void veriry_stmt(TAOS* taos) { char is_null[10] = {0}; params[0].buffer_type = TSDB_DATA_TYPE_TIMESTAMP; - params[0].buffer_length = sizeof(v.ts[0]); + // params[0].buffer_length = sizeof(v.ts[0]); params[0].buffer = v.ts; params[0].length = t64_len; params[0].is_null = is_null; params[0].num = 10; params[1].buffer_type = TSDB_DATA_TYPE_BOOL; - params[1].buffer_length = sizeof(v.b[0]); + // params[1].buffer_length = sizeof(v.b[0]); params[1].buffer = v.b; params[1].length = t8_len; params[1].is_null = is_null; params[1].num = 10; params[2].buffer_type = TSDB_DATA_TYPE_TINYINT; - params[2].buffer_length = sizeof(v.v1[0]); + // params[2].buffer_length = sizeof(v.v1[0]); params[2].buffer = v.v1; params[2].length = t8_len; params[2].is_null = is_null; params[2].num = 10; params[3].buffer_type = TSDB_DATA_TYPE_SMALLINT; - params[3].buffer_length = sizeof(v.v2[0]); + // params[3].buffer_length = sizeof(v.v2[0]); params[3].buffer = v.v2; params[3].length = t16_len; params[3].is_null = is_null; params[3].num = 10; params[4].buffer_type = TSDB_DATA_TYPE_INT; - params[4].buffer_length = sizeof(v.v4[0]); + // params[4].buffer_length = sizeof(v.v4[0]); params[4].buffer = v.v4; params[4].length = t32_len; params[4].is_null = is_null; params[4].num = 10; params[5].buffer_type = TSDB_DATA_TYPE_BIGINT; - params[5].buffer_length = sizeof(v.v8[0]); + // params[5].buffer_length = sizeof(v.v8[0]); params[5].buffer = v.v8; params[5].length = t64_len; params[5].is_null = is_null; params[5].num = 10; params[6].buffer_type = TSDB_DATA_TYPE_FLOAT; - params[6].buffer_length = sizeof(v.f4[0]); + // params[6].buffer_length = sizeof(v.f4[0]); params[6].buffer = v.f4; params[6].length = float_len; params[6].is_null = is_null; params[6].num = 10; params[7].buffer_type = TSDB_DATA_TYPE_DOUBLE; - params[7].buffer_length = sizeof(v.f8[0]); + // params[7].buffer_length = sizeof(v.f8[0]); params[7].buffer = v.f8; params[7].length = double_len; params[7].is_null = is_null; params[7].num = 10; /* params[8].buffer_type = TSDB_DATA_TYPE_BINARY; - params[8].buffer_length = sizeof(v.bin[0]); + //params[8].buffer_length = sizeof(v.bin[0]); params[8].buffer = v.bin; params[8].length = bin_len; params[8].is_null = is_null; @@ -180,7 +180,7 @@ void veriry_stmt(TAOS* taos) { params[8].num = 10; params[9].buffer_type = TSDB_DATA_TYPE_NCHAR; - params[9].buffer_length = sizeof(v.blob[0]); + // params[9].buffer_length = sizeof(v.blob[0]); params[9].buffer = v.blob; params[9].length = blob_len; params[9].is_null = is_null; @@ -205,9 +205,17 @@ void veriry_stmt(TAOS* taos) { } */ - int64_t ts = 1591060628000; - char* blob2_buffer = v.blob2; - char* blob_buffer = v.blob; + int64_t ts = 1591060628000; + char* blob2_buffer = v.blob2; + char* blob_buffer = v.blob; + const char* blob2_str[] = { + "一二三四五六七十九八", "一二三四五六七十九", "一二三四五六七十", "一二三四五六七", "一二三四五六", + "一二三四五", "一二三四", "一二三", "一二", "一", + }; + const char* blob_str[] = { + "一", "一二", "一二三", "一二三四", "一二三四五", + "一二三四五六", "一二三四五六七", "一二三四五六七八", "一二三四五六七八九", "一二三四五六七八九十", + }; for (int i = 0; i < 10; ++i) { is_null[i] = 0; @@ -224,10 +232,10 @@ void veriry_stmt(TAOS* taos) { } // strcpy(v.blob2[i], "一二三四五六七十九八"); // strcpy(v.blob[i], "一二三四五六七八九十"); - const char* blob2_str = "一二三四五六七十九八"; - const char* blob_str = "一二三四五六七八九十"; - strcpy(blob2_buffer, blob2_str); - strcpy(blob_buffer, blob_str); + // const char* blob2_str = "一二三四五六七十九八"; + // const char* blob_str = "一二三四五六七八九十"; + strcpy(blob2_buffer, blob2_str[i]); + strcpy(blob_buffer, blob_str[i]); t8_len[i] = sizeof(int8_t); t16_len[i] = sizeof(int16_t); @@ -238,8 +246,8 @@ void veriry_stmt(TAOS* taos) { bin_len[i] = sizeof(v.bin[0]); // blob_len[i] = (int32_t)strlen(v.blob[i]); // blob_len2[i] = (int32_t)strlen(v.blob2[i]); - blob_len[i] = (int32_t)strlen(blob_str); - blob_len2[i] = (int32_t)strlen(blob2_str); + blob_len[i] = (int32_t)strlen(blob_str[i]); + blob_len2[i] = (int32_t)strlen(blob2_str[i]); blob_buffer += blob_len[i]; blob2_buffer += blob_len2[i]; } From 8190c1043409368055d54b6d0f273899ec3c2400 Mon Sep 17 00:00:00 2001 From: Minglei Jin Date: Wed, 21 Aug 2024 17:25:24 +0800 Subject: [PATCH 07/23] stmt2/example: binary without hole --- tests/script/api/stmt2-example.c | 82 ++++++++++++++++++++++++++++++++ 1 file changed, 82 insertions(+) create mode 100644 tests/script/api/stmt2-example.c diff --git a/tests/script/api/stmt2-example.c b/tests/script/api/stmt2-example.c new file mode 100644 index 0000000000..d5949a6f4c --- /dev/null +++ b/tests/script/api/stmt2-example.c @@ -0,0 +1,82 @@ +#include +#include +#include +#include "taos.h" + +void do_query(TAOS* taos, const char* sql) { + TAOS_RES* result = taos_query(taos, sql); + int code = taos_errno(result); + if (code) { + printf("failed to query: %s, reason:%s\n", sql, taos_errstr(result)); + taos_free_result(result); + return; + } + taos_free_result(result); +} + +void do_stmt(TAOS* taos) { + do_query(taos, "drop database if exists db"); + do_query(taos, "create database db"); + do_query(taos, "create table db.stb (ts timestamp, b binary(10)) tags(t1 int, t2 binary(10))"); + + struct { + int64_t ts[2]; + char b[16]; + } v; + + int32_t b_len[2], t64_len[2]; + char is_null[2] = {0}; + TAOS_STMT2_OPTION option = {0}; + char* tbs[2] = {"tb", "tb2"}; + int t1_val[2] = {0, 1}; + int t2_len[2] = {3, 3}; + TAOS_STMT2_BIND tags[2][2] = {{{0, &t1_val[0], NULL, NULL, 0}, {0, "a1", &t2_len[0], NULL, 0}}, + {{0, &t1_val[1], NULL, NULL, 0}, {0, "a2", &t2_len[1], NULL, 0}}}; + TAOS_STMT2_BIND params[2][2] = { + {{TSDB_DATA_TYPE_TIMESTAMP, v.ts, t64_len, is_null, 2}, {TSDB_DATA_TYPE_BINARY, v.b, b_len, is_null, 2}}, + {{TSDB_DATA_TYPE_TIMESTAMP, v.ts, t64_len, is_null, 2}, {TSDB_DATA_TYPE_BINARY, v.b, b_len, is_null, 2}}}; + TAOS_STMT2_BIND* tagv[2] = {&tags[0][0], &tags[1][0]}; + TAOS_STMT2_BIND* paramv[2] = {¶ms[0][0], ¶ms[1][0]}; + TAOS_STMT2_BINDV bindv = {2, &tbs[0], &tagv[0], ¶mv[0]}; + + TAOS_STMT2* stmt = taos_stmt2_init(taos, &option); + const char* sql = "insert into db.? using db.stb tags(?, ?) values(?,?)"; + int code = taos_stmt2_prepare(stmt, sql, 0); + if (code != 0) { + printf("failed to execute taos_stmt2_prepare. error:%s\n", taos_stmt2_error(stmt)); + taos_stmt_close(stmt); + return; + } + + int64_t ts = 1591060628000; + for (int i = 0; i < 2; ++i) { + v.ts[i] = ts++; + t64_len[i] = sizeof(int64_t); + } + strcpy(v.b, "abcdefg"); + b_len[0] = (int)strlen(v.b); + strcpy(v.b + b_len[0], "xyz"); + b_len[1] = 3; + + taos_stmt2_bind_param(stmt, &bindv, -1); + + if (taos_stmt2_exec(stmt, NULL)) { + printf("failed to execute insert statement.error:%s\n", taos_stmt2_error(stmt)); + taos_stmt2_close(stmt); + return; + } + + taos_stmt2_close(stmt); +} + +int main() { + TAOS* taos = taos_connect("localhost", "root", "taosdata", "", 0); + if (!taos) { + printf("failed to connect to db, reason:%s\n", taos_errstr(taos)); + exit(1); + } + + do_stmt(taos); + taos_close(taos); + taos_cleanup(); +} From a1ee69d148e135452469d985bd21de7687f9ce0d Mon Sep 17 00:00:00 2001 From: Minglei Jin Date: Wed, 21 Aug 2024 18:32:45 +0800 Subject: [PATCH 08/23] stmt2/example: use stmt2's close instead of stmt --- tests/script/api/stmt2-example.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/script/api/stmt2-example.c b/tests/script/api/stmt2-example.c index d5949a6f4c..b91c6831bf 100644 --- a/tests/script/api/stmt2-example.c +++ b/tests/script/api/stmt2-example.c @@ -44,7 +44,7 @@ void do_stmt(TAOS* taos) { int code = taos_stmt2_prepare(stmt, sql, 0); if (code != 0) { printf("failed to execute taos_stmt2_prepare. error:%s\n", taos_stmt2_error(stmt)); - taos_stmt_close(stmt); + taos_stmt2_close(stmt); return; } From 44eb4661dcab742b1fd4085f98196c567484dfc4 Mon Sep 17 00:00:00 2001 From: Minglei Jin Date: Fri, 23 Aug 2024 09:12:22 +0800 Subject: [PATCH 09/23] normalize bool's value --- source/common/src/tdataformat.c | 27 ++++++--- tests/script/api/stmt2-nohole.c | 3 +- tools/shell/src/shellEngine.c | 104 ++++++++++++++++---------------- 3 files changed, 73 insertions(+), 61 deletions(-) diff --git a/source/common/src/tdataformat.c b/source/common/src/tdataformat.c index a014771f38..a101c51d62 100644 --- a/source/common/src/tdataformat.c +++ b/source/common/src/tdataformat.c @@ -3171,8 +3171,12 @@ int32_t tColDataAddValueByBind2(SColData *pColData, TAOS_STMT2_BIND *pBind, int3 if (allValue) { // optimize (todo) for (int32_t i = 0; i < pBind->num; ++i) { - code = tColDataAppendValueImpl[pColData->flag][CV_FLAG_VALUE]( - pColData, (uint8_t *)pBind->buffer + TYPE_BYTES[pColData->type] * i, TYPE_BYTES[pColData->type]); + uint8_t *val = (uint8_t *)pBind->buffer + TYPE_BYTES[pColData->type] * i; + if (TSDB_DATA_TYPE_BOOL == pColData->type && *val > 1) { + *val = 1; + } + + code = tColDataAppendValueImpl[pColData->flag][CV_FLAG_VALUE](pColData, val, TYPE_BYTES[pColData->type]); } } else if (allNull) { // optimize (todo) @@ -3186,8 +3190,12 @@ int32_t tColDataAddValueByBind2(SColData *pColData, TAOS_STMT2_BIND *pBind, int3 code = tColDataAppendValueImpl[pColData->flag][CV_FLAG_NULL](pColData, NULL, 0); if (code) goto _exit; } else { - code = tColDataAppendValueImpl[pColData->flag][CV_FLAG_VALUE]( - pColData, (uint8_t *)pBind->buffer + TYPE_BYTES[pColData->type] * i, TYPE_BYTES[pColData->type]); + uint8_t *val = (uint8_t *)pBind->buffer + TYPE_BYTES[pColData->type] * i; + if (TSDB_DATA_TYPE_BOOL == pColData->type && *val > 1) { + *val = 1; + } + + code = tColDataAppendValueImpl[pColData->flag][CV_FLAG_VALUE](pColData, val, TYPE_BYTES[pColData->type]); } } } @@ -3252,10 +3260,13 @@ int32_t tRowBuildFromBind2(SBindInfo2 *infos, int32_t numOfInfos, bool infoSorte *data += length; // value.pData = (uint8_t *)infos[iInfo].bind->buffer + infos[iInfo].bind->buffer_length * iRow; } else { - (void)memcpy( - &value.val, - (uint8_t *)infos[iInfo].bind->buffer + infos[iInfo].bytes /*infos[iInfo].bind->buffer_length*/ * iRow, - infos[iInfo].bytes /*bind->buffer_length*/); + uint8_t *val = (uint8_t *)infos[iInfo].bind->buffer + infos[iInfo].bytes * iRow; + if (TSDB_DATA_TYPE_BOOL == value.type && *val > 1) { + *val = 1; + } + (void)memcpy(&value.val, val, + /*(uint8_t *)infos[iInfo].bind->buffer + infos[iInfo].bind->buffer_length * iRow,*/ + infos[iInfo].bytes /*bind->buffer_length*/); } colVal = COL_VAL_VALUE(infos[iInfo].columnId, value); } diff --git a/tests/script/api/stmt2-nohole.c b/tests/script/api/stmt2-nohole.c index 9e6b94778c..c74256cc4a 100644 --- a/tests/script/api/stmt2-nohole.c +++ b/tests/script/api/stmt2-nohole.c @@ -220,7 +220,8 @@ void veriry_stmt(TAOS* taos) { is_null[i] = 0; v.ts[i] = ts++; - v.b[i] = (int8_t)i % 2; + // v.b[i] = (int8_t)i % 2; + v.b[i] = (int8_t)i % 10; v.v1[i] = (int8_t)i; v.v2[i] = (int16_t)(i * 2); v.v4[i] = (int32_t)(i * 4); diff --git a/tools/shell/src/shellEngine.c b/tools/shell/src/shellEngine.c index 6fd5f7402f..6da6f05c67 100644 --- a/tools/shell/src/shellEngine.c +++ b/tools/shell/src/shellEngine.c @@ -48,15 +48,15 @@ static char *shellFormatTimestamp(char *buf, int64_t val, int32_t precision); static int64_t shellDumpResultToFile(const char *fname, TAOS_RES *tres); static void shellPrintNChar(const char *str, int32_t length, int32_t width); static void shellPrintGeometry(const unsigned char *str, int32_t length, int32_t width); -static void shellVerticalPrintResult(TAOS_RES *tres, tsDumpInfo* dump_info); -static void shellHorizontalPrintResult(TAOS_RES *tres, tsDumpInfo* dump_info); +static void shellVerticalPrintResult(TAOS_RES *tres, tsDumpInfo *dump_info); +static void shellHorizontalPrintResult(TAOS_RES *tres, tsDumpInfo *dump_info); static int64_t shellDumpResult(TAOS_RES *tres, char *fname, int32_t *error_no, bool vertical, const char *sql); static void shellReadHistory(); static void shellWriteHistory(); static void shellPrintError(TAOS_RES *tres, int64_t st); static bool shellIsCommentLine(char *line); static void shellSourceFile(const char *file); -static bool shellGetGrantInfo(char* buf); +static bool shellGetGrantInfo(char *buf); static void shellCleanup(void *arg); static void *shellCancelHandler(void *arg); @@ -165,12 +165,12 @@ int32_t shellRunCommand(char *command, bool recordHistory) { // add help or help; if (strncasecmp(command, "help", 4) == 0) { - if(command[4] == ';' || command[4] == ' ' || command[4] == 0) { - showHelp(); - return 0; + if (command[4] == ';' || command[4] == ' ' || command[4] == 0) { + showHelp(); + return 0; } } - + if (recordHistory) shellRecordCommandToHistory(command); char quote = 0, *cmd = command; @@ -197,19 +197,18 @@ int32_t shellRunCommand(char *command, bool recordHistory) { return shellRunSingleCommand(cmd); } - -char * strendG(const char* pstr) { - if(pstr == NULL) { +char *strendG(const char *pstr) { + if (pstr == NULL) { return NULL; } size_t len = strlen(pstr); - if(len < 4) { + if (len < 4) { return NULL; } - char * p = (char *)pstr + len - 2; - if (strcmp(p, "\\G") == 0 ){ + char *p = (char *)pstr + len - 2; + if (strcmp(p, "\\G") == 0) { return p; } @@ -285,10 +284,11 @@ void shellRunSingleCommandImp(char *command) { et = taosGetTimestampUs(); if (error_no == 0) { - printf("Query OK, %"PRId64 " row(s) in set (%.6fs)\r\n", numOfRows, (et - st) / 1E6); + printf("Query OK, %" PRId64 " row(s) in set (%.6fs)\r\n", numOfRows, (et - st) / 1E6); } else { terrno = error_no; - printf("Query interrupted (%s), %"PRId64 " row(s) in set (%.6fs)\r\n", taos_errstr(NULL), numOfRows, (et - st) / 1E6); + printf("Query interrupted (%s), %" PRId64 " row(s) in set (%.6fs)\r\n", taos_errstr(NULL), numOfRows, + (et - st) / 1E6); } taos_free_result(pSql); } else { @@ -366,10 +366,10 @@ void shellDumpFieldToFile(TdFilePtr pFile, const char *val, TAOS_FIELD *field, i return; } - char quotationStr[2] ={'"', 0}; + char quotationStr[2] = {'"', 0}; int32_t width; - int n = 0; + int n = 0; #define LENGTH 64 char buf[LENGTH] = {0}; switch (field->type) { @@ -431,8 +431,8 @@ void shellDumpFieldToFile(TdFilePtr pFile, const char *val, TAOS_FIELD *field, i case TSDB_DATA_TYPE_NCHAR: case TSDB_DATA_TYPE_JSON: { int32_t bufIndex = 0; - char* tmp = (char*)taosMemoryCalloc(length * 2 + 1, 1); - if(tmp == NULL) break; + char *tmp = (char *)taosMemoryCalloc(length * 2 + 1, 1); + if (tmp == NULL) break; for (int32_t i = 0; i < length; i++) { tmp[bufIndex] = val[i]; bufIndex++; @@ -446,19 +446,19 @@ void shellDumpFieldToFile(TdFilePtr pFile, const char *val, TAOS_FIELD *field, i taosFprintfFile(pFile, "%s%s%s", quotationStr, tmp, quotationStr); taosMemoryFree(tmp); } break; - case TSDB_DATA_TYPE_VARBINARY:{ - void* tmp = NULL; + case TSDB_DATA_TYPE_VARBINARY: { + void *tmp = NULL; uint32_t size = 0; - if(taosAscii2Hex(val, length, &tmp, &size) < 0){ + if (taosAscii2Hex(val, length, &tmp, &size) < 0) { break; } taosFprintfFile(pFile, "%s%s%s", quotationStr, tmp, quotationStr); taosMemoryFree(tmp); break; } - case TSDB_DATA_TYPE_GEOMETRY:{ - char* tmp = (char*)taosMemoryCalloc(length * 2 + 1, 1); - if(tmp == NULL) break; + case TSDB_DATA_TYPE_GEOMETRY: { + char *tmp = (char *)taosMemoryCalloc(length * 2 + 1, 1); + if (tmp == NULL) break; shellDumpHexValue(tmp, val, length); taosFprintfFile(pFile, "%s", buf); taosMemoryFree(tmp); @@ -635,12 +635,12 @@ void shellPrintField(const char *val, TAOS_FIELD *field, int32_t width, int32_t return; } - int n = 0; -#define LENGTH 64 + int n = 0; +#define LENGTH 64 char buf[LENGTH] = {0}; switch (field->type) { case TSDB_DATA_TYPE_BOOL: - shellPrintString(((((int32_t)(*((char *)val))) == 1) ? "true" : "false"), width); + shellPrintString(((((int32_t)(*((char *)val))) == TSDB_FALSE) ? "false" : "true"), width); break; case TSDB_DATA_TYPE_TINYINT: printf("%*d", width, *((int8_t *)val)); @@ -680,7 +680,7 @@ void shellPrintField(const char *val, TAOS_FIELD *field, int32_t width, int32_t break; case TSDB_DATA_TYPE_DOUBLE: if (tsEnableScience) { - snprintf(buf, LENGTH, "%*.15e", width,GET_DOUBLE_VAL(val)); + snprintf(buf, LENGTH, "%*.15e", width, GET_DOUBLE_VAL(val)); printf("%s", buf); } else { n = snprintf(buf, LENGTH, "%*.15f", width, GET_DOUBLE_VAL(val)); @@ -691,10 +691,10 @@ void shellPrintField(const char *val, TAOS_FIELD *field, int32_t width, int32_t } } break; - case TSDB_DATA_TYPE_VARBINARY:{ - void* data = NULL; + case TSDB_DATA_TYPE_VARBINARY: { + void *data = NULL; uint32_t size = 0; - if(taosAscii2Hex(val, length, &data, &size) < 0){ + if (taosAscii2Hex(val, length, &data, &size) < 0) { break; } shellPrintNChar(data, size, width); @@ -867,7 +867,7 @@ int32_t shellCalcColWidth(TAOS_FIELD *field, int32_t precision) { } else { return TMAX(field->bytes + 2, width); } - case TSDB_DATA_TYPE_VARBINARY:{ + case TSDB_DATA_TYPE_VARBINARY: { int32_t bytes = field->bytes * 2 + 2; if (bytes > shell.args.displayWidth) { return TMAX(shell.args.displayWidth, width); @@ -1121,8 +1121,9 @@ void shellSourceFile(const char *file) { char *line = taosMemoryMalloc(TSDB_MAX_ALLOWED_SQL_LEN + 1); while ((read_len = taosGetsFile(pFile, TSDB_MAX_ALLOWED_SQL_LEN, line)) > 0) { - if ( cmd_len + read_len >= TSDB_MAX_ALLOWED_SQL_LEN) { - printf("read command line too long over 1M, ignore this line. cmd_len = %d read_len=%d \n", (int32_t)cmd_len, read_len); + if (cmd_len + read_len >= TSDB_MAX_ALLOWED_SQL_LEN) { + printf("read command line too long over 1M, ignore this line. cmd_len = %d read_len=%d \n", (int32_t)cmd_len, + read_len); cmd_len = 0; memset(line, 0, TSDB_MAX_ALLOWED_SQL_LEN + 1); continue; @@ -1156,7 +1157,7 @@ void shellSourceFile(const char *file) { taosCloseFile(&pFile); } -bool shellGetGrantInfo(char* buf) { +bool shellGetGrantInfo(char *buf) { bool community = true; char sinfo[256] = {0}; tstrncpy(sinfo, taos_get_server_info(shell.conn), sizeof(sinfo)); @@ -1207,8 +1208,7 @@ bool shellGetGrantInfo(char* buf) { sprintf(buf, "Server is %s, %s and will never expire.\r\n", serverVersion, sinfo); } else { community = false; - sprintf(buf, "Server is %s, %s and will expire at %s.\r\n", serverVersion, sinfo, - expiretime); + sprintf(buf, "Server is %s, %s and will expire at %s.\r\n", serverVersion, sinfo, expiretime); } taos_free_result(tres); @@ -1325,13 +1325,13 @@ int32_t shellExecute() { shellSetConn(shell.conn, runOnce); shellReadHistory(); - if(shell.args.is_bi_mode) { - // need set bi mode - printf("Set BI mode is true.\n"); + if (shell.args.is_bi_mode) { + // need set bi mode + printf("Set BI mode is true.\n"); #ifndef WEBSOCKET taos_set_conn_mode(shell.conn, TAOS_CONN_MODE_BI, 1); #endif - } + } if (runOnce) { if (pArgs->commands != NULL) { @@ -1374,22 +1374,22 @@ int32_t shellExecute() { #ifdef WEBSOCKET if (!shell.args.restful && !shell.args.cloud) { #endif -char* buf = taosMemoryMalloc(512); -bool community = shellGetGrantInfo(buf); + char *buf = taosMemoryMalloc(512); + bool community = shellGetGrantInfo(buf); #ifndef WINDOWS printfIntroduction(community); #else #ifndef WEBSOCKET - if(community) { + if (community) { showAD(false); } -#endif #endif -// printf version -if(!community) { - printf("%s\n", buf); -} -taosMemoryFree(buf); +#endif + // printf version + if (!community) { + printf("%s\n", buf); + } + taosMemoryFree(buf); #ifdef WEBSOCKET } @@ -1408,7 +1408,7 @@ taosMemoryFree(buf); if (community) { showAD(true); } -#endif +#endif taosThreadJoin(spid, NULL); From eef3d8fa5e2288810c2e73703fbae310c5ddc7e9 Mon Sep 17 00:00:00 2001 From: Minglei Jin Date: Fri, 23 Aug 2024 14:12:11 +0800 Subject: [PATCH 10/23] null length array for non-var-data types --- tests/script/api/stmt2-example.c | 4 ++-- tests/script/api/stmt2-nohole.c | 18 +++++++++--------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/tests/script/api/stmt2-example.c b/tests/script/api/stmt2-example.c index b91c6831bf..58ad621b50 100644 --- a/tests/script/api/stmt2-example.c +++ b/tests/script/api/stmt2-example.c @@ -33,8 +33,8 @@ void do_stmt(TAOS* taos) { TAOS_STMT2_BIND tags[2][2] = {{{0, &t1_val[0], NULL, NULL, 0}, {0, "a1", &t2_len[0], NULL, 0}}, {{0, &t1_val[1], NULL, NULL, 0}, {0, "a2", &t2_len[1], NULL, 0}}}; TAOS_STMT2_BIND params[2][2] = { - {{TSDB_DATA_TYPE_TIMESTAMP, v.ts, t64_len, is_null, 2}, {TSDB_DATA_TYPE_BINARY, v.b, b_len, is_null, 2}}, - {{TSDB_DATA_TYPE_TIMESTAMP, v.ts, t64_len, is_null, 2}, {TSDB_DATA_TYPE_BINARY, v.b, b_len, is_null, 2}}}; + {{TSDB_DATA_TYPE_TIMESTAMP, v.ts, NULL, is_null, 2}, {TSDB_DATA_TYPE_BINARY, v.b, b_len, is_null, 2}}, + {{TSDB_DATA_TYPE_TIMESTAMP, v.ts, NULL, is_null, 2}, {TSDB_DATA_TYPE_BINARY, v.b, b_len, is_null, 2}}}; TAOS_STMT2_BIND* tagv[2] = {&tags[0][0], &tags[1][0]}; TAOS_STMT2_BIND* paramv[2] = {¶ms[0][0], ¶ms[1][0]}; TAOS_STMT2_BINDV bindv = {2, &tbs[0], &tagv[0], ¶mv[0]}; diff --git a/tests/script/api/stmt2-nohole.c b/tests/script/api/stmt2-nohole.c index c74256cc4a..7d9df57baf 100644 --- a/tests/script/api/stmt2-nohole.c +++ b/tests/script/api/stmt2-nohole.c @@ -99,7 +99,7 @@ void veriry_stmt(TAOS* taos) { #include "time.h" clock_t start, end; - TAOS_STMT2_OPTION option = {0, true, false, stmtAsyncQueryCb, NULL}; + TAOS_STMT2_OPTION option = {0, true, true, stmtAsyncQueryCb, NULL}; start = clock(); TAOS_STMT2* stmt = taos_stmt2_init(taos, &option); @@ -112,56 +112,56 @@ void veriry_stmt(TAOS* taos) { params[0].buffer_type = TSDB_DATA_TYPE_TIMESTAMP; // params[0].buffer_length = sizeof(v.ts[0]); params[0].buffer = v.ts; - params[0].length = t64_len; + params[0].length = NULL; // t64_len; params[0].is_null = is_null; params[0].num = 10; params[1].buffer_type = TSDB_DATA_TYPE_BOOL; // params[1].buffer_length = sizeof(v.b[0]); params[1].buffer = v.b; - params[1].length = t8_len; + params[1].length = NULL; // t8_len; params[1].is_null = is_null; params[1].num = 10; params[2].buffer_type = TSDB_DATA_TYPE_TINYINT; // params[2].buffer_length = sizeof(v.v1[0]); params[2].buffer = v.v1; - params[2].length = t8_len; + params[2].length = NULL; // t8_len; params[2].is_null = is_null; params[2].num = 10; params[3].buffer_type = TSDB_DATA_TYPE_SMALLINT; // params[3].buffer_length = sizeof(v.v2[0]); params[3].buffer = v.v2; - params[3].length = t16_len; + params[3].length = NULL; // t16_len; params[3].is_null = is_null; params[3].num = 10; params[4].buffer_type = TSDB_DATA_TYPE_INT; // params[4].buffer_length = sizeof(v.v4[0]); params[4].buffer = v.v4; - params[4].length = t32_len; + params[4].length = NULL; // t32_len; params[4].is_null = is_null; params[4].num = 10; params[5].buffer_type = TSDB_DATA_TYPE_BIGINT; // params[5].buffer_length = sizeof(v.v8[0]); params[5].buffer = v.v8; - params[5].length = t64_len; + params[5].length = NULL; // t64_len; params[5].is_null = is_null; params[5].num = 10; params[6].buffer_type = TSDB_DATA_TYPE_FLOAT; // params[6].buffer_length = sizeof(v.f4[0]); params[6].buffer = v.f4; - params[6].length = float_len; + params[6].length = NULL; // float_len; params[6].is_null = is_null; params[6].num = 10; params[7].buffer_type = TSDB_DATA_TYPE_DOUBLE; // params[7].buffer_length = sizeof(v.f8[0]); params[7].buffer = v.f8; - params[7].length = double_len; + params[7].length = NULL; // double_len; params[7].is_null = is_null; params[7].num = 10; /* From f602bd36c650ae36514bb34f7b19836a583d5e33 Mon Sep 17 00:00:00 2001 From: Minglei Jin Date: Fri, 23 Aug 2024 14:49:28 +0800 Subject: [PATCH 11/23] col/add value/bind2: remove assert --- source/common/src/tdataformat.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/source/common/src/tdataformat.c b/source/common/src/tdataformat.c index a101c51d62..9d077469d6 100644 --- a/source/common/src/tdataformat.c +++ b/source/common/src/tdataformat.c @@ -3130,7 +3130,9 @@ int32_t tColDataAddValueByBind2(SColData *pColData, TAOS_STMT2_BIND *pBind, int3 int32_t code = 0; if (!(pBind->num == 1 && pBind->is_null && *pBind->is_null)) { - ASSERT(pColData->type == pBind->buffer_type); + if (!(pColData->type == pBind->buffer_type)) { + return TSDB_CODE_INVALID_PARA; + } } if (IS_VAR_DATA_TYPE(pColData->type)) { // var-length data type From 5421c52fa3e17e9e4a61c7de7cc98067cd6259a5 Mon Sep 17 00:00:00 2001 From: Minglei Jin Date: Fri, 23 Aug 2024 17:09:09 +0800 Subject: [PATCH 12/23] none value for stmt2 --- source/common/src/tdataformat.c | 35 +++++++++++++++++++++++++++------ 1 file changed, 29 insertions(+), 6 deletions(-) diff --git a/source/common/src/tdataformat.c b/source/common/src/tdataformat.c index 9d077469d6..6f07bd7c2e 100644 --- a/source/common/src/tdataformat.c +++ b/source/common/src/tdataformat.c @@ -3143,8 +3143,13 @@ int32_t tColDataAddValueByBind2(SColData *pColData, TAOS_STMT2_BIND *pBind, int3 code = TSDB_CODE_PAR_PRIMARY_KEY_IS_NULL; goto _exit; } - code = tColDataAppendValueImpl[pColData->flag][CV_FLAG_NULL](pColData, NULL, 0); - if (code) goto _exit; + if (pBind->is_null[i] == 1) { + code = tColDataAppendValueImpl[pColData->flag][CV_FLAG_NULL](pColData, NULL, 0); + if (code) goto _exit; + } else { + code = tColDataAppendValueImpl[pColData->flag][CV_FLAG_NONE](pColData, NULL, 0); + if (code) goto _exit; + } } else if (pBind->length[i] > buffMaxLen) { uError("var data length too big, len:%d, max:%d", pBind->length[i], buffMaxLen); return TSDB_CODE_INVALID_PARA; @@ -3156,12 +3161,15 @@ int32_t tColDataAddValueByBind2(SColData *pColData, TAOS_STMT2_BIND *pBind, int3 } else { // fixed-length data type bool allValue; bool allNull; + bool allNone; if (pBind->is_null) { bool same = (memcmp(pBind->is_null, pBind->is_null + 1, pBind->num - 1) == 0); - allNull = (same && pBind->is_null[0] != 0); + allNull = (same && pBind->is_null[0] == 1); + allNone = (same && pBind->is_null[0] > 1); allValue = (same && pBind->is_null[0] == 0); } else { allNull = false; + allNone = false; allValue = true; } @@ -3186,11 +3194,22 @@ int32_t tColDataAddValueByBind2(SColData *pColData, TAOS_STMT2_BIND *pBind, int3 code = tColDataAppendValueImpl[pColData->flag][CV_FLAG_NULL](pColData, NULL, 0); if (code) goto _exit; } + } else if (allNone) { + // optimize (todo) + for (int32_t i = 0; i < pBind->num; ++i) { + code = tColDataAppendValueImpl[pColData->flag][CV_FLAG_NONE](pColData, NULL, 0); + if (code) goto _exit; + } } else { for (int32_t i = 0; i < pBind->num; ++i) { if (pBind->is_null[i]) { - code = tColDataAppendValueImpl[pColData->flag][CV_FLAG_NULL](pColData, NULL, 0); - if (code) goto _exit; + if (pBind->is_null[i] == 1) { + code = tColDataAppendValueImpl[pColData->flag][CV_FLAG_NULL](pColData, NULL, 0); + if (code) goto _exit; + } else { + code = tColDataAppendValueImpl[pColData->flag][CV_FLAG_NONE](pColData, NULL, 0); + if (code) goto _exit; + } } else { uint8_t *val = (uint8_t *)pBind->buffer + TYPE_BYTES[pColData->type] * i; if (TSDB_DATA_TYPE_BOOL == pColData->type && *val > 1) { @@ -3249,7 +3268,11 @@ int32_t tRowBuildFromBind2(SBindInfo2 *infos, int32_t numOfInfos, bool infoSorte for (int32_t iInfo = 0; iInfo < numOfInfos; iInfo++) { if (infos[iInfo].bind->is_null && infos[iInfo].bind->is_null[iRow]) { - colVal = COL_VAL_NULL(infos[iInfo].columnId, infos[iInfo].type); + if (infos[iInfo].bind->is_null[iRow] == 1) { + colVal = COL_VAL_NULL(infos[iInfo].columnId, infos[iInfo].type); + } else { + colVal = COL_VAL_NONE(infos[iInfo].columnId, infos[iInfo].type); + } } else { SValue value = { .type = infos[iInfo].type, From df1195f93b384c5fbe92e20832ab00e593d06c3b Mon Sep 17 00:00:00 2001 From: Minglei Jin Date: Fri, 23 Aug 2024 17:09:47 +0800 Subject: [PATCH 13/23] cleanup client stmt2 --- source/client/src/clientStmt2.c | 164 ++++++++++++++++---------------- 1 file changed, 81 insertions(+), 83 deletions(-) diff --git a/source/client/src/clientStmt2.c b/source/client/src/clientStmt2.c index e938e27cc8..6b9978c2db 100644 --- a/source/client/src/clientStmt2.c +++ b/source/client/src/clientStmt2.c @@ -177,49 +177,6 @@ static int32_t stmtGetTbName(TAOS_STMT2* stmt, char** tbName) { return TSDB_CODE_SUCCESS; } -static int32_t stmtBackupQueryFields(STscStmt2* pStmt) { - SStmtQueryResInfo* pRes = &pStmt->sql.queryRes; - pRes->numOfCols = pStmt->exec.pRequest->body.resInfo.numOfCols; - pRes->precision = pStmt->exec.pRequest->body.resInfo.precision; - - int32_t size = pRes->numOfCols * sizeof(TAOS_FIELD); - pRes->fields = taosMemoryMalloc(size); - pRes->userFields = taosMemoryMalloc(size); - if (NULL == pRes->fields || NULL == pRes->userFields) { - STMT_ERR_RET(TSDB_CODE_OUT_OF_MEMORY); - } - (void)memcpy(pRes->fields, pStmt->exec.pRequest->body.resInfo.fields, size); - (void)memcpy(pRes->userFields, pStmt->exec.pRequest->body.resInfo.userFields, size); - - return TSDB_CODE_SUCCESS; -} - -static int32_t stmtRestoreQueryFields(STscStmt2* pStmt) { - SStmtQueryResInfo* pRes = &pStmt->sql.queryRes; - int32_t size = pRes->numOfCols * sizeof(TAOS_FIELD); - - pStmt->exec.pRequest->body.resInfo.numOfCols = pRes->numOfCols; - pStmt->exec.pRequest->body.resInfo.precision = pRes->precision; - - if (NULL == pStmt->exec.pRequest->body.resInfo.fields) { - pStmt->exec.pRequest->body.resInfo.fields = taosMemoryMalloc(size); - if (NULL == pStmt->exec.pRequest->body.resInfo.fields) { - STMT_ERR_RET(TSDB_CODE_OUT_OF_MEMORY); - } - (void)memcpy(pStmt->exec.pRequest->body.resInfo.fields, pRes->fields, size); - } - - if (NULL == pStmt->exec.pRequest->body.resInfo.userFields) { - pStmt->exec.pRequest->body.resInfo.userFields = taosMemoryMalloc(size); - if (NULL == pStmt->exec.pRequest->body.resInfo.userFields) { - STMT_ERR_RET(TSDB_CODE_OUT_OF_MEMORY); - } - (void)memcpy(pStmt->exec.pRequest->body.resInfo.userFields, pRes->userFields, size); - } - - return TSDB_CODE_SUCCESS; -} - static int32_t stmtUpdateBindInfo(TAOS_STMT2* stmt, STableMeta* pTableMeta, void* tags, SName* tbName, const char* sTableName, bool autoCreateTbl) { STscStmt2* pStmt = (STscStmt2*)stmt; @@ -280,44 +237,6 @@ static int32_t stmtGetExecInfo(TAOS_STMT2* stmt, SHashObj** pVgHash, SHashObj** return TSDB_CODE_SUCCESS; } -static int32_t stmtCacheBlock(STscStmt2* pStmt) { - if (pStmt->sql.type != STMT_TYPE_MULTI_INSERT) { - return TSDB_CODE_SUCCESS; - } - - uint64_t uid = pStmt->bInfo.tbUid; - uint64_t cacheUid = (TSDB_CHILD_TABLE == pStmt->bInfo.tbType) ? pStmt->bInfo.tbSuid : uid; - - if (taosHashGet(pStmt->sql.pTableCache, &cacheUid, sizeof(cacheUid))) { - return TSDB_CODE_SUCCESS; - } - - STableDataCxt** pSrc = taosHashGet(pStmt->exec.pBlockHash, pStmt->bInfo.tbFName, strlen(pStmt->bInfo.tbFName)); - if (!pSrc) { - return TSDB_CODE_OUT_OF_MEMORY; - } - STableDataCxt* pDst = NULL; - - STMT_ERR_RET(qCloneStmtDataBlock(&pDst, *pSrc, true)); - - SStmtTableCache cache = { - .pDataCtx = pDst, - .boundTags = pStmt->bInfo.boundTags, - }; - - if (taosHashPut(pStmt->sql.pTableCache, &cacheUid, sizeof(cacheUid), &cache, sizeof(cache))) { - return TSDB_CODE_OUT_OF_MEMORY; - } - - if (pStmt->sql.autoCreateTbl) { - pStmt->bInfo.tagsCached = true; - } else { - pStmt->bInfo.boundTags = NULL; - } - - return TSDB_CODE_SUCCESS; -} - static int32_t stmtParseSql(STscStmt2* pStmt) { pStmt->exec.pCurrBlock = NULL; @@ -1129,7 +1048,6 @@ static int stmtFetchColFields2(STscStmt2* pStmt, int32_t* fieldNum, TAOS_FIELD_E return TSDB_CODE_SUCCESS; } - /* SArray* stmtGetFreeCol(STscStmt2* pStmt, int32_t* idx) { while (true) { @@ -1147,7 +1065,6 @@ SArray* stmtGetFreeCol(STscStmt2* pStmt, int32_t* idx) { } } */ - static int32_t stmtAppendTablePostHandle(STscStmt2* pStmt, SStmtQNode* param) { if (NULL == pStmt->sql.siInfo.pVgroupHash) { pStmt->sql.siInfo.pVgroupHash = @@ -1212,6 +1129,44 @@ static FORCE_INLINE int32_t stmtGetTableColsFromCache(STscStmt2* pStmt, SArray** return TSDB_CODE_SUCCESS; } +static int32_t stmtCacheBlock(STscStmt2* pStmt) { + if (pStmt->sql.type != STMT_TYPE_MULTI_INSERT) { + return TSDB_CODE_SUCCESS; + } + + uint64_t uid = pStmt->bInfo.tbUid; + uint64_t cacheUid = (TSDB_CHILD_TABLE == pStmt->bInfo.tbType) ? pStmt->bInfo.tbSuid : uid; + + if (taosHashGet(pStmt->sql.pTableCache, &cacheUid, sizeof(cacheUid))) { + return TSDB_CODE_SUCCESS; + } + + STableDataCxt** pSrc = taosHashGet(pStmt->exec.pBlockHash, pStmt->bInfo.tbFName, strlen(pStmt->bInfo.tbFName)); + if (!pSrc) { + return TSDB_CODE_OUT_OF_MEMORY; + } + STableDataCxt* pDst = NULL; + + STMT_ERR_RET(qCloneStmtDataBlock(&pDst, *pSrc, true)); + + SStmtTableCache cache = { + .pDataCtx = pDst, + .boundTags = pStmt->bInfo.boundTags, + }; + + if (taosHashPut(pStmt->sql.pTableCache, &cacheUid, sizeof(cacheUid), &cache, sizeof(cache))) { + return TSDB_CODE_OUT_OF_MEMORY; + } + + if (pStmt->sql.autoCreateTbl) { + pStmt->bInfo.tagsCached = true; + } else { + pStmt->bInfo.boundTags = NULL; + } + + return TSDB_CODE_SUCCESS; +} + static int stmtAddBatch2(TAOS_STMT2* stmt) { STscStmt2* pStmt = (STscStmt2*)stmt; @@ -1245,7 +1200,50 @@ static int stmtAddBatch2(TAOS_STMT2* stmt) { return TSDB_CODE_SUCCESS; } +/* +static int32_t stmtBackupQueryFields(STscStmt2* pStmt) { + SStmtQueryResInfo* pRes = &pStmt->sql.queryRes; + pRes->numOfCols = pStmt->exec.pRequest->body.resInfo.numOfCols; + pRes->precision = pStmt->exec.pRequest->body.resInfo.precision; + int32_t size = pRes->numOfCols * sizeof(TAOS_FIELD); + pRes->fields = taosMemoryMalloc(size); + pRes->userFields = taosMemoryMalloc(size); + if (NULL == pRes->fields || NULL == pRes->userFields) { + STMT_ERR_RET(TSDB_CODE_OUT_OF_MEMORY); + } + (void)memcpy(pRes->fields, pStmt->exec.pRequest->body.resInfo.fields, size); + (void)memcpy(pRes->userFields, pStmt->exec.pRequest->body.resInfo.userFields, size); + + return TSDB_CODE_SUCCESS; +} + +static int32_t stmtRestoreQueryFields(STscStmt2* pStmt) { + SStmtQueryResInfo* pRes = &pStmt->sql.queryRes; + int32_t size = pRes->numOfCols * sizeof(TAOS_FIELD); + + pStmt->exec.pRequest->body.resInfo.numOfCols = pRes->numOfCols; + pStmt->exec.pRequest->body.resInfo.precision = pRes->precision; + + if (NULL == pStmt->exec.pRequest->body.resInfo.fields) { + pStmt->exec.pRequest->body.resInfo.fields = taosMemoryMalloc(size); + if (NULL == pStmt->exec.pRequest->body.resInfo.fields) { + STMT_ERR_RET(TSDB_CODE_OUT_OF_MEMORY); + } + (void)memcpy(pStmt->exec.pRequest->body.resInfo.fields, pRes->fields, size); + } + + if (NULL == pStmt->exec.pRequest->body.resInfo.userFields) { + pStmt->exec.pRequest->body.resInfo.userFields = taosMemoryMalloc(size); + if (NULL == pStmt->exec.pRequest->body.resInfo.userFields) { + STMT_ERR_RET(TSDB_CODE_OUT_OF_MEMORY); + } + (void)memcpy(pStmt->exec.pRequest->body.resInfo.userFields, pRes->userFields, size); + } + + return TSDB_CODE_SUCCESS; +} +*/ int stmtBindBatch2(TAOS_STMT2* stmt, TAOS_STMT2_BIND* bind, int32_t colIdx) { STscStmt2* pStmt = (STscStmt2*)stmt; int32_t code = 0; From e535fadc518bb5f6c484c5f78477290da517f5a0 Mon Sep 17 00:00:00 2001 From: Minglei Jin Date: Fri, 23 Aug 2024 17:10:35 +0800 Subject: [PATCH 14/23] none for stmt2 example --- tests/script/api/stmt2-example.c | 31 ++++++++++++++++++------------- tests/script/api/stmt2-nohole.c | 7 ++++--- 2 files changed, 22 insertions(+), 16 deletions(-) diff --git a/tests/script/api/stmt2-example.c b/tests/script/api/stmt2-example.c index 58ad621b50..c8d48927f8 100644 --- a/tests/script/api/stmt2-example.c +++ b/tests/script/api/stmt2-example.c @@ -24,17 +24,21 @@ void do_stmt(TAOS* taos) { char b[16]; } v; - int32_t b_len[2], t64_len[2]; - char is_null[2] = {0}; - TAOS_STMT2_OPTION option = {0}; - char* tbs[2] = {"tb", "tb2"}; - int t1_val[2] = {0, 1}; - int t2_len[2] = {3, 3}; - TAOS_STMT2_BIND tags[2][2] = {{{0, &t1_val[0], NULL, NULL, 0}, {0, "a1", &t2_len[0], NULL, 0}}, - {{0, &t1_val[1], NULL, NULL, 0}, {0, "a2", &t2_len[1], NULL, 0}}}; - TAOS_STMT2_BIND params[2][2] = { - {{TSDB_DATA_TYPE_TIMESTAMP, v.ts, NULL, is_null, 2}, {TSDB_DATA_TYPE_BINARY, v.b, b_len, is_null, 2}}, - {{TSDB_DATA_TYPE_TIMESTAMP, v.ts, NULL, is_null, 2}, {TSDB_DATA_TYPE_BINARY, v.b, b_len, is_null, 2}}}; + int32_t b_len[2], t64_len[2]; + char is_null[2] = {0}; + char is_null2[2] = {0, 2}; + // TAOS_STMT2_OPTION option = {0}; + // TAOS_STMT2_OPTION option = {0, true, true, stmtAsyncQueryCb, NULL}; + TAOS_STMT2_OPTION option = {0, true, true, NULL, NULL}; + + char* tbs[2] = {"tb", "tb2"}; + int t1_val[2] = {0, 1}; + int t2_len[2] = {3, 3}; + TAOS_STMT2_BIND tags[2][2] = {{{0, &t1_val[0], NULL, NULL, 0}, {0, "a1", &t2_len[0], NULL, 0}}, + {{0, &t1_val[1], NULL, NULL, 0}, {0, "a2", &t2_len[1], NULL, 0}}}; + TAOS_STMT2_BIND params[2][2] = { + {{TSDB_DATA_TYPE_TIMESTAMP, v.ts, NULL, is_null, 2}, {TSDB_DATA_TYPE_BINARY, v.b, b_len, is_null2, 2}}, + {{TSDB_DATA_TYPE_TIMESTAMP, v.ts, NULL, is_null, 2}, {TSDB_DATA_TYPE_BINARY, v.b, b_len, is_null2, 2}}}; TAOS_STMT2_BIND* tagv[2] = {&tags[0][0], &tags[1][0]}; TAOS_STMT2_BIND* paramv[2] = {¶ms[0][0], ¶ms[1][0]}; TAOS_STMT2_BINDV bindv = {2, &tbs[0], &tagv[0], ¶mv[0]}; @@ -50,8 +54,9 @@ void do_stmt(TAOS* taos) { int64_t ts = 1591060628000; for (int i = 0; i < 2; ++i) { - v.ts[i] = ts++; - t64_len[i] = sizeof(int64_t); + // v.ts[i] = ts++; + v.ts[i] = ts; + // t64_len[i] = sizeof(int64_t); } strcpy(v.b, "abcdefg"); b_len[0] = (int)strlen(v.b); diff --git a/tests/script/api/stmt2-nohole.c b/tests/script/api/stmt2-nohole.c index 7d9df57baf..743ec1e695 100644 --- a/tests/script/api/stmt2-nohole.c +++ b/tests/script/api/stmt2-nohole.c @@ -107,13 +107,14 @@ void veriry_stmt(TAOS* taos) { printf("init time:%f\n", (double)(end - start) / CLOCKS_PER_SEC); // TAOS_MULTI_BIND params[10]; TAOS_STMT2_BIND params[10]; - char is_null[10] = {0}; + char is_null2[10] = {0}; + char is_null[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 1}; params[0].buffer_type = TSDB_DATA_TYPE_TIMESTAMP; // params[0].buffer_length = sizeof(v.ts[0]); params[0].buffer = v.ts; params[0].length = NULL; // t64_len; - params[0].is_null = is_null; + params[0].is_null = is_null2; params[0].num = 10; params[1].buffer_type = TSDB_DATA_TYPE_BOOL; @@ -217,7 +218,7 @@ void veriry_stmt(TAOS* taos) { "一二三四五六", "一二三四五六七", "一二三四五六七八", "一二三四五六七八九", "一二三四五六七八九十", }; for (int i = 0; i < 10; ++i) { - is_null[i] = 0; + // is_null[i] = 0; v.ts[i] = ts++; // v.b[i] = (int8_t)i % 2; From 4cab7ea4f7defac442d81fdcd74470919db099f5 Mon Sep 17 00:00:00 2001 From: Minglei Jin Date: Mon, 26 Aug 2024 16:45:18 +0800 Subject: [PATCH 15/23] stmt2/meta: tbname (multi-insert) parameterized or not --- include/client/taos.h | 1 + source/client/inc/clientStmt2.h | 5 +++-- source/client/src/clientMain.c | 2 ++ source/client/src/clientStmt2.c | 32 ++++++++++++++++++++++++++++++++ tests/script/api/stmt2-nohole.c | 16 ++++++++++++++-- 5 files changed, 52 insertions(+), 4 deletions(-) diff --git a/include/client/taos.h b/include/client/taos.h index 90d6712d6e..6a352de0ff 100644 --- a/include/client/taos.h +++ b/include/client/taos.h @@ -199,6 +199,7 @@ typedef enum { TAOS_FIELD_COL = 1, TAOS_FIELD_TAG, TAOS_FIELD_QUERY, + TAOS_FIELD_TBNAME, } TAOS_FIELD_T; typedef struct { diff --git a/source/client/inc/clientStmt2.h b/source/client/inc/clientStmt2.h index e54ac03c55..ad8938c474 100644 --- a/source/client/inc/clientStmt2.h +++ b/source/client/inc/clientStmt2.h @@ -218,12 +218,13 @@ int stmtExec2(TAOS_STMT2 *stmt, int *affected_rows); int stmtPrepare2(TAOS_STMT2 *stmt, const char *sql, unsigned long length); int stmtSetTbName2(TAOS_STMT2 *stmt, const char *tbName); int stmtSetTbTags2(TAOS_STMT2 *stmt, TAOS_STMT2_BIND *tags); +int stmtBindBatch2(TAOS_STMT2 *stmt, TAOS_STMT2_BIND *bind, int32_t colIdx); int stmtGetTagFields2(TAOS_STMT2 *stmt, int *nums, TAOS_FIELD_E **fields); int stmtGetColFields2(TAOS_STMT2 *stmt, int *nums, TAOS_FIELD_E **fields); -int stmtIsInsert2(TAOS_STMT2 *stmt, int *insert); int stmtGetParamNum2(TAOS_STMT2 *stmt, int *nums); +int stmtGetParamTbName(TAOS_STMT2 *stmt, int *nums); +int stmtIsInsert2(TAOS_STMT2 *stmt, int *insert); TAOS_RES *stmtUseResult2(TAOS_STMT2 *stmt); -int stmtBindBatch2(TAOS_STMT2 *stmt, TAOS_STMT2_BIND *bind, int32_t colIdx); const char *stmtErrstr2(TAOS_STMT2 *stmt); #ifdef __cplusplus diff --git a/source/client/src/clientMain.c b/source/client/src/clientMain.c index a81172a737..6fc6eb71b1 100644 --- a/source/client/src/clientMain.c +++ b/source/client/src/clientMain.c @@ -2005,6 +2005,8 @@ int taos_stmt2_get_fields(TAOS_STMT2 *stmt, TAOS_FIELD_T field_type, int *count, return stmtGetTagFields2(stmt, count, fields); } else if (field_type == TAOS_FIELD_QUERY) { return stmtGetParamNum2(stmt, count); + } else if (field_type == TAOS_FIELD_TBNAME) { + return stmtGetParamTbName(stmt, count); } else { tscError("invalid parameter for %s", __FUNCTION__); terrno = TSDB_CODE_INVALID_PARA; diff --git a/source/client/src/clientStmt2.c b/source/client/src/clientStmt2.c index 6b9978c2db..3964cb184f 100644 --- a/source/client/src/clientStmt2.c +++ b/source/client/src/clientStmt2.c @@ -1829,6 +1829,38 @@ int stmtGetParamNum2(TAOS_STMT2* stmt, int* nums) { return TSDB_CODE_SUCCESS; } + +int stmtGetParamTbName(TAOS_STMT2* stmt, int* nums) { + STscStmt2* pStmt = (STscStmt2*)stmt; + + 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 && + STMT_TYPE_MULTI_INSERT != pStmt->sql.type) { + pStmt->bInfo.needParse = false; + } + + if (pStmt->exec.pRequest && STMT_TYPE_QUERY == pStmt->sql.type && pStmt->sql.runTimes) { + taos_free_result(pStmt->exec.pRequest); + pStmt->exec.pRequest = NULL; + } + + STMT_ERR_RET(stmtCreateRequest(pStmt)); + + if (pStmt->bInfo.needParse) { + STMT_ERR_RET(stmtParseSql(pStmt)); + } + + *nums = STMT_TYPE_MULTI_INSERT == pStmt->sql.type ? 1 : 0; + + return TSDB_CODE_SUCCESS; +} /* int stmtGetParam(TAOS_STMT* stmt, int idx, int* type, int* bytes) { STscStmt2* pStmt = (STscStmt2*)stmt; diff --git a/tests/script/api/stmt2-nohole.c b/tests/script/api/stmt2-nohole.c index 743ec1e695..dbd441f136 100644 --- a/tests/script/api/stmt2-nohole.c +++ b/tests/script/api/stmt2-nohole.c @@ -70,6 +70,18 @@ void veriry_stmt(TAOS* taos) { } taos_free_result(result); + sql = + "create table m2 (ts timestamp, b bool, v1 tinyint, v2 smallint, v4 int, v8 bigint, f4 float, f8 double, blob2 " + "nchar(10), blob nchar(10))"; + result = taos_query(taos, sql); + code = taos_errno(result); + if (code != 0) { + printf("\033[31mfailed to create table, reason:%s\033[0m\n", taos_errstr(result)); + taos_free_result(result); + return; + } + taos_free_result(result); + // insert 10 records struct { int64_t ts[10]; @@ -254,7 +266,7 @@ void veriry_stmt(TAOS* taos) { blob2_buffer += blob_len2[i]; } - char* tbname = "m1"; + char* tbname = "m2"; TAOS_STMT2_BIND* bind_cols[1] = {¶ms[0]}; TAOS_STMT2_BINDV bindv = {1, &tbname, NULL, &bind_cols[0]}; start = clock(); @@ -277,7 +289,7 @@ void veriry_stmt(TAOS* taos) { TAOS_FIELD_E* fields = NULL; int field_count = -1; start = clock(); - code = taos_stmt2_get_fields(stmt, TAOS_FIELD_COL, &field_count, NULL); + code = taos_stmt2_get_fields(stmt, TAOS_FIELD_TBNAME, &field_count, NULL); end = clock(); printf("get fields time:%f\n", (double)(end - start) / CLOCKS_PER_SEC); if (code != 0) { From 8cbcdec4bf3761a0afc996ff732a8cf162ef8db0 Mon Sep 17 00:00:00 2001 From: Minglei Jin Date: Thu, 29 Aug 2024 08:56:24 +0800 Subject: [PATCH 16/23] stmt2/async: new sem for api syncing --- source/client/inc/clientStmt2.h | 1 + source/client/src/clientStmt2.c | 82 ++++++++++++++++++++------------- tests/script/api/stmt2-nohole.c | 9 ++++ 3 files changed, 60 insertions(+), 32 deletions(-) diff --git a/source/client/inc/clientStmt2.h b/source/client/inc/clientStmt2.h index ad8938c474..74eb198930 100644 --- a/source/client/inc/clientStmt2.h +++ b/source/client/inc/clientStmt2.h @@ -152,6 +152,7 @@ typedef struct { int64_t reqid; int32_t errCode; + tsem_t asyncQuerySem; SStmtStatInfo stat; } STscStmt2; diff --git a/source/client/src/clientStmt2.c b/source/client/src/clientStmt2.c index 3964cb184f..b3571078cd 100644 --- a/source/client/src/clientStmt2.c +++ b/source/client/src/clientStmt2.c @@ -814,6 +814,7 @@ TAOS_STMT2* stmtInit2(STscObj* taos, TAOS_STMT2_OPTION* pOptions) { } pStmt->sql.siInfo.tableColsReady = true; + (void)tsem_init(&pStmt->asyncQuerySem, 0, 1); STMT_LOG_SEQ(STMT_INIT); @@ -1574,12 +1575,22 @@ static int32_t createParseContext(const SRequestObj* pRequest, SParseContext** p return TSDB_CODE_SUCCESS; } -int stmtExec2(TAOS_STMT2* stmt, int* affected_rows) { - STscStmt2* pStmt = (STscStmt2*)stmt; - int32_t code = 0; - SSubmitRsp* pRsp = NULL; +static void asyncQueryCb(void* userdata, TAOS_RES* res, int code) { + STscStmt2* pStmt = userdata; + __taos_async_fn_t fp = pStmt->options.asyncExecFn; - int64_t startUs = taosGetTimestampUs(); + pStmt->exec.affectedRows = taos_affected_rows(pStmt->exec.pRequest); + pStmt->affectedRows += pStmt->exec.affectedRows; + + fp(pStmt->options.userdata, res, code); + + (void)tsem_post(&pStmt->asyncQuerySem); +} + +int stmtExec2(TAOS_STMT2* stmt, int* affected_rows) { + STscStmt2* pStmt = (STscStmt2*)stmt; + int32_t code = 0; + int64_t startUs = taosGetTimestampUs(); STMT_DLOG_E("start to exec"); @@ -1589,6 +1600,8 @@ int stmtExec2(TAOS_STMT2* stmt, int* affected_rows) { STMT_ERR_RET(stmtSwitchStatus(pStmt, STMT_EXECUTE)); + (void)tsem_wait(&pStmt->asyncQuerySem); + if (STMT_TYPE_QUERY != pStmt->sql.type) { if (pStmt->sql.stbInterlaceMode) { int64_t startTs = taosGetTimestampUs(); @@ -1611,51 +1624,54 @@ int stmtExec2(TAOS_STMT2* stmt, int* affected_rows) { } } - (void)launchQueryImpl(pStmt->exec.pRequest, pStmt->sql.pQuery, true, NULL); + SRequestObj* pRequest = pStmt->exec.pRequest; + __taos_async_fn_t fp = pStmt->options.asyncExecFn; - /* + if (!fp) { + (void)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); + if (code) { + pStmt->exec.pRequest->code = code; + } else { + STMT_ERR_RET(stmtResetStmt(pStmt)); + STMT_ERR_RET(TSDB_CODE_NEED_RETRY); + } + } + + STMT_ERR_JRET(pStmt->exec.pRequest->code); + + pStmt->exec.affectedRows = taos_affected_rows(pStmt->exec.pRequest); + if (affected_rows) { + *affected_rows = pStmt->exec.affectedRows; + } + pStmt->affectedRows += pStmt->exec.affectedRows; + } else { SSqlCallbackWrapper* pWrapper = taosMemoryCalloc(1, sizeof(SSqlCallbackWrapper)); if (pWrapper == NULL) { code = TSDB_CODE_OUT_OF_MEMORY; } else { - pWrapper->pRequest = pStmt->exec.pRequest; - pStmt->exec.pRequest->pWrapper = pWrapper; + pWrapper->pRequest = pRequest; + pRequest->pWrapper = pWrapper; } if (TSDB_CODE_SUCCESS == code) { - code = createParseContext(pStmt->exec.pRequest, &pWrapper->pParseCtx, pWrapper); + code = createParseContext(pRequest, &pWrapper->pParseCtx, pWrapper); } - pStmt->exec.pRequest->syncQuery = false; - pStmt->exec.pRequest->body.queryFp = fp; - ((SSyncQueryParam*)(pStmt->exec.pRequest)->body.interParam)->userParam = param; - launchAsyncQuery(pStmt->exec.pRequest, pStmt->sql.pQuery, NULL, pWrapper); - */ + pRequest->syncQuery = false; + pRequest->body.queryFp = asyncQueryCb; + ((SSyncQueryParam*)(pRequest)->body.interParam)->userParam = pStmt; - if (pStmt->exec.pRequest->code && NEED_CLIENT_HANDLE_ERROR(pStmt->exec.pRequest->code)) { - code = refreshMeta(pStmt->exec.pRequest->pTscObj, pStmt->exec.pRequest); - if (code) { - pStmt->exec.pRequest->code = code; - } else { - tFreeSSubmitRsp(pRsp); - STMT_ERR_RET(stmtResetStmt(pStmt)); - STMT_ERR_RET(TSDB_CODE_NEED_RETRY); - } + launchAsyncQuery(pRequest, pStmt->sql.pQuery, NULL, pWrapper); } - STMT_ERR_JRET(pStmt->exec.pRequest->code); - - pStmt->exec.affectedRows = taos_affected_rows(pStmt->exec.pRequest); - pStmt->affectedRows += pStmt->exec.affectedRows; - _return: - while (0 == atomic_load_8((int8_t*)&pStmt->sql.siInfo.tableColsReady)) { taosUsleep(1); } STMT_ERR_RET(stmtCleanExecInfo(pStmt, (code ? false : true), false)); - tFreeSSubmitRsp(pRsp); - ++pStmt->sql.runTimes; int64_t startUs2 = taosGetTimestampUs(); @@ -1688,6 +1704,8 @@ int stmtClose2(TAOS_STMT2* stmt) { pStmt->stat.addBatchUs, pStmt->stat.execWaitUs, pStmt->stat.execUseUs); STMT_ERR_RET(stmtCleanSQLInfo(pStmt)); + + (void)tsem_destroy(&pStmt->asyncQuerySem); taosMemoryFree(stmt); return TSDB_CODE_SUCCESS; diff --git a/tests/script/api/stmt2-nohole.c b/tests/script/api/stmt2-nohole.c index dbd441f136..1ddb4a66b2 100644 --- a/tests/script/api/stmt2-nohole.c +++ b/tests/script/api/stmt2-nohole.c @@ -1,6 +1,7 @@ // sample code to verify all TDengine API // to compile: gcc -o apitest apitest.c -ltaos +#include #include #include #include @@ -13,8 +14,12 @@ int64_t genReqid() { return count; } +sem_t sem; + void stmtAsyncQueryCb(void* param, TAOS_RES* pRes, int code) { int affected_rows = taos_affected_rows(pRes); + printf("\033[31maffected rows:%d\033[0m\n", affected_rows); + (void)sem_post(&sem); return; /* SSP_CB_PARAM* qParam = (SSP_CB_PARAM*)param; @@ -313,6 +318,7 @@ void veriry_stmt(TAOS* taos) { taos_stmt2_free_fields(stmt, fields); */ // if (taos_stmt_execute(stmt) != 0) { + (void)sem_init(&sem, 0, 0); start = clock(); // if (taos_stmt2_exec(stmt, NULL, stmtAsyncQueryCb, NULL) != 0) { if (taos_stmt2_exec(stmt, NULL) != 0) { @@ -323,6 +329,9 @@ void veriry_stmt(TAOS* taos) { end = clock(); printf("exec time:%f\n", (double)(end - start) / CLOCKS_PER_SEC); + sem_wait(&sem); + (void)sem_destroy(&sem); + taos_stmt2_close(stmt); free(t8_len); From bfde9959130c951c34d35505efb2e5ae5688335d Mon Sep 17 00:00:00 2001 From: Minglei Jin Date: Thu, 29 Aug 2024 09:12:48 +0800 Subject: [PATCH 17/23] stmt2/none: 2 in null array for none --- tests/script/api/stmt2-nohole.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/script/api/stmt2-nohole.c b/tests/script/api/stmt2-nohole.c index 1ddb4a66b2..2e78f7bc60 100644 --- a/tests/script/api/stmt2-nohole.c +++ b/tests/script/api/stmt2-nohole.c @@ -125,7 +125,7 @@ void veriry_stmt(TAOS* taos) { // TAOS_MULTI_BIND params[10]; TAOS_STMT2_BIND params[10]; char is_null2[10] = {0}; - char is_null[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 1}; + char is_null[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 2}; params[0].buffer_type = TSDB_DATA_TYPE_TIMESTAMP; // params[0].buffer_length = sizeof(v.ts[0]); From fea7265c0a6c40939c7955d003a30da9f80f6736 Mon Sep 17 00:00:00 2001 From: Minglei Jin Date: Thu, 29 Aug 2024 17:40:02 +0800 Subject: [PATCH 18/23] multiple binding for example --- tests/script/api/stmt2-example.c | 2 +- tests/script/api/stmt2-nohole.c | 9 ++++++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/tests/script/api/stmt2-example.c b/tests/script/api/stmt2-example.c index c8d48927f8..803e54c156 100644 --- a/tests/script/api/stmt2-example.c +++ b/tests/script/api/stmt2-example.c @@ -29,7 +29,7 @@ void do_stmt(TAOS* taos) { char is_null2[2] = {0, 2}; // TAOS_STMT2_OPTION option = {0}; // TAOS_STMT2_OPTION option = {0, true, true, stmtAsyncQueryCb, NULL}; - TAOS_STMT2_OPTION option = {0, true, true, NULL, NULL}; + TAOS_STMT2_OPTION option = {0, true, false, NULL, NULL}; char* tbs[2] = {"tb", "tb2"}; int t1_val[2] = {0, 1}; diff --git a/tests/script/api/stmt2-nohole.c b/tests/script/api/stmt2-nohole.c index 2e78f7bc60..b29dd3e826 100644 --- a/tests/script/api/stmt2-nohole.c +++ b/tests/script/api/stmt2-nohole.c @@ -116,7 +116,7 @@ void veriry_stmt(TAOS* taos) { #include "time.h" clock_t start, end; - TAOS_STMT2_OPTION option = {0, true, true, stmtAsyncQueryCb, NULL}; + TAOS_STMT2_OPTION option = {0, true, false, stmtAsyncQueryCb, NULL}; start = clock(); TAOS_STMT2* stmt = taos_stmt2_init(taos, &option); @@ -270,10 +270,11 @@ void veriry_stmt(TAOS* taos) { blob_buffer += blob_len[i]; blob2_buffer += blob_len2[i]; } - + int run_time = 0; char* tbname = "m2"; TAOS_STMT2_BIND* bind_cols[1] = {¶ms[0]}; TAOS_STMT2_BINDV bindv = {1, &tbname, NULL, &bind_cols[0]}; +_bind_again: start = clock(); // taos_stmt2_bind_param(stmt, "m1", NULL, params, -1); taos_stmt2_bind_param(stmt, &bindv, -1); @@ -331,7 +332,9 @@ void veriry_stmt(TAOS* taos) { sem_wait(&sem); (void)sem_destroy(&sem); - + if (++run_time < 2) { + goto _bind_again; + } taos_stmt2_close(stmt); free(t8_len); From 2aa14bb8c3586991eba4e8b6d546749af9e13afc Mon Sep 17 00:00:00 2001 From: Minglei Jin Date: Wed, 4 Sep 2024 15:55:15 +0800 Subject: [PATCH 19/23] stmt2/async: move post query actions into cb function --- source/client/src/clientStmt2.c | 42 ++++++++++++++++++++++----------- 1 file changed, 28 insertions(+), 14 deletions(-) diff --git a/source/client/src/clientStmt2.c b/source/client/src/clientStmt2.c index b3571078cd..e8cf9a3bde 100644 --- a/source/client/src/clientStmt2.c +++ b/source/client/src/clientStmt2.c @@ -349,8 +349,10 @@ static int32_t stmtCleanExecInfo(STscStmt2* pStmt, bool keepTable, bool deepClea } } else { if (STMT_TYPE_QUERY != pStmt->sql.type || deepClean) { + // if (!pStmt->options.asyncExecFn) { taos_free_result(pStmt->exec.pRequest); pStmt->exec.pRequest = NULL; + //} } size_t keyLen = 0; @@ -814,7 +816,9 @@ TAOS_STMT2* stmtInit2(STscObj* taos, TAOS_STMT2_OPTION* pOptions) { } pStmt->sql.siInfo.tableColsReady = true; - (void)tsem_init(&pStmt->asyncQuerySem, 0, 1); + if (pStmt->options.asyncExecFn) { + (void)tsem_init(&pStmt->asyncQuerySem, 0, 1); + } STMT_LOG_SEQ(STMT_INIT); @@ -1275,6 +1279,10 @@ int stmtBindBatch2(TAOS_STMT2* stmt, TAOS_STMT2_BIND* bind, int32_t colIdx) { STMT_ERR_RET(stmtParseSql(pStmt)); } + if (pStmt->options.asyncExecFn) { + (void)tsem_wait(&pStmt->asyncQuerySem); + } + if (STMT_TYPE_QUERY == pStmt->sql.type) { STMT_ERR_RET(qStmtBindParams2(pStmt->sql.pQuery, bind, colIdx)); @@ -1584,6 +1592,12 @@ static void asyncQueryCb(void* userdata, TAOS_RES* res, int code) { fp(pStmt->options.userdata, res, code); + while (0 == atomic_load_8((int8_t*)&pStmt->sql.siInfo.tableColsReady)) { + taosUsleep(1); + } + (void)stmtCleanExecInfo(pStmt, (code ? false : true), false); + ++pStmt->sql.runTimes; + (void)tsem_post(&pStmt->asyncQuerySem); } @@ -1600,8 +1614,6 @@ int stmtExec2(TAOS_STMT2* stmt, int* affected_rows) { STMT_ERR_RET(stmtSwitchStatus(pStmt, STMT_EXECUTE)); - (void)tsem_wait(&pStmt->asyncQuerySem); - if (STMT_TYPE_QUERY != pStmt->sql.type) { if (pStmt->sql.stbInterlaceMode) { int64_t startTs = taosGetTimestampUs(); @@ -1647,6 +1659,15 @@ int stmtExec2(TAOS_STMT2* stmt, int* affected_rows) { *affected_rows = pStmt->exec.affectedRows; } pStmt->affectedRows += pStmt->exec.affectedRows; + + while (0 == atomic_load_8((int8_t*)&pStmt->sql.siInfo.tableColsReady)) { + taosUsleep(1); + } + + STMT_ERR_RET(stmtCleanExecInfo(pStmt, (code ? false : true), false)); + + ++pStmt->sql.runTimes; + } else { SSqlCallbackWrapper* pWrapper = taosMemoryCalloc(1, sizeof(SSqlCallbackWrapper)); if (pWrapper == NULL) { @@ -1666,16 +1687,7 @@ int stmtExec2(TAOS_STMT2* stmt, int* affected_rows) { } _return: - while (0 == atomic_load_8((int8_t*)&pStmt->sql.siInfo.tableColsReady)) { - taosUsleep(1); - } - - STMT_ERR_RET(stmtCleanExecInfo(pStmt, (code ? false : true), false)); - - ++pStmt->sql.runTimes; - - int64_t startUs2 = taosGetTimestampUs(); - pStmt->stat.execUseUs += startUs2 - startUs; + pStmt->stat.execUseUs += taosGetTimestampUs() - startUs; STMT_RET(code); } @@ -1705,7 +1717,9 @@ int stmtClose2(TAOS_STMT2* stmt) { STMT_ERR_RET(stmtCleanSQLInfo(pStmt)); - (void)tsem_destroy(&pStmt->asyncQuerySem); + if (pStmt->options.asyncExecFn) { + (void)tsem_destroy(&pStmt->asyncQuerySem); + } taosMemoryFree(stmt); return TSDB_CODE_SUCCESS; From 31b635315997a959084b22578ca71bc67622b3bd Mon Sep 17 00:00:00 2001 From: Minglei Jin Date: Wed, 4 Sep 2024 16:11:46 +0800 Subject: [PATCH 20/23] stmt2/async: wait before pRequest checking --- source/client/src/clientStmt2.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/source/client/src/clientStmt2.c b/source/client/src/clientStmt2.c index e8cf9a3bde..e7e08c0982 100644 --- a/source/client/src/clientStmt2.c +++ b/source/client/src/clientStmt2.c @@ -1263,6 +1263,10 @@ int stmtBindBatch2(TAOS_STMT2* stmt, TAOS_STMT2_BIND* bind, int32_t colIdx) { STMT_ERR_RET(stmtSwitchStatus(pStmt, STMT_BIND)); + if (pStmt->options.asyncExecFn) { + (void)tsem_wait(&pStmt->asyncQuerySem); + } + if (pStmt->bInfo.needParse && pStmt->sql.runTimes && pStmt->sql.type > 0 && STMT_TYPE_MULTI_INSERT != pStmt->sql.type) { pStmt->bInfo.needParse = false; @@ -1279,10 +1283,6 @@ int stmtBindBatch2(TAOS_STMT2* stmt, TAOS_STMT2_BIND* bind, int32_t colIdx) { STMT_ERR_RET(stmtParseSql(pStmt)); } - if (pStmt->options.asyncExecFn) { - (void)tsem_wait(&pStmt->asyncQuerySem); - } - if (STMT_TYPE_QUERY == pStmt->sql.type) { STMT_ERR_RET(qStmtBindParams2(pStmt->sql.pQuery, bind, colIdx)); From 352cf8468b24e174f638b2bc40a3cc60e320d33f Mon Sep 17 00:00:00 2001 From: Minglei Jin Date: Fri, 6 Sep 2024 14:50:35 +0800 Subject: [PATCH 21/23] stmt2/test: new stmt2 api test program --- tests/script/api/makefile | 4 +- tests/script/api/stmt2-test.c | 3201 +++++++++++++++++++++++++++++++++ 2 files changed, 3204 insertions(+), 1 deletion(-) create mode 100644 tests/script/api/stmt2-test.c diff --git a/tests/script/api/makefile b/tests/script/api/makefile index 4457445cdf..d8a4e19218 100644 --- a/tests/script/api/makefile +++ b/tests/script/api/makefile @@ -7,12 +7,13 @@ LFLAGS = '-Wl,-rpath,/usr/local/taos/driver/' -ltaos -lpthread -lm -lrt CFLAGS = -O0 -g -Wno-deprecated -fPIC -Wno-unused-result -Wconversion \ -Wno-char-subscripts -D_REENTRANT -Wno-format -D_REENTRANT -DLINUX \ -Wno-unused-function -D_M_X64 -I/usr/local/taos/include -std=gnu99 -Wno-sign-conversion -CFLAGS += -fsanitize=address -fsanitize=undefined -fsanitize-recover=all -fsanitize=float-divide-by-zero -fsanitize=float-cast-overflow -fno-sanitize=shift-base -fno-sanitize=alignment +#CFLAGS += -fsanitize=address -fsanitize=undefined -fsanitize-recover=all -fsanitize=float-divide-by-zero -fsanitize=float-cast-overflow -fno-sanitize=shift-base -fno-sanitize=alignment all: $(TARGET) exe: gcc $(CFLAGS) ./batchprepare.c -o $(ROOT)batchprepare $(LFLAGS) + gcc $(CFLAGS) ./stmt2-test.c -o $(ROOT)stmt2-test $(LFLAGS) gcc $(CFLAGS) ./stopquery.c -o $(ROOT)stopquery $(LFLAGS) gcc $(CFLAGS) ./dbTableRoute.c -o $(ROOT)dbTableRoute $(LFLAGS) gcc $(CFLAGS) ./insertSameTs.c -o $(ROOT)insertSameTs $(LFLAGS) @@ -29,6 +30,7 @@ exe: clean: rm $(ROOT)batchprepare + rm $(ROOT)stmt2-test rm $(ROOT)stopquery rm $(ROOT)dbTableRoute rm $(ROOT)insertSameTs diff --git a/tests/script/api/stmt2-test.c b/tests/script/api/stmt2-test.c new file mode 100644 index 0000000000..2bbceec92e --- /dev/null +++ b/tests/script/api/stmt2-test.c @@ -0,0 +1,3201 @@ +// TAOS standard API example. The same syntax as MySQL, but only a subet +// to compile: gcc -o prepare prepare.c -ltaos + +#include +#include +#include +#include +#include +#include +#include "../../../include/client/taos.h" + +#define FUNCTION_TEST_IDX 1 +#define TIME_PRECISION_MILLI 0 +#define TIME_PRECISION_MICRO 1 +#define TIME_PRECISION_NANO 2 + +int32_t shortColList[] = {TSDB_DATA_TYPE_TIMESTAMP, TSDB_DATA_TYPE_INT}; +int32_t fullColList[] = {TSDB_DATA_TYPE_TIMESTAMP, TSDB_DATA_TYPE_BOOL, TSDB_DATA_TYPE_TINYINT, + TSDB_DATA_TYPE_UTINYINT, TSDB_DATA_TYPE_SMALLINT, TSDB_DATA_TYPE_USMALLINT, + TSDB_DATA_TYPE_INT, TSDB_DATA_TYPE_UINT, TSDB_DATA_TYPE_BIGINT, + TSDB_DATA_TYPE_UBIGINT, TSDB_DATA_TYPE_FLOAT, TSDB_DATA_TYPE_DOUBLE, + TSDB_DATA_TYPE_BINARY, TSDB_DATA_TYPE_NCHAR}; +int32_t bindColTypeList[] = {TSDB_DATA_TYPE_TIMESTAMP, TSDB_DATA_TYPE_NCHAR}; +int32_t optrIdxList[] = {5, 11}; + +typedef struct { + char *oper; + int32_t paramNum; + bool enclose; +} OperInfo; + +typedef struct { + char *funcName; + int32_t paramNum; +} FuncInfo; + +typedef enum { + BP_BIND_TAG = 1, + BP_BIND_COL, +} BP_BIND_TYPE; + +#define BP_BIND_TYPE_STR(t) (((t) == BP_BIND_COL) ? "column" : "tag") + +OperInfo operInfo[] = { + {">", 2, false}, {">=", 2, false}, {"<", 2, false}, {"<=", 2, false}, + {"=", 2, false}, {"<>", 2, false}, {"in", 2, true}, {"not in", 2, true}, + + {"like", 2, false}, {"not like", 2, false}, {"match", 2, false}, {"nmatch", 2, false}, +}; + +int32_t operatorList[] = {0, 1, 2, 3, 4, 5, 6, 7}; +int32_t varoperatorList[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}; + +FuncInfo funcInfo[] = { + {"count", 1}, + {"sum", 1}, + {"min", 1}, +}; + +#define BP_STARTUP_TS 1591060628000 + +char *bpStbPrefix = "st"; +char *bpTbPrefix = "t"; +int32_t bpDefaultStbId = 1; +int64_t bpTs; + +// char *operatorList[] = {">", ">=", "<", "<=", "=", "<>", "in", "not in"}; +// char *varoperatorList[] = {">", ">=", "<", "<=", "=", "<>", "in", "not in", "like", "not like", "match", "nmatch"}; + +#define tListLen(x) (sizeof(x) / sizeof((x)[0])) +#define IS_SIGNED_NUMERIC_TYPE(_t) ((_t) >= TSDB_DATA_TYPE_TINYINT && (_t) <= TSDB_DATA_TYPE_BIGINT) +#define IS_UNSIGNED_NUMERIC_TYPE(_t) ((_t) >= TSDB_DATA_TYPE_UTINYINT && (_t) <= TSDB_DATA_TYPE_UBIGINT) +#define IS_FLOAT_TYPE(_t) ((_t) == TSDB_DATA_TYPE_FLOAT || (_t) == TSDB_DATA_TYPE_DOUBLE) +#define IS_NUMERIC_TYPE(_t) ((IS_SIGNED_NUMERIC_TYPE(_t)) || (IS_UNSIGNED_NUMERIC_TYPE(_t)) || (IS_FLOAT_TYPE(_t))) + +typedef struct { + bool singleTbInsert; + int32_t singleTbIdx; + + int64_t *tsData; + bool *boolData; + int8_t *tinyData; + uint8_t *utinyData; + int16_t *smallData; + uint16_t *usmallData; + int32_t *intData; + uint32_t *uintData; + int64_t *bigData; + uint64_t *ubigData; + float *floatData; + double *doubleData; + char *binaryData; + char *isNull; + int32_t *binaryLen; + TAOS_STMT2_BIND *pBind; + TAOS_STMT2_BIND *pTags; + char *sql; + int32_t *colTypes; + int32_t colNum; +} BindData; + +int32_t gVarCharSize = 10; +int32_t gVarCharLen = 5; + +int32_t gExecLoopTimes = 1; // no change +int32_t gFullColNum = tListLen(fullColList); + +int insertMBSETest1(TAOS_STMT2 *stmt, TAOS *taos); +int insertMBSETest2(TAOS_STMT2 *stmt, TAOS *taos); +int insertMBMETest1(TAOS_STMT2 *stmt, TAOS *taos); +int insertMBMETest2(TAOS_STMT2 *stmt, TAOS *taos); +int insertMBMETest3(TAOS_STMT2 *stmt, TAOS *taos); +int insertMBMETest4(TAOS_STMT2 *stmt, TAOS *taos); +int insertMPMETest1(TAOS_STMT2 *stmt, TAOS *taos); +int insertAUTOTest1(TAOS_STMT2 *stmt, TAOS *taos); +int insertAUTOTest2(TAOS_STMT2 *stmt, TAOS *taos); +int insertAUTOTest3(TAOS_STMT2 *stmt, TAOS *taos); +int queryColumnTest(TAOS_STMT2 *stmt, TAOS *taos); +int queryMiscTest(TAOS_STMT2 *stmt, TAOS *taos); +int insertNonExistsTb(TAOS_STMT2 *stmt, TAOS *taos); +int insertVarLenErr(TAOS_STMT2 *stmt, TAOS *taos); +int insertStbTest(TAOS_STMT2 *stmt, TAOS *taos); + +enum { + TTYPE_INSERT = 1, + TTYPE_INSERT_NG, + TTYPE_QUERY, +}; + +typedef struct { + char caseDesc[128]; + int32_t colNum; + int32_t *colList; // full table column list + int32_t testType; + int32_t autoCreateTbl; + bool duplicateValue; + bool fullCol; + int32_t (*runFn)(TAOS_STMT2 *, TAOS *); + int32_t tblNum; + int32_t rowNum; + int32_t bindRowNum; + int32_t bindColNum; // equal colNum in full column case + int32_t bindTagNum; // equal colNum in full column case + int32_t bindNullNum; + int32_t runTimes; + int32_t preCaseIdx; + bool stbInsert; +} CaseCfg; + +CaseCfg gCase[] = { + {"insert:MBSE0-FULL", tListLen(shortColList), shortColList, TTYPE_INSERT, 0, false, true, insertMBSETest1, 1, 10, + 10, 0, 0, 0, 1, -1, false}, + {"insert:MBSE0-FULL", tListLen(shortColList), shortColList, TTYPE_INSERT, 0, false, true, insertMBSETest1, 10, 100, + 10, 0, 0, 0, 1, -1, false}, + + {"insert:MBSE1-FULL", tListLen(fullColList), fullColList, TTYPE_INSERT, 0, false, true, insertMBSETest1, 10, 10, 2, + 0, 0, 0, 1, -1, false}, + {"insert:MBSE1-C012", tListLen(fullColList), fullColList, TTYPE_INSERT, 0, false, false, insertMBSETest1, 10, 10, 2, + 12, 0, 0, 1, -1, false}, + {"insert:MBSE1-C002", tListLen(fullColList), fullColList, TTYPE_INSERT, 0, false, false, insertMBSETest1, 10, 10, 2, + 2, 0, 0, 1, -1, false}, + + {"insert:MBSE2-FULL", tListLen(fullColList), fullColList, TTYPE_INSERT, 0, false, true, insertMBSETest2, 10, 10, 2, + 0, 0, 0, 1, -1, false}, + {"insert:MBSE2-C012", tListLen(fullColList), fullColList, TTYPE_INSERT, 0, false, false, insertMBSETest2, 10, 10, 2, + 12, 0, 0, 1, -1, false}, + {"insert:MBSE2-C002", tListLen(fullColList), fullColList, TTYPE_INSERT, 0, false, false, insertMBSETest2, 10, 10, 2, + 2, 0, 0, 1, -1, false}, + + {"insert:MBME1-FULL", tListLen(fullColList), fullColList, TTYPE_INSERT, 0, false, true, insertMBMETest1, 10, 10, 2, + 0, 0, 0, 1, -1, false}, + {"insert:MBME1-C012", tListLen(fullColList), fullColList, TTYPE_INSERT, 0, false, false, insertMBMETest1, 10, 10, 2, + 12, 0, 0, 1, -1, false}, + {"insert:MBME1-C002", tListLen(fullColList), fullColList, TTYPE_INSERT, 0, false, false, insertMBMETest1, 10, 10, 2, + 2, 0, 0, 1, -1, false}, + + // 11 + {"insert:MBME2-FULL", tListLen(fullColList), fullColList, TTYPE_INSERT, 0, false, true, insertMBMETest2, 10, 10, 2, + 0, 0, 0, 1, -1, false}, + {"insert:MBME2-C012", tListLen(fullColList), fullColList, TTYPE_INSERT, 0, false, false, insertMBMETest2, 10, 10, 2, + 12, 0, 0, 1, -1, false}, + {"insert:MBME2-C002", tListLen(fullColList), fullColList, TTYPE_INSERT, 0, false, false, insertMBMETest2, 10, 10, 2, + 2, 0, 0, 1, -1, false}, + + {"insert:MBME3-FULL", tListLen(fullColList), fullColList, TTYPE_INSERT, 0, false, true, insertMBMETest3, 10, 10, 2, + 0, 0, 0, 1, -1, false}, + {"insert:MBME3-C012", tListLen(fullColList), fullColList, TTYPE_INSERT, 0, false, false, insertMBMETest3, 10, 10, 2, + 12, 0, 0, 1, -1, false}, + {"insert:MBME3-C002", tListLen(fullColList), fullColList, TTYPE_INSERT, 0, false, false, insertMBMETest3, 10, 10, 2, + 2, 0, 0, 1, -1, false}, + + {"insert:MBME4-FULL", tListLen(fullColList), fullColList, TTYPE_INSERT, 0, false, true, insertMBMETest4, 10, 10, 2, + 0, 0, 0, 1, -1, false}, + {"insert:MBME4-C012", tListLen(fullColList), fullColList, TTYPE_INSERT, 0, false, false, insertMBMETest4, 10, 10, 2, + 12, 0, 0, 1, -1, false}, + {"insert:MBME4-C002", tListLen(fullColList), fullColList, TTYPE_INSERT, 0, false, false, insertMBMETest4, 10, 10, 2, + 2, 0, 0, 1, -1, false}, + + {"insert:MPME1-FULL", tListLen(fullColList), fullColList, TTYPE_INSERT, 0, false, true, insertMPMETest1, 10, 10, 2, + 0, 0, 0, 1, -1, false}, + {"insert:MPME1-C012", tListLen(fullColList), fullColList, TTYPE_INSERT, 0, false, false, insertMPMETest1, 10, 10, 2, + 12, 0, 0, 1, -1, false}, + + {"insert:STBI-FULL", tListLen(fullColList), fullColList, TTYPE_INSERT, 0, false, true, insertStbTest, 10, 10, 2, 0, + 0, 0, 1, -1, true}, + + // 23 + {"insert:AUTO1-FULL", tListLen(fullColList), fullColList, TTYPE_INSERT, 1, false, true, insertAUTOTest1, 10, 10, 2, + 0, 0, 0, 1, -1, false}, + {"insert:AUTO2-TBEXISTS", tListLen(fullColList), fullColList, TTYPE_INSERT, 3, false, true, insertAUTOTest2, 10, 10, + 2, 0, 0, 0, 1, -1, false}, + // {"insert:AUTO3-NTB", tListLen(fullColList), fullColList, TTYPE_INSERT, 0, true, true, insertAUTOTest3, 10, 10, + // 2, 0, 0, 0, 1, -1, false}, + + {"query:SUBT-COLUMN", tListLen(fullColList), fullColList, TTYPE_QUERY, 0, false, false, queryColumnTest, 10, 10, 1, + 3, 0, 0, 1, 2, false}, + {"query:SUBT-MISC", tListLen(fullColList), fullColList, TTYPE_QUERY, 0, false, false, queryMiscTest, 10, 10, 1, 3, + 0, 0, 1, 2, false}, + + {"query:NG-TBNEXISTS", tListLen(fullColList), fullColList, TTYPE_INSERT_NG, 0, false, false, insertNonExistsTb, 10, + 10, 1, 3, 0, 0, 1, -1, false}, + {"query:NG-VARLENERR", tListLen(fullColList), fullColList, TTYPE_INSERT_NG, 0, false, true, insertVarLenErr, 10, 10, + 1, 3, 0, 0, 1, -1, false}, + + // {"query:SUBT-COLUMN", tListLen(fullColList), fullColList, TTYPE_QUERY, 0, false, false, queryColumnTest, 1, 10, + // 1, 1, 0, 0, 1, 2, false}, + // {"query:SUBT-MISC", tListLen(fullColList), fullColList, TTYPE_QUERY, 0, false, false, queryMiscTest, 2, 10, 1, + // 1, 0, 0, 1, 2, false}, + +}; + +CaseCfg *gCurCase = NULL; + +typedef struct { + char caseCatalog[255]; + int32_t bindNullNum; + bool checkParamNum; + bool printRes; + bool printCreateTblSql; + bool printQuerySql; + bool printStmtSql; + bool printVerbose; + bool autoCreateTbl; + bool numericParam; + uint8_t precision; + int32_t rowNum; // row num for one table + int32_t bindColNum; + int32_t bindTagNum; + int32_t bindRowNum; // row num for once bind + int32_t bindColTypeNum; + int32_t *bindColTypeList; + int32_t bindTagTypeNum; + int32_t *bindTagTypeList; + int32_t optrIdxListNum; + int32_t *optrIdxList; + int32_t funcIdxListNum; + int32_t *funcIdxList; + int32_t runTimes; + int32_t caseIdx; // static case idx + int32_t caseNum; // num in static case list + int32_t caseRunIdx; // runtime case idx + int32_t caseRunNum; // total run case num +} CaseCtrl; + +#if 0 +CaseCtrl gCaseCtrl = { + .precision = TIME_PRECISION_MILLI, + .bindNullNum = 0, + .printCreateTblSql = true, + .printQuerySql = true, + .printStmtSql = true, + .printVerbose = true, + .printRes = true, + .autoCreateTbl = false, + .numericParam = false, + .rowNum = 0, + .bindColNum = 0, + .bindTagNum = 0, + .bindRowNum = 0, + .bindColTypeNum = 0, + .bindColTypeList = NULL, + .bindTagTypeNum = 0, + .bindTagTypeList = NULL, + .optrIdxListNum = 0, + .optrIdxList = NULL, + .funcIdxListNum = 0, + .funcIdxList = NULL, + .checkParamNum = false, + .runTimes = 0, + .caseIdx = 20, + .caseNum = 1, + .caseRunIdx = -1, + .caseRunNum = -1, +}; +#endif + +#if 1 +CaseCtrl gCaseCtrl = { + // default + .precision = TIME_PRECISION_MILLI, + .bindNullNum = 0, + .printCreateTblSql = true, + .printQuerySql = true, + .printStmtSql = true, + .printVerbose = false, + .printRes = true, + .autoCreateTbl = false, + .numericParam = false, + .rowNum = 0, + .bindColNum = 0, + .bindTagNum = 0, + .bindRowNum = 0, + .bindColTypeNum = 0, + .bindColTypeList = NULL, + .bindTagTypeNum = 0, + .bindTagTypeList = NULL, + .optrIdxListNum = 0, + .optrIdxList = NULL, + .funcIdxListNum = 0, + .funcIdxList = NULL, + .checkParamNum = false, + .runTimes = 0, + .caseIdx = -1, + .caseNum = -1, + .caseRunIdx = -1, + .caseRunNum = -1, +}; +#endif + +#if 0 +CaseCtrl gCaseCtrl = { // query case with specified col&oper + .bindNullNum = 1, + .printCreateTblSql = false, + .printQuerySql = true, + .printStmtSql = true, + .rowNum = 0, + .bindColNum = 0, + .bindRowNum = 0, + .optrIdxListNum = tListLen(optrIdxList), + .optrIdxList = optrIdxList, + .bindColTypeNum = tListLen(bindColTypeList), + .bindColTypeList = bindColTypeList, + .checkParamNum = false, + .printRes = true, + .runTimes = 0, + .caseRunIdx = -1, + .caseIdx = 5, + .caseNum = 1, + .caseRunNum = 1, +}; +#endif + +#if 0 +CaseCtrl gCaseCtrl = { // query case with specified col&oper + .bindNullNum = 0, + .printCreateTblSql = true, + .printQuerySql = true, + .printStmtSql = true, + .autoCreateTbl = true, + .rowNum = 0, + .bindColNum = 0, + .bindTagNum = 0, + .bindRowNum = 0, + .bindColTypeNum = 0, + .bindColTypeList = bindColTypeList, + .optrIdxListNum = 0, + .optrIdxList = optrIdxList, + .checkParamNum = false, + .printRes = true, + .runTimes = 0, + .caseRunIdx = -1, + .optrIdxListNum = tListLen(optrIdxList), + .optrIdxList = optrIdxList, + .bindColTypeNum = tListLen(bindColTypeList), + .bindColTypeList = bindColTypeList, + .caseRunIdx = -1, + .caseIdx = 24, + .caseNum = 1, + .caseRunNum = 1, +}; +#endif + +int32_t taosGetTimeOfDay(struct timeval *tv) { return gettimeofday(tv, NULL); } +void *taosMemoryMalloc(uint64_t size) { return malloc(size); } + +void *taosMemoryCalloc(int32_t num, int32_t size) { return calloc(num, size); } +void taosMemoryFree(const void *ptr) { + if (ptr == NULL) return; + + return free((void *)ptr); +} + +static int64_t taosGetTimestampMs() { + struct timeval systemTime; + taosGetTimeOfDay(&systemTime); + return (int64_t)systemTime.tv_sec * 1000LL + (int64_t)systemTime.tv_usec / 1000; +} + +static int64_t taosGetTimestampUs() { + struct timeval systemTime; + taosGetTimeOfDay(&systemTime); + return (int64_t)systemTime.tv_sec * 1000000LL + (int64_t)systemTime.tv_usec; +} + +bool colExists(TAOS_STMT2_BIND *pBind, int32_t dataType) { + int32_t i = 0; + while (true) { + if (0 == pBind[i].buffer_type) { + return false; + } + + if (pBind[i].buffer_type == dataType) { + return true; + } + + ++i; + } +} + +void generateInsertSQL(BindData *data) { + int32_t len = 0; + if (gCurCase->tblNum > 1) { + if (data->singleTbInsert) { + len = sprintf(data->sql, "insert into %s%d ", bpTbPrefix, data->singleTbIdx); + } else { + len = sprintf(data->sql, "insert into ? "); + } + } else { + len = sprintf(data->sql, "insert into %s0 ", bpTbPrefix); + } + + if (gCurCase->bindTagNum > 0) { + len += sprintf(data->sql + len, "using %s%d ", bpStbPrefix, bpDefaultStbId); + + if (!gCurCase->fullCol) { + len += sprintf(data->sql + len, "("); + for (int c = 0; c < gCurCase->bindTagNum; ++c) { + if (c) { + len += sprintf(data->sql + len, ","); + } + switch (data->pTags[c].buffer_type) { + case TSDB_DATA_TYPE_BOOL: + len += sprintf(data->sql + len, "tbooldata"); + break; + case TSDB_DATA_TYPE_TINYINT: + len += sprintf(data->sql + len, "ttinydata"); + break; + case TSDB_DATA_TYPE_SMALLINT: + len += sprintf(data->sql + len, "tsmalldata"); + break; + case TSDB_DATA_TYPE_INT: + len += sprintf(data->sql + len, "tintdata"); + break; + case TSDB_DATA_TYPE_BIGINT: + len += sprintf(data->sql + len, "tbigdata"); + break; + case TSDB_DATA_TYPE_FLOAT: + len += sprintf(data->sql + len, "tfloatdata"); + break; + case TSDB_DATA_TYPE_DOUBLE: + len += sprintf(data->sql + len, "tdoubledata"); + break; + case TSDB_DATA_TYPE_VARCHAR: + len += sprintf(data->sql + len, "tbinarydata"); + break; + case TSDB_DATA_TYPE_TIMESTAMP: + len += sprintf(data->sql + len, "tts"); + break; + case TSDB_DATA_TYPE_NCHAR: + len += sprintf(data->sql + len, "tnchardata"); + break; + case TSDB_DATA_TYPE_UTINYINT: + len += sprintf(data->sql + len, "tutinydata"); + break; + case TSDB_DATA_TYPE_USMALLINT: + len += sprintf(data->sql + len, "tusmalldata"); + break; + case TSDB_DATA_TYPE_UINT: + len += sprintf(data->sql + len, "tuintdata"); + break; + case TSDB_DATA_TYPE_UBIGINT: + len += sprintf(data->sql + len, "tubigdata"); + break; + default: + printf("!!!invalid tag type:%d", data->pTags[c].buffer_type); + exit(1); + } + } + + len += sprintf(data->sql + len, ") "); + } + + len += sprintf(data->sql + len, "tags ("); + for (int c = 0; c < gCurCase->bindTagNum; ++c) { + if (c) { + len += sprintf(data->sql + len, ","); + } + len += sprintf(data->sql + len, "?"); + } + len += sprintf(data->sql + len, ") "); + } + + if (!gCurCase->fullCol) { + len += sprintf(data->sql + len, "("); + for (int c = 0; c < gCurCase->bindColNum; ++c) { + if (c) { + len += sprintf(data->sql + len, ","); + } + switch (data->pBind[c].buffer_type) { + case TSDB_DATA_TYPE_BOOL: + len += sprintf(data->sql + len, "booldata"); + break; + case TSDB_DATA_TYPE_TINYINT: + len += sprintf(data->sql + len, "tinydata"); + break; + case TSDB_DATA_TYPE_SMALLINT: + len += sprintf(data->sql + len, "smalldata"); + break; + case TSDB_DATA_TYPE_INT: + len += sprintf(data->sql + len, "intdata"); + break; + case TSDB_DATA_TYPE_BIGINT: + len += sprintf(data->sql + len, "bigdata"); + break; + case TSDB_DATA_TYPE_FLOAT: + len += sprintf(data->sql + len, "floatdata"); + break; + case TSDB_DATA_TYPE_DOUBLE: + len += sprintf(data->sql + len, "doubledata"); + break; + case TSDB_DATA_TYPE_VARCHAR: + len += sprintf(data->sql + len, "binarydata"); + break; + case TSDB_DATA_TYPE_TIMESTAMP: + len += sprintf(data->sql + len, "ts"); + break; + case TSDB_DATA_TYPE_NCHAR: + len += sprintf(data->sql + len, "nchardata"); + break; + case TSDB_DATA_TYPE_UTINYINT: + len += sprintf(data->sql + len, "utinydata"); + break; + case TSDB_DATA_TYPE_USMALLINT: + len += sprintf(data->sql + len, "usmalldata"); + break; + case TSDB_DATA_TYPE_UINT: + len += sprintf(data->sql + len, "uintdata"); + break; + case TSDB_DATA_TYPE_UBIGINT: + len += sprintf(data->sql + len, "ubigdata"); + break; + default: + printf("!!!invalid col type:%d", data->pBind[c].buffer_type); + exit(1); + } + } + + len += sprintf(data->sql + len, ") "); + } + + len += sprintf(data->sql + len, "values ("); + for (int c = 0; c < gCurCase->bindColNum; ++c) { + if (c) { + len += sprintf(data->sql + len, ","); + } + len += sprintf(data->sql + len, "?"); + } + len += sprintf(data->sql + len, ")"); + + if (gCaseCtrl.printStmtSql) { + printf("\tSQL: %s\n", data->sql); + } +} + +void bpAppendOperatorParam(BindData *data, int32_t *len, int32_t dataType, int32_t idx) { + OperInfo *pInfo = NULL; + + if (gCaseCtrl.optrIdxListNum > 0) { + pInfo = &operInfo[gCaseCtrl.optrIdxList[idx]]; + } else { + if (TSDB_DATA_TYPE_VARCHAR == dataType || TSDB_DATA_TYPE_NCHAR == dataType || TSDB_DATA_TYPE_GEOMETRY == dataType) { +#if 1 + pInfo = &operInfo[varoperatorList[rand() % tListLen(varoperatorList)]]; +#else + pInfo = &operInfo[11]; +#endif + } else { + pInfo = &operInfo[operatorList[rand() % tListLen(operatorList)]]; + } + } + + switch (pInfo->paramNum) { + case 2: + if (pInfo->enclose) { + *len += sprintf(data->sql + *len, " %s (?)", pInfo->oper); + } else { + *len += sprintf(data->sql + *len, " %s ?", pInfo->oper); + } + break; + default: + printf("!!!invalid operator paramNum:%d\n", pInfo->paramNum); + exit(1); + } +} + +void bpAppendFunctionParam(BindData *data, int32_t *len, int32_t dataType, int32_t idx) { + FuncInfo *pInfo = NULL; + + if (gCaseCtrl.funcIdxListNum > 0) { + pInfo = &funcInfo[gCaseCtrl.funcIdxList[idx]]; + } else { + pInfo = &funcInfo[rand() % tListLen(funcInfo)]; + } + + switch (pInfo->paramNum) { + case 1: + *len += sprintf(data->sql + *len, " %s(?)", pInfo->funcName); + break; + default: + printf("!!!invalid function paramNum:%d\n", pInfo->paramNum); + exit(1); + } +} + +int32_t bpAppendColumnName(BindData *data, int32_t type, int32_t len) { + switch (type) { + case TSDB_DATA_TYPE_BOOL: + return sprintf(data->sql + len, "booldata"); + break; + case TSDB_DATA_TYPE_TINYINT: + return sprintf(data->sql + len, "tinydata"); + break; + case TSDB_DATA_TYPE_SMALLINT: + return sprintf(data->sql + len, "smalldata"); + break; + case TSDB_DATA_TYPE_INT: + return sprintf(data->sql + len, "intdata"); + break; + case TSDB_DATA_TYPE_BIGINT: + return sprintf(data->sql + len, "bigdata"); + break; + case TSDB_DATA_TYPE_FLOAT: + return sprintf(data->sql + len, "floatdata"); + break; + case TSDB_DATA_TYPE_DOUBLE: + return sprintf(data->sql + len, "doubledata"); + break; + case TSDB_DATA_TYPE_VARCHAR: + return sprintf(data->sql + len, "binarydata"); + break; + case TSDB_DATA_TYPE_TIMESTAMP: + return sprintf(data->sql + len, "ts"); + break; + case TSDB_DATA_TYPE_NCHAR: + return sprintf(data->sql + len, "nchardata"); + break; + case TSDB_DATA_TYPE_UTINYINT: + return sprintf(data->sql + len, "utinydata"); + break; + case TSDB_DATA_TYPE_USMALLINT: + return sprintf(data->sql + len, "usmalldata"); + break; + case TSDB_DATA_TYPE_UINT: + return sprintf(data->sql + len, "uintdata"); + break; + case TSDB_DATA_TYPE_UBIGINT: + return sprintf(data->sql + len, "ubigdata"); + break; + default: + printf("!!!invalid col type:%d", type); + exit(1); + } + + return 0; +} + +void generateQueryCondSQL(BindData *data, int32_t tblIdx) { + int32_t len = sprintf(data->sql, "select * from %s%d where ", bpTbPrefix, tblIdx); + if (!gCurCase->fullCol) { + for (int c = 0; c < gCurCase->bindColNum; ++c) { + if (c) { + len += sprintf(data->sql + len, " and "); + } + len += bpAppendColumnName(data, data->pBind[c].buffer_type, len); + + bpAppendOperatorParam(data, &len, data->pBind[c].buffer_type, c); + } + } + + if (gCaseCtrl.printStmtSql) { + printf("\tSTMT SQL: %s\n", data->sql); + } +} + +void bpGenerateConstInOpSQL(BindData *data, int32_t tblIdx) { + int32_t len = 0; + len = sprintf(data->sql, "select "); + + for (int c = 0; c < gCurCase->bindColNum; ++c) { + if (c) { + len += sprintf(data->sql + len, ", "); + } + + len += bpAppendColumnName(data, data->pBind[c].buffer_type, len); + + bpAppendOperatorParam(data, &len, data->pBind[c].buffer_type, c); + } + + len += sprintf(data->sql + len, " from %s%d", bpTbPrefix, tblIdx); +} + +void bpGenerateConstInFuncSQL(BindData *data, int32_t tblIdx) { + int32_t len = 0; + len = sprintf(data->sql, "select "); + + for (int c = 0; c < gCurCase->bindColNum; ++c) { + if (c) { + len += sprintf(data->sql + len, ", "); + } + + bpAppendFunctionParam(data, &len, data->pBind[c].buffer_type, c); + } + + len += sprintf(data->sql + len, " from %s%d", bpTbPrefix, tblIdx); +} + +void generateQueryMiscSQL(BindData *data, int32_t tblIdx) { + if (tblIdx == FUNCTION_TEST_IDX && gCurCase->bindNullNum <= 0) { + bpGenerateConstInFuncSQL(data, tblIdx); + } else { + switch (tblIdx) { + case 0: + // TODO FILL TEST + default: + bpGenerateConstInOpSQL(data, tblIdx); + break; + } + } + + if (gCaseCtrl.printStmtSql) { + printf("\tSTMT SQL: %s\n", data->sql); + } +} + +void generateErrorSQL(BindData *data, int32_t tblIdx) { + int32_t len = 0; + data->sql = taosMemoryCalloc(1, 1024); + + switch (tblIdx) { + case 0: + len = sprintf(data->sql, "insert into %s%d values (?, 1)", bpTbPrefix, tblIdx); + break; + case 1: + len = sprintf(data->sql, "select * from ?"); + break; + case 2: + len = sprintf(data->sql, "select * from %s%d where ? = ?", bpTbPrefix, tblIdx); + break; + default: + len = sprintf(data->sql, "select count(*) from %s%d group by ?", bpTbPrefix, tblIdx); + break; + } + + if (gCaseCtrl.printStmtSql) { + printf("\tSTMT SQL: %s\n", data->sql); + } +} + +void generateColDataType(bool isQuery, BindData *data, int32_t bindIdx, int32_t colIdx, int32_t *dataType) { + if (bindIdx < gCurCase->bindColNum) { + if (gCaseCtrl.bindColTypeNum) { + *dataType = gCaseCtrl.bindColTypeList[colIdx]; + return; + } else if (gCurCase->fullCol) { + *dataType = gCurCase->colList[bindIdx]; + return; + } else if (gCaseCtrl.numericParam) { + while (true) { + *dataType = rand() % (TSDB_DATA_TYPE_MAX - 1) + 1; + if (!IS_NUMERIC_TYPE(*dataType)) { + continue; + } + + break; + } + return; + } else if (0 == colIdx && !isQuery) { + *dataType = TSDB_DATA_TYPE_TIMESTAMP; + return; + } else { + while (true) { +#if 1 + *dataType = rand() % (TSDB_DATA_TYPE_MAX - 1) + 1; +#else + if (!colExists(data->pBind, TSDB_DATA_TYPE_NCHAR)) { + *dataType = TSDB_DATA_TYPE_NCHAR; + } else { + *dataType = rand() % (TSDB_DATA_TYPE_MAX - 1) + 1; + } +#endif + if (*dataType == TSDB_DATA_TYPE_JSON || *dataType == TSDB_DATA_TYPE_DECIMAL || + *dataType == TSDB_DATA_TYPE_BLOB || *dataType == TSDB_DATA_TYPE_MEDIUMBLOB || + *dataType == TSDB_DATA_TYPE_VARBINARY || *dataType == TSDB_DATA_TYPE_GEOMETRY) { + continue; + } + + if (colExists(data->pBind, *dataType)) { + continue; + } + + break; + } + } + } else { + *dataType = data->pBind[bindIdx % gCurCase->bindColNum].buffer_type; + } +} + +void generateTagDataType(BindData *data, int32_t bindIdx, int32_t colIdx, int32_t *dataType) { + if (bindIdx < gCurCase->bindTagNum) { + if (gCaseCtrl.bindTagTypeNum) { + *dataType = gCaseCtrl.bindTagTypeList[colIdx]; + return; + } else if (gCurCase->fullCol) { + *dataType = gCurCase->colList[bindIdx]; + return; + } else { + while (true) { + *dataType = rand() % (TSDB_DATA_TYPE_MAX - 1) + 1; + if (*dataType == TSDB_DATA_TYPE_JSON || *dataType == TSDB_DATA_TYPE_DECIMAL || + *dataType == TSDB_DATA_TYPE_BLOB || *dataType == TSDB_DATA_TYPE_MEDIUMBLOB || + *dataType == TSDB_DATA_TYPE_VARBINARY || *dataType == TSDB_DATA_TYPE_GEOMETRY) { + continue; + } + + if (colExists(data->pTags, *dataType)) { + continue; + } + + break; + } + } + } else { + *dataType = data->pTags[bindIdx % gCurCase->bindTagNum].buffer_type; + } +} + +int32_t prepareColData(bool isQuery, BP_BIND_TYPE bType, BindData *data, int32_t bindIdx, int32_t rowIdx, + int32_t colIdx) { + int32_t dataType = TSDB_DATA_TYPE_TIMESTAMP; + TAOS_STMT2_BIND *pBase = NULL; + + if (bType == BP_BIND_TAG) { + pBase = data->pTags; + generateTagDataType(data, bindIdx, colIdx, &dataType); + } else { + pBase = data->pBind; + generateColDataType(isQuery, data, bindIdx, colIdx, &dataType); + } + + switch (dataType) { + case TSDB_DATA_TYPE_BOOL: + // pBase[bindIdx].buffer_length = sizeof(bool); + pBase[bindIdx].buffer = data->boolData + rowIdx; + pBase[bindIdx].length = NULL; + pBase[bindIdx].is_null = data->isNull ? (data->isNull + rowIdx) : NULL; + break; + case TSDB_DATA_TYPE_TINYINT: + // pBase[bindIdx].buffer_length = sizeof(int8_t); + pBase[bindIdx].buffer = data->tinyData + rowIdx; + pBase[bindIdx].length = NULL; + pBase[bindIdx].is_null = data->isNull ? (data->isNull + rowIdx) : NULL; + break; + case TSDB_DATA_TYPE_SMALLINT: + // pBase[bindIdx].buffer_length = sizeof(int16_t); + pBase[bindIdx].buffer = data->smallData + rowIdx; + pBase[bindIdx].length = NULL; + pBase[bindIdx].is_null = data->isNull ? (data->isNull + rowIdx) : NULL; + break; + case TSDB_DATA_TYPE_INT: + // pBase[bindIdx].buffer_length = sizeof(int32_t); + pBase[bindIdx].buffer = data->intData + rowIdx; + pBase[bindIdx].length = NULL; + pBase[bindIdx].is_null = data->isNull ? (data->isNull + rowIdx) : NULL; + break; + case TSDB_DATA_TYPE_BIGINT: + // pBase[bindIdx].buffer_length = sizeof(int64_t); + pBase[bindIdx].buffer = data->bigData + rowIdx; + pBase[bindIdx].length = NULL; + pBase[bindIdx].is_null = data->isNull ? (data->isNull + rowIdx) : NULL; + break; + case TSDB_DATA_TYPE_FLOAT: + // pBase[bindIdx].buffer_length = sizeof(float); + pBase[bindIdx].buffer = data->floatData + rowIdx; + pBase[bindIdx].length = NULL; + pBase[bindIdx].is_null = data->isNull ? (data->isNull + rowIdx) : NULL; + break; + case TSDB_DATA_TYPE_DOUBLE: + // pBase[bindIdx].buffer_length = sizeof(double); + pBase[bindIdx].buffer = data->doubleData + rowIdx; + pBase[bindIdx].length = NULL; + pBase[bindIdx].is_null = data->isNull ? (data->isNull + rowIdx) : NULL; + break; + case TSDB_DATA_TYPE_VARCHAR: + case TSDB_DATA_TYPE_GEOMETRY: + // pBase[bindIdx].buffer_length = gVarCharSize; + // pBase[bindIdx].buffer = data->binaryData + rowIdx * gVarCharSize; + pBase[bindIdx].buffer = data->binaryData + rowIdx * gVarCharLen; + pBase[bindIdx].length = data->binaryLen; + pBase[bindIdx].is_null = data->isNull ? (data->isNull + rowIdx) : NULL; + break; + case TSDB_DATA_TYPE_TIMESTAMP: + // pBase[bindIdx].buffer_length = sizeof(int64_t); + pBase[bindIdx].buffer = data->tsData + rowIdx; + pBase[bindIdx].length = NULL; + pBase[bindIdx].is_null = NULL; + break; + case TSDB_DATA_TYPE_NCHAR: + // pBase[bindIdx].buffer_length = gVarCharSize; + // pBase[bindIdx].buffer = data->binaryData + rowIdx * gVarCharSize; + pBase[bindIdx].buffer = data->binaryData + rowIdx * gVarCharLen; + pBase[bindIdx].length = data->binaryLen; + pBase[bindIdx].is_null = data->isNull ? (data->isNull + rowIdx) : NULL; + break; + case TSDB_DATA_TYPE_UTINYINT: + // pBase[bindIdx].buffer_length = sizeof(uint8_t); + pBase[bindIdx].buffer = data->utinyData + rowIdx; + pBase[bindIdx].length = NULL; + pBase[bindIdx].is_null = data->isNull ? (data->isNull + rowIdx) : NULL; + break; + case TSDB_DATA_TYPE_USMALLINT: + // pBase[bindIdx].buffer_length = sizeof(uint16_t); + pBase[bindIdx].buffer = data->usmallData + rowIdx; + pBase[bindIdx].length = NULL; + pBase[bindIdx].is_null = data->isNull ? (data->isNull + rowIdx) : NULL; + break; + case TSDB_DATA_TYPE_UINT: + // pBase[bindIdx].buffer_length = sizeof(uint32_t); + pBase[bindIdx].buffer = data->uintData + rowIdx; + pBase[bindIdx].length = NULL; + pBase[bindIdx].is_null = data->isNull ? (data->isNull + rowIdx) : NULL; + break; + case TSDB_DATA_TYPE_UBIGINT: + // pBase[bindIdx].buffer_length = sizeof(uint64_t); + pBase[bindIdx].buffer = data->ubigData + rowIdx; + pBase[bindIdx].length = NULL; + pBase[bindIdx].is_null = data->isNull ? (data->isNull + rowIdx) : NULL; + break; + default: + printf("!!!invalid col type:%d", dataType); + exit(1); + } + + pBase[bindIdx].buffer_type = dataType; + pBase[bindIdx].num = gCurCase->bindRowNum; + + if (bType == BP_BIND_TAG) { + pBase[bindIdx].num = 1; + } + + return 0; +} + +int32_t prepareInsertData(BindData *data) { + uint64_t allRowNum = gCurCase->rowNum * gCurCase->tblNum; + + data->colNum = 0; + data->colTypes = taosMemoryCalloc(30, sizeof(int32_t)); + data->sql = taosMemoryCalloc(1, 1024); + data->pBind = + taosMemoryCalloc((int32_t)(allRowNum / gCurCase->bindRowNum) * gCurCase->bindColNum, sizeof(TAOS_STMT2_BIND)); + data->pTags = taosMemoryCalloc(gCurCase->tblNum * gCurCase->bindTagNum, sizeof(TAOS_STMT2_BIND)); + data->tsData = taosMemoryMalloc(allRowNum * sizeof(int64_t)); + data->boolData = taosMemoryMalloc(allRowNum * sizeof(bool)); + data->tinyData = taosMemoryMalloc(allRowNum * sizeof(int8_t)); + data->utinyData = taosMemoryMalloc(allRowNum * sizeof(uint8_t)); + data->smallData = taosMemoryMalloc(allRowNum * sizeof(int16_t)); + data->usmallData = taosMemoryMalloc(allRowNum * sizeof(uint16_t)); + data->intData = taosMemoryMalloc(allRowNum * sizeof(int32_t)); + data->uintData = taosMemoryMalloc(allRowNum * sizeof(uint32_t)); + data->bigData = taosMemoryMalloc(allRowNum * sizeof(int64_t)); + data->ubigData = taosMemoryMalloc(allRowNum * sizeof(uint64_t)); + data->floatData = taosMemoryMalloc(allRowNum * sizeof(float)); + data->doubleData = taosMemoryMalloc(allRowNum * sizeof(double)); + data->binaryData = taosMemoryMalloc(allRowNum * gVarCharSize); + data->binaryLen = taosMemoryMalloc(allRowNum * sizeof(int32_t)); + if (gCurCase->bindNullNum) { + data->isNull = taosMemoryCalloc((int32_t)allRowNum, sizeof(char)); + } + + for (int32_t i = 0; i < allRowNum; ++i) { + if (gCurCase->duplicateValue) { + data->tsData[i] = bpTs; + if (i % 2 == 1) { + bpTs++; + } + } else { + data->tsData[i] = bpTs++; + } + data->boolData[i] = (bool)(i % 2); + data->tinyData[i] = (int8_t)i; + data->utinyData[i] = (uint8_t)(i + 1); + data->smallData[i] = (int16_t)i; + data->usmallData[i] = (uint16_t)(i + 1); + data->intData[i] = (int32_t)i; + data->uintData[i] = (uint32_t)(i + 1); + data->bigData[i] = (int64_t)i; + data->ubigData[i] = (uint64_t)(i + 1); + data->floatData[i] = (float)i; + data->doubleData[i] = (double)(i + 1); + // memset(data->binaryData + gVarCharSize * i, 'a' + i % 26, gVarCharLen); + memset(data->binaryData + gVarCharLen * i, 'a' + i % 26, gVarCharLen); + if (gCurCase->bindNullNum) { + data->isNull[i] = (char)(i % 2); + } + data->binaryLen[i] = gVarCharLen; + } + + for (int b = 0; b < (allRowNum / gCurCase->bindRowNum); b++) { + for (int c = 0; c < gCurCase->bindColNum; ++c) { + prepareColData(false, BP_BIND_COL, data, b * gCurCase->bindColNum + c, b * gCurCase->bindRowNum, c); + } + } + + for (int b = 0; b < gCurCase->tblNum; b++) { + for (int c = 0; c < gCurCase->bindTagNum; ++c) { + prepareColData(false, BP_BIND_TAG, data, b * gCurCase->bindTagNum + c, b, c); + } + } + + generateInsertSQL(data); + + return 0; +} + +int32_t prepareQueryCondData(BindData *data, int32_t tblIdx) { + uint64_t bindNum = gCurCase->rowNum / gCurCase->bindRowNum; + + data->colNum = 0; + data->colTypes = taosMemoryCalloc(30, sizeof(int32_t)); + data->sql = taosMemoryCalloc(1, 1024); + data->pBind = taosMemoryCalloc((int32_t)bindNum * gCurCase->bindColNum, sizeof(TAOS_STMT2_BIND)); + data->tsData = taosMemoryMalloc(bindNum * sizeof(int64_t)); + data->boolData = taosMemoryMalloc(bindNum * sizeof(bool)); + data->tinyData = taosMemoryMalloc(bindNum * sizeof(int8_t)); + data->utinyData = taosMemoryMalloc(bindNum * sizeof(uint8_t)); + data->smallData = taosMemoryMalloc(bindNum * sizeof(int16_t)); + data->usmallData = taosMemoryMalloc(bindNum * sizeof(uint16_t)); + data->intData = taosMemoryMalloc(bindNum * sizeof(int32_t)); + data->uintData = taosMemoryMalloc(bindNum * sizeof(uint32_t)); + data->bigData = taosMemoryMalloc(bindNum * sizeof(int64_t)); + data->ubigData = taosMemoryMalloc(bindNum * sizeof(uint64_t)); + data->floatData = taosMemoryMalloc(bindNum * sizeof(float)); + data->doubleData = taosMemoryMalloc(bindNum * sizeof(double)); + data->binaryData = taosMemoryMalloc(bindNum * gVarCharSize); + data->binaryLen = taosMemoryMalloc(bindNum * sizeof(int32_t)); + if (gCurCase->bindNullNum) { + data->isNull = taosMemoryCalloc((int32_t)bindNum, sizeof(char)); + } + + for (int32_t i = 0; i < bindNum; ++i) { + data->tsData[i] = bpTs + tblIdx * gCurCase->rowNum + rand() % gCurCase->rowNum; + data->boolData[i] = (bool)(tblIdx * gCurCase->rowNum + rand() % gCurCase->rowNum); + data->tinyData[i] = (int8_t)(tblIdx * gCurCase->rowNum + rand() % gCurCase->rowNum); + data->utinyData[i] = (uint8_t)(tblIdx * gCurCase->rowNum + rand() % gCurCase->rowNum); + data->smallData[i] = (int16_t)(tblIdx * gCurCase->rowNum + rand() % gCurCase->rowNum); + data->usmallData[i] = (uint16_t)(tblIdx * gCurCase->rowNum + rand() % gCurCase->rowNum); + data->intData[i] = (int32_t)(tblIdx * gCurCase->rowNum + rand() % gCurCase->rowNum); + data->uintData[i] = (uint32_t)(tblIdx * gCurCase->rowNum + rand() % gCurCase->rowNum); + data->bigData[i] = (int64_t)(tblIdx * gCurCase->rowNum + rand() % gCurCase->rowNum); + data->ubigData[i] = (uint64_t)(tblIdx * gCurCase->rowNum + rand() % gCurCase->rowNum); + data->floatData[i] = (float)(tblIdx * gCurCase->rowNum + rand() % gCurCase->rowNum); + data->doubleData[i] = (double)(tblIdx * gCurCase->rowNum + rand() % gCurCase->rowNum); + // memset(data->binaryData + gVarCharSize * i, 'a' + i % 26, gVarCharLen); + memset(data->binaryData + gVarCharLen * i, 'a' + i % 26, gVarCharLen); + if (gCurCase->bindNullNum) { + data->isNull[i] = (char)(i % 2); + } + data->binaryLen[i] = gVarCharLen; + } + + for (int b = 0; b < bindNum; b++) { + for (int c = 0; c < gCurCase->bindColNum; ++c) { + prepareColData(true, BP_BIND_COL, data, b * gCurCase->bindColNum + c, b * gCurCase->bindRowNum, c); + } + } + + generateQueryCondSQL(data, tblIdx); + + return 0; +} + +int32_t prepareQueryMiscData(BindData *data, int32_t tblIdx) { + uint64_t bindNum = gCurCase->rowNum / gCurCase->bindRowNum; + + data->colNum = 0; + data->colTypes = taosMemoryCalloc(30, sizeof(int32_t)); + data->sql = taosMemoryCalloc(1, 1024); + data->pBind = taosMemoryCalloc((int32_t)bindNum * gCurCase->bindColNum, sizeof(TAOS_STMT2_BIND)); + data->tsData = taosMemoryMalloc(bindNum * sizeof(int64_t)); + data->boolData = taosMemoryMalloc(bindNum * sizeof(bool)); + data->tinyData = taosMemoryMalloc(bindNum * sizeof(int8_t)); + data->utinyData = taosMemoryMalloc(bindNum * sizeof(uint8_t)); + data->smallData = taosMemoryMalloc(bindNum * sizeof(int16_t)); + data->usmallData = taosMemoryMalloc(bindNum * sizeof(uint16_t)); + data->intData = taosMemoryMalloc(bindNum * sizeof(int32_t)); + data->uintData = taosMemoryMalloc(bindNum * sizeof(uint32_t)); + data->bigData = taosMemoryMalloc(bindNum * sizeof(int64_t)); + data->ubigData = taosMemoryMalloc(bindNum * sizeof(uint64_t)); + data->floatData = taosMemoryMalloc(bindNum * sizeof(float)); + data->doubleData = taosMemoryMalloc(bindNum * sizeof(double)); + data->binaryData = taosMemoryMalloc(bindNum * gVarCharSize); + data->binaryLen = taosMemoryMalloc(bindNum * sizeof(int32_t)); + if (gCurCase->bindNullNum) { + data->isNull = taosMemoryCalloc((int32_t)bindNum, sizeof(char)); + } + + for (int32_t i = 0; i < bindNum; ++i) { + data->tsData[i] = bpTs + tblIdx * gCurCase->rowNum + rand() % gCurCase->rowNum; + data->boolData[i] = (bool)(tblIdx * gCurCase->rowNum + rand() % gCurCase->rowNum); + data->tinyData[i] = (int8_t)(tblIdx * gCurCase->rowNum + rand() % gCurCase->rowNum); + data->utinyData[i] = (uint8_t)(tblIdx * gCurCase->rowNum + rand() % gCurCase->rowNum); + data->smallData[i] = (int16_t)(tblIdx * gCurCase->rowNum + rand() % gCurCase->rowNum); + data->usmallData[i] = (uint16_t)(tblIdx * gCurCase->rowNum + rand() % gCurCase->rowNum); + data->intData[i] = (int32_t)(tblIdx * gCurCase->rowNum + rand() % gCurCase->rowNum); + data->uintData[i] = (uint32_t)(tblIdx * gCurCase->rowNum + rand() % gCurCase->rowNum); + data->bigData[i] = (int64_t)(tblIdx * gCurCase->rowNum + rand() % gCurCase->rowNum); + data->ubigData[i] = (uint64_t)(tblIdx * gCurCase->rowNum + rand() % gCurCase->rowNum); + data->floatData[i] = (float)(tblIdx * gCurCase->rowNum + rand() % gCurCase->rowNum); + data->doubleData[i] = (double)(tblIdx * gCurCase->rowNum + rand() % gCurCase->rowNum); + // memset(data->binaryData + gVarCharSize * i, 'a' + i % 26, gVarCharLen); + memset(data->binaryData + gVarCharLen * i, 'a' + i % 26, gVarCharLen); + if (gCurCase->bindNullNum) { + data->isNull[i] = (char)(i % 2); + } + data->binaryLen[i] = gVarCharLen; + } + + if (tblIdx == FUNCTION_TEST_IDX) { + gCaseCtrl.numericParam = true; + } else { + gCaseCtrl.numericParam = false; + } + + for (int b = 0; b < bindNum; b++) { + for (int c = 0; c < gCurCase->bindColNum; ++c) { + prepareColData(true, BP_BIND_COL, data, b * gCurCase->bindColNum + c, b * gCurCase->bindRowNum, c); + } + } + + gCaseCtrl.numericParam = false; + + generateQueryMiscSQL(data, tblIdx); + + return 0; +} + +void destroyData(BindData *data) { + taosMemoryFree(data->tsData); + taosMemoryFree(data->boolData); + taosMemoryFree(data->tinyData); + taosMemoryFree(data->utinyData); + taosMemoryFree(data->smallData); + taosMemoryFree(data->usmallData); + taosMemoryFree(data->intData); + taosMemoryFree(data->uintData); + taosMemoryFree(data->bigData); + taosMemoryFree(data->ubigData); + taosMemoryFree(data->floatData); + taosMemoryFree(data->doubleData); + taosMemoryFree(data->binaryData); + taosMemoryFree(data->binaryLen); + taosMemoryFree(data->isNull); + taosMemoryFree(data->pBind); + taosMemoryFree(data->pTags); + taosMemoryFree(data->colTypes); + taosMemoryFree(data->sql); +} + +void bpFetchRows(TAOS_RES *result, bool printr, int32_t *rows) { + TAOS_ROW row; + int num_fields = taos_num_fields(result); + TAOS_FIELD *fields = taos_fetch_fields(result); + char temp[256]; + + // fetch the records row by row + while ((row = taos_fetch_row(result))) { + (*rows)++; + if (printr) { + memset(temp, 0, sizeof(temp)); + taos_print_row(temp, row, fields, num_fields); + printf("\t[%s]\n", temp); + } + } +} + +void bpExecQuery(TAOS *taos, char *sql, bool printr, int32_t *rows) { + TAOS_RES *result = taos_query(taos, sql); + int code = taos_errno(result); + if (code != 0) { + printf("!!!failed to query table, reason:%s\n", taos_errstr(result)); + taos_free_result(result); + exit(1); + } + + bpFetchRows(result, printr, rows); + + taos_free_result(result); +} + +int32_t bpAppendValueString(char *buf, int type, void *value, int32_t valueLen, int32_t *len) { + switch (type) { + case TSDB_DATA_TYPE_NULL: + *len += sprintf(buf + *len, "null"); + break; + + case TSDB_DATA_TYPE_BOOL: + *len += sprintf(buf + *len, (*(bool *)value) ? "true" : "false"); + break; + + case TSDB_DATA_TYPE_TINYINT: + *len += sprintf(buf + *len, "%d", *(int8_t *)value); + break; + + case TSDB_DATA_TYPE_SMALLINT: + *len += sprintf(buf + *len, "%d", *(int16_t *)value); + break; + + case TSDB_DATA_TYPE_INT: + *len += sprintf(buf + *len, "%d", *(int32_t *)value); + break; + + case TSDB_DATA_TYPE_BIGINT: + case TSDB_DATA_TYPE_TIMESTAMP: + *len += sprintf(buf + *len, "%ld", *(int64_t *)value); + break; + + case TSDB_DATA_TYPE_FLOAT: + *len += sprintf(buf + *len, "%e", *(float *)value); + break; + + case TSDB_DATA_TYPE_DOUBLE: + *len += sprintf(buf + *len, "%e", *(double *)value); + break; + + case TSDB_DATA_TYPE_BINARY: + case TSDB_DATA_TYPE_VARBINARY: + case TSDB_DATA_TYPE_NCHAR: + case TSDB_DATA_TYPE_GEOMETRY: + buf[*len] = '\''; + ++(*len); + memcpy(buf + *len, value, valueLen); + *len += valueLen; + buf[*len] = '\''; + ++(*len); + break; + + case TSDB_DATA_TYPE_UTINYINT: + *len += sprintf(buf + *len, "%d", *(uint8_t *)value); + break; + + case TSDB_DATA_TYPE_USMALLINT: + *len += sprintf(buf + *len, "%d", *(uint16_t *)value); + break; + + case TSDB_DATA_TYPE_UINT: + *len += sprintf(buf + *len, "%u", *(uint32_t *)value); + break; + + case TSDB_DATA_TYPE_UBIGINT: + *len += sprintf(buf + *len, "%lu", *(uint64_t *)value); + break; + + default: + printf("!!!invalid data type:%d\n", type); + exit(1); + } +} + +static TAOS_STMT2 *st_stmt2_init(TAOS *taos, bool stb_insert) { + TAOS_STMT2_OPTION option = {0}; + if (stb_insert) { + option.singleStbInsert = true; + option.singleTableBindOnce = true; + } + + return taos_stmt2_init(taos, &option); +} + +static int st_stmt2_close(TAOS_STMT2 *stmt) { return taos_stmt2_close(stmt); } + +static char *st_stmt2_error(TAOS_STMT2 *stmt) { return taos_stmt2_error(stmt); } + +static int st_stmt2_prepare(TAOS_STMT2 *stmt, const char *sql, unsigned long length) { + return taos_stmt2_prepare(stmt, sql, length); +} + +static int st_stmt2_bind(TAOS_STMT2 *stmt, TAOS_STMT2_BINDV *bindv, int32_t col_idx) { + return taos_stmt2_bind_param(stmt, bindv, col_idx); +} + +static int st_stmt2_exec(TAOS_STMT2 *stmt, int *affected_rows) { return taos_stmt2_exec(stmt, affected_rows); } + +static int st_stmt2_is_insert(TAOS_STMT2 *stmt, int *insert) { return taos_stmt2_is_insert(stmt, insert); } + +static int st_stmt2_num_params(TAOS_STMT2 *stmt, int *count) { + return taos_stmt2_get_fields(stmt, TAOS_FIELD_QUERY, count, NULL); +} + +static int st_stmt2_get_tag_fields(TAOS_STMT2 *stmt, int *count, TAOS_FIELD_E **fields) { + return taos_stmt2_get_fields(stmt, TAOS_FIELD_TAG, count, fields); +} + +static int st_stmt2_get_col_fields(TAOS_STMT2 *stmt, int *count, TAOS_FIELD_E **fields) { + return taos_stmt2_get_fields(stmt, TAOS_FIELD_COL, count, fields); +} + +static int st_stmt2_get_param(TAOS_STMT2 *stmt, int idx, int *type, int *bytes) { + int32_t code = 0, nums = 0; + TAOS_FIELD_E *fields = NULL; + + code = taos_stmt2_get_fields(stmt, TAOS_FIELD_COL, &nums, &fields); + if (code) { + return code; + } + + if (idx > nums) { + taosMemoryFree(fields); + return -1; + } + + *type = fields[idx].type; + *bytes = fields[idx].bytes; + + taosMemoryFree(fields); + return 0; +} + +static int st_stmt2_set_tbname(TAOS_STMT2 *stmt, char *name) { + TAOS_STMT2_BINDV bindv = {0}; + bindv.count = 1; + bindv.tbnames = &name; + return taos_stmt2_bind_param(stmt, &bindv, -1); +} + +static int st_stmt2_set_tags(TAOS_STMT2 *stmt, TAOS_STMT2_BIND *tags) { + TAOS_STMT2_BINDV bindv = {0}; + bindv.count = 1; + bindv.tags = &tags; + return taos_stmt2_bind_param(stmt, &bindv, -1); +} + +static int st_stmt2_set_tbname_tags(TAOS_STMT2 *stmt, char *name, TAOS_STMT2_BIND *tags) { + TAOS_STMT2_BINDV bindv = {0}; + bindv.count = 1; + bindv.tbnames = &name; + bindv.tags = &tags; + return taos_stmt2_bind_param(stmt, &bindv, -1); +} + +static int st_stmt2_bind_param_batch(TAOS_STMT2 *stmt, TAOS_STMT2_BIND *bind) { + TAOS_STMT2_BINDV bindv = {0}; + bindv.count = 1; + bindv.bind_cols = &bind; + return taos_stmt2_bind_param(stmt, &bindv, -1); +} + +static int st_stmt2_bind_single_param_batch(TAOS_STMT2 *stmt, TAOS_STMT2_BIND *bind, int col_idx) { + TAOS_STMT2_BINDV bindv = {0}; + bindv.count = 1; + bindv.bind_cols = &bind; + return taos_stmt2_bind_param(stmt, &bindv, col_idx); +} + +static int st_stmt2_bind_param(TAOS_STMT2 *stmt, TAOS_STMT2_BIND *bind) { + TAOS_STMT2_BINDV bindv = {0}; + bindv.count = 1; + bindv.bind_cols = &bind; + return taos_stmt2_bind_param(stmt, &bindv, -1); +} + +static int st_stmt2_add_batch(TAOS_STMT2 *stmt) { return 0; } + +static TAOS_RES *st_stmt2_use_result(TAOS_STMT2 *stmt) { return taos_stmt2_result(stmt); } + +void bpCheckIsInsert(TAOS_STMT2 *stmt, int32_t insert) { + int32_t isInsert = 0; + if (st_stmt2_is_insert(stmt, &isInsert)) { + printf("!!!st_stmt2_is_insert error:%s\n", st_stmt2_error(stmt)); + exit(1); + } + + if (insert != isInsert) { + printf("!!!is insert failed\n"); + exit(1); + } +} + +void bpCheckParamNum(TAOS_STMT2 *stmt) { + int32_t num = 0; + if (st_stmt2_num_params(stmt, &num)) { + printf("!!!st_stmt2_num_params error:%s\n", st_stmt2_error(stmt)); + exit(1); + } + + if (gCurCase->bindColNum != num) { + printf("!!!is insert failed\n"); + exit(1); + } +} + +void bpCheckAffectedRows(TAOS_STMT2 *stmt, int32_t times) { + /* TODO: affected rows from exec + int32_t rows = taos_stmt_affected_rows(stmt); + int32_t insertNum = gCurCase->rowNum * gCurCase->tblNum * times; + if (gCurCase->duplicateValue) { + insertNum /= 2; + } + if (insertNum != rows) { + printf("!!!affected rows %d mis-match with insert num %d\n", rows, insertNum); + exit(1); + } + */ +} + +void bpCheckQueryResult(TAOS_STMT2 *stmt, TAOS *taos, char *stmtSql, TAOS_STMT2_BIND *bind) { + // query using sql + char sql[1024]; + int32_t len = 0; + char *p = stmtSql; + char *s = NULL; + int32_t sqlResNum = 0; + + for (int32_t i = 0; true; ++i, p = s + 1) { + s = strchr(p, '?'); + if (NULL == s) { + strcpy(&sql[len], p); + break; + } + + memcpy(&sql[len], p, (int64_t)s - (int64_t)p); + len += (int32_t)((int64_t)s - (int64_t)p); + + if (bind[i].is_null && bind[i].is_null[0]) { + bpAppendValueString(sql, TSDB_DATA_TYPE_NULL, NULL, 0, &len); + continue; + } + + bpAppendValueString(sql, bind[i].buffer_type, bind[i].buffer, (bind[i].length ? bind[i].length[0] : 0), &len); + } + + if (gCaseCtrl.printQuerySql) { + printf("\tQuery SQL: %s\n", sql); + } + + bpExecQuery(taos, sql, gCaseCtrl.printRes, &sqlResNum); + + // query using stmt + TAOS_RES *res = st_stmt2_use_result(stmt); + int32_t stmtResNum = 0; + bpFetchRows(res, gCaseCtrl.printRes, &stmtResNum); + + if (sqlResNum != stmtResNum) { + printf("!!!sql res num %d mis-match stmt res num %d\n", sqlResNum, stmtResNum); + exit(1); + } + + printf("***sql res num match stmt res num %d\n", stmtResNum); +} + +void bpCheckColTagFields(TAOS_STMT2 *stmt, int32_t fieldNum, TAOS_FIELD_E *pFields, int32_t expecteNum, + TAOS_STMT2_BIND *pBind, BP_BIND_TYPE type) { + int32_t code = 0; + + if (fieldNum != expecteNum) { + printf("!!!%s field num %d mis-match expect num %d\n", BP_BIND_TYPE_STR(type), fieldNum, expecteNum); + exit(1); + } + + if (type == BP_BIND_COL) { + if (pFields[0].precision != gCaseCtrl.precision) { + printf("!!!db precision %d mis-match expect %d\n", pFields[0].precision, gCaseCtrl.precision); + exit(1); + } + } + + for (int32_t i = 0; i < fieldNum; ++i) { + if (pFields[i].type != pBind[i].buffer_type) { + printf("!!!%s %dth field type %d mis-match expect type %d\n", BP_BIND_TYPE_STR(type), i, pFields[i].type, + pBind[i].buffer_type); + exit(1); + } + + if (pFields[i].type == TSDB_DATA_TYPE_BINARY || pFields[i].type == TSDB_DATA_TYPE_VARBINARY || + pFields[i].type == TSDB_DATA_TYPE_GEOMETRY) { + /* + if (pFields[i].bytes != (pBind[i].buffer_length + 2)) { + printf("!!!%s %dth field len %d mis-match expect len %d\n", BP_BIND_TYPE_STR(type), i, pFields[i].bytes, + (pBind[i].buffer_length + 2)); + exit(1); + } + */ + } else if (pFields[i].type == TSDB_DATA_TYPE_NCHAR) { + /* + if (pFields[i].bytes != (pBind[i].buffer_length * 4 + 2)) { + printf("!!!%s %dth field len %d mis-match expect len %d\n", BP_BIND_TYPE_STR(type), i, pFields[i].bytes, + (pBind[i].buffer_length + 2)); + exit(1); + } + */ + /*} else if (pFields[i].bytes != pBind[i].buffer_length) { + printf("!!!%s %dth field len %d mis-match expect len %d\n", BP_BIND_TYPE_STR(type), i, pFields[i].bytes, + pBind[i].buffer_length); + exit(1);*/ + } + } + + if (type == BP_BIND_COL) { + int fieldType = 0; + int fieldBytes = 0; + for (int32_t i = 0; i < fieldNum; ++i) { + code = st_stmt2_get_param(stmt, i, &fieldType, &fieldBytes); + if (code) { + printf("!!!st_stmt2_get_param error:%s\n", st_stmt2_error(stmt)); + exit(1); + } + + if (pFields[i].type != fieldType) { + printf("!!!%s %dth field type %d mis-match expect type %d\n", BP_BIND_TYPE_STR(type), i, fieldType, + pFields[i].type); + exit(1); + } + + if (pFields[i].bytes != fieldBytes) { + printf("!!!%s %dth field len %d mis-match expect len %d\n", BP_BIND_TYPE_STR(type), i, fieldBytes, + pFields[i].bytes); + exit(1); + } + } + } + + if (gCaseCtrl.printVerbose) { + printf("%s fields check passed\n", BP_BIND_TYPE_STR(type)); + } +} + +void bpCheckTagFields(TAOS_STMT2 *stmt, TAOS_STMT2_BIND *pBind) { + int32_t code = 0; + int fieldNum = 0; + TAOS_FIELD_E *pFields = NULL; + code = st_stmt2_get_tag_fields(stmt, &fieldNum, &pFields); + if (code != 0) { + printf("!!!st_stmt2_get_tag_fields error:%s\n", st_stmt2_error(stmt)); + exit(1); + } + + bpCheckColTagFields(stmt, fieldNum, pFields, gCurCase->bindTagNum, pBind, BP_BIND_TAG); + taosMemoryFree(pFields); +} + +void bpCheckColFields(TAOS_STMT2 *stmt, TAOS_STMT2_BIND *pBind) { + if (gCurCase->testType == TTYPE_QUERY) { + return; + } + + int32_t code = 0; + int fieldNum = 0; + TAOS_FIELD_E *pFields = NULL; + code = st_stmt2_get_col_fields(stmt, &fieldNum, &pFields); + if (code != 0) { + printf("!!!st_stmt2_get_col_fields error:%s\n", st_stmt2_error(stmt)); + exit(1); + } + + bpCheckColTagFields(stmt, fieldNum, pFields, gCurCase->bindColNum, pBind, BP_BIND_COL); + taosMemoryFree(pFields); +} + +void bpShowBindParam(TAOS_STMT2_BIND *bind, int32_t num) { + for (int32_t i = 0; i < num; ++i) { + TAOS_STMT2_BIND *b = &bind[i]; + printf("Bind %d: type[%d],buf[%p],len[%d],null[%d],num[%d]\n", i, b->buffer_type, b->buffer, + /*b->buffer_length,*/ b->length ? *b->length : 0, b->is_null ? *b->is_null : 0, b->num); + } +} + +int32_t bpBindParam(TAOS_STMT2 *stmt, TAOS_STMT2_BIND *bind, bool expectFail) { + static int32_t n = 0; + + if (!expectFail) { + bpCheckColFields(stmt, bind); + } + + if (gCurCase->bindRowNum > 1) { + if (0 == (n++ % 2) || gCurCase->stbInsert) { + if (st_stmt2_bind_param_batch(stmt, bind)) { + if (expectFail) return 0; + printf("!!!st_stmt2_bind_param_batch error:%s\n", st_stmt2_error(stmt)); + bpShowBindParam(bind, gCurCase->bindColNum); + exit(1); + } + } else { + for (int32_t i = 0; i < gCurCase->bindColNum; ++i) { + if (st_stmt2_bind_single_param_batch(stmt, bind + i, i)) { + if (expectFail) continue; + printf("!!!st_stmt2_bind_single_param_batch %d error:%s\n", i, st_stmt2_error(stmt)); + bpShowBindParam(bind, gCurCase->bindColNum); + exit(1); + } + } + } + } else { + if (0 == (n++ % 2)) { + if (st_stmt2_bind_param_batch(stmt, bind)) { + if (expectFail) return 0; + printf("!!!st_stmt2_bind_param_batch error:%s\n", st_stmt2_error(stmt)); + bpShowBindParam(bind, gCurCase->bindColNum); + exit(1); + } + } else { + if (st_stmt2_bind_param(stmt, bind)) { + if (expectFail) return 0; + printf("!!!st_stmt2_bind_param error:%s\n", st_stmt2_error(stmt)); + bpShowBindParam(bind, gCurCase->bindColNum); + exit(1); + } + } + } + + return 0; +} + +int32_t bpSetTableNameTags(BindData *data, int32_t tblIdx, char *tblName, TAOS_STMT2 *stmt) { + int32_t code = 0; + if (gCurCase->bindTagNum > 0) { + if ((rand() % 2) == 0) { + code = st_stmt2_set_tbname(stmt, tblName); + if (code != 0) { + printf("!!!st_stmt2_set_tbname error:%s\n", st_stmt2_error(stmt)); + exit(1); + } + + bpCheckTagFields(stmt, data->pTags + tblIdx * gCurCase->bindTagNum); + + return st_stmt2_set_tags(stmt, data->pTags + tblIdx * gCurCase->bindTagNum); + } else { + return st_stmt2_set_tbname_tags(stmt, tblName, data->pTags + tblIdx * gCurCase->bindTagNum); + } + } else { + return st_stmt2_set_tbname(stmt, tblName); + } +} + +/* prepare [settbname [bind add]] exec */ +int insertMBSETest1(TAOS_STMT2 *stmt, TAOS *taos) { + BindData data = {0}; + prepareInsertData(&data); + + int code = st_stmt2_prepare(stmt, data.sql, 0); + if (code != 0) { + printf("!!!failed to execute st_stmt2_prepare. error:%s\n", st_stmt2_error(stmt)); + exit(1); + } + + bpCheckIsInsert(stmt, 1); + + int32_t bindTimes = gCurCase->rowNum / gCurCase->bindRowNum; + for (int32_t t = 0; t < gCurCase->tblNum; ++t) { + if (gCurCase->tblNum > 1) { + char buf[32]; + sprintf(buf, "t%d", t); + code = bpSetTableNameTags(&data, t, buf, stmt); + if (code != 0) { + printf("!!!st_stmt2_set_tbname error:%s\n", st_stmt2_error(stmt)); + exit(1); + } + } + + if (gCaseCtrl.checkParamNum) { + bpCheckParamNum(stmt); + } + + for (int32_t b = 0; b < bindTimes; ++b) { + if (bpBindParam(stmt, data.pBind + t * bindTimes * gCurCase->bindColNum + b * gCurCase->bindColNum, false)) { + exit(1); + } + + if (st_stmt2_add_batch(stmt)) { + printf("!!!st_stmt2_add_batch error:%s\n", st_stmt2_error(stmt)); + exit(1); + } + } + } + + if (st_stmt2_exec(stmt, NULL) != 0) { + printf("!!!st_stmt2_exec error:%s\n", st_stmt2_error(stmt)); + exit(1); + } + + bpCheckIsInsert(stmt, 1); + bpCheckAffectedRows(stmt, 1); + + destroyData(&data); + + return 0; +} + +/* prepare [settbname bind add] exec */ +int insertMBSETest2(TAOS_STMT2 *stmt, TAOS *taos) { + BindData data = {0}; + prepareInsertData(&data); + + int code = st_stmt2_prepare(stmt, data.sql, 0); + if (code != 0) { + printf("!!!failed to execute st_stmt2_prepare. error:%s\n", st_stmt2_error(stmt)); + exit(1); + } + + bpCheckIsInsert(stmt, 1); + + int32_t bindTimes = gCurCase->rowNum / gCurCase->bindRowNum; + + for (int32_t b = 0; b < bindTimes; ++b) { + for (int32_t t = 0; t < gCurCase->tblNum; ++t) { + if (gCurCase->tblNum > 1) { + char buf[32]; + sprintf(buf, "t%d", t); + code = bpSetTableNameTags(&data, t, buf, stmt); + if (code != 0) { + printf("!!!st_stmt2_set_tbname error:%s\n", st_stmt2_error(stmt)); + exit(1); + } + } + + if (bpBindParam(stmt, data.pBind + t * bindTimes * gCurCase->bindColNum + b * gCurCase->bindColNum, false)) { + exit(1); + } + + if (gCaseCtrl.checkParamNum) { + bpCheckParamNum(stmt); + } + + if (st_stmt2_add_batch(stmt)) { + printf("!!!st_stmt2_add_batch error:%s\n", st_stmt2_error(stmt)); + exit(1); + } + } + } + + if (st_stmt2_exec(stmt, NULL) != 0) { + printf("!!!st_stmt2_exec error:%s\n", st_stmt2_error(stmt)); + exit(1); + } + + bpCheckIsInsert(stmt, 1); + bpCheckAffectedRows(stmt, 1); + + destroyData(&data); + + return 0; +} + +/* prepare [settbname [bind add] exec] */ +int insertMBMETest1(TAOS_STMT2 *stmt, TAOS *taos) { + BindData data = {0}; + prepareInsertData(&data); + + int code = st_stmt2_prepare(stmt, data.sql, 0); + if (code != 0) { + printf("!!!failed to execute st_stmt2_prepare. error:%s\n", st_stmt2_error(stmt)); + exit(1); + } + + bpCheckIsInsert(stmt, 1); + + int32_t bindTimes = gCurCase->rowNum / gCurCase->bindRowNum; + for (int32_t t = 0; t < gCurCase->tblNum; ++t) { + if (gCurCase->tblNum > 1) { + char buf[32]; + sprintf(buf, "t%d", t); + code = bpSetTableNameTags(&data, t, buf, stmt); + if (code != 0) { + printf("!!!st_stmt2_set_tbname error:%s\n", st_stmt2_error(stmt)); + exit(1); + } + } + + if (gCaseCtrl.checkParamNum) { + bpCheckParamNum(stmt); + } + + for (int32_t b = 0; b < bindTimes; ++b) { + if (bpBindParam(stmt, data.pBind + t * bindTimes * gCurCase->bindColNum + b * gCurCase->bindColNum, false)) { + exit(1); + } + + if (st_stmt2_add_batch(stmt)) { + printf("!!!st_stmt2_add_batch error:%s\n", st_stmt2_error(stmt)); + exit(1); + } + } + + if (st_stmt2_exec(stmt, NULL) != 0) { + printf("!!!st_stmt2_exec error:%s\n", st_stmt2_error(stmt)); + exit(1); + } + } + + bpCheckIsInsert(stmt, 1); + bpCheckAffectedRows(stmt, 1); + + destroyData(&data); + + return 0; +} + +/* prepare [settbname [bind add exec]] */ +int insertMBMETest2(TAOS_STMT2 *stmt, TAOS *taos) { + BindData data = {0}; + prepareInsertData(&data); + + int code = st_stmt2_prepare(stmt, data.sql, 0); + if (code != 0) { + printf("!!!failed to execute st_stmt2_prepare. error:%s\n", st_stmt2_error(stmt)); + exit(1); + } + + bpCheckIsInsert(stmt, 1); + + int32_t bindTimes = gCurCase->rowNum / gCurCase->bindRowNum; + for (int32_t t = 0; t < gCurCase->tblNum; ++t) { + if (gCurCase->tblNum > 1) { + char buf[32]; + sprintf(buf, "t%d", t); + code = bpSetTableNameTags(&data, t, buf, stmt); + if (code != 0) { + printf("!!!st_stmt2_set_tbname error:%s\n", st_stmt2_error(stmt)); + exit(1); + } + } + + for (int32_t b = 0; b < bindTimes; ++b) { + if (bpBindParam(stmt, data.pBind + t * bindTimes * gCurCase->bindColNum + b * gCurCase->bindColNum, false)) { + exit(1); + } + + if (gCaseCtrl.checkParamNum) { + bpCheckParamNum(stmt); + } + + if (st_stmt2_add_batch(stmt)) { + printf("!!!st_stmt2_add_batch error:%s\n", st_stmt2_error(stmt)); + exit(1); + } + + if (st_stmt2_exec(stmt, NULL) != 0) { + printf("!!!st_stmt2_exec error:%s\n", st_stmt2_error(stmt)); + exit(1); + } + } + } + + bpCheckIsInsert(stmt, 1); + bpCheckAffectedRows(stmt, 1); + + destroyData(&data); + + return 0; +} + +/* prepare [settbname [settbname bind add exec]] */ +int insertMBMETest3(TAOS_STMT2 *stmt, TAOS *taos) { + BindData data = {0}; + prepareInsertData(&data); + + int code = st_stmt2_prepare(stmt, data.sql, 0); + if (code != 0) { + printf("!!!failed to execute st_stmt2_prepare. error:%s\n", st_stmt2_error(stmt)); + exit(1); + } + + bpCheckIsInsert(stmt, 1); + + int32_t bindTimes = gCurCase->rowNum / gCurCase->bindRowNum; + for (int32_t t = 0; t < gCurCase->tblNum; ++t) { + if (gCurCase->tblNum > 1) { + char buf[32]; + sprintf(buf, "t%d", t); + code = bpSetTableNameTags(&data, t, buf, stmt); + if (code != 0) { + printf("!!!st_stmt2_set_tbname error:%s\n", st_stmt2_error(stmt)); + exit(1); + } + } + + if (gCaseCtrl.checkParamNum) { + bpCheckParamNum(stmt); + } + + for (int32_t b = 0; b < bindTimes; ++b) { + if (gCurCase->tblNum > 1) { + char buf[32]; + sprintf(buf, "t%d", t); + code = bpSetTableNameTags(&data, t, buf, stmt); + if (code != 0) { + printf("!!!st_stmt2_set_tbname error:%s\n", st_stmt2_error(stmt)); + exit(1); + } + } + + if (bpBindParam(stmt, data.pBind + t * bindTimes * gCurCase->bindColNum + b * gCurCase->bindColNum, false)) { + exit(1); + } + + if (st_stmt2_add_batch(stmt)) { + printf("!!!st_stmt2_add_batch error:%s\n", st_stmt2_error(stmt)); + exit(1); + } + + if (st_stmt2_exec(stmt, NULL) != 0) { + printf("!!!st_stmt2_exec error:%s\n", st_stmt2_error(stmt)); + exit(1); + } + } + } + + bpCheckIsInsert(stmt, 1); + bpCheckAffectedRows(stmt, 1); + + destroyData(&data); + + return 0; +} + +/* prepare [settbname bind add exec] */ +int insertMBMETest4(TAOS_STMT2 *stmt, TAOS *taos) { + BindData data = {0}; + prepareInsertData(&data); + + int code = st_stmt2_prepare(stmt, data.sql, 0); + if (code != 0) { + printf("!!!failed to execute st_stmt2_prepare. error:%s\n", st_stmt2_error(stmt)); + exit(1); + } + + bpCheckIsInsert(stmt, 1); + + int32_t bindTimes = gCurCase->rowNum / gCurCase->bindRowNum; + + for (int32_t b = 0; b < bindTimes; ++b) { + for (int32_t t = 0; t < gCurCase->tblNum; ++t) { + if (gCurCase->tblNum > 1) { + char buf[32]; + sprintf(buf, "t%d", t); + code = bpSetTableNameTags(&data, t, buf, stmt); + if (code != 0) { + printf("!!!st_stmt2_set_tbname error:%s\n", st_stmt2_error(stmt)); + exit(1); + } + } + + if (bpBindParam(stmt, data.pBind + t * bindTimes * gCurCase->bindColNum + b * gCurCase->bindColNum, false)) { + exit(1); + } + + if (gCaseCtrl.checkParamNum) { + bpCheckParamNum(stmt); + } + + if (st_stmt2_add_batch(stmt)) { + printf("!!!st_stmt2_add_batch error:%s\n", st_stmt2_error(stmt)); + exit(1); + } + + if (st_stmt2_exec(stmt, NULL) != 0) { + printf("!!!st_stmt2_exec error:%s\n", st_stmt2_error(stmt)); + exit(1); + } + } + } + + bpCheckIsInsert(stmt, 1); + bpCheckAffectedRows(stmt, 1); + + destroyData(&data); + + return 0; +} + +/* [prepare [settbname [bind add] exec]] */ +int insertMPMETest1(TAOS_STMT2 *stmt, TAOS *taos) { + int32_t loop = 0; + + while (gCurCase->bindColNum >= 2) { + BindData data = {0}; + prepareInsertData(&data); + + int code = st_stmt2_prepare(stmt, data.sql, 0); + if (code != 0) { + printf("!!!failed to execute st_stmt2_prepare. error:%s\n", st_stmt2_error(stmt)); + exit(1); + } + + bpCheckIsInsert(stmt, 1); + + int32_t bindTimes = gCurCase->rowNum / gCurCase->bindRowNum; + for (int32_t t = 0; t < gCurCase->tblNum; ++t) { + if (gCurCase->tblNum > 1) { + char buf[32]; + sprintf(buf, "t%d", t); + code = bpSetTableNameTags(&data, t, buf, stmt); + if (code != 0) { + printf("!!!st_stmt2_set_tbname error:%s\n", st_stmt2_error(stmt)); + exit(1); + } + } + + if (gCaseCtrl.checkParamNum) { + bpCheckParamNum(stmt); + } + + for (int32_t b = 0; b < bindTimes; ++b) { + if (bpBindParam(stmt, data.pBind + t * bindTimes * gCurCase->bindColNum + b * gCurCase->bindColNum, false)) { + exit(1); + } + + if (st_stmt2_add_batch(stmt)) { + printf("!!!st_stmt2_add_batch error:%s\n", st_stmt2_error(stmt)); + exit(1); + } + } + + if (st_stmt2_exec(stmt, NULL) != 0) { + printf("!!!st_stmt2_exec error:%s\n", st_stmt2_error(stmt)); + exit(1); + } + } + + bpCheckIsInsert(stmt, 1); + + destroyData(&data); + + gCurCase->bindColNum -= 2; + gCurCase->fullCol = false; + loop++; + } + + bpCheckAffectedRows(stmt, loop); + + gExecLoopTimes = loop; + + return 0; +} + +/* prepare [settbname [bind] exec] */ +int insertStbTest(TAOS_STMT2 *stmt, TAOS *taos) { + BindData data = {0}; + prepareInsertData(&data); + + int code = st_stmt2_prepare(stmt, data.sql, 0); + if (code != 0) { + printf("!!!failed to execute st_stmt2_prepare. error:%s\n", st_stmt2_error(stmt)); + exit(1); + } + + bpCheckIsInsert(stmt, 1); + + int32_t bindTimes = gCurCase->rowNum / gCurCase->bindRowNum; + for (int32_t t = 0; t < gCurCase->tblNum; ++t) { + if (gCurCase->tblNum > 1) { + char buf[32]; + sprintf(buf, "t%d", t); + code = bpSetTableNameTags(&data, t, buf, stmt); + if (code != 0) { + printf("!!!st_stmt2_set_tbname error:%s\n", st_stmt2_error(stmt)); + exit(1); + } + } + + if (gCaseCtrl.checkParamNum) { + bpCheckParamNum(stmt); + } + + for (int32_t b = 0; b < bindTimes; ++b) { + if (bpBindParam(stmt, data.pBind + t * bindTimes * gCurCase->bindColNum + b * gCurCase->bindColNum, false)) { + exit(1); + } + } + + if (st_stmt2_add_batch(stmt)) { + printf("!!!st_stmt2_add_batch error:%s\n", st_stmt2_error(stmt)); + exit(1); + } + + if (st_stmt2_exec(stmt, NULL) != 0) { + printf("!!!st_stmt2_exec error:%s\n", st_stmt2_error(stmt)); + exit(1); + } + } + + bpCheckIsInsert(stmt, 1); + + destroyData(&data); + + bpCheckAffectedRows(stmt, 1); + + return 0; +} + +/* [prepare [settbnametag [bind add] exec]] */ +int insertAUTOTest1(TAOS_STMT2 *stmt, TAOS *taos) { + int32_t loop = 0; + + while (gCurCase->bindTagNum > 0 && gCurCase->bindColNum > 0) { + BindData data = {0}; + prepareInsertData(&data); + + int code = st_stmt2_prepare(stmt, data.sql, 0); + if (code != 0) { + printf("!!!failed to execute st_stmt2_prepare. error:%s\n", st_stmt2_error(stmt)); + exit(1); + } + + bpCheckIsInsert(stmt, 1); + + int32_t bindTimes = gCurCase->rowNum / gCurCase->bindRowNum; + for (int32_t t = 0; t < gCurCase->tblNum; ++t) { + if (gCurCase->tblNum > 1) { + char buf[32]; + sprintf(buf, "t%d", t); + code = bpSetTableNameTags(&data, t, buf, stmt); + if (code != 0) { + printf("!!!st_stmt2_set_tbname_tags error:%s\n", st_stmt2_error(stmt)); + exit(1); + } + } + + if (gCaseCtrl.checkParamNum) { + bpCheckParamNum(stmt); + } + + for (int32_t b = 0; b < bindTimes; ++b) { + if (bpBindParam(stmt, data.pBind + t * bindTimes * gCurCase->bindColNum + b * gCurCase->bindColNum, false)) { + exit(1); + } + + if (st_stmt2_add_batch(stmt)) { + printf("!!!st_stmt2_add_batch error:%s\n", st_stmt2_error(stmt)); + exit(1); + } + } + + if (st_stmt2_exec(stmt, NULL) != 0) { + printf("!!!st_stmt2_exec error:%s\n", st_stmt2_error(stmt)); + exit(1); + } + } + + bpCheckIsInsert(stmt, 1); + + destroyData(&data); + + gCurCase->bindColNum -= 2; + gCurCase->bindTagNum -= 2; + gCurCase->fullCol = false; + loop++; + } + + bpCheckAffectedRows(stmt, loop); + + gExecLoopTimes = loop; + + return 0; +} + +/* [prepare [settbnametag [bind add exec]]] */ +int insertAUTOTest2(TAOS_STMT2 *stmt, TAOS *taos) { + int32_t loop = 0; + + while (gCurCase->bindTagNum > 0 && gCurCase->bindColNum > 0) { + BindData data = {0}; + prepareInsertData(&data); + + int code = st_stmt2_prepare(stmt, data.sql, 0); + if (code != 0) { + printf("!!!failed to execute st_stmt2_prepare. error:%s\n", st_stmt2_error(stmt)); + exit(1); + } + + bpCheckIsInsert(stmt, 1); + + int32_t bindTimes = gCurCase->rowNum / gCurCase->bindRowNum; + for (int32_t b = 0; b < bindTimes; ++b) { + for (int32_t t = 0; t < gCurCase->tblNum; ++t) { + if (gCurCase->tblNum > 1) { + char buf[32]; + sprintf(buf, "t%d", t); + code = bpSetTableNameTags(&data, t, buf, stmt); + if (code != 0) { + printf("!!!st_stmt2_set_tbname_tags error:%s\n", st_stmt2_error(stmt)); + exit(1); + } + } + + if (gCaseCtrl.checkParamNum) { + bpCheckParamNum(stmt); + } + if (bpBindParam(stmt, data.pBind + t * bindTimes * gCurCase->bindColNum + b * gCurCase->bindColNum, false)) { + exit(1); + } + + if (st_stmt2_add_batch(stmt)) { + printf("!!!st_stmt2_add_batch error:%s\n", st_stmt2_error(stmt)); + exit(1); + } + + if (st_stmt2_exec(stmt, NULL) != 0) { + printf("!!!st_stmt2_exec error:%s\n", st_stmt2_error(stmt)); + exit(1); + } + } + } + + bpCheckIsInsert(stmt, 1); + + destroyData(&data); + + gCurCase->bindColNum -= 2; + gCurCase->bindTagNum -= 2; + gCurCase->fullCol = false; + loop++; + } + + bpCheckAffectedRows(stmt, loop); + + gExecLoopTimes = loop; + + return 0; +} + +/* normal table [prepare [bind add exec]] */ +int insertAUTOTest3(TAOS_STMT2 *stmt, TAOS *taos) { + int32_t loop = 0; + + while (gCurCase->bindColNum > 0) { + BindData data = {0}; + data.singleTbInsert = true; + prepareInsertData(&data); + + int32_t bindTimes = gCurCase->rowNum / gCurCase->bindRowNum; + for (int32_t t = 0; t < gCurCase->tblNum; ++t) { + data.singleTbIdx = t; + generateInsertSQL(&data); + + int code = st_stmt2_prepare(stmt, data.sql, 0); + if (code != 0) { + printf("!!!failed to execute st_stmt2_prepare. error:%s\n", st_stmt2_error(stmt)); + exit(1); + } + + for (int32_t b = 0; b < bindTimes; ++b) { + bpCheckIsInsert(stmt, 1); + + if (gCaseCtrl.checkParamNum) { + bpCheckParamNum(stmt); + } + + if (bpBindParam(stmt, data.pBind + t * bindTimes * gCurCase->bindColNum + b * gCurCase->bindColNum, false)) { + exit(1); + } + + if (st_stmt2_add_batch(stmt)) { + printf("!!!st_stmt2_add_batch error:%s\n", st_stmt2_error(stmt)); + exit(1); + } + + if (st_stmt2_exec(stmt, NULL) != 0) { + printf("!!!st_stmt2_exec error:%s\n", st_stmt2_error(stmt)); + exit(1); + } + } + } + + bpCheckIsInsert(stmt, 1); + + destroyData(&data); + + gCurCase->bindColNum -= 2; + gCurCase->fullCol = false; + loop++; + } + + bpCheckAffectedRows(stmt, loop); + + gExecLoopTimes = loop; + + return 0; +} + +/* select * from table */ +int queryColumnTest(TAOS_STMT2 *stmt, TAOS *taos) { + BindData data = {0}; + + for (int32_t t = 0; t < gCurCase->tblNum; ++t) { + memset(&data, 0, sizeof(data)); + prepareQueryCondData(&data, t); + + int code = st_stmt2_prepare(stmt, data.sql, 0); + if (code != 0) { + printf("!!!failed to execute st_stmt2_prepare. error:%s\n", st_stmt2_error(stmt)); + exit(1); + } + + for (int32_t n = 0; n < (gCurCase->rowNum / gCurCase->bindRowNum); ++n) { + bpCheckIsInsert(stmt, 0); + + if (gCaseCtrl.checkParamNum) { + bpCheckParamNum(stmt); + } + + if (bpBindParam(stmt, data.pBind + n * gCurCase->bindColNum, false)) { + exit(1); + } + + if (rand() % 2 == 0) { + if (st_stmt2_add_batch(stmt)) { + printf("!!!st_stmt2_add_batch error:%s\n", st_stmt2_error(stmt)); + exit(1); + } + } + + if (st_stmt2_exec(stmt, NULL) != 0) { + printf("!!!st_stmt2_exec error:%s\n", st_stmt2_error(stmt)); + exit(1); + } + + bpCheckQueryResult(stmt, taos, data.sql, data.pBind + n * gCurCase->bindColNum); + } + + bpCheckIsInsert(stmt, 0); + + destroyData(&data); + } + + return 0; +} + +/* value in query sql */ +int queryMiscTest(TAOS_STMT2 *stmt, TAOS *taos) { + BindData data = {0}; + + for (int32_t t = 0; t < gCurCase->tblNum; ++t) { + memset(&data, 0, sizeof(data)); + prepareQueryMiscData(&data, t); + + int code = st_stmt2_prepare(stmt, data.sql, 0); + if (code != 0) { + printf("!!!failed to execute st_stmt2_prepare. error:%s\n", st_stmt2_error(stmt)); + exit(1); + } + + for (int32_t n = 0; n < (gCurCase->rowNum / gCurCase->bindRowNum); ++n) { + bpCheckIsInsert(stmt, 0); + + if (gCaseCtrl.checkParamNum) { + bpCheckParamNum(stmt); + } + + if (bpBindParam(stmt, data.pBind + n * gCurCase->bindColNum, false)) { + exit(1); + } + + if (rand() % 2 == 0) { + if (st_stmt2_add_batch(stmt)) { + printf("!!!st_stmt2_add_batch error:%s\n", st_stmt2_error(stmt)); + exit(1); + } + } + + if (st_stmt2_exec(stmt, NULL) != 0) { + printf("!!!st_stmt2_exec error:%s\n", st_stmt2_error(stmt)); + exit(1); + } + + bpCheckQueryResult(stmt, taos, data.sql, data.pBind + n * gCurCase->bindColNum); + } + + bpCheckIsInsert(stmt, 0); + + destroyData(&data); + } + + return 0; +} + +int insertNonExistsTb(TAOS_STMT2 *stmt, TAOS *taos) { + BindData data = {0}; + prepareInsertData(&data); + + int code = st_stmt2_prepare(stmt, data.sql, 0); + if (code != 0) { + printf("!!!failed to execute st_stmt2_prepare. error:%s\n", st_stmt2_error(stmt)); + exit(1); + } + + bpCheckIsInsert(stmt, 1); + + char *buf = "tbnexist"; + code = bpSetTableNameTags(&data, 0, buf, stmt); + if (code == 0) { + printf("!!!st_stmt2_set_tbname expected error not occurred\n"); + exit(1); + } + + if (0 == st_stmt2_bind_param_batch(stmt, data.pBind)) { + printf("!!!st_stmt2_bind_param_batch expected error not occurred\n"); + exit(1); + } + + if (0 == st_stmt2_exec(stmt, NULL)) { + printf("!!!st_stmt2_execute expected error not occurred\n"); + exit(1); + } + + destroyData(&data); + + return 0; +} + +void bpAddWrongVarBuffLen(TAOS_STMT2_BIND *pBind) { + for (int32_t i = 0; i < gCurCase->bindColNum; ++i) { + if (pBind[i].buffer_type == TSDB_DATA_TYPE_BINARY || pBind[i].buffer_type == TSDB_DATA_TYPE_VARBINARY || + pBind[i].buffer_type == TSDB_DATA_TYPE_NCHAR) { + *pBind[i].length += 100; + } + } +} + +int insertVarLenErr(TAOS_STMT2 *stmt, TAOS *taos) { + BindData data = {0}; + prepareInsertData(&data); + + int code = st_stmt2_prepare(stmt, data.sql, 0); + if (code != 0) { + printf("!!!failed to execute st_stmt2_prepare. error:%s\n", st_stmt2_error(stmt)); + exit(1); + } + + bpCheckIsInsert(stmt, 1); + + code = bpSetTableNameTags(&data, 0, "t0", stmt); + if (code != 0) { + printf("!!!st_stmt2_set_tbname error:%s\n", st_stmt2_error(stmt)); + exit(1); + } + + bpAddWrongVarBuffLen(data.pBind); + + if (bpBindParam(stmt, data.pBind, true)) { + exit(1); + } + + destroyData(&data); + + return 0; +} + +int errorSQLTest1(TAOS_STMT2 *stmt, TAOS *taos) { + BindData data = {0}; + + for (int32_t t = 0; t < gCurCase->tblNum; ++t) { + memset(&data, 0, sizeof(data)); + generateErrorSQL(&data, t); + + int code = st_stmt2_prepare(stmt, data.sql, 0); + if (code != 0) { + printf("*st_stmt2_prepare error as expected, error:%s\n", st_stmt2_error(stmt)); + } else { + printf("!!!st_stmt2_prepare succeed, which should be error\n"); + exit(1); + } + + destroyData(&data); + } + + return 0; +} + +void prepareCheckResultImpl(TAOS *taos, char *tname, bool printr, int expected, bool silent) { + if (TTYPE_INSERT_NG == gCurCase->testType) { + return; + } + + char sql[255] = "SELECT * FROM "; + int32_t rows = 0; + + strcat(sql, tname); + bpExecQuery(taos, sql, printr, &rows); + + if (rows == expected) { + if (!silent) { + printf("***%d rows are fetched as expected from %s\n", rows, tname); + } + } else { + printf("!!!expect rows %d mis-match rows %d fetched from %s\n", expected, rows, tname); + exit(1); + } +} + +void prepareCheckResult(TAOS *taos, bool silent) { + char buf[32]; + for (int32_t t = 0; t < gCurCase->tblNum; ++t) { + if (gCurCase->tblNum > 1) { + sprintf(buf, "%s%d", bpTbPrefix, t); + } else { + sprintf(buf, "%s%d", bpTbPrefix, 0); + } + + prepareCheckResultImpl( + taos, buf, gCaseCtrl.printRes, + gCurCase->duplicateValue ? (gCurCase->rowNum * gExecLoopTimes / 2) : (gCurCase->rowNum * gExecLoopTimes), + silent); + } + + gExecLoopTimes = 1; +} + +// 120table 60 record each table +int sql_perf1(TAOS *taos) { + char *sql[3000] = {0}; + TAOS_RES *result; + + for (int i = 0; i < 3000; i++) { + sql[i] = taosMemoryCalloc(1, 1048576); + } + + int len = 0; + int tss = 0; + for (int l = 0; l < 3000; ++l) { + len = sprintf(sql[l], "insert into "); + for (int t = 0; t < 120; ++t) { + len += sprintf(sql[l] + len, "m%d values ", t); + for (int m = 0; m < 60; ++m) { + len += sprintf(sql[l] + len, + "(%d, %d, %d, %d, %d, %d, %f, %f, \"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\", " + "\"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\") ", + tss++, m, m, m, m, m, m + 1.0, m + 1.0); + } + } + } + + int64_t starttime = taosGetTimestampUs(); + for (int i = 0; i < 3000; ++i) { + result = taos_query(taos, sql[i]); + int code = taos_errno(result); + if (code != 0) { + printf("%d failed to query table, reason:%s\n", taos_errstr(result)); + taos_free_result(result); + exit(1); + } + + taos_free_result(result); + } + int64_t endtime = taosGetTimestampUs(); + printf("insert total %d records, used %u seconds, avg:%.1f useconds\n", 3000 * 120 * 60, + (endtime - starttime) / 1000000UL, (endtime - starttime) / (3000 * 120 * 60)); + + for (int i = 0; i < 3000; i++) { + taosMemoryFree(sql[i]); + } + + return 0; +} + +// one table 60 records one time +int sql_perf_s1(TAOS *taos) { + char **sql = calloc(1, sizeof(char *) * 360000); + TAOS_RES *result; + + for (int i = 0; i < 360000; i++) { + sql[i] = taosMemoryCalloc(1, 9000); + } + + int len = 0; + int tss = 0; + int id = 0; + for (int t = 0; t < 120; ++t) { + for (int l = 0; l < 3000; ++l) { + len = sprintf(sql[id], "insert into m%d values ", t); + for (int m = 0; m < 60; ++m) { + len += sprintf(sql[id] + len, + "(%d, %d, %d, %d, %d, %d, %f, %f, \"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\", " + "\"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\") ", + tss++, m, m, m, m, m, m + 1.0, m + 1.0); + } + if (len >= 9000) { + printf("sql:%s,len:%d\n", sql[id], len); + exit(1); + } + ++id; + } + } + + unsigned long long starttime = taosGetTimestampUs(); + for (int i = 0; i < 360000; ++i) { + result = taos_query(taos, sql[i]); + int code = taos_errno(result); + if (code != 0) { + printf("failed to query table, reason:%s\n", taos_errstr(result)); + taos_free_result(result); + exit(1); + } + + taos_free_result(result); + } + unsigned long long endtime = taosGetTimestampUs(); + printf("insert total %d records, used %u seconds, avg:%.1f useconds\n", 3000 * 120 * 60, + (endtime - starttime) / 1000000UL, (endtime - starttime) / (3000 * 120 * 60)); + + for (int i = 0; i < 360000; i++) { + taosMemoryFree(sql[i]); + } + + taosMemoryFree(sql); + + return 0; +} + +// small record size +int sql_s_perf1(TAOS *taos) { + char *sql[3000] = {0}; + TAOS_RES *result; + + for (int i = 0; i < 3000; i++) { + sql[i] = taosMemoryCalloc(1, 1048576); + } + + int len = 0; + int tss = 0; + for (int l = 0; l < 3000; ++l) { + len = sprintf(sql[l], "insert into "); + for (int t = 0; t < 120; ++t) { + len += sprintf(sql[l] + len, "m%d values ", t); + for (int m = 0; m < 60; ++m) { + len += sprintf(sql[l] + len, "(%d, %d) ", tss++, m % 2); + } + } + } + + unsigned long long starttime = taosGetTimestampUs(); + for (int i = 0; i < 3000; ++i) { + result = taos_query(taos, sql[i]); + int code = taos_errno(result); + if (code != 0) { + printf("failed to query table, reason:%s\n", taos_errstr(result)); + taos_free_result(result); + exit(1); + } + + taos_free_result(result); + } + unsigned long long endtime = taosGetTimestampUs(); + printf("insert total %d records, used %u seconds, avg:%.1f useconds\n", 3000 * 120 * 60, + (endtime - starttime) / 1000000UL, (endtime - starttime) / (3000 * 120 * 60)); + + for (int i = 0; i < 3000; i++) { + taosMemoryFree(sql[i]); + } + + return 0; +} + +void generateCreateTableSQL(char *buf, int32_t tblIdx, int32_t colNum, int32_t *colList, int32_t tableType) { + int32_t blen = 0; + blen = sprintf(buf, "create table %s%d ", (1 == tableType ? bpStbPrefix : bpTbPrefix), tblIdx); + + if (tableType == 3) { + blen += sprintf(buf + blen, "using %s%d", bpStbPrefix, bpDefaultStbId); + } + + if (tableType == 0 || tableType == 1) { + blen += sprintf(buf + blen, " ("); + + for (int c = 0; c < colNum; ++c) { + if (c > 0) { + blen += sprintf(buf + blen, ","); + } + + switch (colList[c]) { + case TSDB_DATA_TYPE_BOOL: + blen += sprintf(buf + blen, "booldata bool"); + break; + case TSDB_DATA_TYPE_TINYINT: + blen += sprintf(buf + blen, "tinydata tinyint"); + break; + case TSDB_DATA_TYPE_SMALLINT: + blen += sprintf(buf + blen, "smalldata smallint"); + break; + case TSDB_DATA_TYPE_INT: + blen += sprintf(buf + blen, "intdata int"); + break; + case TSDB_DATA_TYPE_BIGINT: + blen += sprintf(buf + blen, "bigdata bigint"); + break; + case TSDB_DATA_TYPE_FLOAT: + blen += sprintf(buf + blen, "floatdata float"); + break; + case TSDB_DATA_TYPE_DOUBLE: + blen += sprintf(buf + blen, "doubledata double"); + break; + case TSDB_DATA_TYPE_VARCHAR: + blen += sprintf(buf + blen, "binarydata binary(%d)", gVarCharSize); + break; + case TSDB_DATA_TYPE_TIMESTAMP: + blen += sprintf(buf + blen, "ts timestamp"); + break; + case TSDB_DATA_TYPE_NCHAR: + blen += sprintf(buf + blen, "nchardata nchar(%d)", gVarCharSize); + break; + case TSDB_DATA_TYPE_UTINYINT: + blen += sprintf(buf + blen, "utinydata tinyint unsigned"); + break; + case TSDB_DATA_TYPE_USMALLINT: + blen += sprintf(buf + blen, "usmalldata smallint unsigned"); + break; + case TSDB_DATA_TYPE_UINT: + blen += sprintf(buf + blen, "uintdata int unsigned"); + break; + case TSDB_DATA_TYPE_UBIGINT: + blen += sprintf(buf + blen, "ubigdata bigint unsigned"); + break; + default: + printf("invalid col type:%d", colList[c]); + exit(1); + } + } + + blen += sprintf(buf + blen, ")"); + } + + if (1 == tableType) { + blen += sprintf(buf + blen, " tags ("); + for (int c = 0; c < colNum; ++c) { + if (c > 0) { + blen += sprintf(buf + blen, ","); + } + switch (colList[c]) { + case TSDB_DATA_TYPE_BOOL: + blen += sprintf(buf + blen, "tbooldata bool"); + break; + case TSDB_DATA_TYPE_TINYINT: + blen += sprintf(buf + blen, "ttinydata tinyint"); + break; + case TSDB_DATA_TYPE_SMALLINT: + blen += sprintf(buf + blen, "tsmalldata smallint"); + break; + case TSDB_DATA_TYPE_INT: + blen += sprintf(buf + blen, "tintdata int"); + break; + case TSDB_DATA_TYPE_BIGINT: + blen += sprintf(buf + blen, "tbigdata bigint"); + break; + case TSDB_DATA_TYPE_FLOAT: + blen += sprintf(buf + blen, "tfloatdata float"); + break; + case TSDB_DATA_TYPE_DOUBLE: + blen += sprintf(buf + blen, "tdoubledata double"); + break; + case TSDB_DATA_TYPE_VARCHAR: + blen += sprintf(buf + blen, "tbinarydata binary(%d)", gVarCharSize); + break; + case TSDB_DATA_TYPE_TIMESTAMP: + blen += sprintf(buf + blen, "tts timestamp"); + break; + case TSDB_DATA_TYPE_NCHAR: + blen += sprintf(buf + blen, "tnchardata nchar(%d)", gVarCharSize); + break; + case TSDB_DATA_TYPE_UTINYINT: + blen += sprintf(buf + blen, "tutinydata tinyint unsigned"); + break; + case TSDB_DATA_TYPE_USMALLINT: + blen += sprintf(buf + blen, "tusmalldata smallint unsigned"); + break; + case TSDB_DATA_TYPE_UINT: + blen += sprintf(buf + blen, "tuintdata int unsigned"); + break; + case TSDB_DATA_TYPE_UBIGINT: + blen += sprintf(buf + blen, "tubigdata bigint unsigned"); + break; + default: + printf("invalid col type:%d", colList[c]); + exit(1); + } + } + + blen += sprintf(buf + blen, ")"); + } + + if (3 == tableType) { + blen += sprintf(buf + blen, " tags ("); + for (int c = 0; c < colNum; ++c) { + if (c > 0) { + blen += sprintf(buf + blen, ","); + } + switch (colList[c]) { + case TSDB_DATA_TYPE_BOOL: + blen += sprintf(buf + blen, "%s", rand() % 2 ? "true" : "false"); + break; + case TSDB_DATA_TYPE_TINYINT: + blen += sprintf(buf + blen, "%d", rand() % 128); + break; + case TSDB_DATA_TYPE_SMALLINT: + blen += sprintf(buf + blen, "%d", rand() % 128); + break; + case TSDB_DATA_TYPE_INT: + blen += sprintf(buf + blen, "%d", rand() % 128); + break; + case TSDB_DATA_TYPE_BIGINT: + blen += sprintf(buf + blen, "%d", rand() % 128); + break; + case TSDB_DATA_TYPE_FLOAT: + blen += sprintf(buf + blen, "%f", rand() % 128); + break; + case TSDB_DATA_TYPE_DOUBLE: + blen += sprintf(buf + blen, "%f", rand() % 128); + break; + case TSDB_DATA_TYPE_VARCHAR: + blen += sprintf(buf + blen, "'var%d'", rand() % 128); + break; + case TSDB_DATA_TYPE_TIMESTAMP: + blen += sprintf(buf + blen, "%lld", bpTs); + break; + case TSDB_DATA_TYPE_NCHAR: + blen += sprintf(buf + blen, "'nch%d'", rand() % 128); + break; + case TSDB_DATA_TYPE_UTINYINT: + blen += sprintf(buf + blen, "%d", rand() % 128); + break; + case TSDB_DATA_TYPE_USMALLINT: + blen += sprintf(buf + blen, "%d", rand() % 128); + break; + case TSDB_DATA_TYPE_UINT: + blen += sprintf(buf + blen, "%d", rand() % 128); + break; + case TSDB_DATA_TYPE_UBIGINT: + blen += sprintf(buf + blen, "%d", rand() % 128); + break; + default: + printf("invalid col type:%d", colList[c]); + exit(1); + } + } + + blen += sprintf(buf + blen, ")"); + } + + if (gCaseCtrl.printCreateTblSql) { + printf("\tCreate Table SQL:%s\n", buf); + } +} + +char *bpPrecisionStr(uint8_t precision) { + switch (precision) { + case TIME_PRECISION_MILLI: + return "ms"; + case TIME_PRECISION_MICRO: + return "us"; + case TIME_PRECISION_NANO: + return "ns"; + default: + return "unknwon"; + } +} + +void bpSetStartupTs() { + switch (gCaseCtrl.precision) { + case TIME_PRECISION_MILLI: + bpTs = BP_STARTUP_TS; + break; + case TIME_PRECISION_MICRO: + bpTs = BP_STARTUP_TS * 1000; + break; + case TIME_PRECISION_NANO: + bpTs = BP_STARTUP_TS * 1000000; + break; + default: + bpTs = BP_STARTUP_TS; + break; + } +} + +void prepare(TAOS *taos, int32_t colNum, int32_t *colList, int prepareStb) { + TAOS_RES *result; + int code; + char createDbSql[128] = {0}; + + result = taos_query(taos, "drop database demo"); + taos_free_result(result); + + sprintf(createDbSql, "create database demo keep 36500 precision \"%s\"", bpPrecisionStr(gCaseCtrl.precision)); + printf("\tCreate Database SQL:%s\n", createDbSql); + + result = taos_query(taos, createDbSql); + code = taos_errno(result); + if (code != 0) { + printf("!!!failed to create database, reason:%s\n", taos_errstr(result)); + taos_free_result(result); + exit(1); + } + taos_free_result(result); + + result = taos_query(taos, "use demo"); + taos_free_result(result); + + if (0 == prepareStb) { + // create table + for (int i = 0; i < 10; i++) { + char buf[1024]; + generateCreateTableSQL(buf, i, colNum, colList, 0); + result = taos_query(taos, buf); + code = taos_errno(result); + if (code != 0) { + printf("!!!failed to create table, reason:%s\n", taos_errstr(result)); + taos_free_result(result); + exit(1); + } + taos_free_result(result); + } + } else { + if (1 == prepareStb || 3 == prepareStb) { + char buf[1024]; + generateCreateTableSQL(buf, bpDefaultStbId, colNum, colList, 1); + + result = taos_query(taos, buf); + code = taos_errno(result); + if (code != 0) { + printf("!!!failed to create table, reason:%s\n", taos_errstr(result)); + taos_free_result(result); + exit(1); + } + taos_free_result(result); + } + + if (3 == prepareStb) { + for (int i = 0; i < 10; i++) { + char buf[1024]; + generateCreateTableSQL(buf, i, colNum, colList, 3); + result = taos_query(taos, buf); + code = taos_errno(result); + if (code != 0) { + printf("!!!failed to create table, reason:%s\n", taos_errstr(result)); + taos_free_result(result); + exit(1); + } + taos_free_result(result); + } + } + } +} + +int32_t runCase(TAOS *taos, int32_t caseIdx, int32_t caseRunIdx, bool silent) { + TAOS_STMT2 *stmt = NULL; + int64_t beginUs, endUs, totalUs; + CaseCfg cfg = gCase[caseIdx]; + CaseCfg cfgBk; + gCurCase = &cfg; + + bpSetStartupTs(); + + if ((gCaseCtrl.bindColTypeNum || gCaseCtrl.bindColNum) && (gCurCase->colNum != gFullColNum)) { + return 1; + } + + if (gCurCase->preCaseIdx >= 0) { + bool printRes = gCaseCtrl.printRes; + bool printStmtSql = gCaseCtrl.printStmtSql; + gCaseCtrl.printRes = false; + gCaseCtrl.printStmtSql = false; + runCase(taos, gCurCase->preCaseIdx, caseRunIdx, true); + gCaseCtrl.printRes = printRes; + gCaseCtrl.printStmtSql = printStmtSql; + + gCurCase = &cfg; + } + + if (gCaseCtrl.runTimes) { + gCurCase->runTimes = gCaseCtrl.runTimes; + } + + if (gCaseCtrl.rowNum) { + gCurCase->rowNum = gCaseCtrl.rowNum; + } + + if (gCaseCtrl.autoCreateTbl) { + if (gCurCase->testType == TTYPE_INSERT && gCurCase->tblNum > 1) { + gCurCase->autoCreateTbl = 1; + if (gCurCase->bindTagNum <= 0) { + gCurCase->bindTagNum = gCurCase->colNum; + } + } else { + return 1; + } + } + + if (gCurCase->fullCol) { + gCurCase->bindColNum = gCurCase->colNum; + if (gCurCase->autoCreateTbl) { + gCurCase->bindTagNum = gCurCase->colNum; + } + } + + gCurCase->bindNullNum = gCaseCtrl.bindNullNum; + if (gCaseCtrl.bindColNum) { + gCurCase->bindColNum = gCaseCtrl.bindColNum; + gCurCase->fullCol = false; + } + if (gCaseCtrl.bindTagNum) { + gCurCase->bindTagNum = gCaseCtrl.bindTagNum; + gCurCase->fullCol = false; + } + if (gCaseCtrl.bindRowNum) { + gCurCase->bindRowNum = gCaseCtrl.bindRowNum; + } + if (gCaseCtrl.bindColTypeNum) { + gCurCase->bindColNum = gCaseCtrl.bindColTypeNum; + gCurCase->fullCol = false; + } + if (gCaseCtrl.bindTagTypeNum) { + gCurCase->bindTagNum = gCaseCtrl.bindTagTypeNum; + gCurCase->fullCol = false; + } + + if (!silent) { + printf("* Case %d - [%s]%s Begin *\n", caseRunIdx, gCaseCtrl.caseCatalog, gCurCase->caseDesc); + } + + totalUs = 0; + cfgBk = cfg; + for (int32_t n = 0; n < gCurCase->runTimes; ++n) { + if (gCurCase->preCaseIdx < 0) { + prepare(taos, gCurCase->colNum, gCurCase->colList, gCurCase->autoCreateTbl); + } + + beginUs = taosGetTimestampUs(); + + stmt = st_stmt2_init(taos, gCurCase->stbInsert); + if (!stmt) { + printf("!!!st_stmt2_init failed, error:%s\n", st_stmt2_error(stmt)); + exit(1); + } + + (*gCurCase->runFn)(stmt, taos); + + (void)st_stmt2_close(stmt); + + endUs = taosGetTimestampUs(); + totalUs += (endUs - beginUs); + + prepareCheckResult(taos, silent); + + cfg = cfgBk; + } + + if (!silent) { + printf("* Case %d - [%s]%s [AvgTime:%.3fms] End *\n", caseRunIdx, gCaseCtrl.caseCatalog, gCurCase->caseDesc, + ((double)totalUs) / 1000 / gCurCase->runTimes); + } + + return 0; +} + +void *runCaseList(TAOS *taos) { + static int32_t caseRunIdx = 0; + static int32_t caseRunNum = 0; + int32_t caseNum = 0; + int32_t caseIdx = (gCaseCtrl.caseIdx >= 0) ? gCaseCtrl.caseIdx : 0; + + for (int32_t i = caseIdx; i < sizeof(gCase) / sizeof(gCase[0]); ++i) { + if (gCaseCtrl.caseNum > 0 && caseNum >= gCaseCtrl.caseNum) { + break; + } + + if (gCaseCtrl.caseRunNum > 0 && caseRunNum >= gCaseCtrl.caseRunNum) { + break; + } + + if (gCaseCtrl.caseRunIdx >= 0 && caseRunIdx < gCaseCtrl.caseRunIdx) { + caseRunIdx++; + continue; + } + + if (runCase(taos, i, caseRunIdx, false)) { + continue; + } + + caseRunIdx++; + caseNum++; + caseRunNum++; + } + + return NULL; +} + +void runAll(TAOS *taos) { + strcpy(gCaseCtrl.caseCatalog, "Default Test"); + printf("%s Begin\n", gCaseCtrl.caseCatalog); + runCaseList(taos); + +#if 1 + strcpy(gCaseCtrl.caseCatalog, "Micro DB precision Test"); + printf("%s Begin\n", gCaseCtrl.caseCatalog); + gCaseCtrl.precision = TIME_PRECISION_MICRO; + runCaseList(taos); + gCaseCtrl.precision = TIME_PRECISION_MILLI; + + strcpy(gCaseCtrl.caseCatalog, "Nano DB precision Test"); + printf("%s Begin\n", gCaseCtrl.caseCatalog); + gCaseCtrl.precision = TIME_PRECISION_NANO; + runCaseList(taos); + gCaseCtrl.precision = TIME_PRECISION_MILLI; + + strcpy(gCaseCtrl.caseCatalog, "Auto Create Table Test"); + gCaseCtrl.autoCreateTbl = true; + printf("%s Begin\n", gCaseCtrl.caseCatalog); + runCaseList(taos); + gCaseCtrl.autoCreateTbl = false; + + strcpy(gCaseCtrl.caseCatalog, "Null Test"); + printf("%s Begin\n", gCaseCtrl.caseCatalog); + gCaseCtrl.bindNullNum = 1; + runCaseList(taos); + gCaseCtrl.bindNullNum = 0; + + strcpy(gCaseCtrl.caseCatalog, "Bind Row Test"); + printf("%s Begin\n", gCaseCtrl.caseCatalog); + gCaseCtrl.bindRowNum = 1; + runCaseList(taos); + gCaseCtrl.bindRowNum = 0; + + strcpy(gCaseCtrl.caseCatalog, "Row Num Test"); + printf("%s Begin\n", gCaseCtrl.caseCatalog); + gCaseCtrl.rowNum = 1000; + gCaseCtrl.printRes = false; + runCaseList(taos); + gCaseCtrl.rowNum = 0; + gCaseCtrl.printRes = true; + + strcpy(gCaseCtrl.caseCatalog, "Runtimes Test"); + printf("%s Begin\n", gCaseCtrl.caseCatalog); + gCaseCtrl.runTimes = 2; + runCaseList(taos); + gCaseCtrl.runTimes = 0; + + strcpy(gCaseCtrl.caseCatalog, "Check Param Test"); + printf("%s Begin\n", gCaseCtrl.caseCatalog); + gCaseCtrl.checkParamNum = true; + runCaseList(taos); + gCaseCtrl.checkParamNum = false; + + strcpy(gCaseCtrl.caseCatalog, "Bind Col Num Test"); + printf("%s Begin\n", gCaseCtrl.caseCatalog); + gCaseCtrl.bindColNum = 6; + runCaseList(taos); + gCaseCtrl.bindColNum = 0; + +#endif + + /* + strcpy(gCaseCtrl.caseCatalog, "Bind Col Type Test"); + printf("%s Begin\n", gCaseCtrl.caseCatalog); + gCaseCtrl.bindColTypeNum = tListLen(bindColTypeList); + gCaseCtrl.bindColTypeList = bindColTypeList; + runCaseList(taos); + */ + + printf("All Test End\n"); +} + +int main(int argc, char *argv[]) { + TAOS *taos = NULL; + + srand((unsigned int)time(NULL)); + + // connect to server + if (argc < 2) { + printf("please input server ip \n"); + return 0; + } + + taos = taos_connect(argv[1], "root", "taosdata", NULL, 0); + if (taos == NULL) { + printf("failed to connect to db, reason:%s\n", taos_errstr(taos)); + exit(1); + } + + runAll(taos); + + taos_close(taos); + + return 0; +} From 26a28c9474de052424ff6cfff7389503d657eb9f Mon Sep 17 00:00:00 2001 From: Minglei Jin Date: Fri, 6 Sep 2024 16:18:02 +0800 Subject: [PATCH 22/23] stmt2 example --- tests/script/api/stmt2.c | 323 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 323 insertions(+) create mode 100644 tests/script/api/stmt2.c diff --git a/tests/script/api/stmt2.c b/tests/script/api/stmt2.c new file mode 100644 index 0000000000..82537905dc --- /dev/null +++ b/tests/script/api/stmt2.c @@ -0,0 +1,323 @@ +// sample code to verify all TDengine API +// to compile: gcc -o apitest apitest.c -ltaos + +#include +#include +#include +#include +#include "taos.h" +static int64_t count = 10000; + +int64_t genReqid() { + count += 100; + return count; +} + +void stmtAsyncQueryCb(void* param, TAOS_RES* pRes, int code) { + int affected_rows = taos_affected_rows(pRes); + return; + /* + SSP_CB_PARAM* qParam = (SSP_CB_PARAM*)param; + if (code == 0 && pRes) { + if (qParam->fetch) { + taos_fetch_rows_a(pRes, sqAsyncFetchCb, param); + } else { + if (qParam->free) { + taos_free_result(pRes); + } + *qParam->end = 1; + } + } else { + sqError("select", taos_errstr(pRes)); + *qParam->end = 1; + taos_free_result(pRes); + } + */ +} + +void veriry_stmt(TAOS* taos) { + TAOS_RES* result = taos_query(taos, "drop database if exists test;"); + taos_free_result(result); + usleep(100000); + result = taos_query(taos, "create database test;"); + + int code = taos_errno(result); + if (code != 0) { + printf("\033[31mfailed to create database, reason:%s\033[0m\n", taos_errstr(result)); + taos_free_result(result); + return; + } + taos_free_result(result); + + usleep(100000); + taos_select_db(taos, "test"); + + // create table + /* + const char* sql = + "create table m1 (ts timestamp, b bool, v1 tinyint, v2 smallint, v4 int, v8 bigint, f4 float, f8 double, bin " + "binary(40), blob nchar(10))"; + */ + const char* sql = + "create table m1 (ts timestamp, b bool, v1 tinyint, v2 smallint, v4 int, v8 bigint, f4 float, f8 double, blob2 " + "nchar(10), blob nchar(10))"; + result = taos_query(taos, sql); + code = taos_errno(result); + if (code != 0) { + printf("\033[31mfailed to create table, reason:%s\033[0m\n", taos_errstr(result)); + taos_free_result(result); + return; + } + taos_free_result(result); + + // insert 10 records + struct { + int64_t ts[10]; + int8_t b[10]; + int8_t v1[10]; + int16_t v2[10]; + int32_t v4[10]; + int64_t v8[10]; + float f4[10]; + double f8[10]; + char bin[10][40]; + char blob[10][80]; + char blob2[10][80]; + } v; + + int32_t* t8_len = malloc(sizeof(int32_t) * 10); + int32_t* t16_len = malloc(sizeof(int32_t) * 10); + int32_t* t32_len = malloc(sizeof(int32_t) * 10); + int32_t* t64_len = malloc(sizeof(int32_t) * 10); + int32_t* float_len = malloc(sizeof(int32_t) * 10); + int32_t* double_len = malloc(sizeof(int32_t) * 10); + int32_t* bin_len = malloc(sizeof(int32_t) * 10); + int32_t* blob_len = malloc(sizeof(int32_t) * 10); + int32_t* blob_len2 = malloc(sizeof(int32_t) * 10); + +#include "time.h" + clock_t start, end; + TAOS_STMT2_OPTION option = {0, true, true, stmtAsyncQueryCb, NULL}; + + start = clock(); + TAOS_STMT2* stmt = taos_stmt2_init(taos, &option); + end = clock(); + printf("init time:%f\n", (double)(end - start) / CLOCKS_PER_SEC); + // TAOS_MULTI_BIND params[10]; + TAOS_STMT2_BIND params[10]; + char is_null[10] = {0}; + + params[0].buffer_type = TSDB_DATA_TYPE_TIMESTAMP; + // params[0].buffer_length = sizeof(v.ts[0]); + params[0].buffer = v.ts; + params[0].length = t64_len; + params[0].is_null = is_null; + params[0].num = 10; + + params[1].buffer_type = TSDB_DATA_TYPE_BOOL; + // params[1].buffer_length = sizeof(v.b[0]); + params[1].buffer = v.b; + params[1].length = t8_len; + params[1].is_null = is_null; + params[1].num = 10; + + params[2].buffer_type = TSDB_DATA_TYPE_TINYINT; + // params[2].buffer_length = sizeof(v.v1[0]); + params[2].buffer = v.v1; + params[2].length = t8_len; + params[2].is_null = is_null; + params[2].num = 10; + + params[3].buffer_type = TSDB_DATA_TYPE_SMALLINT; + // params[3].buffer_length = sizeof(v.v2[0]); + params[3].buffer = v.v2; + params[3].length = t16_len; + params[3].is_null = is_null; + params[3].num = 10; + + params[4].buffer_type = TSDB_DATA_TYPE_INT; + // params[4].buffer_length = sizeof(v.v4[0]); + params[4].buffer = v.v4; + params[4].length = t32_len; + params[4].is_null = is_null; + params[4].num = 10; + + params[5].buffer_type = TSDB_DATA_TYPE_BIGINT; + // params[5].buffer_length = sizeof(v.v8[0]); + params[5].buffer = v.v8; + params[5].length = t64_len; + params[5].is_null = is_null; + params[5].num = 10; + + params[6].buffer_type = TSDB_DATA_TYPE_FLOAT; + // params[6].buffer_length = sizeof(v.f4[0]); + params[6].buffer = v.f4; + params[6].length = float_len; + params[6].is_null = is_null; + params[6].num = 10; + + params[7].buffer_type = TSDB_DATA_TYPE_DOUBLE; + // params[7].buffer_length = sizeof(v.f8[0]); + params[7].buffer = v.f8; + params[7].length = double_len; + params[7].is_null = is_null; + params[7].num = 10; + /* + params[8].buffer_type = TSDB_DATA_TYPE_BINARY; + //params[8].buffer_length = sizeof(v.bin[0]); + params[8].buffer = v.bin; + params[8].length = bin_len; + params[8].is_null = is_null; + params[8].num = 10; + */ + params[8].buffer_type = TSDB_DATA_TYPE_NCHAR; + // params[8].buffer_length = sizeof(v.blob2[0]); + params[8].buffer = v.blob2; + params[8].length = blob_len2; + params[8].is_null = is_null; + params[8].num = 10; + + params[9].buffer_type = TSDB_DATA_TYPE_NCHAR; + // params[9].buffer_length = sizeof(v.blob[0]); + params[9].buffer = v.blob; + params[9].length = blob_len; + params[9].is_null = is_null; + params[9].num = 10; + + sql = "insert into ? (ts, b, v1, v2, v4, v8, f4, f8, blob2, blob) values(?,?,?,?,?,?,?,?,?,?)"; + start = clock(); + code = taos_stmt2_prepare(stmt, sql, 0); + end = clock(); + printf("prepare time:%f\n", (double)(end - start) / CLOCKS_PER_SEC); + if (code != 0) { + printf("\033[31mfailed to execute taos_stmt_prepare. error:%s\033[0m\n", taos_stmt_errstr(stmt)); + taos_stmt_close(stmt); + return; + } + /* + code = taos_stmt_set_tbname(stmt, "m1"); + if (code != 0) { + printf("\033[31mfailed to execute taos_stmt_prepare. error:%s\033[0m\n", taos_stmt_errstr(stmt)); + taos_stmt_close(stmt); + return; + } + */ + + int64_t ts = 1591060628000; + for (int i = 0; i < 10; ++i) { + is_null[i] = 0; + + v.ts[i] = ts++; + v.b[i] = (int8_t)i % 2; + v.v1[i] = (int8_t)i; + v.v2[i] = (int16_t)(i * 2); + v.v4[i] = (int32_t)(i * 4); + v.v8[i] = (int64_t)(i * 8); + v.f4[i] = (float)(i * 40); + v.f8[i] = (double)(i * 80); + for (int j = 0; j < sizeof(v.bin[0]); ++j) { + v.bin[i][j] = (char)(i + '0'); + } + strcpy(v.blob2[i], "一二三四五六七十九八"); + strcpy(v.blob[i], "一二三四五六七八九十"); + + t8_len[i] = sizeof(int8_t); + t16_len[i] = sizeof(int16_t); + t32_len[i] = sizeof(int32_t); + t64_len[i] = sizeof(int64_t); + float_len[i] = sizeof(float); + double_len[i] = sizeof(double); + bin_len[i] = sizeof(v.bin[0]); + blob_len[i] = (int32_t)strlen(v.blob[i]); + blob_len2[i] = (int32_t)strlen(v.blob2[i]); + } + + char* tbname = "m1"; + TAOS_STMT2_BIND* bind_cols[1] = {¶ms[0]}; + TAOS_STMT2_BINDV bindv = {1, &tbname, NULL, &bind_cols[0]}; + start = clock(); + // taos_stmt2_bind_param(stmt, "m1", NULL, params, -1); + taos_stmt2_bind_param(stmt, &bindv, -1); + end = clock(); + printf("bind time:%f\n", (double)(end - start) / CLOCKS_PER_SEC); + // taos_stmt_bind_param_batch(stmt, params); + // taos_stmt_add_batch(stmt); + /* + int param_count = -1; + code = taos_stmt2_param_count(stmt, ¶m_count); + if (code != 0) { + printf("\033[31mfailed to execute taos_stmt_param_count. error:%s\033[0m\n", taos_stmt_errstr(stmt)); + taos_stmt_close(stmt); + return; + } + printf("param_count: %d\n", param_count); + */ + TAOS_FIELD_E* fields = NULL; + int field_count = -1; + start = clock(); + code = taos_stmt2_get_fields(stmt, TAOS_FIELD_COL, &field_count, NULL); + end = clock(); + printf("get fields time:%f\n", (double)(end - start) / CLOCKS_PER_SEC); + if (code != 0) { + printf("\033[31mfailed to execute taos_stmt_param_count. error:%s\033[0m\n", taos_stmt_errstr(stmt)); + taos_stmt_close(stmt); + return; + } + printf("col field_count: %d\n", field_count); + start = clock(); + taos_stmt2_free_fields(stmt, fields); + end = clock(); + printf("free time:%f\n", (double)(end - start) / CLOCKS_PER_SEC); + /* + code = taos_stmt2_get_fields(stmt, TAOS_FIELD_TAG, &field_count, &fields); + if (code != 0) { + printf("\033[31mfailed to execute taos_stmt_param_count. error:%s\033[0m\n", taos_stmt_errstr(stmt)); + taos_stmt_close(stmt); + return; + } + printf("tag field_count: %d\n", field_count); + taos_stmt2_free_fields(stmt, fields); + */ + // if (taos_stmt_execute(stmt) != 0) { + start = clock(); + // if (taos_stmt2_exec(stmt, NULL, stmtAsyncQueryCb, NULL) != 0) { + if (taos_stmt2_exec(stmt, NULL) != 0) { + printf("\033[31mfailed to execute insert statement.error:%s\033[0m\n", taos_stmt_errstr(stmt)); + taos_stmt2_close(stmt); + return; + } + end = clock(); + printf("exec time:%f\n", (double)(end - start) / CLOCKS_PER_SEC); + + taos_stmt2_close(stmt); + + free(t8_len); + free(t16_len); + free(t32_len); + free(t64_len); + free(float_len); + free(double_len); + free(bin_len); + free(blob_len); + free(blob_len2); +} + +int main(int argc, char* argv[]) { + const char* host = "127.0.0.1"; + const char* user = "root"; + const char* passwd = "taosdata"; + + taos_options(TSDB_OPTION_TIMEZONE, "GMT-8"); + TAOS* taos = taos_connect(host, user, passwd, "", 0); + if (taos == NULL) { + printf("\033[31mfailed to connect to db, reason:%s\033[0m\n", taos_errstr(taos)); + exit(1); + } + + printf("********* verify stmt query **********\n"); + veriry_stmt(taos); + + printf("done\n"); + taos_close(taos); + taos_cleanup(); +} From 65018eec566f0f3ee33e0e0194e621204636ef85 Mon Sep 17 00:00:00 2001 From: Minglei Jin Date: Fri, 6 Sep 2024 17:03:39 +0800 Subject: [PATCH 23/23] stmt crash test case --- tests/script/api/stmt-crash.c | 289 ++++++++++++++++++++++++++++++++++ 1 file changed, 289 insertions(+) create mode 100644 tests/script/api/stmt-crash.c diff --git a/tests/script/api/stmt-crash.c b/tests/script/api/stmt-crash.c new file mode 100644 index 0000000000..310e7c4910 --- /dev/null +++ b/tests/script/api/stmt-crash.c @@ -0,0 +1,289 @@ +// TAOS standard API example. The same syntax as MySQL, but only a subet +// to compile: gcc -o prepare prepare.c -ltaos + +#include +#include +#include +#include "taos.h" + +void taosMsleep(int mseconds); + +int main(int argc, char *argv[]) { + TAOS *taos; + TAOS_RES *result; + int code; + TAOS_STMT *stmt; + + // connect to server + if (argc < 2) { + printf("please input server ip \n"); + return 0; + } + + // taos = taos_connect(argv[1], "root", "Taosdata.1234", NULL, 0); + taos = taos_connect(argv[1], "root", "taosdata", NULL, 0); + if (taos == NULL) { + printf("failed to connect to db, reason:%s\n", taos_errstr(taos)); + exit(1); + } + + result = taos_query(taos, "drop database demo"); + taos_free_result(result); + + result = taos_query(taos, "create database demo"); + code = taos_errno(result); + if (code != 0) { + printf("failed to create database, reason:%s\n", taos_errstr(result)); + taos_free_result(result); + exit(1); + } + taos_free_result(result); + + result = taos_query(taos, "use demo"); + taos_free_result(result); + + // create table + const char *sql = + "create stable s1 (ts timestamp, b bool, v1 tinyint, v2 smallint, v4 int, v8 bigint, f4 float, f8 double, bin " + "binary(40), blob nchar(10), varbin varbinary(16)) tags(groupId INT);"; + result = taos_query(taos, sql); + code = taos_errno(result); + if (code != 0) { + printf("failed to create table, reason:%s\n", taos_errstr(result)); + taos_free_result(result); + exit(1); + } + taos_free_result(result); + + // sleep for one second to make sure table is created on data node + // taosMsleep(1000); + + // insert 10 records + struct { + int64_t ts; + int8_t b; + int8_t v1; + int16_t v2; + int32_t v4; + int64_t v8; + float f4; + double f8; + char bin[40]; + char blob[80]; + int8_t varbin[16]; + } v = {0}; + + int32_t boolLen = sizeof(int8_t); + int32_t sintLen = sizeof(int16_t); + int32_t intLen = sizeof(int32_t); + int32_t bintLen = sizeof(int64_t); + int32_t floatLen = sizeof(float); + int32_t doubleLen = sizeof(double); + int32_t binLen = sizeof(v.bin); + int32_t ncharLen = 30; + + stmt = taos_stmt_init(taos); + TAOS_MULTI_BIND params[11]; + params[0].buffer_type = TSDB_DATA_TYPE_TIMESTAMP; + params[0].buffer_length = sizeof(v.ts); + params[0].buffer = &v.ts; + params[0].length = &bintLen; + params[0].is_null = NULL; + params[0].num = 1; + + params[1].buffer_type = TSDB_DATA_TYPE_BOOL; + params[1].buffer_length = sizeof(v.b); + params[1].buffer = &v.b; + params[1].length = &boolLen; + params[1].is_null = NULL; + params[1].num = 1; + + params[2].buffer_type = TSDB_DATA_TYPE_TINYINT; + params[2].buffer_length = sizeof(v.v1); + params[2].buffer = &v.v1; + params[2].length = &boolLen; + params[2].is_null = NULL; + params[2].num = 1; + + params[3].buffer_type = TSDB_DATA_TYPE_SMALLINT; + params[3].buffer_length = sizeof(v.v2); + params[3].buffer = &v.v2; + params[3].length = &sintLen; + params[3].is_null = NULL; + params[3].num = 1; + + params[4].buffer_type = TSDB_DATA_TYPE_INT; + params[4].buffer_length = sizeof(v.v4); + params[4].buffer = &v.v4; + params[4].length = &intLen; + params[4].is_null = NULL; + params[4].num = 1; + + params[5].buffer_type = TSDB_DATA_TYPE_BIGINT; + params[5].buffer_length = sizeof(v.v8); + params[5].buffer = &v.v8; + params[5].length = &bintLen; + params[5].is_null = NULL; + params[5].num = 1; + + params[6].buffer_type = TSDB_DATA_TYPE_FLOAT; + params[6].buffer_length = sizeof(v.f4); + params[6].buffer = &v.f4; + params[6].length = &floatLen; + params[6].is_null = NULL; + params[6].num = 1; + + params[7].buffer_type = TSDB_DATA_TYPE_DOUBLE; + params[7].buffer_length = sizeof(v.f8); + params[7].buffer = &v.f8; + params[7].length = &doubleLen; + params[7].is_null = NULL; + params[7].num = 1; + + params[8].buffer_type = TSDB_DATA_TYPE_BINARY; + params[8].buffer_length = sizeof(v.bin); + params[8].buffer = v.bin; + params[8].length = &binLen; + params[8].is_null = NULL; + params[8].num = 1; + + strcpy(v.blob, "一二三四五六七八九十"); + params[9].buffer_type = TSDB_DATA_TYPE_NCHAR; + params[9].buffer_length = sizeof(v.blob); + params[9].buffer = v.blob; + params[9].length = &ncharLen; + params[9].is_null = NULL; + params[9].num = 1; + + int8_t tmp[16] = {'a', 0, 1, 13, '1'}; + int32_t vbinLen = 5; + memcpy(v.varbin, tmp, sizeof(v.varbin)); + params[10].buffer_type = TSDB_DATA_TYPE_VARBINARY; + params[10].buffer_length = sizeof(v.varbin); + params[10].buffer = v.varbin; + params[10].length = &vbinLen; + params[10].is_null = NULL; + params[10].num = 1; + + TAOS_MULTI_BIND tags[1]; + + int32_t id1 = 0; + + tags[0].buffer_type = TSDB_DATA_TYPE_INT; + tags[0].buffer_length = sizeof(int); + tags[0].buffer = &id1; + tags[0].length = NULL; + tags[0].is_null = NULL; + tags[0].num = 1; + + char is_null = 1; + + sql = "insert into ? using s1 tags(?) values(?,?,?,?,?,?,?,?,?,?,?)"; + code = taos_stmt_prepare(stmt, sql, 0); + if (code != 0) { + printf("failed to execute taos_stmt_prepare. code:0x%x\n", code); + } + + if (code != 0) { + printf("\033[31mfailed to execute taos_stmt_prepare. error:%s\033[0m\n", taos_stmt_errstr(stmt)); + taos_stmt_close(stmt); + exit(EXIT_FAILURE); + } + code = taos_stmt_set_tbname_tags(stmt, "m1", tags); + v.ts = 1591060628000; + v.b = (int8_t)0 % 2; + v.v1 = (int8_t)0; + v.v2 = (int16_t)(0 * 2); + v.v4 = (int32_t)(0 * 4); + v.v8 = (int64_t)(0 * 8); + v.f4 = (float)(0 * 40); + v.f8 = (double)(0 * 80); + for (int j = 0; j < sizeof(v.bin); ++j) { + v.bin[j] = (char)(0 + '0'); + } + taos_stmt_bind_param(stmt, params); + taos_stmt_add_batch(stmt); + + code = taos_stmt_set_tbname_tags(stmt, "m2", tags); + v.ts = 1591060628000 + 1; + v.b = (int8_t)1 % 2; + v.v1 = (int8_t)1; + v.v2 = (int16_t)(1 * 2); + v.v4 = (int32_t)(1 * 4); + v.v8 = (int64_t)(1 * 8); + v.f4 = (float)(1 * 40); + v.f8 = (double)(1 * 80); + for (int j = 0; j < sizeof(v.bin); ++j) { + v.bin[j] = (char)(1 + '0'); + } + taos_stmt_bind_param(stmt, params); + taos_stmt_add_batch(stmt); + /* + for (int i = 0; i < 10; ++i) { + if(i % 2 != 0) { + code = taos_stmt_set_tbname(stmt, "m1"); + } else { + code = taos_stmt_set_tbname(stmt, "m2"); + } + v.ts += 1; + for (int j = 1; j < 11; ++j) { + params[j].is_null = ((i == j) ? &is_null : 0); + } + v.b = (int8_t)i % 2; + v.v1 = (int8_t)i; + v.v2 = (int16_t)(i * 2); + v.v4 = (int32_t)(i * 4); + v.v8 = (int64_t)(i * 8); + v.f4 = (float)(i * 40); + v.f8 = (double)(i * 80); + for (int j = 0; j < sizeof(v.bin); ++j) { + v.bin[j] = (char)(i + '0'); + } + + taos_stmt_bind_param(stmt, params); + taos_stmt_add_batch(stmt); + } + */ + // printf("taos multi bind num:%d\n", params[1].num); + if (taos_stmt_execute(stmt) != 0) { + printf("failed to execute insert statement.\n"); + exit(1); + } + taos_stmt_close(stmt); + + // query the records + stmt = taos_stmt_init(taos); + taos_stmt_prepare(stmt, "SELECT * FROM m1 WHERE v1 > ? AND v2 < ?", 0); + v.v1 = 5; + v.v2 = 15; + taos_stmt_bind_param(stmt, params + 2); + if (taos_stmt_execute(stmt) != 0) { + printf("failed to execute select statement.\n"); + exit(1); + } + + result = taos_stmt_use_result(stmt); + + TAOS_ROW row; + int rows = 0; + int num_fields = taos_num_fields(result); + TAOS_FIELD *fields = taos_fetch_fields(result); + + // fetch the records row by row + while ((row = taos_fetch_row(result))) { + char temp[256] = {0}; + rows++; + taos_print_row(temp, row, fields, num_fields); + printf("%s\n", temp); + } + if (rows == 2) { + printf("two rows are fetched as expectation\n"); + } else { + printf("expect two rows, but %d rows are fetched\n", rows); + } + + // taos_free_result(result); + taos_stmt_close(stmt); + + return 0; +}