Merge branch '3.0' into feature/TD-14481-3.0
This commit is contained in:
commit
3b424ad1cc
20
Jenkinsfile2
20
Jenkinsfile2
|
@ -88,6 +88,12 @@ def pre_test(){
|
||||||
cmake .. > /dev/null
|
cmake .. > /dev/null
|
||||||
make -j4> /dev/null
|
make -j4> /dev/null
|
||||||
'''
|
'''
|
||||||
|
sh'''
|
||||||
|
cd ${WKPY}
|
||||||
|
git reset --hard
|
||||||
|
git pull
|
||||||
|
pip3 install .
|
||||||
|
'''
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -97,6 +103,7 @@ pipeline {
|
||||||
environment{
|
environment{
|
||||||
WK = '/var/lib/jenkins/workspace/TDinternal'
|
WK = '/var/lib/jenkins/workspace/TDinternal'
|
||||||
WKC= '/var/lib/jenkins/workspace/TDengine'
|
WKC= '/var/lib/jenkins/workspace/TDengine'
|
||||||
|
WKPY= '/var/lib/jenkins/workspace/taos-connector-python'
|
||||||
}
|
}
|
||||||
stages {
|
stages {
|
||||||
stage('pre_build'){
|
stage('pre_build'){
|
||||||
|
@ -113,13 +120,18 @@ pipeline {
|
||||||
timeout(time: 45, unit: 'MINUTES'){
|
timeout(time: 45, unit: 'MINUTES'){
|
||||||
pre_test()
|
pre_test()
|
||||||
sh'''
|
sh'''
|
||||||
cd ${WKC}/tests
|
|
||||||
./test-all.sh b1fq
|
|
||||||
'''
|
|
||||||
sh'''
|
|
||||||
cd ${WKC}/debug
|
cd ${WKC}/debug
|
||||||
ctest
|
ctest
|
||||||
'''
|
'''
|
||||||
|
sh'''
|
||||||
|
export LD_LIBRARY_PATH=${WKC}/debug/build/lib
|
||||||
|
cd ${WKC}/tests/system-test
|
||||||
|
./fulltest.sh
|
||||||
|
'''
|
||||||
|
sh'''
|
||||||
|
cd ${WKC}/tests
|
||||||
|
./test-all.sh b1fq
|
||||||
|
'''
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
cmake_minimum_required(VERSION 3.16)
|
cmake_minimum_required(VERSION 3.16)
|
||||||
|
|
||||||
set(CMAKE_VERBOSE_MAKEFILE ON)
|
set(CMAKE_VERBOSE_MAKEFILE OFF)
|
||||||
|
|
||||||
#set output directory
|
#set output directory
|
||||||
SET(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/build/lib)
|
SET(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/build/lib)
|
||||||
|
|
|
@ -45,7 +45,7 @@ typedef struct {
|
||||||
|
|
||||||
void taos_insert_call_back(void *param, TAOS_RES *tres, int code);
|
void taos_insert_call_back(void *param, TAOS_RES *tres, int code);
|
||||||
void taos_select_call_back(void *param, TAOS_RES *tres, int code);
|
void taos_select_call_back(void *param, TAOS_RES *tres, int code);
|
||||||
void taos_error(TAOS *taos);
|
void shellPrintError(TAOS *taos);
|
||||||
|
|
||||||
static void queryDB(TAOS *taos, char *command) {
|
static void queryDB(TAOS *taos, char *command) {
|
||||||
int i;
|
int i;
|
||||||
|
@ -102,7 +102,7 @@ int main(int argc, char *argv[])
|
||||||
|
|
||||||
taos = taos_connect(argv[1], "root", "taosdata", NULL, 0);
|
taos = taos_connect(argv[1], "root", "taosdata", NULL, 0);
|
||||||
if (taos == NULL)
|
if (taos == NULL)
|
||||||
taos_error(taos);
|
shellPrintError(taos);
|
||||||
|
|
||||||
printf("success to connect to server\n");
|
printf("success to connect to server\n");
|
||||||
|
|
||||||
|
@ -193,7 +193,7 @@ int main(int argc, char *argv[])
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void taos_error(TAOS *con)
|
void shellPrintError(TAOS *con)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "TDengine error: %s\n", taos_errstr(con));
|
fprintf(stderr, "TDengine error: %s\n", taos_errstr(con));
|
||||||
taos_close(con);
|
taos_close(con);
|
||||||
|
|
|
@ -74,8 +74,8 @@ static FORCE_INLINE bool colDataIsNull_s(const SColumnInfoData* pColumnInfoData,
|
||||||
}
|
}
|
||||||
char *data = colDataGetVarData(pColumnInfoData, row);
|
char *data = colDataGetVarData(pColumnInfoData, row);
|
||||||
return (*data == TSDB_DATA_TYPE_NULL);
|
return (*data == TSDB_DATA_TYPE_NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!pColumnInfoData->hasNull) {
|
if (!pColumnInfoData->hasNull) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,13 +34,9 @@ extern int32_t tsVersion;
|
||||||
extern int32_t tsStatusInterval;
|
extern int32_t tsStatusInterval;
|
||||||
|
|
||||||
// common
|
// common
|
||||||
extern int32_t tsRpcTimer;
|
|
||||||
extern int32_t tsRpcMaxTime;
|
|
||||||
extern bool tsRpcForceTcp; // all commands go to tcp protocol if this is enabled
|
|
||||||
extern int32_t tsMaxConnections;
|
extern int32_t tsMaxConnections;
|
||||||
extern int32_t tsMaxShellConns;
|
extern int32_t tsMaxShellConns;
|
||||||
extern int32_t tsShellActivityTimer;
|
extern int32_t tsShellActivityTimer;
|
||||||
extern int32_t tsMaxTmrCtrl;
|
|
||||||
extern int32_t tsCompressMsgSize;
|
extern int32_t tsCompressMsgSize;
|
||||||
extern int32_t tsCompressColData;
|
extern int32_t tsCompressColData;
|
||||||
extern int32_t tsMaxNumOfDistinctResults;
|
extern int32_t tsMaxNumOfDistinctResults;
|
||||||
|
@ -98,9 +94,6 @@ extern bool tsDeadLockKillQuery;
|
||||||
extern int32_t tsQueryPolicy;
|
extern int32_t tsQueryPolicy;
|
||||||
|
|
||||||
// client
|
// client
|
||||||
extern int32_t tsMaxWildCardsLen;
|
|
||||||
extern int32_t tsMaxRegexStringLen;
|
|
||||||
extern int32_t tsMaxNumOfOrderedResults;
|
|
||||||
extern int32_t tsMinSlidingTime;
|
extern int32_t tsMinSlidingTime;
|
||||||
extern int32_t tsMinIntervalTime;
|
extern int32_t tsMinIntervalTime;
|
||||||
extern int32_t tsMaxStreamComputDelay;
|
extern int32_t tsMaxStreamComputDelay;
|
||||||
|
|
|
@ -85,6 +85,7 @@ enum {
|
||||||
TD_DEF_MSG_TYPE(TDMT_DND_DROP_VNODE, "dnode-drop-vnode", NULL, NULL)
|
TD_DEF_MSG_TYPE(TDMT_DND_DROP_VNODE, "dnode-drop-vnode", NULL, NULL)
|
||||||
TD_DEF_MSG_TYPE(TDMT_DND_CONFIG_DNODE, "dnode-config-dnode", NULL, NULL)
|
TD_DEF_MSG_TYPE(TDMT_DND_CONFIG_DNODE, "dnode-config-dnode", NULL, NULL)
|
||||||
TD_DEF_MSG_TYPE(TDMT_DND_SERVER_STATUS, "dnode-server-status", NULL, NULL)
|
TD_DEF_MSG_TYPE(TDMT_DND_SERVER_STATUS, "dnode-server-status", NULL, NULL)
|
||||||
|
TD_DEF_MSG_TYPE(TDMT_DND_NET_TEST, "dnode-net-test", NULL, NULL)
|
||||||
|
|
||||||
// Requests handled by MNODE
|
// Requests handled by MNODE
|
||||||
TD_NEW_MSG_SEG(TDMT_MND_MSG)
|
TD_NEW_MSG_SEG(TDMT_MND_MSG)
|
||||||
|
|
|
@ -46,7 +46,7 @@ typedef struct SScanLogicNode {
|
||||||
struct STableMeta* pMeta;
|
struct STableMeta* pMeta;
|
||||||
SVgroupsInfo* pVgroupList;
|
SVgroupsInfo* pVgroupList;
|
||||||
EScanType scanType;
|
EScanType scanType;
|
||||||
uint8_t scanFlag; // denotes reversed scan of data or not
|
uint8_t scanSeq[2]; // first is scan count, and second is reverse scan count
|
||||||
STimeWindow scanRange;
|
STimeWindow scanRange;
|
||||||
SName tableName;
|
SName tableName;
|
||||||
bool showRewrite;
|
bool showRewrite;
|
||||||
|
@ -189,9 +189,6 @@ typedef struct SScanPhysiNode {
|
||||||
SNodeList* pScanCols;
|
SNodeList* pScanCols;
|
||||||
uint64_t uid; // unique id of the table
|
uint64_t uid; // unique id of the table
|
||||||
int8_t tableType;
|
int8_t tableType;
|
||||||
int32_t order; // scan order: TSDB_ORDER_ASC|TSDB_ORDER_DESC
|
|
||||||
int32_t count; // repeat count
|
|
||||||
int32_t reverse; // reverse scan count
|
|
||||||
SName tableName;
|
SName tableName;
|
||||||
} SScanPhysiNode;
|
} SScanPhysiNode;
|
||||||
|
|
||||||
|
@ -207,7 +204,7 @@ typedef struct SSystemTableScanPhysiNode {
|
||||||
|
|
||||||
typedef struct STableScanPhysiNode {
|
typedef struct STableScanPhysiNode {
|
||||||
SScanPhysiNode scan;
|
SScanPhysiNode scan;
|
||||||
uint8_t scanFlag; // denotes reversed scan of data or not
|
uint8_t scanSeq[2]; // first is scan count, and second is reverse scan count
|
||||||
STimeWindow scanRange;
|
STimeWindow scanRange;
|
||||||
double ratio;
|
double ratio;
|
||||||
int32_t dataRequired;
|
int32_t dataRequired;
|
||||||
|
|
|
@ -37,6 +37,8 @@ typedef struct SPlanContext {
|
||||||
bool isStmtQuery;
|
bool isStmtQuery;
|
||||||
void* pTransporter;
|
void* pTransporter;
|
||||||
struct SCatalog* pCatalog;
|
struct SCatalog* pCatalog;
|
||||||
|
char* pMsg;
|
||||||
|
int32_t msgLen;
|
||||||
} SPlanContext;
|
} SPlanContext;
|
||||||
|
|
||||||
// Create the physical plan for the query, according to the AST.
|
// Create the physical plan for the query, according to the AST.
|
||||||
|
|
|
@ -31,19 +31,19 @@ extern "C" {
|
||||||
|
|
||||||
typedef struct TdCmd *TdCmdPtr;
|
typedef struct TdCmd *TdCmdPtr;
|
||||||
|
|
||||||
TdCmdPtr taosOpenCmd(const char *cmd);
|
TdCmdPtr taosOpenCmd(const char* cmd);
|
||||||
int64_t taosGetLineCmd(TdCmdPtr pCmd, char ** __restrict ptrBuf);
|
int64_t taosGetLineCmd(TdCmdPtr pCmd, char** __restrict ptrBuf);
|
||||||
int32_t taosEOFCmd(TdCmdPtr pCmd);
|
int32_t taosEOFCmd(TdCmdPtr pCmd);
|
||||||
int64_t taosCloseCmd(TdCmdPtr *ppCmd);
|
int64_t taosCloseCmd(TdCmdPtr* ppCmd);
|
||||||
|
|
||||||
void* taosLoadDll(const char* filename);
|
void* taosLoadDll(const char* filename);
|
||||||
void* taosLoadSym(void* handle, char* name);
|
void* taosLoadSym(void* handle, char* name);
|
||||||
void taosCloseDll(void* handle);
|
void taosCloseDll(void* handle);
|
||||||
|
|
||||||
int32_t taosSetConsoleEcho(bool on);
|
int32_t taosSetConsoleEcho(bool on);
|
||||||
void setTerminalMode();
|
void taosSetTerminalMode();
|
||||||
int32_t getOldTerminalMode();
|
int32_t taosGetOldTerminalMode();
|
||||||
void resetTerminalMode();
|
void taosResetTerminalMode();
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|
|
@ -623,6 +623,7 @@ int32_t* taosGetErrno();
|
||||||
#define TSDB_CODE_PAR_INVALID_DAYS_VALUE TAOS_DEF_ERROR_CODE(0, 0x2636)
|
#define TSDB_CODE_PAR_INVALID_DAYS_VALUE TAOS_DEF_ERROR_CODE(0, 0x2636)
|
||||||
#define TSDB_CODE_PAR_OFFSET_LESS_ZERO TAOS_DEF_ERROR_CODE(0, 0x2637)
|
#define TSDB_CODE_PAR_OFFSET_LESS_ZERO TAOS_DEF_ERROR_CODE(0, 0x2637)
|
||||||
#define TSDB_CODE_PAR_SLIMIT_LEAK_PARTITION_BY TAOS_DEF_ERROR_CODE(0, 0x2638)
|
#define TSDB_CODE_PAR_SLIMIT_LEAK_PARTITION_BY TAOS_DEF_ERROR_CODE(0, 0x2638)
|
||||||
|
#define TSDB_CODE_PAR_INVALID_TOPIC_QUERY TAOS_DEF_ERROR_CODE(0, 0x2639)
|
||||||
|
|
||||||
//planner
|
//planner
|
||||||
#define TSDB_CODE_PLAN_INTERNAL_ERROR TAOS_DEF_ERROR_CODE(0, 0x2700)
|
#define TSDB_CODE_PLAN_INTERNAL_ERROR TAOS_DEF_ERROR_CODE(0, 0x2700)
|
||||||
|
|
|
@ -76,8 +76,6 @@ extern const int32_t TYPE_BYTES[15];
|
||||||
#define TSDB_DEFAULT_PASS "taosdata"
|
#define TSDB_DEFAULT_PASS "taosdata"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define SHELL_MAX_PASSWORD_LEN 20
|
|
||||||
|
|
||||||
#define TSDB_TRUE 1
|
#define TSDB_TRUE 1
|
||||||
#define TSDB_FALSE 0
|
#define TSDB_FALSE 0
|
||||||
#define TSDB_OK 0
|
#define TSDB_OK 0
|
||||||
|
|
|
@ -232,7 +232,9 @@ int32_t getPlan(SRequestObj* pRequest, SQuery* pQuery, SQueryPlan** pPlan, SArra
|
||||||
.mgmtEpSet = getEpSet_s(&pRequest->pTscObj->pAppInfo->mgmtEp),
|
.mgmtEpSet = getEpSet_s(&pRequest->pTscObj->pAppInfo->mgmtEp),
|
||||||
.pAstRoot = pQuery->pRoot,
|
.pAstRoot = pQuery->pRoot,
|
||||||
.showRewrite = pQuery->showRewrite,
|
.showRewrite = pQuery->showRewrite,
|
||||||
.pTransporter = pRequest->pTscObj->pAppInfo->pTransporter
|
.pTransporter = pRequest->pTscObj->pAppInfo->pTransporter,
|
||||||
|
.pMsg = pRequest->msgBuf,
|
||||||
|
.msgLen = ERROR_MSG_BUF_DEFAULT_SIZE
|
||||||
};
|
};
|
||||||
int32_t code = catalogGetHandle(pRequest->pTscObj->pAppInfo->clusterId, &cxt.pCatalog);
|
int32_t code = catalogGetHandle(pRequest->pTscObj->pAppInfo->clusterId, &cxt.pCatalog);
|
||||||
if (TSDB_CODE_SUCCESS == code) {
|
if (TSDB_CODE_SUCCESS == code) {
|
||||||
|
|
|
@ -32,13 +32,9 @@ int32_t tsVersion = 30000000;
|
||||||
int32_t tsStatusInterval = 1; // second
|
int32_t tsStatusInterval = 1; // second
|
||||||
|
|
||||||
// common
|
// common
|
||||||
int32_t tsRpcTimer = 300;
|
|
||||||
int32_t tsRpcMaxTime = 600; // seconds;
|
|
||||||
bool tsRpcForceTcp = true; // disable this, means query, show command use udp protocol as default
|
|
||||||
int32_t tsMaxShellConns = 50000;
|
int32_t tsMaxShellConns = 50000;
|
||||||
int32_t tsMaxConnections = 50000;
|
int32_t tsMaxConnections = 50000;
|
||||||
int32_t tsShellActivityTimer = 3; // second
|
int32_t tsShellActivityTimer = 3; // second
|
||||||
int32_t tsMaxBinaryDisplayWidth = 30;
|
|
||||||
bool tsEnableSlaveQuery = true;
|
bool tsEnableSlaveQuery = true;
|
||||||
bool tsPrintAuth = false;
|
bool tsPrintAuth = false;
|
||||||
|
|
||||||
|
@ -105,14 +101,6 @@ int32_t tsCompressColData = -1;
|
||||||
*/
|
*/
|
||||||
int32_t tsCompatibleModel = 1;
|
int32_t tsCompatibleModel = 1;
|
||||||
|
|
||||||
// client
|
|
||||||
int32_t tsMaxWildCardsLen = TSDB_PATTERN_STRING_DEFAULT_LEN;
|
|
||||||
int32_t tsMaxRegexStringLen = TSDB_REGEX_STRING_DEFAULT_LEN;
|
|
||||||
|
|
||||||
// the maximum number of results for projection query on super table that are returned from
|
|
||||||
// one virtual node, to order according to timestamp
|
|
||||||
int32_t tsMaxNumOfOrderedResults = 100000;
|
|
||||||
|
|
||||||
// 10 ms for sliding time, the value will changed in case of time precision changed
|
// 10 ms for sliding time, the value will changed in case of time precision changed
|
||||||
int32_t tsMinSlidingTime = 10;
|
int32_t tsMinSlidingTime = 10;
|
||||||
|
|
||||||
|
@ -314,19 +302,10 @@ static int32_t taosAddClientCfg(SConfig *pCfg) {
|
||||||
if (cfgAddInt32(pCfg, "serverPort", defaultServerPort, 1, 65056, 1) != 0) return -1;
|
if (cfgAddInt32(pCfg, "serverPort", defaultServerPort, 1, 65056, 1) != 0) return -1;
|
||||||
if (cfgAddDir(pCfg, "tempDir", tsTempDir, 1) != 0) return -1;
|
if (cfgAddDir(pCfg, "tempDir", tsTempDir, 1) != 0) return -1;
|
||||||
if (cfgAddFloat(pCfg, "minimalTempDirGB", 1.0f, 0.001f, 10000000, 1) != 0) return -1;
|
if (cfgAddFloat(pCfg, "minimalTempDirGB", 1.0f, 0.001f, 10000000, 1) != 0) return -1;
|
||||||
if (cfgAddInt32(pCfg, "maxTmrCtrl", tsMaxTmrCtrl, 8, 2048, 1) != 0) return -1;
|
|
||||||
if (cfgAddInt32(pCfg, "rpcTimer", tsRpcTimer, 100, 3000, 1) != 0) return -1;
|
|
||||||
if (cfgAddInt32(pCfg, "rpcMaxTime", tsRpcMaxTime, 100, 7200, 1) != 0) return -1;
|
|
||||||
if (cfgAddBool(pCfg, "rpcForceTcp", tsRpcForceTcp, 1) != 0) return -1;
|
|
||||||
if (cfgAddInt32(pCfg, "shellActivityTimer", tsShellActivityTimer, 1, 120, 1) != 0) return -1;
|
if (cfgAddInt32(pCfg, "shellActivityTimer", tsShellActivityTimer, 1, 120, 1) != 0) return -1;
|
||||||
if (cfgAddInt32(pCfg, "compressMsgSize", tsCompressMsgSize, -1, 100000000, 1) != 0) return -1;
|
if (cfgAddInt32(pCfg, "compressMsgSize", tsCompressMsgSize, -1, 100000000, 1) != 0) return -1;
|
||||||
if (cfgAddInt32(pCfg, "compressColData", tsCompressColData, -1, 100000000, 1) != 0) return -1;
|
if (cfgAddInt32(pCfg, "compressColData", tsCompressColData, -1, 100000000, 1) != 0) return -1;
|
||||||
if (cfgAddInt32(pCfg, "maxWildCardsLength", tsMaxWildCardsLen, 0, TSDB_MAX_FIELD_LEN, 1) != 0) return -1;
|
|
||||||
if (cfgAddInt32(pCfg, "maxRegexStringLen", tsMaxRegexStringLen, 0, TSDB_MAX_FIELD_LEN, 1) != 0) return -1;
|
|
||||||
if (cfgAddInt32(pCfg, "maxNumOfOrderedRes", tsMaxNumOfOrderedResults, 128, TSDB_MAX_ALLOWED_SQL_LEN, 1) != 0)
|
|
||||||
return -1;
|
|
||||||
if (cfgAddBool(pCfg, "keepColumnName", tsKeepOriginalColumnName, 1) != 0) return -1;
|
if (cfgAddBool(pCfg, "keepColumnName", tsKeepOriginalColumnName, 1) != 0) return -1;
|
||||||
if (cfgAddInt32(pCfg, "maxBinaryDisplayWidth", tsMaxBinaryDisplayWidth, 1, 65536, 1) != 0) return -1;
|
|
||||||
if (cfgAddInt32(pCfg, "queryPolicy", tsQueryPolicy, 1, 3, 1) != 0) return -1;
|
if (cfgAddInt32(pCfg, "queryPolicy", tsQueryPolicy, 1, 3, 1) != 0) return -1;
|
||||||
|
|
||||||
tsNumOfTaskQueueThreads = tsNumOfCores / 4;
|
tsNumOfTaskQueueThreads = tsNumOfCores / 4;
|
||||||
|
@ -508,18 +487,10 @@ static int32_t taosSetClientCfg(SConfig *pCfg) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
tsMaxTmrCtrl = cfgGetItem(pCfg, "maxTmrCtrl")->i32;
|
|
||||||
tsRpcTimer = cfgGetItem(pCfg, "rpcTimer")->i32;
|
|
||||||
tsRpcMaxTime = cfgGetItem(pCfg, "rpcMaxTime")->i32;
|
|
||||||
tsRpcForceTcp = cfgGetItem(pCfg, "rpcForceTcp")->i32;
|
|
||||||
tsShellActivityTimer = cfgGetItem(pCfg, "shellActivityTimer")->i32;
|
tsShellActivityTimer = cfgGetItem(pCfg, "shellActivityTimer")->i32;
|
||||||
tsCompressMsgSize = cfgGetItem(pCfg, "compressMsgSize")->i32;
|
tsCompressMsgSize = cfgGetItem(pCfg, "compressMsgSize")->i32;
|
||||||
tsCompressColData = cfgGetItem(pCfg, "compressColData")->i32;
|
tsCompressColData = cfgGetItem(pCfg, "compressColData")->i32;
|
||||||
tsMaxWildCardsLen = cfgGetItem(pCfg, "maxWildCardsLength")->i32;
|
|
||||||
tsMaxRegexStringLen = cfgGetItem(pCfg, "maxRegexStringLen")->i32;
|
|
||||||
tsMaxNumOfOrderedResults = cfgGetItem(pCfg, "maxNumOfOrderedRes")->i32;
|
|
||||||
tsKeepOriginalColumnName = cfgGetItem(pCfg, "keepColumnName")->bval;
|
tsKeepOriginalColumnName = cfgGetItem(pCfg, "keepColumnName")->bval;
|
||||||
tsMaxBinaryDisplayWidth = cfgGetItem(pCfg, "maxBinaryDisplayWidth")->i32;
|
|
||||||
tsNumOfTaskQueueThreads = cfgGetItem(pCfg, "numOfTaskQueueThreads")->i32;
|
tsNumOfTaskQueueThreads = cfgGetItem(pCfg, "numOfTaskQueueThreads")->i32;
|
||||||
tsQueryPolicy = cfgGetItem(pCfg, "queryPolicy")->i32;
|
tsQueryPolicy = cfgGetItem(pCfg, "queryPolicy")->i32;
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -710,6 +681,6 @@ void taosCfgDynamicOptions(const char *option, const char *value) {
|
||||||
|
|
||||||
if (strcasecmp(option, "resetlog") == 0) {
|
if (strcasecmp(option, "resetlog") == 0) {
|
||||||
taosResetLog();
|
taosResetLog();
|
||||||
cfgDumpCfg(tsCfg, 1, false);
|
cfgDumpCfg(tsCfg, 0, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -106,7 +106,7 @@ static void dmPrintVersion() {
|
||||||
|
|
||||||
static void dmDumpCfg() {
|
static void dmDumpCfg() {
|
||||||
SConfig *pCfg = taosGetCfg();
|
SConfig *pCfg = taosGetCfg();
|
||||||
cfgDumpCfg(pCfg, 0, 1);
|
cfgDumpCfg(pCfg, 0, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
static SDnodeOpt dmGetOpt() {
|
static SDnodeOpt dmGetOpt() {
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
#include "dmImp.h"
|
#include "dmImp.h"
|
||||||
|
|
||||||
static void dmUpdateDnodeCfg(SDnode *pDnode, SDnodeCfg *pCfg) {
|
static void dmUpdateDnodeCfg(SDnode *pDnode, SDnodeCfg *pCfg) {
|
||||||
if (pDnode->data.dnodeId == 0) {
|
if (pDnode->data.dnodeId == 0 || pDnode->data.clusterId == 0) {
|
||||||
dInfo("set dnodeId:%d clusterId:%" PRId64, pCfg->dnodeId, pCfg->clusterId);
|
dInfo("set dnodeId:%d clusterId:%" PRId64, pCfg->dnodeId, pCfg->clusterId);
|
||||||
taosWLockLatch(&pDnode->data.latch);
|
taosWLockLatch(&pDnode->data.latch);
|
||||||
pDnode->data.dnodeId = pCfg->dnodeId;
|
pDnode->data.dnodeId = pCfg->dnodeId;
|
||||||
|
@ -57,6 +57,7 @@ void dmSendStatusReq(SDnode *pDnode) {
|
||||||
req.dnodeVer = pDnode->data.dnodeVer;
|
req.dnodeVer = pDnode->data.dnodeVer;
|
||||||
req.dnodeId = pDnode->data.dnodeId;
|
req.dnodeId = pDnode->data.dnodeId;
|
||||||
req.clusterId = pDnode->data.clusterId;
|
req.clusterId = pDnode->data.clusterId;
|
||||||
|
if (req.clusterId == 0) req.dnodeId = 0;
|
||||||
req.rebootTime = pDnode->data.rebootTime;
|
req.rebootTime = pDnode->data.rebootTime;
|
||||||
req.updateTime = pDnode->data.updateTime;
|
req.updateTime = pDnode->data.updateTime;
|
||||||
req.numOfCores = tsNumOfCores;
|
req.numOfCores = tsNumOfCores;
|
||||||
|
@ -145,10 +146,10 @@ int32_t dmProcessCreateNodeReq(SDnode *pDnode, EDndNodeType ntype, SNodeMsg *pMs
|
||||||
dError("node:%s, failed to create since %s", pWrapper->name, terrstr());
|
dError("node:%s, failed to create since %s", pWrapper->name, terrstr());
|
||||||
} else {
|
} else {
|
||||||
dDebug("node:%s, has been created", pWrapper->name);
|
dDebug("node:%s, has been created", pWrapper->name);
|
||||||
|
(void)dmOpenNode(pWrapper);
|
||||||
pWrapper->required = true;
|
pWrapper->required = true;
|
||||||
pWrapper->deployed = true;
|
pWrapper->deployed = true;
|
||||||
pWrapper->procType = pDnode->ptype;
|
pWrapper->procType = pDnode->ptype;
|
||||||
(void)dmOpenNode(pWrapper);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
taosThreadMutexUnlock(&pDnode->mutex);
|
taosThreadMutexUnlock(&pDnode->mutex);
|
||||||
|
@ -170,13 +171,13 @@ int32_t dmProcessDropNodeReq(SDnode *pDnode, EDndNodeType ntype, SNodeMsg *pMsg)
|
||||||
dError("node:%s, failed to drop since %s", pWrapper->name, terrstr());
|
dError("node:%s, failed to drop since %s", pWrapper->name, terrstr());
|
||||||
} else {
|
} else {
|
||||||
dDebug("node:%s, has been dropped", pWrapper->name);
|
dDebug("node:%s, has been dropped", pWrapper->name);
|
||||||
|
pWrapper->required = false;
|
||||||
|
pWrapper->deployed = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
dmReleaseWrapper(pWrapper);
|
dmReleaseWrapper(pWrapper);
|
||||||
|
|
||||||
if (code == 0) {
|
if (code == 0) {
|
||||||
pWrapper->required = false;
|
|
||||||
pWrapper->deployed = false;
|
|
||||||
dmCloseNode(pWrapper);
|
dmCloseNode(pWrapper);
|
||||||
taosRemoveDir(pWrapper->path);
|
taosRemoveDir(pWrapper->path);
|
||||||
}
|
}
|
||||||
|
|
|
@ -71,12 +71,15 @@ static void dmProcessRpcMsg(SMgmtWrapper *pWrapper, SRpcMsg *pRpc, SEpSet *pEpSe
|
||||||
SNodeMsg *pMsg = NULL;
|
SNodeMsg *pMsg = NULL;
|
||||||
NodeMsgFp msgFp = NULL;
|
NodeMsgFp msgFp = NULL;
|
||||||
uint16_t msgType = pRpc->msgType;
|
uint16_t msgType = pRpc->msgType;
|
||||||
|
bool needRelease = false;
|
||||||
|
|
||||||
if (pEpSet && pEpSet->numOfEps > 0 && msgType == TDMT_MND_STATUS_RSP) {
|
if (pEpSet && pEpSet->numOfEps > 0 && msgType == TDMT_MND_STATUS_RSP) {
|
||||||
dmSetMnodeEpSet(pWrapper->pDnode, pEpSet);
|
dmSetMnodeEpSet(pWrapper->pDnode, pEpSet);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dmMarkWrapper(pWrapper) != 0) goto _OVER;
|
if (dmMarkWrapper(pWrapper) != 0) goto _OVER;
|
||||||
|
|
||||||
|
needRelease = true;
|
||||||
if ((msgFp = dmGetMsgFp(pWrapper, pRpc)) == NULL) goto _OVER;
|
if ((msgFp = dmGetMsgFp(pWrapper, pRpc)) == NULL) goto _OVER;
|
||||||
if ((pMsg = taosAllocateQitem(sizeof(SNodeMsg))) == NULL) goto _OVER;
|
if ((pMsg = taosAllocateQitem(sizeof(SNodeMsg))) == NULL) goto _OVER;
|
||||||
if (dmBuildMsg(pMsg, pRpc) != 0) goto _OVER;
|
if (dmBuildMsg(pMsg, pRpc) != 0) goto _OVER;
|
||||||
|
@ -119,7 +122,9 @@ _OVER:
|
||||||
rpcFreeCont(pRpc->pCont);
|
rpcFreeCont(pRpc->pCont);
|
||||||
}
|
}
|
||||||
|
|
||||||
dmReleaseWrapper(pWrapper);
|
if (needRelease) {
|
||||||
|
dmReleaseWrapper(pWrapper);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void dmProcessMsg(SDnode *pDnode, SRpcMsg *pMsg, SEpSet *pEpSet) {
|
static void dmProcessMsg(SDnode *pDnode, SRpcMsg *pMsg, SEpSet *pEpSet) {
|
||||||
|
@ -135,6 +140,12 @@ static void dmProcessMsg(SDnode *pDnode, SRpcMsg *pMsg, SEpSet *pEpSet) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (msgType == TDMT_DND_NET_TEST) {
|
||||||
|
dTrace("net test req will be processed, handle:%p, app:%p", pMsg->handle, pMsg->ahandle);
|
||||||
|
dmProcessServerStatusReq(pDnode, pMsg);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (pDnode->status != DND_STAT_RUNNING) {
|
if (pDnode->status != DND_STAT_RUNNING) {
|
||||||
dError("msg:%s ignored since dnode not running, handle:%p app:%p", TMSG_INFO(msgType), pMsg->handle, pMsg->ahandle);
|
dError("msg:%s ignored since dnode not running, handle:%p app:%p", TMSG_INFO(msgType), pMsg->handle, pMsg->ahandle);
|
||||||
if (isReq) {
|
if (isReq) {
|
||||||
|
|
|
@ -37,6 +37,7 @@ void dmSetMsgHandle(SMgmtWrapper *pWrapper, tmsg_t msgType, NodeMsgFp nodeMsgF
|
||||||
void dmReportStartup(SDnode *pDnode, const char *pName, const char *pDesc);
|
void dmReportStartup(SDnode *pDnode, const char *pName, const char *pDesc);
|
||||||
void dmReportStartupByWrapper(SMgmtWrapper *pWrapper, const char *pName, const char *pDesc);
|
void dmReportStartupByWrapper(SMgmtWrapper *pWrapper, const char *pName, const char *pDesc);
|
||||||
void dmProcessServerStatusReq(SDnode *pDnode, SRpcMsg *pMsg);
|
void dmProcessServerStatusReq(SDnode *pDnode, SRpcMsg *pMsg);
|
||||||
|
void dmProcessNettestReq(SDnode *pDnode, SRpcMsg *pMsg);
|
||||||
void dmGetMonitorSysInfo(SMonSysInfo *pInfo);
|
void dmGetMonitorSysInfo(SMonSysInfo *pInfo);
|
||||||
|
|
||||||
// dmFile.c
|
// dmFile.c
|
||||||
|
|
|
@ -171,6 +171,14 @@ static void dmGetServerStatus(SDnode *pDnode, SServerStatusRsp *pStatus) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void dmProcessNettestReq(SDnode *pDnode, SRpcMsg *pRpc) {
|
||||||
|
dDebug("net test req is received");
|
||||||
|
SRpcMsg rsp = {.handle = pRpc->handle, .ahandle = pRpc->ahandle, .code = 0};
|
||||||
|
rsp.pCont = rpcMallocCont(pRpc->contLen);
|
||||||
|
rsp.contLen = pRpc->contLen;
|
||||||
|
rpcSendResponse(&rsp);
|
||||||
|
}
|
||||||
|
|
||||||
void dmProcessServerStatusReq(SDnode *pDnode, SRpcMsg *pReq) {
|
void dmProcessServerStatusReq(SDnode *pDnode, SRpcMsg *pReq) {
|
||||||
dDebug("server status req is received");
|
dDebug("server status req is received");
|
||||||
|
|
||||||
|
|
|
@ -161,9 +161,9 @@ static int32_t mmOpen(SMgmtWrapper *pWrapper) {
|
||||||
SMnodeOpt option = {0};
|
SMnodeOpt option = {0};
|
||||||
if (!deployed) {
|
if (!deployed) {
|
||||||
dInfo("mnode start to deploy");
|
dInfo("mnode start to deploy");
|
||||||
if (pWrapper->procType == DND_PROC_CHILD) {
|
// if (pWrapper->procType == DND_PROC_CHILD) {
|
||||||
pWrapper->pDnode->data.dnodeId = 1;
|
pWrapper->pDnode->data.dnodeId = 1;
|
||||||
}
|
// }
|
||||||
mmBuildOptionForDeploy(pMgmt, &option);
|
mmBuildOptionForDeploy(pMgmt, &option);
|
||||||
} else {
|
} else {
|
||||||
dInfo("mnode start to open");
|
dInfo("mnode start to open");
|
||||||
|
|
|
@ -385,7 +385,11 @@ int32_t mndProcessMsg(SNodeMsg *pMsg) {
|
||||||
terrno = code;
|
terrno = code;
|
||||||
mTrace("msg:%p, in progress, app:%p", pMsg, ahandle);
|
mTrace("msg:%p, in progress, app:%p", pMsg, ahandle);
|
||||||
} else if (code != 0) {
|
} else if (code != 0) {
|
||||||
mError("msg:%p, failed to process since %s, app:%p", pMsg, terrstr(), ahandle);
|
if (terrno != TSDB_CODE_OPS_NOT_SUPPORT) {
|
||||||
|
mError("msg:%p, failed to process since %s, app:%p", pMsg, terrstr(), ahandle);
|
||||||
|
} else {
|
||||||
|
mTrace("msg:%p, failed to process since %s, app:%p", pMsg, terrstr(), ahandle);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
mTrace("msg:%p, is processed, app:%p", pMsg, ahandle);
|
mTrace("msg:%p, is processed, app:%p", pMsg, ahandle);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1565,7 +1565,6 @@ static int32_t tsdbGetTSmaDataImpl(STsdb *pTsdb, char *pData, int64_t indexUid,
|
||||||
}
|
}
|
||||||
|
|
||||||
STSma *pTSma = pItem->pSma;
|
STSma *pTSma = pItem->pSma;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
STSmaReadH tReadH = {0};
|
STSmaReadH tReadH = {0};
|
||||||
|
|
|
@ -344,11 +344,6 @@ int32_t qExplainResNodeToRowsImpl(SExplainResNode *pResNode, SExplainCtx *ctx, i
|
||||||
EXPLAIN_ROW_APPEND(EXPLAIN_BLANK_FORMAT);
|
EXPLAIN_ROW_APPEND(EXPLAIN_BLANK_FORMAT);
|
||||||
EXPLAIN_ROW_APPEND(EXPLAIN_WIDTH_FORMAT, pTagScanNode->node.pOutputDataBlockDesc->totalRowSize);
|
EXPLAIN_ROW_APPEND(EXPLAIN_WIDTH_FORMAT, pTagScanNode->node.pOutputDataBlockDesc->totalRowSize);
|
||||||
EXPLAIN_ROW_APPEND(EXPLAIN_BLANK_FORMAT);
|
EXPLAIN_ROW_APPEND(EXPLAIN_BLANK_FORMAT);
|
||||||
EXPLAIN_ROW_APPEND(EXPLAIN_LOOPS_FORMAT, pTagScanNode->count);
|
|
||||||
if (pTagScanNode->reverse) {
|
|
||||||
EXPLAIN_ROW_APPEND(EXPLAIN_BLANK_FORMAT);
|
|
||||||
EXPLAIN_ROW_APPEND(EXPLAIN_REVERSE_FORMAT, pTagScanNode->reverse);
|
|
||||||
}
|
|
||||||
EXPLAIN_ROW_APPEND(EXPLAIN_RIGHT_PARENTHESIS_FORMAT);
|
EXPLAIN_ROW_APPEND(EXPLAIN_RIGHT_PARENTHESIS_FORMAT);
|
||||||
EXPLAIN_ROW_END();
|
EXPLAIN_ROW_END();
|
||||||
QRY_ERR_RET(qExplainResAppendRow(ctx, tbuf, tlen, level));
|
QRY_ERR_RET(qExplainResAppendRow(ctx, tbuf, tlen, level));
|
||||||
|
@ -361,10 +356,6 @@ int32_t qExplainResNodeToRowsImpl(SExplainResNode *pResNode, SExplainCtx *ctx, i
|
||||||
EXPLAIN_ROW_END();
|
EXPLAIN_ROW_END();
|
||||||
QRY_ERR_RET(qExplainResAppendRow(ctx, tbuf, tlen, level + 1));
|
QRY_ERR_RET(qExplainResAppendRow(ctx, tbuf, tlen, level + 1));
|
||||||
|
|
||||||
EXPLAIN_ROW_NEW(level + 1, EXPLAIN_ORDER_FORMAT, EXPLAIN_ORDER_STRING(pTagScanNode->order));
|
|
||||||
EXPLAIN_ROW_END();
|
|
||||||
QRY_ERR_RET(qExplainResAppendRow(ctx, tbuf, tlen, level + 1));
|
|
||||||
|
|
||||||
if (pResNode->pExecInfo) {
|
if (pResNode->pExecInfo) {
|
||||||
QRY_ERR_RET(qExplainBufAppendVerboseExecInfo(pResNode->pExecInfo, tbuf, &tlen));
|
QRY_ERR_RET(qExplainBufAppendVerboseExecInfo(pResNode->pExecInfo, tbuf, &tlen));
|
||||||
if (tlen) {
|
if (tlen) {
|
||||||
|
@ -388,11 +379,6 @@ int32_t qExplainResNodeToRowsImpl(SExplainResNode *pResNode, SExplainCtx *ctx, i
|
||||||
EXPLAIN_ROW_APPEND(EXPLAIN_BLANK_FORMAT);
|
EXPLAIN_ROW_APPEND(EXPLAIN_BLANK_FORMAT);
|
||||||
EXPLAIN_ROW_APPEND(EXPLAIN_WIDTH_FORMAT, pTblScanNode->scan.node.pOutputDataBlockDesc->totalRowSize);
|
EXPLAIN_ROW_APPEND(EXPLAIN_WIDTH_FORMAT, pTblScanNode->scan.node.pOutputDataBlockDesc->totalRowSize);
|
||||||
EXPLAIN_ROW_APPEND(EXPLAIN_BLANK_FORMAT);
|
EXPLAIN_ROW_APPEND(EXPLAIN_BLANK_FORMAT);
|
||||||
EXPLAIN_ROW_APPEND(EXPLAIN_LOOPS_FORMAT, pTblScanNode->scan.count);
|
|
||||||
if (pTblScanNode->scan.reverse) {
|
|
||||||
EXPLAIN_ROW_APPEND(EXPLAIN_BLANK_FORMAT);
|
|
||||||
EXPLAIN_ROW_APPEND(EXPLAIN_REVERSE_FORMAT, pTblScanNode->scan.reverse);
|
|
||||||
}
|
|
||||||
EXPLAIN_ROW_APPEND(EXPLAIN_RIGHT_PARENTHESIS_FORMAT);
|
EXPLAIN_ROW_APPEND(EXPLAIN_RIGHT_PARENTHESIS_FORMAT);
|
||||||
EXPLAIN_ROW_END();
|
EXPLAIN_ROW_END();
|
||||||
QRY_ERR_RET(qExplainResAppendRow(ctx, tbuf, tlen, level));
|
QRY_ERR_RET(qExplainResAppendRow(ctx, tbuf, tlen, level));
|
||||||
|
@ -405,10 +391,6 @@ int32_t qExplainResNodeToRowsImpl(SExplainResNode *pResNode, SExplainCtx *ctx, i
|
||||||
EXPLAIN_ROW_END();
|
EXPLAIN_ROW_END();
|
||||||
QRY_ERR_RET(qExplainResAppendRow(ctx, tbuf, tlen, level + 1));
|
QRY_ERR_RET(qExplainResAppendRow(ctx, tbuf, tlen, level + 1));
|
||||||
|
|
||||||
EXPLAIN_ROW_NEW(level + 1, EXPLAIN_ORDER_FORMAT, EXPLAIN_ORDER_STRING(pTblScanNode->scan.order));
|
|
||||||
EXPLAIN_ROW_END();
|
|
||||||
QRY_ERR_RET(qExplainResAppendRow(ctx, tbuf, tlen, level + 1));
|
|
||||||
|
|
||||||
EXPLAIN_ROW_NEW(level + 1, EXPLAIN_TIMERANGE_FORMAT, pTblScanNode->scanRange.skey, pTblScanNode->scanRange.ekey);
|
EXPLAIN_ROW_NEW(level + 1, EXPLAIN_TIMERANGE_FORMAT, pTblScanNode->scanRange.skey, pTblScanNode->scanRange.ekey);
|
||||||
EXPLAIN_ROW_END();
|
EXPLAIN_ROW_END();
|
||||||
QRY_ERR_RET(qExplainResAppendRow(ctx, tbuf, tlen, level + 1));
|
QRY_ERR_RET(qExplainResAppendRow(ctx, tbuf, tlen, level + 1));
|
||||||
|
@ -434,11 +416,6 @@ int32_t qExplainResNodeToRowsImpl(SExplainResNode *pResNode, SExplainCtx *ctx, i
|
||||||
EXPLAIN_ROW_APPEND(EXPLAIN_BLANK_FORMAT);
|
EXPLAIN_ROW_APPEND(EXPLAIN_BLANK_FORMAT);
|
||||||
EXPLAIN_ROW_APPEND(EXPLAIN_WIDTH_FORMAT, pSTblScanNode->scan.node.pOutputDataBlockDesc->totalRowSize);
|
EXPLAIN_ROW_APPEND(EXPLAIN_WIDTH_FORMAT, pSTblScanNode->scan.node.pOutputDataBlockDesc->totalRowSize);
|
||||||
EXPLAIN_ROW_APPEND(EXPLAIN_BLANK_FORMAT);
|
EXPLAIN_ROW_APPEND(EXPLAIN_BLANK_FORMAT);
|
||||||
EXPLAIN_ROW_APPEND(EXPLAIN_LOOPS_FORMAT, pSTblScanNode->scan.count);
|
|
||||||
if (pSTblScanNode->scan.reverse) {
|
|
||||||
EXPLAIN_ROW_APPEND(EXPLAIN_BLANK_FORMAT);
|
|
||||||
EXPLAIN_ROW_APPEND(EXPLAIN_REVERSE_FORMAT, pSTblScanNode->scan.reverse);
|
|
||||||
}
|
|
||||||
EXPLAIN_ROW_APPEND(EXPLAIN_RIGHT_PARENTHESIS_FORMAT);
|
EXPLAIN_ROW_APPEND(EXPLAIN_RIGHT_PARENTHESIS_FORMAT);
|
||||||
EXPLAIN_ROW_END();
|
EXPLAIN_ROW_END();
|
||||||
QRY_ERR_RET(qExplainResAppendRow(ctx, tbuf, tlen, level));
|
QRY_ERR_RET(qExplainResAppendRow(ctx, tbuf, tlen, level));
|
||||||
|
@ -451,10 +428,6 @@ int32_t qExplainResNodeToRowsImpl(SExplainResNode *pResNode, SExplainCtx *ctx, i
|
||||||
EXPLAIN_ROW_END();
|
EXPLAIN_ROW_END();
|
||||||
QRY_ERR_RET(qExplainResAppendRow(ctx, tbuf, tlen, level + 1));
|
QRY_ERR_RET(qExplainResAppendRow(ctx, tbuf, tlen, level + 1));
|
||||||
|
|
||||||
EXPLAIN_ROW_NEW(level + 1, EXPLAIN_ORDER_FORMAT, EXPLAIN_ORDER_STRING(pSTblScanNode->scan.order));
|
|
||||||
EXPLAIN_ROW_END();
|
|
||||||
QRY_ERR_RET(qExplainResAppendRow(ctx, tbuf, tlen, level + 1));
|
|
||||||
|
|
||||||
if (pSTblScanNode->scan.node.pConditions) {
|
if (pSTblScanNode->scan.node.pConditions) {
|
||||||
EXPLAIN_ROW_NEW(level + 1, EXPLAIN_FILTER_FORMAT);
|
EXPLAIN_ROW_NEW(level + 1, EXPLAIN_FILTER_FORMAT);
|
||||||
QRY_ERR_RET(nodesNodeToSQL(pSTblScanNode->scan.node.pConditions, tbuf + VARSTR_HEADER_SIZE, TSDB_EXPLAIN_RESULT_ROW_SIZE, &tlen));
|
QRY_ERR_RET(nodesNodeToSQL(pSTblScanNode->scan.node.pConditions, tbuf + VARSTR_HEADER_SIZE, TSDB_EXPLAIN_RESULT_ROW_SIZE, &tlen));
|
||||||
|
|
|
@ -1121,6 +1121,10 @@ static int32_t doSetInputDataBlock(SOperatorInfo* pOperator, SqlFunctionCtx* pCt
|
||||||
// todo avoid case: top(k, 12), 12 is the value parameter.
|
// todo avoid case: top(k, 12), 12 is the value parameter.
|
||||||
// sum(11), 11 is also the value parameter.
|
// sum(11), 11 is also the value parameter.
|
||||||
if (createDummyCol && pOneExpr->base.numOfParams == 1) {
|
if (createDummyCol && pOneExpr->base.numOfParams == 1) {
|
||||||
|
pInput->totalRows = pBlock->info.rows;
|
||||||
|
pInput->numOfRows = pBlock->info.rows;
|
||||||
|
pInput->startRowIndex = 0;
|
||||||
|
|
||||||
code = doCreateConstantValColumnInfo(pInput, pFuncParam, pFuncParam->param.nType, j, pBlock->info.rows);
|
code = doCreateConstantValColumnInfo(pInput, pFuncParam, pFuncParam->param.nType, j, pBlock->info.rows);
|
||||||
if (code != TSDB_CODE_SUCCESS) {
|
if (code != TSDB_CODE_SUCCESS) {
|
||||||
return code;
|
return code;
|
||||||
|
@ -6571,9 +6575,9 @@ SOperatorInfo* createOperatorTree(SPhysiNode* pPhyNode, SExecTaskInfo* pTaskInfo
|
||||||
.offset = pTableScanNode->offset,
|
.offset = pTableScanNode->offset,
|
||||||
};
|
};
|
||||||
|
|
||||||
return createTableScanOperatorInfo(pDataReader, pScanPhyNode->order, numOfCols, pTableScanNode->dataRequired,
|
return createTableScanOperatorInfo(pDataReader, pTableScanNode->scanSeq[0] > 0 ? TSDB_ORDER_ASC : TSDB_ORDER_DESC,
|
||||||
pScanPhyNode->count, pScanPhyNode->reverse, pColList, pResBlock,
|
numOfCols, pTableScanNode->dataRequired, pTableScanNode->scanSeq[0], pTableScanNode->scanSeq[1], pColList,
|
||||||
pScanPhyNode->node.pConditions, &interval, pTableScanNode->ratio, pTaskInfo);
|
pResBlock, pScanPhyNode->node.pConditions, &interval, pTableScanNode->ratio, pTaskInfo);
|
||||||
} else if (QUERY_NODE_PHYSICAL_PLAN_EXCHANGE == type) {
|
} else if (QUERY_NODE_PHYSICAL_PLAN_EXCHANGE == type) {
|
||||||
SExchangePhysiNode* pExchange = (SExchangePhysiNode*)pPhyNode;
|
SExchangePhysiNode* pExchange = (SExchangePhysiNode*)pPhyNode;
|
||||||
SSDataBlock* pResBlock = createResDataBlock(pExchange->node.pOutputDataBlockDesc);
|
SSDataBlock* pResBlock = createResDataBlock(pExchange->node.pOutputDataBlockDesc);
|
||||||
|
@ -6721,7 +6725,7 @@ static tsdbReaderT createDataReaderImpl(STableScanPhysiNode* pTableScanNode, STa
|
||||||
void* readHandle, uint64_t queryId, uint64_t taskId) {
|
void* readHandle, uint64_t queryId, uint64_t taskId) {
|
||||||
STsdbQueryCond cond = {.loadExternalRows = false};
|
STsdbQueryCond cond = {.loadExternalRows = false};
|
||||||
|
|
||||||
cond.order = pTableScanNode->scan.order;
|
cond.order = pTableScanNode->scanSeq[0] > 0 ? TSDB_ORDER_ASC : TSDB_ORDER_DESC;
|
||||||
cond.numOfCols = LIST_LENGTH(pTableScanNode->scan.pScanCols);
|
cond.numOfCols = LIST_LENGTH(pTableScanNode->scan.pScanCols);
|
||||||
cond.colList = taosMemoryCalloc(cond.numOfCols, sizeof(SColumnInfo));
|
cond.colList = taosMemoryCalloc(cond.numOfCols, sizeof(SColumnInfo));
|
||||||
if (cond.colList == NULL) {
|
if (cond.colList == NULL) {
|
||||||
|
|
|
@ -40,6 +40,11 @@ bool getMinmaxFuncEnv(struct SFunctionNode* pFunc, SFuncExecEnv* pEnv);
|
||||||
int32_t minFunction(SqlFunctionCtx* pCtx);
|
int32_t minFunction(SqlFunctionCtx* pCtx);
|
||||||
int32_t maxFunction(SqlFunctionCtx *pCtx);
|
int32_t maxFunction(SqlFunctionCtx *pCtx);
|
||||||
|
|
||||||
|
bool getAvgFuncEnv(struct SFunctionNode* pFunc, SFuncExecEnv* pEnv);
|
||||||
|
bool avgFunctionSetup(SqlFunctionCtx *pCtx, SResultRowEntryInfo* pResultInfo);
|
||||||
|
int32_t avgFunction(SqlFunctionCtx* pCtx);
|
||||||
|
int32_t avgFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock, int32_t slotId);
|
||||||
|
|
||||||
bool getStddevFuncEnv(struct SFunctionNode* pFunc, SFuncExecEnv* pEnv);
|
bool getStddevFuncEnv(struct SFunctionNode* pFunc, SFuncExecEnv* pEnv);
|
||||||
bool stddevFunctionSetup(SqlFunctionCtx *pCtx, SResultRowEntryInfo* pResultInfo);
|
bool stddevFunctionSetup(SqlFunctionCtx *pCtx, SResultRowEntryInfo* pResultInfo);
|
||||||
int32_t stddevFunction(SqlFunctionCtx* pCtx);
|
int32_t stddevFunction(SqlFunctionCtx* pCtx);
|
||||||
|
|
|
@ -104,7 +104,7 @@ static int32_t translateCount(SFunctionNode* pFunc, char* pErrBuf, int32_t len)
|
||||||
if (1 != LIST_LENGTH(pFunc->pParameterList)) {
|
if (1 != LIST_LENGTH(pFunc->pParameterList)) {
|
||||||
return invaildFuncParaNumErrMsg(pErrBuf, len, pFunc->functionName);
|
return invaildFuncParaNumErrMsg(pErrBuf, len, pFunc->functionName);
|
||||||
}
|
}
|
||||||
pFunc->node.resType = (SDataType){.bytes = sizeof(int64_t), .type = TSDB_DATA_TYPE_BIGINT};
|
pFunc->node.resType = (SDataType){.bytes = tDataTypes[TSDB_DATA_TYPE_BIGINT].bytes, .type = TSDB_DATA_TYPE_BIGINT};
|
||||||
return TSDB_CODE_SUCCESS;
|
return TSDB_CODE_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -355,7 +355,7 @@ static int32_t translateToIso8601(SFunctionNode* pFunc, char* pErrBuf, int32_t l
|
||||||
return invaildFuncParaTypeErrMsg(pErrBuf, len, pFunc->functionName);
|
return invaildFuncParaTypeErrMsg(pErrBuf, len, pFunc->functionName);
|
||||||
}
|
}
|
||||||
|
|
||||||
pFunc->node.resType = (SDataType) { .bytes = 64, .type = TSDB_DATA_TYPE_BINARY};
|
pFunc->node.resType = (SDataType) { .bytes = 24, .type = TSDB_DATA_TYPE_BINARY};
|
||||||
return TSDB_CODE_SUCCESS;
|
return TSDB_CODE_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -479,6 +479,16 @@ const SBuiltinFuncDefinition funcMgtBuiltins[] = {
|
||||||
.processFunc = stddevFunction,
|
.processFunc = stddevFunction,
|
||||||
.finalizeFunc = stddevFinalize
|
.finalizeFunc = stddevFinalize
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
.name = "avg",
|
||||||
|
.type = FUNCTION_TYPE_AVG,
|
||||||
|
.classification = FUNC_MGT_AGG_FUNC,
|
||||||
|
.translateFunc = translateInNumOutDou,
|
||||||
|
.getEnvFunc = getAvgFuncEnv,
|
||||||
|
.initFunc = avgFunctionSetup,
|
||||||
|
.processFunc = avgFunction,
|
||||||
|
.finalizeFunc = avgFinalize
|
||||||
|
},
|
||||||
{
|
{
|
||||||
.name = "percentile",
|
.name = "percentile",
|
||||||
.type = FUNCTION_TYPE_PERCENTILE,
|
.type = FUNCTION_TYPE_PERCENTILE,
|
||||||
|
|
|
@ -20,6 +20,59 @@
|
||||||
#include "tdatablock.h"
|
#include "tdatablock.h"
|
||||||
#include "tpercentile.h"
|
#include "tpercentile.h"
|
||||||
|
|
||||||
|
typedef struct SSumRes {
|
||||||
|
union {
|
||||||
|
int64_t isum;
|
||||||
|
uint64_t usum;
|
||||||
|
double dsum;
|
||||||
|
};
|
||||||
|
} SSumRes;
|
||||||
|
|
||||||
|
typedef struct SAvgRes {
|
||||||
|
double result;
|
||||||
|
SSumRes sum;
|
||||||
|
int64_t count;
|
||||||
|
} SAvgRes;
|
||||||
|
|
||||||
|
typedef struct STopBotResItem {
|
||||||
|
SVariant v;
|
||||||
|
uint64_t uid; // it is a table uid, used to extract tag data during building of the final result for the tag data
|
||||||
|
struct {
|
||||||
|
int32_t pageId;
|
||||||
|
int32_t offset;
|
||||||
|
} tuplePos; // tuple data of this chosen row
|
||||||
|
} STopBotResItem;
|
||||||
|
|
||||||
|
typedef struct STopBotRes {
|
||||||
|
int32_t pageId;
|
||||||
|
// int32_t num;
|
||||||
|
STopBotResItem *pItems;
|
||||||
|
} STopBotRes;
|
||||||
|
|
||||||
|
typedef struct SStddevRes {
|
||||||
|
double result;
|
||||||
|
int64_t count;
|
||||||
|
union {double quadraticDSum; int64_t quadraticISum;};
|
||||||
|
union {double dsum; int64_t isum;};
|
||||||
|
} SStddevRes;
|
||||||
|
|
||||||
|
typedef struct SPercentileInfo {
|
||||||
|
double result;
|
||||||
|
tMemBucket *pMemBucket;
|
||||||
|
int32_t stage;
|
||||||
|
double minval;
|
||||||
|
double maxval;
|
||||||
|
int64_t numOfElems;
|
||||||
|
} SPercentileInfo;
|
||||||
|
|
||||||
|
typedef struct SDiffInfo {
|
||||||
|
bool hasPrev;
|
||||||
|
bool includeNull;
|
||||||
|
bool ignoreNegative;
|
||||||
|
bool firstOutput;
|
||||||
|
union { int64_t i64; double d64;} prev;
|
||||||
|
} SDiffInfo;
|
||||||
|
|
||||||
#define SET_VAL(_info, numOfElem, res) \
|
#define SET_VAL(_info, numOfElem, res) \
|
||||||
do { \
|
do { \
|
||||||
if ((numOfElem) <= 0) { \
|
if ((numOfElem) <= 0) { \
|
||||||
|
@ -28,13 +81,50 @@
|
||||||
(_info)->numOfRes = (res); \
|
(_info)->numOfRes = (res); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
typedef struct SSumRes {
|
#define GET_TS_LIST(x) ((TSKEY*)((x)->ptsList))
|
||||||
union {
|
#define GET_TS_DATA(x, y) (GET_TS_LIST(x)[(y)])
|
||||||
int64_t isum;
|
|
||||||
uint64_t usum;
|
#define DO_UPDATE_TAG_COLUMNS_WITHOUT_TS(ctx) \
|
||||||
double dsum;
|
do { \
|
||||||
};
|
for (int32_t _i = 0; _i < (ctx)->tagInfo.numOfTagCols; ++_i) { \
|
||||||
} SSumRes;
|
SqlFunctionCtx *__ctx = (ctx)->tagInfo.pTagCtxList[_i]; \
|
||||||
|
__ctx->fpSet.process(__ctx); \
|
||||||
|
} \
|
||||||
|
} while (0);
|
||||||
|
|
||||||
|
#define DO_UPDATE_SUBSID_RES(ctx, ts) \
|
||||||
|
do { \
|
||||||
|
for (int32_t _i = 0; _i < (ctx)->subsidiaryRes.numOfCols; ++_i) { \
|
||||||
|
SqlFunctionCtx *__ctx = (ctx)->subsidiaryRes.pCtx[_i]; \
|
||||||
|
if (__ctx->functionId == FUNCTION_TS_DUMMY) { \
|
||||||
|
__ctx->tag.i = (ts); \
|
||||||
|
__ctx->tag.nType = TSDB_DATA_TYPE_BIGINT; \
|
||||||
|
} \
|
||||||
|
__ctx->fpSet.process(__ctx); \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define UPDATE_DATA(ctx, left, right, num, sign, _ts) \
|
||||||
|
do { \
|
||||||
|
if (((left) < (right)) ^ (sign)) { \
|
||||||
|
(left) = (right); \
|
||||||
|
DO_UPDATE_SUBSID_RES(ctx, _ts); \
|
||||||
|
(num) += 1; \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define LOOPCHECK_N(val, _col, ctx, _t, _nrow, _start, sign, num) \
|
||||||
|
do { \
|
||||||
|
_t *d = (_t *)((_col)->pData); \
|
||||||
|
for (int32_t i = (_start); i < (_nrow) + (_start); ++i) { \
|
||||||
|
if (((_col)->hasNull) && colDataIsNull_f((_col)->nullbitmap, i)) { \
|
||||||
|
continue; \
|
||||||
|
} \
|
||||||
|
TSKEY ts = (ctx)->ptsList != NULL ? GET_TS_DATA(ctx, i) : 0; \
|
||||||
|
UPDATE_DATA(ctx, val, d[i], num, sign, ts); \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
|
||||||
bool functionSetup(SqlFunctionCtx *pCtx, SResultRowEntryInfo* pResultInfo) {
|
bool functionSetup(SqlFunctionCtx *pCtx, SResultRowEntryInfo* pResultInfo) {
|
||||||
if (pResultInfo->initialized) {
|
if (pResultInfo->initialized) {
|
||||||
|
@ -135,7 +225,7 @@ int32_t sumFunction(SqlFunctionCtx *pCtx) {
|
||||||
int32_t type = pInput->pData[0]->info.type;
|
int32_t type = pInput->pData[0]->info.type;
|
||||||
|
|
||||||
SSumRes* pSumRes = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
|
SSumRes* pSumRes = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
|
||||||
|
|
||||||
if (pInput->colDataAggIsSet) {
|
if (pInput->colDataAggIsSet) {
|
||||||
numOfElem = pInput->numOfRows - pAgg->numOfNull;
|
numOfElem = pInput->numOfRows - pAgg->numOfNull;
|
||||||
ASSERT(numOfElem >= 0);
|
ASSERT(numOfElem >= 0);
|
||||||
|
@ -190,6 +280,145 @@ bool getSumFuncEnv(SFunctionNode* UNUSED_PARAM(pFunc), SFuncExecEnv* pEnv) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool getAvgFuncEnv(SFunctionNode* UNUSED_PARAM(pFunc), SFuncExecEnv* pEnv) {
|
||||||
|
pEnv->calcMemSize = sizeof(double);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool avgFunctionSetup(SqlFunctionCtx *pCtx, SResultRowEntryInfo* pResultInfo) {
|
||||||
|
if (!functionSetup(pCtx, pResultInfo)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
SAvgRes* pRes = GET_ROWCELL_INTERBUF(pResultInfo);
|
||||||
|
memset(pRes, 0, sizeof(SAvgRes));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t avgFunction(SqlFunctionCtx* pCtx) {
|
||||||
|
int32_t numOfElem = 0;
|
||||||
|
|
||||||
|
// Only the pre-computing information loaded and actual data does not loaded
|
||||||
|
SInputColumnInfoData* pInput = &pCtx->input;
|
||||||
|
int32_t type = pInput->pData[0]->info.type;
|
||||||
|
|
||||||
|
SAvgRes* pAvgRes = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
|
||||||
|
|
||||||
|
// computing based on the true data block
|
||||||
|
SColumnInfoData* pCol = pInput->pData[0];
|
||||||
|
|
||||||
|
int32_t start = pInput->startRowIndex;
|
||||||
|
int32_t numOfRows = pInput->numOfRows;
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case TSDB_DATA_TYPE_TINYINT: {
|
||||||
|
int8_t* plist = (int8_t*)pCol->pData;
|
||||||
|
for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
|
||||||
|
if (pCol->hasNull && colDataIsNull_f(pCol->nullbitmap, i)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
numOfElem += 1;
|
||||||
|
pAvgRes->count += 1;
|
||||||
|
pAvgRes->sum.isum += plist[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case TSDB_DATA_TYPE_SMALLINT: {
|
||||||
|
int16_t* plist = (int16_t*)pCol->pData;
|
||||||
|
for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
|
||||||
|
if (pCol->hasNull && colDataIsNull_f(pCol->nullbitmap, i)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
numOfElem += 1;
|
||||||
|
pAvgRes->count += 1;
|
||||||
|
pAvgRes->sum.isum += plist[i];
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case TSDB_DATA_TYPE_INT: {
|
||||||
|
int32_t* plist = (int32_t*)pCol->pData;
|
||||||
|
for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
|
||||||
|
if (pCol->hasNull && colDataIsNull_f(pCol->nullbitmap, i)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
numOfElem += 1;
|
||||||
|
pAvgRes->count += 1;
|
||||||
|
pAvgRes->sum.isum += plist[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case TSDB_DATA_TYPE_BIGINT: {
|
||||||
|
int64_t* plist = (int64_t*)pCol->pData;
|
||||||
|
for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
|
||||||
|
if (pCol->hasNull && colDataIsNull_f(pCol->nullbitmap, i)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
numOfElem += 1;
|
||||||
|
pAvgRes->count += 1;
|
||||||
|
pAvgRes->sum.isum += plist[i];
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case TSDB_DATA_TYPE_FLOAT: {
|
||||||
|
float* plist = (float*)pCol->pData;
|
||||||
|
for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
|
||||||
|
if (pCol->hasNull && colDataIsNull_f(pCol->nullbitmap, i)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
numOfElem += 1;
|
||||||
|
pAvgRes->count += 1;
|
||||||
|
pAvgRes->sum.dsum += plist[i];
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case TSDB_DATA_TYPE_DOUBLE: {
|
||||||
|
double* plist = (double*)pCol->pData;
|
||||||
|
for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
|
||||||
|
if (pCol->hasNull && colDataIsNull_f(pCol->nullbitmap, i)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
numOfElem += 1;
|
||||||
|
pAvgRes->count += 1;
|
||||||
|
pAvgRes->sum.dsum += plist[i];
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// data in the check operation are all null, not output
|
||||||
|
SET_VAL(GET_RES_INFO(pCtx), numOfElem, 1);
|
||||||
|
return TSDB_CODE_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t avgFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock, int32_t slotId) {
|
||||||
|
SInputColumnInfoData* pInput = &pCtx->input;
|
||||||
|
int32_t type = pInput->pData[0]->info.type;
|
||||||
|
SAvgRes* pAvgRes = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
|
||||||
|
if (IS_INTEGER_TYPE(type)) {
|
||||||
|
pAvgRes->result = pAvgRes->sum.isum / ((double) pAvgRes->count);
|
||||||
|
} else {
|
||||||
|
pAvgRes->result = pAvgRes->sum.dsum / ((double) pAvgRes->count);
|
||||||
|
}
|
||||||
|
|
||||||
|
return functionFinalize(pCtx, pBlock, slotId);
|
||||||
|
}
|
||||||
|
|
||||||
EFuncDataRequired statisDataRequired(SFunctionNode* pFunc, STimeWindow* pTimeWindow){
|
EFuncDataRequired statisDataRequired(SFunctionNode* pFunc, STimeWindow* pTimeWindow){
|
||||||
return FUNC_DATA_REQUIRED_STATIS_LOAD;
|
return FUNC_DATA_REQUIRED_STATIS_LOAD;
|
||||||
}
|
}
|
||||||
|
@ -292,49 +521,6 @@ bool getMinmaxFuncEnv(SFunctionNode* UNUSED_PARAM(pFunc), SFuncExecEnv* pEnv) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define GET_TS_LIST(x) ((TSKEY*)((x)->ptsList))
|
|
||||||
#define GET_TS_DATA(x, y) (GET_TS_LIST(x)[(y)])
|
|
||||||
|
|
||||||
#define DO_UPDATE_TAG_COLUMNS_WITHOUT_TS(ctx) \
|
|
||||||
do { \
|
|
||||||
for (int32_t _i = 0; _i < (ctx)->tagInfo.numOfTagCols; ++_i) { \
|
|
||||||
SqlFunctionCtx *__ctx = (ctx)->tagInfo.pTagCtxList[_i]; \
|
|
||||||
__ctx->fpSet.process(__ctx); \
|
|
||||||
} \
|
|
||||||
} while (0);
|
|
||||||
|
|
||||||
#define DO_UPDATE_SUBSID_RES(ctx, ts) \
|
|
||||||
do { \
|
|
||||||
for (int32_t _i = 0; _i < (ctx)->subsidiaryRes.numOfCols; ++_i) { \
|
|
||||||
SqlFunctionCtx *__ctx = (ctx)->subsidiaryRes.pCtx[_i]; \
|
|
||||||
if (__ctx->functionId == FUNCTION_TS_DUMMY) { \
|
|
||||||
__ctx->tag.i = (ts); \
|
|
||||||
__ctx->tag.nType = TSDB_DATA_TYPE_BIGINT; \
|
|
||||||
} \
|
|
||||||
__ctx->fpSet.process(__ctx); \
|
|
||||||
} \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
#define UPDATE_DATA(ctx, left, right, num, sign, _ts) \
|
|
||||||
do { \
|
|
||||||
if (((left) < (right)) ^ (sign)) { \
|
|
||||||
(left) = (right); \
|
|
||||||
DO_UPDATE_SUBSID_RES(ctx, _ts); \
|
|
||||||
(num) += 1; \
|
|
||||||
} \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
#define LOOPCHECK_N(val, _col, ctx, _t, _nrow, _start, sign, num) \
|
|
||||||
do { \
|
|
||||||
_t *d = (_t *)((_col)->pData); \
|
|
||||||
for (int32_t i = (_start); i < (_nrow) + (_start); ++i) { \
|
|
||||||
if (((_col)->hasNull) && colDataIsNull_f((_col)->nullbitmap, i)) { \
|
|
||||||
continue; \
|
|
||||||
} \
|
|
||||||
TSKEY ts = (ctx)->ptsList != NULL ? GET_TS_DATA(ctx, i) : 0; \
|
|
||||||
UPDATE_DATA(ctx, val, d[i], num, sign, ts); \
|
|
||||||
} \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
int32_t doMinMaxHelper(SqlFunctionCtx *pCtx, int32_t isMinFunc) {
|
int32_t doMinMaxHelper(SqlFunctionCtx *pCtx, int32_t isMinFunc) {
|
||||||
int32_t numOfElems = 0;
|
int32_t numOfElems = 0;
|
||||||
|
@ -479,13 +665,6 @@ int32_t maxFunction(SqlFunctionCtx *pCtx) {
|
||||||
return TSDB_CODE_SUCCESS;
|
return TSDB_CODE_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef struct SStddevRes {
|
|
||||||
double result;
|
|
||||||
int64_t count;
|
|
||||||
union {double quadraticDSum; int64_t quadraticISum;};
|
|
||||||
union {double dsum; int64_t isum;};
|
|
||||||
} SStddevRes;
|
|
||||||
|
|
||||||
bool getStddevFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
|
bool getStddevFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
|
||||||
pEnv->calcMemSize = sizeof(SStddevRes);
|
pEnv->calcMemSize = sizeof(SStddevRes);
|
||||||
return true;
|
return true;
|
||||||
|
@ -588,8 +767,8 @@ int32_t stddevFunction(SqlFunctionCtx* pCtx) {
|
||||||
|
|
||||||
numOfElem += 1;
|
numOfElem += 1;
|
||||||
pStddevRes->count += 1;
|
pStddevRes->count += 1;
|
||||||
pStddevRes->isum += plist[i];
|
pStddevRes->dsum += plist[i];
|
||||||
pStddevRes->quadraticISum += plist[i] * plist[i];
|
pStddevRes->quadraticDSum += plist[i] * plist[i];
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -603,8 +782,8 @@ int32_t stddevFunction(SqlFunctionCtx* pCtx) {
|
||||||
|
|
||||||
numOfElem += 1;
|
numOfElem += 1;
|
||||||
pStddevRes->count += 1;
|
pStddevRes->count += 1;
|
||||||
pStddevRes->isum += plist[i];
|
pStddevRes->dsum += plist[i];
|
||||||
pStddevRes->quadraticISum += plist[i] * plist[i];
|
pStddevRes->quadraticDSum += plist[i] * plist[i];
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -619,21 +798,21 @@ int32_t stddevFunction(SqlFunctionCtx* pCtx) {
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t stddevFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock, int32_t slotId) {
|
int32_t stddevFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock, int32_t slotId) {
|
||||||
|
SInputColumnInfoData* pInput = &pCtx->input;
|
||||||
|
int32_t type = pInput->pData[0]->info.type;
|
||||||
SStddevRes* pStddevRes = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
|
SStddevRes* pStddevRes = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
|
||||||
double avg = pStddevRes->isum / ((double) pStddevRes->count);
|
double avg;
|
||||||
pStddevRes->result = sqrt(pStddevRes->quadraticISum/((double)pStddevRes->count) - avg*avg);
|
if (IS_INTEGER_TYPE(type)) {
|
||||||
|
avg = pStddevRes->isum / ((double) pStddevRes->count);
|
||||||
|
pStddevRes->result = sqrt(pStddevRes->quadraticISum/((double)pStddevRes->count) - avg*avg);
|
||||||
|
} else {
|
||||||
|
avg = pStddevRes->dsum / ((double) pStddevRes->count);
|
||||||
|
pStddevRes->result = sqrt(pStddevRes->quadraticDSum/((double)pStddevRes->count) - avg*avg);
|
||||||
|
}
|
||||||
|
|
||||||
return functionFinalize(pCtx, pBlock, slotId);
|
return functionFinalize(pCtx, pBlock, slotId);
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef struct SPercentileInfo {
|
|
||||||
double result;
|
|
||||||
tMemBucket *pMemBucket;
|
|
||||||
int32_t stage;
|
|
||||||
double minval;
|
|
||||||
double maxval;
|
|
||||||
int64_t numOfElems;
|
|
||||||
} SPercentileInfo;
|
|
||||||
|
|
||||||
bool getPercentileFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
|
bool getPercentileFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
|
||||||
pEnv->calcMemSize = sizeof(SPercentileInfo);
|
pEnv->calcMemSize = sizeof(SPercentileInfo);
|
||||||
return true;
|
return true;
|
||||||
|
@ -928,14 +1107,6 @@ int32_t lastFunction(SqlFunctionCtx *pCtx) {
|
||||||
return TSDB_CODE_SUCCESS;
|
return TSDB_CODE_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef struct SDiffInfo {
|
|
||||||
bool hasPrev;
|
|
||||||
bool includeNull;
|
|
||||||
bool ignoreNegative;
|
|
||||||
bool firstOutput;
|
|
||||||
union { int64_t i64; double d64;} prev;
|
|
||||||
} SDiffInfo;
|
|
||||||
|
|
||||||
bool getDiffFuncEnv(SFunctionNode* UNUSED_PARAM(pFunc), SFuncExecEnv* pEnv) {
|
bool getDiffFuncEnv(SFunctionNode* UNUSED_PARAM(pFunc), SFuncExecEnv* pEnv) {
|
||||||
pEnv->calcMemSize = sizeof(SDiffInfo);
|
pEnv->calcMemSize = sizeof(SDiffInfo);
|
||||||
return true;
|
return true;
|
||||||
|
@ -1168,21 +1339,6 @@ int32_t diffFunction(SqlFunctionCtx *pCtx) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef struct STopBotResItem {
|
|
||||||
SVariant v;
|
|
||||||
uint64_t uid; // it is a table uid, used to extract tag data during building of the final result for the tag data
|
|
||||||
struct {
|
|
||||||
int32_t pageId;
|
|
||||||
int32_t offset;
|
|
||||||
} tuplePos; // tuple data of this chosen row
|
|
||||||
} STopBotResItem;
|
|
||||||
|
|
||||||
typedef struct STopBotRes {
|
|
||||||
int32_t pageId;
|
|
||||||
// int32_t num;
|
|
||||||
STopBotResItem *pItems;
|
|
||||||
} STopBotRes;
|
|
||||||
|
|
||||||
bool getTopBotFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
|
bool getTopBotFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
|
||||||
SValueNode* pkNode = (SValueNode*) nodesListGetNode(pFunc->pParameterList, 1);
|
SValueNode* pkNode = (SValueNode*) nodesListGetNode(pFunc->pParameterList, 1);
|
||||||
pEnv->calcMemSize = sizeof(STopBotRes) + pkNode->datum.i * sizeof(STopBotResItem);
|
pEnv->calcMemSize = sizeof(STopBotRes) + pkNode->datum.i * sizeof(STopBotResItem);
|
||||||
|
@ -1335,4 +1491,4 @@ int32_t topBotFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock, int32_t slotId
|
||||||
return pEntryInfo->numOfRes;
|
return pEntryInfo->numOfRes;
|
||||||
|
|
||||||
// return functionFinalize(pCtx, pBlock, slotId);
|
// return functionFinalize(pCtx, pBlock, slotId);
|
||||||
}
|
}
|
||||||
|
|
|
@ -671,9 +671,6 @@ static int32_t jsonToName(const SJson* pJson, void* pObj) {
|
||||||
static const char* jkScanPhysiPlanScanCols = "ScanCols";
|
static const char* jkScanPhysiPlanScanCols = "ScanCols";
|
||||||
static const char* jkScanPhysiPlanTableId = "TableId";
|
static const char* jkScanPhysiPlanTableId = "TableId";
|
||||||
static const char* jkScanPhysiPlanTableType = "TableType";
|
static const char* jkScanPhysiPlanTableType = "TableType";
|
||||||
static const char* jkScanPhysiPlanScanOrder = "ScanOrder";
|
|
||||||
static const char* jkScanPhysiPlanScanCount = "ScanCount";
|
|
||||||
static const char* jkScanPhysiPlanReverseScanCount = "ReverseScanCount";
|
|
||||||
static const char* jkScanPhysiPlanTableName = "TableName";
|
static const char* jkScanPhysiPlanTableName = "TableName";
|
||||||
|
|
||||||
static int32_t physiScanNodeToJson(const void* pObj, SJson* pJson) {
|
static int32_t physiScanNodeToJson(const void* pObj, SJson* pJson) {
|
||||||
|
@ -689,15 +686,6 @@ static int32_t physiScanNodeToJson(const void* pObj, SJson* pJson) {
|
||||||
if (TSDB_CODE_SUCCESS == code) {
|
if (TSDB_CODE_SUCCESS == code) {
|
||||||
code = tjsonAddIntegerToObject(pJson, jkScanPhysiPlanTableType, pNode->tableType);
|
code = tjsonAddIntegerToObject(pJson, jkScanPhysiPlanTableType, pNode->tableType);
|
||||||
}
|
}
|
||||||
if (TSDB_CODE_SUCCESS == code) {
|
|
||||||
code = tjsonAddIntegerToObject(pJson, jkScanPhysiPlanScanOrder, pNode->order);
|
|
||||||
}
|
|
||||||
if (TSDB_CODE_SUCCESS == code) {
|
|
||||||
code = tjsonAddIntegerToObject(pJson, jkScanPhysiPlanScanCount, pNode->count);
|
|
||||||
}
|
|
||||||
if (TSDB_CODE_SUCCESS == code) {
|
|
||||||
code = tjsonAddIntegerToObject(pJson, jkScanPhysiPlanReverseScanCount, pNode->reverse);
|
|
||||||
}
|
|
||||||
if (TSDB_CODE_SUCCESS == code) {
|
if (TSDB_CODE_SUCCESS == code) {
|
||||||
code = tjsonAddObject(pJson, jkScanPhysiPlanTableName, nameToJson, &pNode->tableName);
|
code = tjsonAddObject(pJson, jkScanPhysiPlanTableName, nameToJson, &pNode->tableName);
|
||||||
}
|
}
|
||||||
|
@ -718,15 +706,6 @@ static int32_t jsonToPhysiScanNode(const SJson* pJson, void* pObj) {
|
||||||
if (TSDB_CODE_SUCCESS == code) {
|
if (TSDB_CODE_SUCCESS == code) {
|
||||||
code = tjsonGetTinyIntValue(pJson, jkScanPhysiPlanTableType, &pNode->tableType);
|
code = tjsonGetTinyIntValue(pJson, jkScanPhysiPlanTableType, &pNode->tableType);
|
||||||
}
|
}
|
||||||
if (TSDB_CODE_SUCCESS == code) {
|
|
||||||
code = tjsonGetIntValue(pJson, jkScanPhysiPlanScanOrder, &pNode->order);
|
|
||||||
}
|
|
||||||
if (TSDB_CODE_SUCCESS == code) {
|
|
||||||
code = tjsonGetIntValue(pJson, jkScanPhysiPlanScanCount, &pNode->count);
|
|
||||||
}
|
|
||||||
if (TSDB_CODE_SUCCESS == code) {
|
|
||||||
code = tjsonGetIntValue(pJson, jkScanPhysiPlanReverseScanCount, &pNode->reverse);
|
|
||||||
}
|
|
||||||
if (TSDB_CODE_SUCCESS == code) {
|
if (TSDB_CODE_SUCCESS == code) {
|
||||||
code = tjsonToObject(pJson, jkScanPhysiPlanTableName, jsonToName, &pNode->tableName);
|
code = tjsonToObject(pJson, jkScanPhysiPlanTableName, jsonToName, &pNode->tableName);
|
||||||
}
|
}
|
||||||
|
@ -742,7 +721,8 @@ static int32_t jsonToPhysiTagScanNode(const SJson* pJson, void* pObj) {
|
||||||
return jsonToPhysiScanNode(pJson, pObj);
|
return jsonToPhysiScanNode(pJson, pObj);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char* jkTableScanPhysiPlanScanFlag = "ScanFlag";
|
static const char* jkTableScanPhysiPlanScanCount = "ScanCount";
|
||||||
|
static const char* jkTableScanPhysiPlanReverseScanCount = "ReverseScanCount";
|
||||||
static const char* jkTableScanPhysiPlanStartKey = "StartKey";
|
static const char* jkTableScanPhysiPlanStartKey = "StartKey";
|
||||||
static const char* jkTableScanPhysiPlanEndKey = "EndKey";
|
static const char* jkTableScanPhysiPlanEndKey = "EndKey";
|
||||||
static const char* jkTableScanPhysiPlanRatio = "Ratio";
|
static const char* jkTableScanPhysiPlanRatio = "Ratio";
|
||||||
|
@ -759,7 +739,10 @@ static int32_t physiTableScanNodeToJson(const void* pObj, SJson* pJson) {
|
||||||
|
|
||||||
int32_t code = physiScanNodeToJson(pObj, pJson);
|
int32_t code = physiScanNodeToJson(pObj, pJson);
|
||||||
if (TSDB_CODE_SUCCESS == code) {
|
if (TSDB_CODE_SUCCESS == code) {
|
||||||
code = tjsonAddIntegerToObject(pJson, jkTableScanPhysiPlanScanFlag, pNode->scanFlag);
|
code = tjsonAddIntegerToObject(pJson, jkTableScanPhysiPlanScanCount, pNode->scanSeq[0]);
|
||||||
|
}
|
||||||
|
if (TSDB_CODE_SUCCESS == code) {
|
||||||
|
code = tjsonAddIntegerToObject(pJson, jkTableScanPhysiPlanReverseScanCount, pNode->scanSeq[1]);
|
||||||
}
|
}
|
||||||
if (TSDB_CODE_SUCCESS == code) {
|
if (TSDB_CODE_SUCCESS == code) {
|
||||||
code = tjsonAddIntegerToObject(pJson, jkTableScanPhysiPlanStartKey, pNode->scanRange.skey);
|
code = tjsonAddIntegerToObject(pJson, jkTableScanPhysiPlanStartKey, pNode->scanRange.skey);
|
||||||
|
@ -800,7 +783,10 @@ static int32_t jsonToPhysiTableScanNode(const SJson* pJson, void* pObj) {
|
||||||
|
|
||||||
int32_t code = jsonToPhysiScanNode(pJson, pObj);
|
int32_t code = jsonToPhysiScanNode(pJson, pObj);
|
||||||
if (TSDB_CODE_SUCCESS == code) {
|
if (TSDB_CODE_SUCCESS == code) {
|
||||||
code = tjsonGetUTinyIntValue(pJson, jkTableScanPhysiPlanScanFlag, &pNode->scanFlag);
|
code = tjsonGetUTinyIntValue(pJson, jkTableScanPhysiPlanScanCount, &pNode->scanSeq[0]);
|
||||||
|
}
|
||||||
|
if (TSDB_CODE_SUCCESS == code) {
|
||||||
|
code = tjsonGetUTinyIntValue(pJson, jkTableScanPhysiPlanReverseScanCount, &pNode->scanSeq[1]);
|
||||||
}
|
}
|
||||||
if (TSDB_CODE_SUCCESS == code) {
|
if (TSDB_CODE_SUCCESS == code) {
|
||||||
code = tjsonGetBigIntValue(pJson, jkTableScanPhysiPlanStartKey, &pNode->scanRange.skey);
|
code = tjsonGetBigIntValue(pJson, jkTableScanPhysiPlanStartKey, &pNode->scanRange.skey);
|
||||||
|
|
|
@ -611,6 +611,7 @@ function_expression(A) ::= function_name(B) NK_LP expression_list(C) NK_RP(D).
|
||||||
function_expression(A) ::= star_func(B) NK_LP star_func_para_list(C) NK_RP(D). { A = createRawExprNodeExt(pCxt, &B, &D, createFunctionNode(pCxt, &B, C)); }
|
function_expression(A) ::= star_func(B) NK_LP star_func_para_list(C) NK_RP(D). { A = createRawExprNodeExt(pCxt, &B, &D, createFunctionNode(pCxt, &B, C)); }
|
||||||
function_expression(A) ::= CAST(B) NK_LP expression(C) AS type_name(D) NK_RP(E). { A = createRawExprNodeExt(pCxt, &B, &E, createCastFunctionNode(pCxt, releaseRawExprNode(pCxt, C), D)); }
|
function_expression(A) ::= CAST(B) NK_LP expression(C) AS type_name(D) NK_RP(E). { A = createRawExprNodeExt(pCxt, &B, &E, createCastFunctionNode(pCxt, releaseRawExprNode(pCxt, C), D)); }
|
||||||
function_expression(A) ::= noarg_func(B) NK_LP NK_RP(C). { A = createRawExprNodeExt(pCxt, &B, &C, createFunctionNodeNoArg(pCxt, &B)); }
|
function_expression(A) ::= noarg_func(B) NK_LP NK_RP(C). { A = createRawExprNodeExt(pCxt, &B, &C, createFunctionNodeNoArg(pCxt, &B)); }
|
||||||
|
//function_expression(A) ::= NOW(B). { A = createRawExprNode(pCxt, &B, createFunctionNode(pCxt, &B, NULL)); }
|
||||||
|
|
||||||
%type noarg_func { SToken }
|
%type noarg_func { SToken }
|
||||||
%destructor noarg_func { }
|
%destructor noarg_func { }
|
||||||
|
|
|
@ -83,7 +83,7 @@ static EDealRes calcConstOperator(SOperatorNode** pNode, void* pContext) {
|
||||||
|
|
||||||
static EDealRes calcConstFunction(SFunctionNode** pNode, void* pContext) {
|
static EDealRes calcConstFunction(SFunctionNode** pNode, void* pContext) {
|
||||||
SFunctionNode* pFunc = *pNode;
|
SFunctionNode* pFunc = *pNode;
|
||||||
if (!fmIsScalarFunc(pFunc->funcId)) {
|
if (!fmIsScalarFunc(pFunc->funcId) || fmIsUserDefinedFunc(pFunc->funcId)) {
|
||||||
return DEAL_RES_CONTINUE;
|
return DEAL_RES_CONTINUE;
|
||||||
}
|
}
|
||||||
SNode* pParam = NULL;
|
SNode* pParam = NULL;
|
||||||
|
|
|
@ -543,7 +543,9 @@ static EDealRes translateOperator(STranslateContext* pCxt, SOperatorNode* pOp) {
|
||||||
TSDB_DATA_TYPE_BLOB == rdt.type) {
|
TSDB_DATA_TYPE_BLOB == rdt.type) {
|
||||||
return generateDealNodeErrMsg(pCxt, TSDB_CODE_PAR_WRONG_VALUE_TYPE, ((SExprNode*)(pOp->pRight))->aliasName);
|
return generateDealNodeErrMsg(pCxt, TSDB_CODE_PAR_WRONG_VALUE_TYPE, ((SExprNode*)(pOp->pRight))->aliasName);
|
||||||
}
|
}
|
||||||
if (TSDB_DATA_TYPE_TIMESTAMP == ldt.type && TSDB_DATA_TYPE_TIMESTAMP == rdt.type) {
|
if ((TSDB_DATA_TYPE_TIMESTAMP == ldt.type && TSDB_DATA_TYPE_TIMESTAMP == rdt.type) ||
|
||||||
|
(TSDB_DATA_TYPE_TIMESTAMP == ldt.type && IS_VAR_DATA_TYPE(rdt.type)) ||
|
||||||
|
(TSDB_DATA_TYPE_TIMESTAMP == rdt.type && IS_VAR_DATA_TYPE(ldt.type))) {
|
||||||
return generateDealNodeErrMsg(pCxt, TSDB_CODE_PAR_WRONG_VALUE_TYPE, ((SExprNode*)(pOp->pRight))->aliasName);
|
return generateDealNodeErrMsg(pCxt, TSDB_CODE_PAR_WRONG_VALUE_TYPE, ((SExprNode*)(pOp->pRight))->aliasName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2614,37 +2616,62 @@ static int32_t translateDropComponentNode(STranslateContext* pCxt, SDropComponen
|
||||||
(FSerializeFunc)tSerializeSCreateDropMQSBNodeReq, &dropReq);
|
(FSerializeFunc)tSerializeSCreateDropMQSBNodeReq, &dropReq);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int32_t translateCreateTopic(STranslateContext* pCxt, SCreateTopicStmt* pStmt) {
|
static int32_t buildCreateTopicReq(STranslateContext* pCxt, SCreateTopicStmt* pStmt, SCMCreateTopicReq* pReq) {
|
||||||
SCMCreateTopicReq createReq = {0};
|
SName name;
|
||||||
|
// tNameSetDbName(&name, pCxt->pParseCxt->acctId, pStmt->topicName, strlen(pStmt->topicName));
|
||||||
|
// tNameGetFullDbName(&name, pReq->name);
|
||||||
|
tNameExtractFullName(toName(pCxt->pParseCxt->acctId, pCxt->pParseCxt->db, pStmt->topicName, &name), pReq->name);
|
||||||
|
pReq->igExists = pStmt->ignoreExists;
|
||||||
|
pReq->withTbName = pStmt->pOptions->withTable;
|
||||||
|
pReq->withSchema = pStmt->pOptions->withSchema;
|
||||||
|
pReq->withTag = pStmt->pOptions->withTag;
|
||||||
|
|
||||||
if (NULL != pStmt->pQuery) {
|
pReq->sql = strdup(pCxt->pParseCxt->pSql);
|
||||||
pCxt->pParseCxt->topicQuery = true;
|
if (NULL == pReq->sql) {
|
||||||
int32_t code = translateQuery(pCxt, pStmt->pQuery);
|
|
||||||
if (TSDB_CODE_SUCCESS == code) {
|
|
||||||
code = nodesNodeToString(pStmt->pQuery, false, &createReq.ast, NULL);
|
|
||||||
}
|
|
||||||
if (TSDB_CODE_SUCCESS != code) {
|
|
||||||
return code;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
strcpy(createReq.subscribeDbName, pStmt->subscribeDbName);
|
|
||||||
}
|
|
||||||
|
|
||||||
createReq.sql = strdup(pCxt->pParseCxt->pSql);
|
|
||||||
if (NULL == createReq.sql) {
|
|
||||||
return TSDB_CODE_OUT_OF_MEMORY;
|
return TSDB_CODE_OUT_OF_MEMORY;
|
||||||
}
|
}
|
||||||
|
|
||||||
SName name;
|
int32_t code = TSDB_CODE_SUCCESS;
|
||||||
// tNameSetDbName(&name, pCxt->pParseCxt->acctId, pCxt->pParseCxt->db, strlen(pCxt->pParseCxt->db));
|
|
||||||
// tNameGetFullDbName(&name, createReq.name);
|
|
||||||
tNameExtractFullName(toName(pCxt->pParseCxt->acctId, pCxt->pParseCxt->db, pStmt->topicName, &name), createReq.name);
|
|
||||||
createReq.igExists = pStmt->ignoreExists;
|
|
||||||
createReq.withTbName = pStmt->pOptions->withTable;
|
|
||||||
createReq.withSchema = pStmt->pOptions->withSchema;
|
|
||||||
createReq.withTag = pStmt->pOptions->withTag;
|
|
||||||
|
|
||||||
int32_t code = buildCmdMsg(pCxt, TDMT_MND_CREATE_TOPIC, (FSerializeFunc)tSerializeSCMCreateTopicReq, &createReq);
|
if (NULL != pStmt->pQuery) {
|
||||||
|
strcpy(pReq->subscribeDbName, ((SRealTableNode*)(((SSelectStmt*)pStmt->pQuery)->pFromTable))->table.dbName);
|
||||||
|
pCxt->pParseCxt->topicQuery = true;
|
||||||
|
code = translateQuery(pCxt, pStmt->pQuery);
|
||||||
|
if (TSDB_CODE_SUCCESS == code) {
|
||||||
|
code = nodesNodeToString(pStmt->pQuery, false, &pReq->ast, NULL);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
strcpy(pReq->subscribeDbName, pStmt->subscribeDbName);
|
||||||
|
}
|
||||||
|
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int32_t checkCreateTopic(STranslateContext* pCxt, SCreateTopicStmt* pStmt) {
|
||||||
|
if (NULL == pStmt->pQuery) {
|
||||||
|
return TSDB_CODE_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (QUERY_NODE_SELECT_STMT == nodeType(pStmt->pQuery)) {
|
||||||
|
SSelectStmt* pSelect = (SSelectStmt*)pStmt->pQuery;
|
||||||
|
if (!pSelect->isDistinct && QUERY_NODE_REAL_TABLE == nodeType(pSelect->pFromTable) && NULL == pSelect->pGroupByList &&
|
||||||
|
NULL == pSelect->pLimit && NULL == pSelect->pSlimit && NULL == pSelect->pOrderByList && NULL == pSelect->pPartitionByList) {
|
||||||
|
return TSDB_CODE_SUCCESS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return generateSyntaxErrMsg(&pCxt->msgBuf, TSDB_CODE_PAR_INVALID_TOPIC_QUERY);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int32_t translateCreateTopic(STranslateContext* pCxt, SCreateTopicStmt* pStmt) {
|
||||||
|
SCMCreateTopicReq createReq = {0};
|
||||||
|
int32_t code = checkCreateTopic(pCxt, pStmt);
|
||||||
|
if (TSDB_CODE_SUCCESS == code) {
|
||||||
|
code = buildCreateTopicReq(pCxt, pStmt, &createReq);
|
||||||
|
}
|
||||||
|
if (TSDB_CODE_SUCCESS == code) {
|
||||||
|
code = buildCmdMsg(pCxt, TDMT_MND_CREATE_TOPIC, (FSerializeFunc)tSerializeSCMCreateTopicReq, &createReq);
|
||||||
|
}
|
||||||
tFreeSCMCreateTopicReq(&createReq);
|
tFreeSCMCreateTopicReq(&createReq);
|
||||||
return code;
|
return code;
|
||||||
}
|
}
|
||||||
|
|
|
@ -128,6 +128,8 @@ static char* getSyntaxErrFormat(int32_t errCode) {
|
||||||
return "soffset/offset can not be less than 0";
|
return "soffset/offset can not be less than 0";
|
||||||
case TSDB_CODE_PAR_SLIMIT_LEAK_PARTITION_BY:
|
case TSDB_CODE_PAR_SLIMIT_LEAK_PARTITION_BY:
|
||||||
return "slimit/soffset only available for PARTITION BY query";
|
return "slimit/soffset only available for PARTITION BY query";
|
||||||
|
case TSDB_CODE_PAR_INVALID_TOPIC_QUERY:
|
||||||
|
return "Invalid topic query";
|
||||||
case TSDB_CODE_OUT_OF_MEMORY:
|
case TSDB_CODE_OUT_OF_MEMORY:
|
||||||
return "Out of memory";
|
return "Out of memory";
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -199,7 +199,8 @@ static int32_t createScanLogicNode(SLogicPlanContext* pCxt, SSelectStmt* pSelect
|
||||||
|
|
||||||
TSWAP(pScan->pMeta, pRealTable->pMeta, STableMeta*);
|
TSWAP(pScan->pMeta, pRealTable->pMeta, STableMeta*);
|
||||||
TSWAP(pScan->pVgroupList, pRealTable->pVgroupList, SVgroupsInfo*);
|
TSWAP(pScan->pVgroupList, pRealTable->pVgroupList, SVgroupsInfo*);
|
||||||
pScan->scanFlag = MAIN_SCAN;
|
pScan->scanSeq[0] = 1;
|
||||||
|
pScan->scanSeq[1] = 0;
|
||||||
pScan->scanRange = TSWINDOW_INITIALIZER;
|
pScan->scanRange = TSWINDOW_INITIALIZER;
|
||||||
pScan->tableName.type = TSDB_TABLE_NAME_T;
|
pScan->tableName.type = TSDB_TABLE_NAME_T;
|
||||||
pScan->tableName.acctId = pCxt->pPlanCxt->acctId;
|
pScan->tableName.acctId = pCxt->pPlanCxt->acctId;
|
||||||
|
|
|
@ -20,11 +20,14 @@
|
||||||
#define OPTIMIZE_FLAG_MASK(n) (1 << n)
|
#define OPTIMIZE_FLAG_MASK(n) (1 << n)
|
||||||
|
|
||||||
#define OPTIMIZE_FLAG_OSD OPTIMIZE_FLAG_MASK(0)
|
#define OPTIMIZE_FLAG_OSD OPTIMIZE_FLAG_MASK(0)
|
||||||
|
#define OPTIMIZE_FLAG_CPD OPTIMIZE_FLAG_MASK(1)
|
||||||
|
#define OPTIMIZE_FLAG_OPK OPTIMIZE_FLAG_MASK(2)
|
||||||
|
|
||||||
#define OPTIMIZE_FLAG_SET_MASK(val, mask) (val) |= (mask)
|
#define OPTIMIZE_FLAG_SET_MASK(val, mask) (val) |= (mask)
|
||||||
#define OPTIMIZE_FLAG_TEST_MASK(val, mask) (((val) & (mask)) != 0)
|
#define OPTIMIZE_FLAG_TEST_MASK(val, mask) (((val) & (mask)) != 0)
|
||||||
|
|
||||||
typedef struct SOptimizeContext {
|
typedef struct SOptimizeContext {
|
||||||
|
SPlanContext* pPlanCxt;
|
||||||
bool optimized;
|
bool optimized;
|
||||||
} SOptimizeContext;
|
} SOptimizeContext;
|
||||||
|
|
||||||
|
@ -57,7 +60,23 @@ typedef enum ECondAction {
|
||||||
// after supporting outer join, there are other possibilities
|
// after supporting outer join, there are other possibilities
|
||||||
} ECondAction;
|
} ECondAction;
|
||||||
|
|
||||||
EDealRes haveNormalColImpl(SNode* pNode, void* pContext) {
|
typedef bool (*FMayBeOptimized)(SLogicNode* pNode);
|
||||||
|
|
||||||
|
static SLogicNode* optFindPossibleNode(SLogicNode* pNode, FMayBeOptimized func) {
|
||||||
|
if (func(pNode)) {
|
||||||
|
return pNode;
|
||||||
|
}
|
||||||
|
SNode* pChild;
|
||||||
|
FOREACH(pChild, pNode->pChildren) {
|
||||||
|
SLogicNode* pScanNode = optFindPossibleNode((SLogicNode*)pChild, func);
|
||||||
|
if (NULL != pScanNode) {
|
||||||
|
return pScanNode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
EDealRes osdHaveNormalColImpl(SNode* pNode, void* pContext) {
|
||||||
if (QUERY_NODE_COLUMN == nodeType(pNode)) {
|
if (QUERY_NODE_COLUMN == nodeType(pNode)) {
|
||||||
*((bool*)pContext) = (COLUMN_TYPE_TAG != ((SColumnNode*)pNode)->colType);
|
*((bool*)pContext) = (COLUMN_TYPE_TAG != ((SColumnNode*)pNode)->colType);
|
||||||
return *((bool*)pContext) ? DEAL_RES_END : DEAL_RES_IGNORE_CHILD;
|
return *((bool*)pContext) ? DEAL_RES_END : DEAL_RES_IGNORE_CHILD;
|
||||||
|
@ -65,9 +84,9 @@ EDealRes haveNormalColImpl(SNode* pNode, void* pContext) {
|
||||||
return DEAL_RES_CONTINUE;
|
return DEAL_RES_CONTINUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool haveNormalCol(SNodeList* pList) {
|
static bool osdHaveNormalCol(SNodeList* pList) {
|
||||||
bool res = false;
|
bool res = false;
|
||||||
nodesWalkExprsPostOrder(pList, haveNormalColImpl, &res);
|
nodesWalkExprsPostOrder(pList, osdHaveNormalColImpl, &res);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -89,21 +108,7 @@ static bool osdMayBeOptimized(SLogicNode* pNode) {
|
||||||
if (QUERY_NODE_LOGIC_PLAN_WINDOW == nodeType(pNode->pParent)) {
|
if (QUERY_NODE_LOGIC_PLAN_WINDOW == nodeType(pNode->pParent)) {
|
||||||
return (WINDOW_TYPE_INTERVAL == ((SWindowLogicNode*)pNode->pParent)->winType);
|
return (WINDOW_TYPE_INTERVAL == ((SWindowLogicNode*)pNode->pParent)->winType);
|
||||||
}
|
}
|
||||||
return !haveNormalCol(((SAggLogicNode*)pNode->pParent)->pGroupKeys);
|
return !osdHaveNormalCol(((SAggLogicNode*)pNode->pParent)->pGroupKeys);
|
||||||
}
|
|
||||||
|
|
||||||
static SLogicNode* osdFindPossibleScanNode(SLogicNode* pNode) {
|
|
||||||
if (osdMayBeOptimized(pNode)) {
|
|
||||||
return pNode;
|
|
||||||
}
|
|
||||||
SNode* pChild;
|
|
||||||
FOREACH(pChild, pNode->pChildren) {
|
|
||||||
SLogicNode* pScanNode = osdFindPossibleScanNode((SLogicNode*)pChild);
|
|
||||||
if (NULL != pScanNode) {
|
|
||||||
return pScanNode;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static SNodeList* osdGetAllFuncs(SLogicNode* pNode) {
|
static SNodeList* osdGetAllFuncs(SLogicNode* pNode) {
|
||||||
|
@ -138,7 +143,7 @@ static int32_t osdGetRelatedFuncs(SScanLogicNode* pScan, SNodeList** pSdrFuncs,
|
||||||
}
|
}
|
||||||
|
|
||||||
static int32_t osdMatch(SOptimizeContext* pCxt, SLogicNode* pLogicNode, SOsdInfo* pInfo) {
|
static int32_t osdMatch(SOptimizeContext* pCxt, SLogicNode* pLogicNode, SOsdInfo* pInfo) {
|
||||||
pInfo->pScan = (SScanLogicNode*)osdFindPossibleScanNode(pLogicNode);
|
pInfo->pScan = (SScanLogicNode*)optFindPossibleNode(pLogicNode, osdMayBeOptimized);
|
||||||
if (NULL == pInfo->pScan) {
|
if (NULL == pInfo->pScan) {
|
||||||
return TSDB_CODE_SUCCESS;
|
return TSDB_CODE_SUCCESS;
|
||||||
}
|
}
|
||||||
|
@ -345,7 +350,7 @@ static int32_t cpdCalcTimeRange(SScanLogicNode* pScan, SNode** pPrimaryKeyCond,
|
||||||
}
|
}
|
||||||
|
|
||||||
static int32_t cpdOptimizeScanCondition(SOptimizeContext* pCxt, SScanLogicNode* pScan) {
|
static int32_t cpdOptimizeScanCondition(SOptimizeContext* pCxt, SScanLogicNode* pScan) {
|
||||||
if (NULL == pScan->node.pConditions) {
|
if (NULL == pScan->node.pConditions || OPTIMIZE_FLAG_TEST_MASK(pScan->node.optimizedFlag, OPTIMIZE_FLAG_CPD)) {
|
||||||
return TSDB_CODE_SUCCESS;
|
return TSDB_CODE_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -359,7 +364,10 @@ static int32_t cpdOptimizeScanCondition(SOptimizeContext* pCxt, SScanLogicNode*
|
||||||
pScan->node.pConditions = pOtherCond;
|
pScan->node.pConditions = pOtherCond;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (TSDB_CODE_SUCCESS != code) {
|
if (TSDB_CODE_SUCCESS == code) {
|
||||||
|
OPTIMIZE_FLAG_SET_MASK(pScan->node.optimizedFlag, OPTIMIZE_FLAG_CPD);
|
||||||
|
pCxt->optimized = true;
|
||||||
|
} else {
|
||||||
nodesDestroyNode(pPrimaryKeyCond);
|
nodesDestroyNode(pPrimaryKeyCond);
|
||||||
nodesDestroyNode(pOtherCond);
|
nodesDestroyNode(pOtherCond);
|
||||||
}
|
}
|
||||||
|
@ -367,7 +375,7 @@ static int32_t cpdOptimizeScanCondition(SOptimizeContext* pCxt, SScanLogicNode*
|
||||||
return code;
|
return code;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool belongThisTable(SNode* pCondCol, SNodeList* pTableCols) {
|
static bool cpdBelongThisTable(SNode* pCondCol, SNodeList* pTableCols) {
|
||||||
SNode* pTableCol = NULL;
|
SNode* pTableCol = NULL;
|
||||||
FOREACH(pTableCol, pTableCols) {
|
FOREACH(pTableCol, pTableCols) {
|
||||||
if (nodesEqualNode(pCondCol, pTableCol)) {
|
if (nodesEqualNode(pCondCol, pTableCol)) {
|
||||||
|
@ -380,9 +388,9 @@ static bool belongThisTable(SNode* pCondCol, SNodeList* pTableCols) {
|
||||||
static EDealRes cpdIsMultiTableCondImpl(SNode* pNode, void* pContext) {
|
static EDealRes cpdIsMultiTableCondImpl(SNode* pNode, void* pContext) {
|
||||||
SCpdIsMultiTableCondCxt* pCxt = pContext;
|
SCpdIsMultiTableCondCxt* pCxt = pContext;
|
||||||
if (QUERY_NODE_COLUMN == nodeType(pNode)) {
|
if (QUERY_NODE_COLUMN == nodeType(pNode)) {
|
||||||
if (belongThisTable(pNode, pCxt->pLeftCols)) {
|
if (cpdBelongThisTable(pNode, pCxt->pLeftCols)) {
|
||||||
pCxt->havaLeftCol = true;
|
pCxt->havaLeftCol = true;
|
||||||
} else if (belongThisTable(pNode, pCxt->pRightCols)) {
|
} else if (cpdBelongThisTable(pNode, pCxt->pRightCols)) {
|
||||||
pCxt->haveRightCol = true;
|
pCxt->haveRightCol = true;
|
||||||
}
|
}
|
||||||
return pCxt->havaLeftCol && pCxt->haveRightCol ? DEAL_RES_END : DEAL_RES_CONTINUE;
|
return pCxt->havaLeftCol && pCxt->haveRightCol ? DEAL_RES_END : DEAL_RES_CONTINUE;
|
||||||
|
@ -508,11 +516,76 @@ static int32_t cpdPushCondToChild(SOptimizeContext* pCxt, SLogicNode* pChild, SN
|
||||||
return TSDB_CODE_PLAN_INTERNAL_ERROR;
|
return TSDB_CODE_PLAN_INTERNAL_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool cpdIsPrimaryKey(SNode* pNode, SNodeList* pTableCols) {
|
||||||
|
if (QUERY_NODE_COLUMN != nodeType(pNode)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
SColumnNode* pCol = (SColumnNode*)pNode;
|
||||||
|
if (PRIMARYKEY_TIMESTAMP_COL_ID != pCol->colId) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return cpdBelongThisTable(pNode, pTableCols);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool cpdIsPrimaryKeyEqualCond(SJoinLogicNode* pJoin, SNode* pCond) {
|
||||||
|
if (QUERY_NODE_OPERATOR != nodeType(pCond)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
SNodeList* pLeftCols = ((SLogicNode*)nodesListGetNode(pJoin->node.pChildren, 0))->pTargets;
|
||||||
|
SNodeList* pRightCols = ((SLogicNode*)nodesListGetNode(pJoin->node.pChildren, 1))->pTargets;
|
||||||
|
SOperatorNode* pOper = (SOperatorNode*)pJoin->pOnConditions;
|
||||||
|
if (cpdIsPrimaryKey(pOper->pLeft, pLeftCols)) {
|
||||||
|
return cpdIsPrimaryKey(pOper->pRight, pRightCols);
|
||||||
|
} else if (cpdIsPrimaryKey(pOper->pLeft, pRightCols)) {
|
||||||
|
return cpdIsPrimaryKey(pOper->pRight, pLeftCols);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int32_t cpdCheckOpCond(SOptimizeContext* pCxt, SJoinLogicNode* pJoin, SNode* pOnCond) {
|
||||||
|
if (!cpdIsPrimaryKeyEqualCond(pJoin, pOnCond)) {
|
||||||
|
snprintf(pCxt->pPlanCxt->pMsg, pCxt->pPlanCxt->msgLen, "l.ts = r.ts is expected in join expression");
|
||||||
|
return TSDB_CODE_FAILED;
|
||||||
|
}
|
||||||
|
return TSDB_CODE_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int32_t cpdCheckLogicCond(SOptimizeContext* pCxt, SJoinLogicNode* pJoin, SLogicConditionNode* pOnCond) {
|
||||||
|
if (LOGIC_COND_TYPE_AND != pOnCond->condType) {
|
||||||
|
snprintf(pCxt->pPlanCxt->pMsg, pCxt->pPlanCxt->msgLen, "l.ts = r.ts is expected in join expression");
|
||||||
|
return TSDB_CODE_FAILED;
|
||||||
|
}
|
||||||
|
SNode* pCond = NULL;
|
||||||
|
FOREACH(pCond, pOnCond->pParameterList) {
|
||||||
|
if (!cpdIsPrimaryKeyEqualCond(pJoin, pCond)) {
|
||||||
|
snprintf(pCxt->pPlanCxt->pMsg, pCxt->pPlanCxt->msgLen, "l.ts = r.ts is expected in join expression");
|
||||||
|
return TSDB_CODE_FAILED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return TSDB_CODE_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int32_t cpdCheckJoinOnCond(SOptimizeContext* pCxt, SJoinLogicNode* pJoin) {
|
||||||
|
if (NULL == pJoin->pOnConditions) {
|
||||||
|
snprintf(pCxt->pPlanCxt->pMsg, pCxt->pPlanCxt->msgLen, "not support cross join");
|
||||||
|
return TSDB_CODE_FAILED;
|
||||||
|
}
|
||||||
|
if (QUERY_NODE_LOGIC_CONDITION == nodeType(pJoin->pOnConditions)) {
|
||||||
|
return cpdCheckLogicCond(pCxt, pJoin, (SLogicConditionNode*)pJoin->pOnConditions);
|
||||||
|
} else {
|
||||||
|
return cpdCheckOpCond(pCxt, pJoin, pJoin->pOnConditions);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static int32_t cpdPushJoinCondition(SOptimizeContext* pCxt, SJoinLogicNode* pJoin) {
|
static int32_t cpdPushJoinCondition(SOptimizeContext* pCxt, SJoinLogicNode* pJoin) {
|
||||||
if (NULL == pJoin->node.pConditions) {
|
if (OPTIMIZE_FLAG_TEST_MASK(pJoin->node.optimizedFlag, OPTIMIZE_FLAG_CPD)) {
|
||||||
return TSDB_CODE_SUCCESS;
|
return TSDB_CODE_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (NULL == pJoin->node.pConditions) {
|
||||||
|
return cpdCheckJoinOnCond(pCxt, pJoin);
|
||||||
|
}
|
||||||
|
|
||||||
SNode* pOnCond = NULL;
|
SNode* pOnCond = NULL;
|
||||||
SNode* pLeftChildCond = NULL;
|
SNode* pLeftChildCond = NULL;
|
||||||
SNode* pRightChildCond = NULL;
|
SNode* pRightChildCond = NULL;
|
||||||
|
@ -527,7 +600,11 @@ static int32_t cpdPushJoinCondition(SOptimizeContext* pCxt, SJoinLogicNode* pJoi
|
||||||
code = cpdPushCondToChild(pCxt, (SLogicNode*)nodesListGetNode(pJoin->node.pChildren, 1), &pRightChildCond);
|
code = cpdPushCondToChild(pCxt, (SLogicNode*)nodesListGetNode(pJoin->node.pChildren, 1), &pRightChildCond);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (TSDB_CODE_SUCCESS != code) {
|
if (TSDB_CODE_SUCCESS == code) {
|
||||||
|
OPTIMIZE_FLAG_SET_MASK(pJoin->node.optimizedFlag, OPTIMIZE_FLAG_CPD);
|
||||||
|
pCxt->optimized = true;
|
||||||
|
code = cpdCheckJoinOnCond(pCxt, pJoin);
|
||||||
|
} else {
|
||||||
nodesDestroyNode(pOnCond);
|
nodesDestroyNode(pOnCond);
|
||||||
nodesDestroyNode(pLeftChildCond);
|
nodesDestroyNode(pLeftChildCond);
|
||||||
nodesDestroyNode(pRightChildCond);
|
nodesDestroyNode(pRightChildCond);
|
||||||
|
@ -572,15 +649,129 @@ static int32_t cpdOptimize(SOptimizeContext* pCxt, SLogicNode* pLogicNode) {
|
||||||
return cpdPushCondition(pCxt, pLogicNode);
|
return cpdPushCondition(pCxt, pLogicNode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool opkIsPrimaryKeyOrderBy(SNodeList* pSortKeys) {
|
||||||
|
if (1 != LIST_LENGTH(pSortKeys)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
SNode* pNode = ((SOrderByExprNode*)nodesListGetNode(pSortKeys, 0))->pExpr;
|
||||||
|
return (QUERY_NODE_COLUMN == nodeType(pNode) ? (PRIMARYKEY_TIMESTAMP_COL_ID == ((SColumnNode*)pNode)->colId) : false);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool opkSortMayBeOptimized(SLogicNode* pNode) {
|
||||||
|
if (QUERY_NODE_LOGIC_PLAN_SORT != nodeType(pNode)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (OPTIMIZE_FLAG_TEST_MASK(pNode->optimizedFlag, OPTIMIZE_FLAG_OPK)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int32_t opkGetScanNodesImpl(SLogicNode* pNode, bool* pNotOptimize, SNodeList** pScanNodes) {
|
||||||
|
int32_t code = TSDB_CODE_SUCCESS;
|
||||||
|
|
||||||
|
switch (nodeType(pNode)) {
|
||||||
|
case QUERY_NODE_LOGIC_PLAN_SCAN:
|
||||||
|
return nodesListMakeAppend(pScanNodes, pNode);
|
||||||
|
case QUERY_NODE_LOGIC_PLAN_JOIN:
|
||||||
|
code = opkGetScanNodesImpl(nodesListGetNode(pNode->pChildren, 0), pNotOptimize, pScanNodes);
|
||||||
|
if (TSDB_CODE_SUCCESS == code) {
|
||||||
|
code = opkGetScanNodesImpl(nodesListGetNode(pNode->pChildren, 1), pNotOptimize, pScanNodes);
|
||||||
|
}
|
||||||
|
return code;
|
||||||
|
case QUERY_NODE_LOGIC_PLAN_AGG:
|
||||||
|
*pNotOptimize = true;
|
||||||
|
return code;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (1 != LIST_LENGTH(pNode->pChildren)) {
|
||||||
|
*pNotOptimize = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return opkGetScanNodesImpl(nodesListGetNode(pNode->pChildren, 0), pNotOptimize, pScanNodes);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int32_t opkGetScanNodes(SLogicNode* pNode, SNodeList** pScanNodes) {
|
||||||
|
bool notOptimize = false;
|
||||||
|
int32_t code = opkGetScanNodesImpl(pNode, ¬Optimize, pScanNodes);
|
||||||
|
if (TSDB_CODE_SUCCESS != code || notOptimize) {
|
||||||
|
nodesClearList(*pScanNodes);
|
||||||
|
}
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
||||||
|
static EOrder opkGetPrimaryKeyOrder(SSortLogicNode* pSort) {
|
||||||
|
return ((SOrderByExprNode*)nodesListGetNode(pSort->pSortKeys, 0))->order;
|
||||||
|
}
|
||||||
|
|
||||||
|
static SNode* opkRewriteDownNode(SSortLogicNode* pSort) {
|
||||||
|
SNode* pDownNode = nodesListGetNode(pSort->node.pChildren, 0);
|
||||||
|
// todo
|
||||||
|
pSort->node.pChildren = NULL;
|
||||||
|
return pDownNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int32_t opkDoOptimized(SOptimizeContext* pCxt, SSortLogicNode* pSort, SNodeList* pScanNodes) {
|
||||||
|
EOrder order = opkGetPrimaryKeyOrder(pSort);
|
||||||
|
if (ORDER_DESC == order) {
|
||||||
|
SNode* pScan = NULL;
|
||||||
|
FOREACH(pScan, pScanNodes) {
|
||||||
|
((SScanLogicNode*)pScan)->scanSeq[0] = 0;
|
||||||
|
((SScanLogicNode*)pScan)->scanSeq[1] = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (NULL == pSort->node.pParent) {
|
||||||
|
// todo
|
||||||
|
return TSDB_CODE_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
SNode* pDownNode = opkRewriteDownNode(pSort);
|
||||||
|
SNode* pNode;
|
||||||
|
FOREACH(pNode, pSort->node.pParent->pChildren) {
|
||||||
|
if (nodesEqualNode(pNode, pSort)) {
|
||||||
|
REPLACE_NODE(pDownNode);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
nodesDestroyNode(pSort);
|
||||||
|
return TSDB_CODE_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int32_t opkOptimizeImpl(SOptimizeContext* pCxt, SSortLogicNode* pSort) {
|
||||||
|
OPTIMIZE_FLAG_SET_MASK(pSort->node.optimizedFlag, OPTIMIZE_FLAG_OPK);
|
||||||
|
if (!opkIsPrimaryKeyOrderBy(pSort->pSortKeys) || 1 != LIST_LENGTH(pSort->node.pChildren)) {
|
||||||
|
return TSDB_CODE_SUCCESS;
|
||||||
|
}
|
||||||
|
SNodeList* pScanNodes = NULL;
|
||||||
|
int32_t code = opkGetScanNodes(nodesListGetNode(pSort->node.pChildren, 0), &pScanNodes);
|
||||||
|
if (TSDB_CODE_SUCCESS == code && NULL != pScanNodes) {
|
||||||
|
code = opkDoOptimized(pCxt, pSort, pScanNodes);
|
||||||
|
}
|
||||||
|
nodesClearList(pScanNodes);
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int32_t opkOptimize(SOptimizeContext* pCxt, SLogicNode* pLogicNode) {
|
||||||
|
SSortLogicNode* pSort = (SSortLogicNode*)optFindPossibleNode(pLogicNode, opkSortMayBeOptimized);
|
||||||
|
if (NULL == pSort) {
|
||||||
|
return TSDB_CODE_SUCCESS;
|
||||||
|
}
|
||||||
|
return opkOptimizeImpl(pCxt, pSort);
|
||||||
|
}
|
||||||
|
|
||||||
static const SOptimizeRule optimizeRuleSet[] = {
|
static const SOptimizeRule optimizeRuleSet[] = {
|
||||||
{ .pName = "OptimizeScanData", .optimizeFunc = osdOptimize },
|
{ .pName = "OptimizeScanData", .optimizeFunc = osdOptimize },
|
||||||
{ .pName = "ConditionPushDown", .optimizeFunc = cpdOptimize }
|
{ .pName = "ConditionPushDown", .optimizeFunc = cpdOptimize },
|
||||||
|
{ .pName = "OrderByPrimaryKey", .optimizeFunc = opkOptimize }
|
||||||
};
|
};
|
||||||
|
|
||||||
static const int32_t optimizeRuleNum = (sizeof(optimizeRuleSet) / sizeof(SOptimizeRule));
|
static const int32_t optimizeRuleNum = (sizeof(optimizeRuleSet) / sizeof(SOptimizeRule));
|
||||||
|
|
||||||
static int32_t applyOptimizeRule(SLogicNode* pLogicNode) {
|
static int32_t applyOptimizeRule(SPlanContext* pCxt, SLogicNode* pLogicNode) {
|
||||||
SOptimizeContext cxt = { .optimized = false };
|
SOptimizeContext cxt = { .pPlanCxt = pCxt, .optimized = false };
|
||||||
do {
|
do {
|
||||||
cxt.optimized = false;
|
cxt.optimized = false;
|
||||||
for (int32_t i = 0; i < optimizeRuleNum; ++i) {
|
for (int32_t i = 0; i < optimizeRuleNum; ++i) {
|
||||||
|
@ -594,5 +785,5 @@ static int32_t applyOptimizeRule(SLogicNode* pLogicNode) {
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t optimizeLogicPlan(SPlanContext* pCxt, SLogicNode* pLogicNode) {
|
int32_t optimizeLogicPlan(SPlanContext* pCxt, SLogicNode* pLogicNode) {
|
||||||
return applyOptimizeRule(pLogicNode);
|
return applyOptimizeRule(pCxt, pLogicNode);
|
||||||
}
|
}
|
||||||
|
|
|
@ -398,9 +398,6 @@ static int32_t createScanPhysiNodeFinalize(SPhysiPlanContext* pCxt, SScanLogicNo
|
||||||
if (TSDB_CODE_SUCCESS == code) {
|
if (TSDB_CODE_SUCCESS == code) {
|
||||||
pScanPhysiNode->uid = pScanLogicNode->pMeta->uid;
|
pScanPhysiNode->uid = pScanLogicNode->pMeta->uid;
|
||||||
pScanPhysiNode->tableType = pScanLogicNode->pMeta->tableType;
|
pScanPhysiNode->tableType = pScanLogicNode->pMeta->tableType;
|
||||||
pScanPhysiNode->order = TSDB_ORDER_ASC;
|
|
||||||
pScanPhysiNode->count = 1;
|
|
||||||
pScanPhysiNode->reverse = 0;
|
|
||||||
memcpy(&pScanPhysiNode->tableName, &pScanLogicNode->tableName, sizeof(SName));
|
memcpy(&pScanPhysiNode->tableName, &pScanLogicNode->tableName, sizeof(SName));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -432,7 +429,7 @@ static int32_t createTableScanPhysiNode(SPhysiPlanContext* pCxt, SSubplan* pSubp
|
||||||
return TSDB_CODE_OUT_OF_MEMORY;
|
return TSDB_CODE_OUT_OF_MEMORY;
|
||||||
}
|
}
|
||||||
|
|
||||||
pTableScan->scanFlag = pScanLogicNode->scanFlag;
|
memcpy(pTableScan->scanSeq, pScanLogicNode->scanSeq, sizeof(pScanLogicNode->scanSeq));
|
||||||
pTableScan->scanRange = pScanLogicNode->scanRange;
|
pTableScan->scanRange = pScanLogicNode->scanRange;
|
||||||
pTableScan->ratio = pScanLogicNode->ratio;
|
pTableScan->ratio = pScanLogicNode->ratio;
|
||||||
vgroupInfoToNodeAddr(pScanLogicNode->pVgroupList->vgroups, &pSubplan->execNode);
|
vgroupInfoToNodeAddr(pScanLogicNode->pVgroupList->vgroups, &pSubplan->execNode);
|
||||||
|
|
|
@ -13,17 +13,20 @@
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef TDENGINE_TNETTEST_H
|
#include "planTestUtil.h"
|
||||||
#define TDENGINE_TNETTEST_H
|
#include "planner.h"
|
||||||
|
|
||||||
#ifdef __cplusplus
|
using namespace std;
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void taosNetTest(char *role, char *host, int32_t port, int32_t pkgLen, int32_t pkgNum, char *pkgType);
|
class PlanOptimizeTest : public PlannerTestBase {
|
||||||
|
|
||||||
#ifdef __cplusplus
|
};
|
||||||
|
|
||||||
|
TEST_F(PlanOptimizeTest, orderByPrimaryKey) {
|
||||||
|
useDb("root", "test");
|
||||||
|
|
||||||
|
run("select * from t1 order by ts");
|
||||||
|
run("select * from t1 order by ts desc");
|
||||||
|
run("select c1 from t1 order by ts");
|
||||||
|
run("select c1 from t1 order by ts desc");
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif // TDENGINE_TNETTEST_H
|
|
|
@ -32,8 +32,8 @@ int32_t absFunction(SScalarParam *pInput, int32_t inputNum, SScalarParam *pOutpu
|
||||||
float *in = (float *)pInputData->pData;
|
float *in = (float *)pInputData->pData;
|
||||||
float *out = (float *)pOutputData->pData;
|
float *out = (float *)pOutputData->pData;
|
||||||
for (int32_t i = 0; i < pInput->numOfRows; ++i) {
|
for (int32_t i = 0; i < pInput->numOfRows; ++i) {
|
||||||
if (colDataIsNull_f(pInputData->nullbitmap, i)) {
|
if (colDataIsNull_s(pInputData, i)) {
|
||||||
colDataSetNull_f(pOutputData->nullbitmap, i);
|
colDataAppendNULL(pOutputData, i);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
out[i] = (in[i] >= 0)? in[i] : -in[i];
|
out[i] = (in[i] >= 0)? in[i] : -in[i];
|
||||||
|
@ -45,8 +45,8 @@ int32_t absFunction(SScalarParam *pInput, int32_t inputNum, SScalarParam *pOutpu
|
||||||
double *in = (double *)pInputData->pData;
|
double *in = (double *)pInputData->pData;
|
||||||
double *out = (double *)pOutputData->pData;
|
double *out = (double *)pOutputData->pData;
|
||||||
for (int32_t i = 0; i < pInput->numOfRows; ++i) {
|
for (int32_t i = 0; i < pInput->numOfRows; ++i) {
|
||||||
if (colDataIsNull_f(pInputData->nullbitmap, i)) {
|
if (colDataIsNull_s(pInputData, i)) {
|
||||||
colDataSetNull_f(pOutputData->nullbitmap, i);
|
colDataAppendNULL(pOutputData, i);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
out[i] = (in[i] >= 0)? in[i] : -in[i];
|
out[i] = (in[i] >= 0)? in[i] : -in[i];
|
||||||
|
@ -58,8 +58,8 @@ int32_t absFunction(SScalarParam *pInput, int32_t inputNum, SScalarParam *pOutpu
|
||||||
int8_t *in = (int8_t *)pInputData->pData;
|
int8_t *in = (int8_t *)pInputData->pData;
|
||||||
int8_t *out = (int8_t *)pOutputData->pData;
|
int8_t *out = (int8_t *)pOutputData->pData;
|
||||||
for (int32_t i = 0; i < pInput->numOfRows; ++i) {
|
for (int32_t i = 0; i < pInput->numOfRows; ++i) {
|
||||||
if (colDataIsNull_f(pInputData->nullbitmap, i)) {
|
if (colDataIsNull_s(pInputData, i)) {
|
||||||
colDataSetNull_f(pOutputData->nullbitmap, i);
|
colDataAppendNULL(pOutputData, i);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
out[i] = (in[i] >= 0)? in[i] : -in[i];
|
out[i] = (in[i] >= 0)? in[i] : -in[i];
|
||||||
|
@ -71,8 +71,8 @@ int32_t absFunction(SScalarParam *pInput, int32_t inputNum, SScalarParam *pOutpu
|
||||||
int16_t *in = (int16_t *)pInputData->pData;
|
int16_t *in = (int16_t *)pInputData->pData;
|
||||||
int16_t *out = (int16_t *)pOutputData->pData;
|
int16_t *out = (int16_t *)pOutputData->pData;
|
||||||
for (int32_t i = 0; i < pInput->numOfRows; ++i) {
|
for (int32_t i = 0; i < pInput->numOfRows; ++i) {
|
||||||
if (colDataIsNull_f(pInputData->nullbitmap, i)) {
|
if (colDataIsNull_s(pInputData, i)) {
|
||||||
colDataSetNull_f(pOutputData->nullbitmap, i);
|
colDataAppendNULL(pOutputData, i);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
out[i] = (in[i] >= 0)? in[i] : -in[i];
|
out[i] = (in[i] >= 0)? in[i] : -in[i];
|
||||||
|
@ -84,8 +84,8 @@ int32_t absFunction(SScalarParam *pInput, int32_t inputNum, SScalarParam *pOutpu
|
||||||
int32_t *in = (int32_t *)pInputData->pData;
|
int32_t *in = (int32_t *)pInputData->pData;
|
||||||
int32_t *out = (int32_t *)pOutputData->pData;
|
int32_t *out = (int32_t *)pOutputData->pData;
|
||||||
for (int32_t i = 0; i < pInput->numOfRows; ++i) {
|
for (int32_t i = 0; i < pInput->numOfRows; ++i) {
|
||||||
if (colDataIsNull_f(pInputData->nullbitmap, i)) {
|
if (colDataIsNull_s(pInputData, i)) {
|
||||||
colDataSetNull_f(pOutputData->nullbitmap, i);
|
colDataAppendNULL(pOutputData, i);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
out[i] = (in[i] >= 0)? in[i] : -in[i];
|
out[i] = (in[i] >= 0)? in[i] : -in[i];
|
||||||
|
@ -97,8 +97,8 @@ int32_t absFunction(SScalarParam *pInput, int32_t inputNum, SScalarParam *pOutpu
|
||||||
int64_t *in = (int64_t *)pInputData->pData;
|
int64_t *in = (int64_t *)pInputData->pData;
|
||||||
int64_t *out = (int64_t *)pOutputData->pData;
|
int64_t *out = (int64_t *)pOutputData->pData;
|
||||||
for (int32_t i = 0; i < pInput->numOfRows; ++i) {
|
for (int32_t i = 0; i < pInput->numOfRows; ++i) {
|
||||||
if (colDataIsNull_f(pInputData->nullbitmap, i)) {
|
if (colDataIsNull_s(pInputData, i)) {
|
||||||
colDataSetNull_f(pOutputData->nullbitmap, i);
|
colDataAppendNULL(pOutputData, i);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
out[i] = (in[i] >= 0)? in[i] : -in[i];
|
out[i] = (in[i] >= 0)? in[i] : -in[i];
|
||||||
|
@ -129,8 +129,8 @@ static int32_t doScalarFunctionUnique(SScalarParam *pInput, int32_t inputNum, SS
|
||||||
double *out = (double *)pOutputData->pData;
|
double *out = (double *)pOutputData->pData;
|
||||||
|
|
||||||
for (int32_t i = 0; i < pInput->numOfRows; ++i) {
|
for (int32_t i = 0; i < pInput->numOfRows; ++i) {
|
||||||
if (colDataIsNull_f(pInputData->nullbitmap, i)) {
|
if (colDataIsNull_s(pInputData, i)) {
|
||||||
colDataSetNull_f(pOutputData->nullbitmap, i);
|
colDataAppendNULL(pOutputData, i);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
out[i] = valFn(getValueFn(pInputData->pData, i));
|
out[i] = valFn(getValueFn(pInputData->pData, i));
|
||||||
|
@ -157,9 +157,9 @@ static int32_t doScalarFunctionUnique2(SScalarParam *pInput, int32_t inputNum, S
|
||||||
double *out = (double *)pOutputData->pData;
|
double *out = (double *)pOutputData->pData;
|
||||||
|
|
||||||
for (int32_t i = 0; i < pInput->numOfRows; ++i) {
|
for (int32_t i = 0; i < pInput->numOfRows; ++i) {
|
||||||
if (colDataIsNull_f(pInputData[0]->nullbitmap, i) ||
|
if (colDataIsNull_s(pInputData[0], i) ||
|
||||||
colDataIsNull_f(pInputData[1]->nullbitmap, 0)) {
|
colDataIsNull_s(pInputData[1], 0)) {
|
||||||
colDataSetNull_f(pOutputData->nullbitmap, i);
|
colDataAppendNULL(pOutputData, i);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
out[i] = valFn(getValueFn[0](pInputData[0]->pData, i), getValueFn[1](pInputData[1]->pData, 0));
|
out[i] = valFn(getValueFn[0](pInputData[0]->pData, i), getValueFn[1](pInputData[1]->pData, 0));
|
||||||
|
@ -184,8 +184,8 @@ static int32_t doScalarFunction(SScalarParam *pInput, int32_t inputNum, SScalarP
|
||||||
float *out = (float *)pOutputData->pData;
|
float *out = (float *)pOutputData->pData;
|
||||||
|
|
||||||
for (int32_t i = 0; i < pInput->numOfRows; ++i) {
|
for (int32_t i = 0; i < pInput->numOfRows; ++i) {
|
||||||
if (colDataIsNull_f(pInputData->nullbitmap, i)) {
|
if (colDataIsNull_s(pInputData, i)) {
|
||||||
colDataSetNull_f(pOutputData->nullbitmap, i);
|
colDataAppendNULL(pOutputData, i);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
out[i] = f1(in[i]);
|
out[i] = f1(in[i]);
|
||||||
|
@ -198,8 +198,8 @@ static int32_t doScalarFunction(SScalarParam *pInput, int32_t inputNum, SScalarP
|
||||||
double *out = (double *)pOutputData->pData;
|
double *out = (double *)pOutputData->pData;
|
||||||
|
|
||||||
for (int32_t i = 0; i < pInput->numOfRows; ++i) {
|
for (int32_t i = 0; i < pInput->numOfRows; ++i) {
|
||||||
if (colDataIsNull_f(pInputData->nullbitmap, i)) {
|
if (colDataIsNull_s(pInputData, i)) {
|
||||||
colDataSetNull_f(pOutputData->nullbitmap, i);
|
colDataAppendNULL(pOutputData, i);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
out[i] = d1(in[i]);
|
out[i] = d1(in[i]);
|
||||||
|
@ -301,7 +301,7 @@ static int32_t doLengthFunction(SScalarParam *pInput, int32_t inputNum, SScalarP
|
||||||
|
|
||||||
for (int32_t i = 0; i < pInput->numOfRows; ++i) {
|
for (int32_t i = 0; i < pInput->numOfRows; ++i) {
|
||||||
if (colDataIsNull_s(pInputData, i)) {
|
if (colDataIsNull_s(pInputData, i)) {
|
||||||
colDataSetNull_f(pOutputData->nullbitmap, i);
|
colDataAppendNULL(pOutputData, i);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1247,26 +1247,28 @@ int32_t timeDiffFunction(SScalarParam *pInput, int32_t inputNum, SScalarParam *p
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t nowFunction(SScalarParam *pInput, int32_t inputNum, SScalarParam *pOutput) {
|
int32_t nowFunction(SScalarParam *pInput, int32_t inputNum, SScalarParam *pOutput) {
|
||||||
if (inputNum != 1) {
|
int64_t ts = taosGetTimestamp(TSDB_TIME_PRECISION_MILLI);
|
||||||
return TSDB_CODE_FAILED;
|
for (int32_t i = 0; i < pInput->numOfRows; ++i) {
|
||||||
|
colDataAppendInt64(pOutput->columnData, i, &ts);
|
||||||
}
|
}
|
||||||
colDataAppendInt64(pOutput->columnData, pOutput->numOfRows, (int64_t *)colDataGetData(pInput->columnData, 0));
|
pOutput->numOfRows = pInput->numOfRows;
|
||||||
return TSDB_CODE_SUCCESS;
|
return TSDB_CODE_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t todayFunction(SScalarParam *pInput, int32_t inputNum, SScalarParam *pOutput) {
|
int32_t todayFunction(SScalarParam *pInput, int32_t inputNum, SScalarParam *pOutput) {
|
||||||
if (inputNum != 1) {
|
int64_t ts = taosGetTimestampToday(TSDB_TIME_PRECISION_MILLI);
|
||||||
return TSDB_CODE_FAILED;
|
for (int32_t i = 0; i < pInput->numOfRows; ++i) {
|
||||||
|
colDataAppendInt64(pOutput->columnData, i, &ts);
|
||||||
}
|
}
|
||||||
colDataAppendInt64(pOutput->columnData, pOutput->numOfRows, (int64_t *)colDataGetData(pInput->columnData, 0));
|
pOutput->numOfRows = pInput->numOfRows;
|
||||||
return TSDB_CODE_SUCCESS;
|
return TSDB_CODE_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t timezoneFunction(SScalarParam *pInput, int32_t inputNum, SScalarParam *pOutput) {
|
int32_t timezoneFunction(SScalarParam *pInput, int32_t inputNum, SScalarParam *pOutput) {
|
||||||
if (inputNum != 1) {
|
for (int32_t i = 0; i < pInput->numOfRows; ++i) {
|
||||||
return TSDB_CODE_FAILED;
|
colDataAppend(pOutput->columnData, i, tsTimezoneStr, false);
|
||||||
}
|
}
|
||||||
colDataAppend(pOutput->columnData, pOutput->numOfRows, (char *)colDataGetData(pInput->columnData, 0), false);
|
pOutput->numOfRows = pInput->numOfRows;
|
||||||
return TSDB_CODE_SUCCESS;
|
return TSDB_CODE_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -170,7 +170,6 @@ static int32_t syncIOStartInternal(SSyncIO *io) {
|
||||||
taosBlockSIGPIPE();
|
taosBlockSIGPIPE();
|
||||||
|
|
||||||
rpcInit();
|
rpcInit();
|
||||||
tsRpcForceTcp = 1;
|
|
||||||
|
|
||||||
// cient rpc init
|
// cient rpc init
|
||||||
{
|
{
|
||||||
|
|
|
@ -119,7 +119,7 @@ int taosSetConsoleEcho(bool on) {
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void setTerminalMode() {
|
void taosSetTerminalMode() {
|
||||||
#if defined(WINDOWS)
|
#if defined(WINDOWS)
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
@ -152,7 +152,7 @@ void setTerminalMode() {
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t getOldTerminalMode() {
|
int32_t taosGetOldTerminalMode() {
|
||||||
#if defined(WINDOWS)
|
#if defined(WINDOWS)
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
@ -170,7 +170,7 @@ int32_t getOldTerminalMode() {
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void resetTerminalMode() {
|
void taosResetTerminalMode() {
|
||||||
#if defined(WINDOWS)
|
#if defined(WINDOWS)
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
|
@ -513,6 +513,8 @@ void cfgDumpCfg(SConfig *pCfg, bool tsc, bool dump) {
|
||||||
for (int32_t i = 0; i < size; ++i) {
|
for (int32_t i = 0; i < size; ++i) {
|
||||||
SConfigItem *pItem = taosArrayGet(pCfg->array, i);
|
SConfigItem *pItem = taosArrayGet(pCfg->array, i);
|
||||||
if (tsc && !pItem->tsc) continue;
|
if (tsc && !pItem->tsc) continue;
|
||||||
|
if (dump && strcmp(pItem->name, "scriptDir") == 0) continue;
|
||||||
|
if (dump && strcmp(pItem->name, "simDebugFlag") == 0) continue;
|
||||||
tstrncpy(src, cfgStypeStr(pItem->stype), CFG_SRC_PRINT_LEN);
|
tstrncpy(src, cfgStypeStr(pItem->stype), CFG_SRC_PRINT_LEN);
|
||||||
for (int32_t i = 0; i < CFG_SRC_PRINT_LEN; ++i) {
|
for (int32_t i = 0; i < CFG_SRC_PRINT_LEN; ++i) {
|
||||||
if (src[i] == 0) src[i] = ' ';
|
if (src[i] == 0) src[i] = ' ';
|
||||||
|
@ -551,10 +553,10 @@ void cfgDumpCfg(SConfig *pCfg, bool tsc, bool dump) {
|
||||||
break;
|
break;
|
||||||
case CFG_DTYPE_FLOAT:
|
case CFG_DTYPE_FLOAT:
|
||||||
if (dump) {
|
if (dump) {
|
||||||
printf("%s %s %f", src, name, pItem->fval);
|
printf("%s %s %.2f", src, name, pItem->fval);
|
||||||
printf("\n");
|
printf("\n");
|
||||||
} else {
|
} else {
|
||||||
uInfo("%s %s %f", src, name, pItem->fval);
|
uInfo("%s %s %.2f", src, name, pItem->fval);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case CFG_DTYPE_STRING:
|
case CFG_DTYPE_STRING:
|
||||||
|
|
|
@ -110,7 +110,7 @@ typedef struct time_wheel_t {
|
||||||
tmr_obj_t** slots;
|
tmr_obj_t** slots;
|
||||||
} time_wheel_t;
|
} time_wheel_t;
|
||||||
|
|
||||||
int32_t tsMaxTmrCtrl = 512;
|
static int32_t tsMaxTmrCtrl = 512;
|
||||||
|
|
||||||
static TdThreadOnce tmrModuleInit = PTHREAD_ONCE_INIT;
|
static TdThreadOnce tmrModuleInit = PTHREAD_ONCE_INIT;
|
||||||
static TdThreadMutex tmrCtrlMutex;
|
static TdThreadMutex tmrCtrlMutex;
|
||||||
|
|
|
@ -76,7 +76,7 @@
|
||||||
./test.sh -f tsim/insert/backquote.sim -m
|
./test.sh -f tsim/insert/backquote.sim -m
|
||||||
./test.sh -f tsim/parser/fourArithmetic-basic.sim -m
|
./test.sh -f tsim/parser/fourArithmetic-basic.sim -m
|
||||||
./test.sh -f tsim/query/interval-offset.sim -m
|
./test.sh -f tsim/query/interval-offset.sim -m
|
||||||
./test.sh -f tsim/tmq/basic1.sim -m
|
#./test.sh -f tsim/tmq/basic1.sim -m
|
||||||
./test.sh -f tsim/stable/vnode3.sim -m
|
./test.sh -f tsim/stable/vnode3.sim -m
|
||||||
./test.sh -f tsim/qnode/basic1.sim -m
|
./test.sh -f tsim/qnode/basic1.sim -m
|
||||||
./test.sh -f tsim/mnode/basic1.sim -m
|
./test.sh -f tsim/mnode/basic1.sim -m
|
||||||
|
@ -85,6 +85,6 @@
|
||||||
./test.sh -f tsim/sma/tsmaCreateInsertData.sim
|
./test.sh -f tsim/sma/tsmaCreateInsertData.sim
|
||||||
|
|
||||||
# --- valgrind
|
# --- valgrind
|
||||||
./test.sh -f tsim/valgrind/checkError.sim -v
|
#./test.sh -f tsim/valgrind/checkError.sim -v
|
||||||
|
|
||||||
#======================b1-end===============
|
#======================b1-end===============
|
||||||
|
|
|
@ -0,0 +1,103 @@
|
||||||
|
system sh/stop_dnodes.sh
|
||||||
|
system sh/deploy.sh -n dnode1 -i 1
|
||||||
|
system sh/exec.sh -n dnode1 -s start
|
||||||
|
|
||||||
|
$loop_cnt = 0
|
||||||
|
check_dnode_ready:
|
||||||
|
$loop_cnt = $loop_cnt + 1
|
||||||
|
sleep 200
|
||||||
|
if $loop_cnt == 10 then
|
||||||
|
print ====> dnode not ready!
|
||||||
|
return -1
|
||||||
|
endi
|
||||||
|
|
||||||
|
sql show dnodes
|
||||||
|
print ===> $rows $data00 $data01 $data02 $data03 $data04 $data05
|
||||||
|
if $data00 != 1 then
|
||||||
|
return -1
|
||||||
|
endi
|
||||||
|
if $data04 != ready then
|
||||||
|
goto check_dnode_ready
|
||||||
|
endi
|
||||||
|
|
||||||
|
sql connect
|
||||||
|
|
||||||
|
print =============== create database
|
||||||
|
sql create database db
|
||||||
|
sql show databases
|
||||||
|
if $rows != 2 then
|
||||||
|
return -1
|
||||||
|
endi
|
||||||
|
|
||||||
|
sql use db
|
||||||
|
|
||||||
|
print =============== create super table and child table
|
||||||
|
sql create table stb1 (ts timestamp, c1 int, c2 bigint, c3 smallint, c4 tinyint, c5 float, c6 double, c7 bool, c8 binary(16),c9 nchar(32), c10 timestamp) tags (t1 int)
|
||||||
|
sql show stables
|
||||||
|
print $rows $data00 $data01 $data02
|
||||||
|
if $rows != 1 then
|
||||||
|
return -1
|
||||||
|
endi
|
||||||
|
|
||||||
|
sql create table ct1 using stb1 tags ( 1 )
|
||||||
|
sql create table ct2 using stb1 tags ( 2 )
|
||||||
|
sql create table ct3 using stb1 tags ( 3 )
|
||||||
|
sql create table ct4 using stb1 tags ( 4 )
|
||||||
|
sql show tables
|
||||||
|
print $rows $data00 $data10 $data20
|
||||||
|
if $rows != 4 then
|
||||||
|
return -1
|
||||||
|
endi
|
||||||
|
|
||||||
|
print =============== insert data into child table ct1 (s)
|
||||||
|
sql insert into ct1 values ( '2022-01-01 01:01:01.000', 1, 11111, 111, 11, 1.11, 11.11, 1, "binary1", "nchar1", now+1a )
|
||||||
|
sql insert into ct1 values ( '2022-01-01 01:01:06.000', 2, 22222, 222, 22, 2.22, 22.22, 0, "binary2", "nchar2", now+2a )
|
||||||
|
sql insert into ct1 values ( '2022-01-01 01:01:10.000', 3, 33333, 333, 33, 3.33, 33.33, 0, "binary3", "nchar3", now+3a )
|
||||||
|
sql insert into ct1 values ( '2022-01-01 01:01:16.000', 4, 44444, 444, 44, 4.44, 44.44, 1, "binary4", "nchar4", now+4a )
|
||||||
|
sql insert into ct1 values ( '2022-01-01 01:01:20.000', 5, 55555, 555, 55, 5.55, 55.55, 0, "binary5", "nchar5", now+5a )
|
||||||
|
sql insert into ct1 values ( '2022-01-01 01:01:26.000', 6, 66666, 666, 66, 6.66, 66.66, 1, "binary6", "nchar6", now+6a )
|
||||||
|
sql insert into ct1 values ( '2022-01-01 01:01:30.000', 7, 00000, 000, 00, 0.00, 00.00, 1, "binary7", "nchar7", now+7a )
|
||||||
|
sql insert into ct1 values ( '2022-01-01 01:01:36.000', 8, -88888, -888, -88, -8.88, -88.88, 0, "binary8", "nchar8", now+8a )
|
||||||
|
|
||||||
|
print =============== insert data into child table ct2 (d)
|
||||||
|
sql insert into ct2 values ( '2022-01-01 01:00:01.000', 1, 11111, 111, 11, 1.11, 11.11, 1, "binary1", "nchar1", now+1a )
|
||||||
|
sql insert into ct2 values ( '2022-01-01 10:00:01.000', 2, 22222, 222, 22, 2.22, 22.22, 0, "binary2", "nchar2", now+2a )
|
||||||
|
sql insert into ct2 values ( '2022-01-01 20:00:01.000', 3, 33333, 333, 33, 3.33, 33.33, 0, "binary3", "nchar3", now+3a )
|
||||||
|
sql insert into ct2 values ( '2022-01-02 10:00:01.000', 4, 44444, 444, 44, 4.44, 44.44, 1, "binary4", "nchar4", now+4a )
|
||||||
|
sql insert into ct2 values ( '2022-01-02 20:00:01.000', 5, 55555, 555, 55, 5.55, 55.55, 0, "binary5", "nchar5", now+5a )
|
||||||
|
sql insert into ct2 values ( '2022-01-03 10:00:01.000', 7, 00000, 000, 00, 0.00, 00.00, 1, "binary7", "nchar7", now+6a )
|
||||||
|
sql insert into ct2 values ( '2022-01-03 20:00:01.000', 8, -88888, -888, -88, -8.88, -88.88, 0, "binary8", "nchar8", now+7a )
|
||||||
|
|
||||||
|
print =============== insert data into child table ct3 (n)
|
||||||
|
sql insert into ct3 values ( '2021-12-21 01:01:01.000', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL )
|
||||||
|
sql insert into ct3 values ( '2021-12-31 01:01:01.000', 1, 11111, 111, 11, 1.11, 11.11, 1, "binary1", "nchar1", now+1a )
|
||||||
|
sql insert into ct3 values ( '2022-01-01 01:01:06.000', 2, 22222, 222, 22, 2.22, 22.22, 0, "binary2", "nchar2", now+2a )
|
||||||
|
sql insert into ct3 values ( '2022-01-07 01:01:10.000', 3, 33333, 333, 33, 3.33, 33.33, 0, "binary3", "nchar3", now+3a )
|
||||||
|
sql insert into ct3 values ( '2022-01-31 01:01:16.000', 4, 44444, 444, 44, 4.44, 44.44, 1, "binary4", "nchar4", now+4a )
|
||||||
|
sql insert into ct3 values ( '2022-02-01 01:01:20.000', 5, 55555, 555, 55, 5.55, 55.55, 0, "binary5", "nchar5", now+5a )
|
||||||
|
sql insert into ct3 values ( '2022-02-28 01:01:26.000', 6, 66666, 666, 66, 6.66, 66.66, 1, "binary6", "nchar6", now+6a )
|
||||||
|
sql insert into ct3 values ( '2022-03-01 01:01:30.000', 7, 00000, 000, 00, 0.00, 00.00, 1, "binary7", "nchar7", "1970-01-01 08:00:00.000" )
|
||||||
|
sql insert into ct3 values ( '2022-03-08 01:01:36.000', 8, -88888, -888, -88, -8.88, -88.88, 0, "binary8", "nchar8", "1969-01-01 01:00:00.000" )
|
||||||
|
|
||||||
|
print =============== insert data into child table ct4 (y)
|
||||||
|
sql insert into ct4 values ( '2019-01-21 01:01:01.000', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL )
|
||||||
|
sql insert into ct4 values ( '2019-10-21 01:01:01.000', 1, 11111, 111, 11, 1.11, 11.11, 1, "binary1", "nchar1", now+1a )
|
||||||
|
sql insert into ct4 values ( '2019-12-31 01:01:01.000', 2, 22222, 222, 22, 2.22, 22.22, 0, "binary2", "nchar2", now+2a )
|
||||||
|
sql insert into ct4 values ( '2020-01-01 01:01:06.000', 3, 33333, 333, 33, 3.33, 33.33, 0, "binary3", "nchar3", now+3a )
|
||||||
|
sql insert into ct4 values ( '2020-05-07 01:01:10.000', 4, 44444, 444, 44, 4.44, 44.44, 1, "binary4", "nchar4", now+4a )
|
||||||
|
sql insert into ct4 values ( '2020-09-30 01:01:16.000', 5, 55555, 555, 55, 5.55, 55.55, 0, "binary5", "nchar5", now+5a )
|
||||||
|
sql insert into ct4 values ( '2020-12-21 01:01:01.000', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL )
|
||||||
|
sql insert into ct4 values ( '2021-02-01 01:01:20.000', 6, 66666, 666, 66, 6.66, 66.66, 1, "binary6", "nchar6", now+6a )
|
||||||
|
sql insert into ct4 values ( '2021-10-28 01:01:26.000', 7, 00000, 000, 00, 0.00, 00.00, 1, "binary7", "nchar7", "1970-01-01 08:00:00.000" )
|
||||||
|
sql insert into ct4 values ( '2021-12-01 01:01:30.000', 8, -88888, -888, -88, -8.88, -88.88, 0, "binary8", "nchar8", "1969-01-01 01:00:00.000" )
|
||||||
|
sql insert into ct4 values ( '2022-02-31 01:01:36.000', 9, -99999999999999999, -999, -99, -9.99, -999999999999999999999.99, 1, "binary9", "nchar9", "1900-01-01 00:00:00.000" )
|
||||||
|
sql insert into ct4 values ( '2022-05-21 01:01:01.000', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL )
|
||||||
|
|
||||||
|
|
||||||
|
print ================ start query ======================
|
||||||
|
print ================ SQL used to cause taosd or taos shell crash
|
||||||
|
sql select sum(c1) ,count(c1) from ct4 group by c1 having sum(c10) between 0 and 1 ;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#system sh/exec.sh -n dnode1 -s stop -x SIGINT
|
|
@ -292,7 +292,7 @@ print ==> rows[0]: $data[0][0] $data[0][1] $data[0][2] $data[0][3] $data[0][4] $
|
||||||
print ==> rows[1]: $data[1][0] $data[1][1] $data[1][2] $data[1][3] $data[1][4] $data[1][5] $data[1][6]
|
print ==> rows[1]: $data[1][0] $data[1][1] $data[1][2] $data[1][3] $data[1][4] $data[1][5] $data[1][6]
|
||||||
if $rows != 2 then
|
if $rows != 2 then
|
||||||
sleep 1000
|
sleep 1000
|
||||||
goto wait_consumer_end_from_ctb
|
goto wait_consumer_end_from_ntb
|
||||||
endi
|
endi
|
||||||
if $data[0][1] == 0 then
|
if $data[0][1] == 0 then
|
||||||
if $data[1][1] != 1 then
|
if $data[1][1] != 1 then
|
||||||
|
|
|
@ -6,6 +6,7 @@ import inspect
|
||||||
from util.log import *
|
from util.log import *
|
||||||
from util.sql import *
|
from util.sql import *
|
||||||
from util.cases import *
|
from util.cases import *
|
||||||
|
from util.dnodes import *
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -15,56 +16,50 @@ class TDTestCase:
|
||||||
tdLog.debug(f"start to excute {__file__}")
|
tdLog.debug(f"start to excute {__file__}")
|
||||||
tdSql.init(conn.cursor())
|
tdSql.init(conn.cursor())
|
||||||
|
|
||||||
def run(self): # sourcery skip: extract-duplicate-method, remove-redundant-fstring
|
def __cast_to_bigint(self, col_name, tbname):
|
||||||
tdSql.prepare()
|
__sql = f"select cast({col_name} as bigint), {col_name} from {tbname}"
|
||||||
|
tdSql.query(sql=__sql)
|
||||||
|
data_tb_col = [result[1] for result in tdSql.queryResult]
|
||||||
|
for i in range(len(tdSql.queryRows)):
|
||||||
|
tdSql.checkData( i, 0, None ) if data_tb_col[i] is None else tdSql.checkData( i, 0, int(data_tb_col[i]) )
|
||||||
|
|
||||||
tdLog.printNoPrefix("==========step1:create table")
|
def __range_to_bigint(self,cols,tables):
|
||||||
tdSql.execute(
|
for col in cols:
|
||||||
'''create table stb1
|
for table in tables:
|
||||||
(ts timestamp, c1 int, c2 bigint, c3 smallint, c4 tinyint, c5 float, c6 double, c7 bool, c8 binary(16),c9 nchar(32), c10 timestamp)
|
self.__cast_to_bigint(col_name=col, tbname=table)
|
||||||
tags (t1 int)
|
|
||||||
'''
|
|
||||||
)
|
|
||||||
tdSql.execute(
|
|
||||||
'''
|
|
||||||
create table t1
|
|
||||||
(ts timestamp, c1 int, c2 bigint, c3 smallint, c4 tinyint, c5 float, c6 double, c7 bool, c8 binary(16),c9 nchar(32), c10 timestamp)
|
|
||||||
'''
|
|
||||||
)
|
|
||||||
for i in range(4):
|
|
||||||
tdSql.execute(f'create table ct{i+1} using stb1 tags ( {i+1} )')
|
|
||||||
|
|
||||||
tdLog.printNoPrefix("==========step2:insert data")
|
def __cast_to_timestamp(self, col_name, tbname):
|
||||||
for i in range(9):
|
__sql = f"select cast({col_name} as timestamp), {col_name} from {tbname}"
|
||||||
tdSql.execute(
|
tdSql.query(sql=__sql)
|
||||||
f"insert into ct1 values ( now()-{i*10}s, {1*i}, {11111*i}, {111*i}, {11*i}, {1.11*i}, {11.11*i}, {i%2}, 'binary{i}', 'nchar{i}', now()+{1*i}a )"
|
data_tb_col = [result[1] for result in tdSql.queryResult]
|
||||||
)
|
for i in range(len(tdSql.queryRows)):
|
||||||
tdSql.execute(
|
if data_tb_col[i] is None:
|
||||||
f"insert into ct4 values ( now()-{i*90}d, {1*i}, {11111*i}, {111*i}, {11*i}, {1.11*i}, {11.11*i}, {i%2}, 'binary{i}', 'nchar{i}', now()+{1*i}a )"
|
tdSql.checkData( i, 0 , None )
|
||||||
)
|
if (col_name == "c2" or col_name == "double" ) and tbname == "t1" and i == 10:
|
||||||
tdSql.execute("insert into ct1 values (now()-45s, 0, 0, 0, 0, 0, 0, 0, 'binary0', 'nchar0', now()+8a )")
|
continue
|
||||||
tdSql.execute("insert into ct1 values (now()+10s, 9, -99999, -999, -99, -9.99, -99.99, 1, 'binary9', 'nchar9', now()+9a )")
|
else:
|
||||||
|
utc_zone = datetime.timezone.utc
|
||||||
|
utc_8 = datetime.timezone(datetime.timedelta(hours=8))
|
||||||
|
date_init_stamp = datetime.datetime.utcfromtimestamp(data_tb_col[i]/1000)
|
||||||
|
date_data = date_init_stamp.replace(tzinfo=utc_zone).astimezone(utc_8).strftime("%Y-%m-%d %H:%M:%S.%f")
|
||||||
|
tdSql.checkData( i, 0, date_data)
|
||||||
|
|
||||||
tdSql.execute("insert into ct4 values (now()-810d, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL ) ")
|
def __range_to_timestamp(self, cols, tables):
|
||||||
tdSql.execute("insert into ct4 values (now()-400d, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL ) ")
|
for col in cols:
|
||||||
tdSql.execute("insert into ct4 values (now()+90d, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL ) ")
|
for table in tables:
|
||||||
|
self.__cast_to_timestamp(col_name=col, tbname=table)
|
||||||
|
|
||||||
tdSql.execute(
|
def __test_bigint(self):
|
||||||
f'''insert into t1 values
|
__table_list = ["ct1", "ct4", "t1"]
|
||||||
( '2020-04-21 01:01:01.000', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL )
|
__col_list = ["c1","c2","c3","c4","c5","c6","c7","c10","c1+c2"]
|
||||||
( '2020-10-21 01:01:01.000', 1, 11111, 111, 11, 1.11, 11.11, 1, "binary1", "nchar1", now()+1a )
|
self.__range_to_bigint(cols=__col_list, tables=__table_list)
|
||||||
( '2020-12-31 01:01:01.000', 2, 22222, 222, 22, 2.22, 22.22, 0, "binary2", "nchar2", now()+2a )
|
|
||||||
( '2021-01-01 01:01:06.000', 3, 33333, 333, 33, 3.33, 33.33, 0, "binary3", "nchar3", now()+3a )
|
def __test_timestamp(self):
|
||||||
( '2021-05-07 01:01:10.000', 4, 44444, 444, 44, 4.44, 44.44, 1, "binary4", "nchar4", now()+4a )
|
__table_list = ["ct1", "ct4", "t1"]
|
||||||
( '2021-07-21 01:01:01.000', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL )
|
__col_list = ["c1","c2","c3","c4","c5","c6","c7","c1+c2"]
|
||||||
( '2021-09-30 01:01:16.000', 5, 55555, 555, 55, 5.55, 55.55, 0, "binary5", "nchar5", now()+5a )
|
self.__range_to_timestamp(cols=__col_list, tables=__table_list)
|
||||||
( '2022-02-01 01:01:20.000', 6, 66666, 666, 66, 6.66, 66.66, 1, "binary6", "nchar6", now()+6a )
|
|
||||||
( '2022-10-28 01:01:26.000', 7, 00000, 000, 00, 0.00, 00.00, 1, "binary7", "nchar7", "1970-01-01 08:00:00.000" )
|
def all_test(self):
|
||||||
( '2022-12-01 01:01:30.000', 8, -88888, -888, -88, -8.88, -88.88, 0, "binary8", "nchar8", "1969-01-01 01:00:00.000" )
|
|
||||||
( '2022-12-31 01:01:36.000', 9, -99999999999999999, -999, -99, -9.99, -999999999999999999999.99, 1, "binary9", "nchar9", "1900-01-01 00:00:00.000" )
|
|
||||||
( '2023-02-21 01:01:01.000', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL )
|
|
||||||
'''
|
|
||||||
)
|
|
||||||
|
|
||||||
tdSql.query("select c1 from ct4")
|
tdSql.query("select c1 from ct4")
|
||||||
data_ct4_c1 = [tdSql.getData(i,0) for i in range(tdSql.queryRows)]
|
data_ct4_c1 = [tdSql.getData(i,0) for i in range(tdSql.queryRows)]
|
||||||
|
@ -240,7 +235,7 @@ class TDTestCase:
|
||||||
tdSql.checkData( i, 0, date_data)
|
tdSql.checkData( i, 0, date_data)
|
||||||
|
|
||||||
|
|
||||||
tdLog.printNoPrefix("==========step16: cast smallint to bigint, expect no changes")
|
tdLog.printNoPrefix("==========step16: cast tinyint to bigint, expect no changes")
|
||||||
tdSql.query("select c4 from ct4")
|
tdSql.query("select c4 from ct4")
|
||||||
data_ct4_c4 = [tdSql.getData(i,0) for i in range(tdSql.queryRows)]
|
data_ct4_c4 = [tdSql.getData(i,0) for i in range(tdSql.queryRows)]
|
||||||
tdSql.query("select c4 from t1")
|
tdSql.query("select c4 from t1")
|
||||||
|
@ -254,7 +249,7 @@ class TDTestCase:
|
||||||
tdSql.checkData( i, 0, data_t1_c4[i])
|
tdSql.checkData( i, 0, data_t1_c4[i])
|
||||||
|
|
||||||
|
|
||||||
tdLog.printNoPrefix("==========step17: cast smallint to binary, expect changes to str(int) ")
|
tdLog.printNoPrefix("==========step17: cast tinyint to binary, expect changes to str(int) ")
|
||||||
|
|
||||||
tdSql.query("select cast(c4 as binary(32)) as b from ct4")
|
tdSql.query("select cast(c4 as binary(32)) as b from ct4")
|
||||||
for i in range(len(data_ct4_c4)):
|
for i in range(len(data_ct4_c4)):
|
||||||
|
@ -263,7 +258,7 @@ class TDTestCase:
|
||||||
for i in range(len(data_t1_c4)):
|
for i in range(len(data_t1_c4)):
|
||||||
tdSql.checkData( i, 0, str(data_t1_c4[i]) )
|
tdSql.checkData( i, 0, str(data_t1_c4[i]) )
|
||||||
|
|
||||||
tdLog.printNoPrefix("==========step18: cast smallint to nchar, expect changes to str(int) ")
|
tdLog.printNoPrefix("==========step18: cast tinyint to nchar, expect changes to str(int) ")
|
||||||
|
|
||||||
tdSql.query("select cast(c4 as nchar(32)) as b from ct4")
|
tdSql.query("select cast(c4 as nchar(32)) as b from ct4")
|
||||||
for i in range(len(data_ct4_c4)):
|
for i in range(len(data_ct4_c4)):
|
||||||
|
@ -272,7 +267,7 @@ class TDTestCase:
|
||||||
for i in range(len(data_t1_c4)):
|
for i in range(len(data_t1_c4)):
|
||||||
tdSql.checkData( i, 0, str(data_t1_c4[i]) )
|
tdSql.checkData( i, 0, str(data_t1_c4[i]) )
|
||||||
|
|
||||||
tdLog.printNoPrefix("==========step19: cast smallint to timestamp, expect changes to timestamp ")
|
tdLog.printNoPrefix("==========step19: cast tinyint to timestamp, expect changes to timestamp ")
|
||||||
|
|
||||||
tdSql.query("select cast(c4 as timestamp) as b from ct4")
|
tdSql.query("select cast(c4 as timestamp) as b from ct4")
|
||||||
for i in range(len(data_ct4_c4)):
|
for i in range(len(data_ct4_c4)):
|
||||||
|
@ -624,7 +619,67 @@ class TDTestCase:
|
||||||
tdSql.error("select cast(c8 as timestamp ) as b from ct4")
|
tdSql.error("select cast(c8 as timestamp ) as b from ct4")
|
||||||
tdSql.error("select cast(c9 as timestamp ) as b from ct4")
|
tdSql.error("select cast(c9 as timestamp ) as b from ct4")
|
||||||
tdSql.error("select cast(c9 as binary(64) ) as b from ct4")
|
tdSql.error("select cast(c9 as binary(64) ) as b from ct4")
|
||||||
|
pass
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
tdSql.prepare()
|
||||||
|
|
||||||
|
tdLog.printNoPrefix("==========step1:create table")
|
||||||
|
tdSql.execute(
|
||||||
|
'''create table stb1
|
||||||
|
(ts timestamp, c1 int, c2 bigint, c3 smallint, c4 tinyint, c5 float, c6 double, c7 bool, c8 binary(16),c9 nchar(32), c10 timestamp)
|
||||||
|
tags (t1 int)
|
||||||
|
'''
|
||||||
|
)
|
||||||
|
tdSql.execute(
|
||||||
|
'''
|
||||||
|
create table t1
|
||||||
|
(ts timestamp, c1 int, c2 bigint, c3 smallint, c4 tinyint, c5 float, c6 double, c7 bool, c8 binary(16),c9 nchar(32), c10 timestamp)
|
||||||
|
'''
|
||||||
|
)
|
||||||
|
for i in range(4):
|
||||||
|
tdSql.execute(f'create table ct{i+1} using stb1 tags ( {i+1} )')
|
||||||
|
|
||||||
|
tdLog.printNoPrefix("==========step2:insert data")
|
||||||
|
for i in range(9):
|
||||||
|
tdSql.execute(
|
||||||
|
f"insert into ct1 values ( now()-{i*10}s, {1*i}, {11111*i}, {111*i}, {11*i}, {1.11*i}, {11.11*i}, {i%2}, 'binary{i}', 'nchar{i}', now()+{1*i}a )"
|
||||||
|
)
|
||||||
|
tdSql.execute(
|
||||||
|
f"insert into ct4 values ( now()-{i*90}d, {1*i}, {11111*i}, {111*i}, {11*i}, {1.11*i}, {11.11*i}, {i%2}, 'binary{i}', 'nchar{i}', now()+{1*i}a )"
|
||||||
|
)
|
||||||
|
tdSql.execute("insert into ct1 values (now()-45s, 0, 0, 0, 0, 0, 0, 0, 'binary0', 'nchar0', now()+8a )")
|
||||||
|
tdSql.execute("insert into ct1 values (now()+10s, 9, -99999, -999, -99, -9.99, -99.99, 1, 'binary9', 'nchar9', now()+9a )")
|
||||||
|
|
||||||
|
tdSql.execute("insert into ct4 values (now()-810d, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL ) ")
|
||||||
|
tdSql.execute("insert into ct4 values (now()-400d, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL ) ")
|
||||||
|
tdSql.execute("insert into ct4 values (now()+90d, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL ) ")
|
||||||
|
|
||||||
|
tdSql.execute(
|
||||||
|
f'''insert into t1 values
|
||||||
|
( '2020-04-21 01:01:01.000', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL )
|
||||||
|
( '2020-10-21 01:01:01.000', 1, 11111, 111, 11, 1.11, 11.11, 1, "binary1", "nchar1", now()+1a )
|
||||||
|
( '2020-12-31 01:01:01.000', 2, 22222, 222, 22, 2.22, 22.22, 0, "binary2", "nchar2", now()+2a )
|
||||||
|
( '2021-01-01 01:01:06.000', 3, 33333, 333, 33, 3.33, 33.33, 0, "binary3", "nchar3", now()+3a )
|
||||||
|
( '2021-05-07 01:01:10.000', 4, 44444, 444, 44, 4.44, 44.44, 1, "binary4", "nchar4", now()+4a )
|
||||||
|
( '2021-07-21 01:01:01.000', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL )
|
||||||
|
( '2021-09-30 01:01:16.000', 5, 55555, 555, 55, 5.55, 55.55, 0, "binary5", "nchar5", now()+5a )
|
||||||
|
( '2022-02-01 01:01:20.000', 6, 66666, 666, 66, 6.66, 66.66, 1, "binary6", "nchar6", now()+6a )
|
||||||
|
( '2022-10-28 01:01:26.000', 7, 00000, 000, 00, 0.00, 00.00, 1, "binary7", "nchar7", "1970-01-01 08:00:00.000" )
|
||||||
|
( '2022-12-01 01:01:30.000', 8, -88888, -888, -88, -8.88, -88.88, 0, "binary8", "nchar8", "1969-01-01 01:00:00.000" )
|
||||||
|
( '2022-12-31 01:01:36.000', 9, -99999999999999999, -999, -99, -9.99, -999999999999999999999.99, 1, "binary9", "nchar9", "1900-01-01 00:00:00.000" )
|
||||||
|
( '2023-02-21 01:01:01.000', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL )
|
||||||
|
'''
|
||||||
|
)
|
||||||
|
|
||||||
|
self.all_test()
|
||||||
|
|
||||||
|
tdDnodes.stop(1)
|
||||||
|
tdDnodes.start(1)
|
||||||
|
|
||||||
|
tdSql.execute("use db")
|
||||||
|
|
||||||
|
self.all_test()
|
||||||
|
|
||||||
def stop(self):
|
def stop(self):
|
||||||
tdSql.close()
|
tdSql.close()
|
||||||
|
|
|
@ -0,0 +1,232 @@
|
||||||
|
from util.log import *
|
||||||
|
from util.sql import *
|
||||||
|
from util.cases import *
|
||||||
|
from util.dnodes import *
|
||||||
|
|
||||||
|
|
||||||
|
INT_COL = "c1"
|
||||||
|
BINT_COL = "c2"
|
||||||
|
SINT_COL = "c3"
|
||||||
|
TINT_COL = "c4"
|
||||||
|
FLOAT_COL = "c5"
|
||||||
|
DOUBLE_COL = "c6"
|
||||||
|
BOOL_COL = "c7"
|
||||||
|
|
||||||
|
BINARY_COL = "c8"
|
||||||
|
NCHAR_COL = "c9"
|
||||||
|
TS_COL = "c10"
|
||||||
|
|
||||||
|
NUM_COL = [INT_COL, BINT_COL, SINT_COL, TINT_COL, FLOAT_COL, DOUBLE_COL, ]
|
||||||
|
UN_NUM_COL = [BOOL_COL, BINARY_COL, NCHAR_COL, ]
|
||||||
|
TS_TYPE_COL = [TS_COL]
|
||||||
|
|
||||||
|
class TDTestCase:
|
||||||
|
|
||||||
|
def init(self, conn, logSql):
|
||||||
|
tdLog.debug(f"start to excute {__file__}")
|
||||||
|
tdSql.init(conn.cursor())
|
||||||
|
|
||||||
|
def __sum_condition(self):
|
||||||
|
sum_condition = []
|
||||||
|
for num_col in NUM_COL:
|
||||||
|
sum_condition.extend(
|
||||||
|
(
|
||||||
|
num_col,
|
||||||
|
f"ceil( {num_col} )",
|
||||||
|
)
|
||||||
|
)
|
||||||
|
sum_condition.extend( f"{num_col} + {num_col_2}" for num_col_2 in NUM_COL )
|
||||||
|
sum_condition.extend( f"{num_col} + {un_num_col} " for un_num_col in UN_NUM_COL )
|
||||||
|
|
||||||
|
sum_condition.append(1)
|
||||||
|
|
||||||
|
return sum_condition
|
||||||
|
|
||||||
|
def __where_condition(self, col):
|
||||||
|
return f" where abs( {col} ) < 1000000 "
|
||||||
|
|
||||||
|
def __group_condition(self, col, having = ""):
|
||||||
|
return f" group by {col} having {having}" if having else f" group by {col} "
|
||||||
|
|
||||||
|
def __sum_current_check(self, tbname):
|
||||||
|
sum_condition = self.__sum_condition()
|
||||||
|
for condition in sum_condition:
|
||||||
|
where_condition = self.__where_condition(condition)
|
||||||
|
group_condition = self.__group_condition(condition, having=f"{condition} is not null " )
|
||||||
|
|
||||||
|
tdSql.query(f"select {condition} from {tbname} {where_condition} ")
|
||||||
|
datas = [tdSql.getData(i,0) for i in range(tdSql.queryRows)]
|
||||||
|
sum_data = sum(filter(None, datas))
|
||||||
|
tdSql.query(f"select sum( {condition} ) from {tbname} {where_condition} ")
|
||||||
|
tdSql.checkData(0, 0, sum_data)
|
||||||
|
|
||||||
|
tdSql.query(f"select {condition} from {tbname} {where_condition} {group_condition} ")
|
||||||
|
|
||||||
|
def __sum_err_check(self,tbanme):
|
||||||
|
sqls = []
|
||||||
|
|
||||||
|
for un_num_col in UN_NUM_COL:
|
||||||
|
sqls.extend(
|
||||||
|
(
|
||||||
|
f"select sum( {un_num_col} ) from {tbanme} ",
|
||||||
|
f"select sum(ceil( {un_num_col} )) from {tbanme} ",
|
||||||
|
)
|
||||||
|
)
|
||||||
|
sqls.extend( f"select sum( {un_num_col} + {un_num_col_2} ) from {tbanme} " for un_num_col_2 in UN_NUM_COL )
|
||||||
|
|
||||||
|
sqls.extend( f"select sum( {num_col} + {ts_col} ) from {tbanme} " for num_col in NUM_COL for ts_col in TS_TYPE_COL)
|
||||||
|
sqls.extend(
|
||||||
|
(
|
||||||
|
f"select sum() from {tbanme} ",
|
||||||
|
f"select sum(*) from {tbanme} ",
|
||||||
|
f"select sum(ccccccc) from {tbanme} ",
|
||||||
|
f"select sum('test') from {tbanme} ",
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
return sqls
|
||||||
|
|
||||||
|
def __test_current(self):
|
||||||
|
tdLog.printNoPrefix("==========current sql condition check , must return query ok==========")
|
||||||
|
tbname = ["ct1", "ct2", "ct4", "t1"]
|
||||||
|
for tb in tbname:
|
||||||
|
self.__sum_current_check(tb)
|
||||||
|
tdLog.printNoPrefix(f"==========current sql condition check in {tb} over==========")
|
||||||
|
|
||||||
|
def __test_error(self):
|
||||||
|
tdLog.printNoPrefix("==========err sql condition check , must return error==========")
|
||||||
|
tbname = ["ct1", "ct2", "ct4", "t1"]
|
||||||
|
|
||||||
|
for tb in tbname:
|
||||||
|
for errsql in self.__sum_err_check(tb):
|
||||||
|
tdSql.error(sql=errsql)
|
||||||
|
tdLog.printNoPrefix(f"==========err sql condition check in {tb} over==========")
|
||||||
|
|
||||||
|
|
||||||
|
def all_test(self):
|
||||||
|
self.__test_current()
|
||||||
|
self.__test_error()
|
||||||
|
|
||||||
|
|
||||||
|
def __create_tb(self):
|
||||||
|
tdSql.prepare()
|
||||||
|
|
||||||
|
tdLog.printNoPrefix("==========step1:create table")
|
||||||
|
create_stb_sql = f'''create table stb1(
|
||||||
|
ts timestamp, {INT_COL} int, {BINT_COL} bigint, {SINT_COL} smallint, {TINT_COL} tinyint,
|
||||||
|
{FLOAT_COL} float, {DOUBLE_COL} double, {BOOL_COL} bool,
|
||||||
|
{BINARY_COL} binary(16), {NCHAR_COL} nchar(32), {TS_COL} timestamp
|
||||||
|
) tags (t1 int)
|
||||||
|
'''
|
||||||
|
create_ntb_sql = f'''create table t1(
|
||||||
|
ts timestamp, {INT_COL} int, {BINT_COL} bigint, {SINT_COL} smallint, {TINT_COL} tinyint,
|
||||||
|
{FLOAT_COL} float, {DOUBLE_COL} double, {BOOL_COL} bool,
|
||||||
|
{BINARY_COL} binary(16), {NCHAR_COL} nchar(32), {TS_COL} timestamp
|
||||||
|
)
|
||||||
|
'''
|
||||||
|
tdSql.execute(create_stb_sql)
|
||||||
|
tdSql.execute(create_ntb_sql)
|
||||||
|
|
||||||
|
for i in range(4):
|
||||||
|
tdSql.execute(f'create table ct{i+1} using stb1 tags ( {i+1} )')
|
||||||
|
|
||||||
|
def __insert_data(self, rows):
|
||||||
|
for i in range(9):
|
||||||
|
tdSql.execute(
|
||||||
|
f"insert into ct1 values ( now()-{i*10}s, {1*i}, {11111*i}, {111*i}, {11*i}, {1.11*i}, {11.11*i}, {i%2}, 'binary{i}', 'nchar{i}', now()+{1*i}a )"
|
||||||
|
)
|
||||||
|
tdSql.execute(
|
||||||
|
f"insert into ct4 values ( now()-{i*90}d, {1*i}, {11111*i}, {111*i}, {11*i}, {1.11*i}, {11.11*i}, {i%2}, 'binary{i}', 'nchar{i}', now()+{1*i}a )"
|
||||||
|
)
|
||||||
|
tdSql.execute(
|
||||||
|
f"insert into ct2 values ( now()-{i*90}d, {-1*i}, {-11111*i}, {-111*i}, {-11*i}, {-1.11*i}, {-11.11*i}, {i%2}, 'binary{i}', 'nchar{i}', now()+{1*i}a )"
|
||||||
|
)
|
||||||
|
tdSql.execute(
|
||||||
|
'''insert into ct1 values
|
||||||
|
( now()-45s, 0, 0, 0, 0, 0, 0, 0, 'binary0', 'nchar0', now()+8a )
|
||||||
|
( now()+10s, 9, -99999, -999, -99, -9.99, -99.99, 1, 'binary9', 'nchar9', now()+9a )
|
||||||
|
'''
|
||||||
|
)
|
||||||
|
|
||||||
|
tdSql.execute(
|
||||||
|
f'''insert into ct4 values
|
||||||
|
( now()-810d, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL )
|
||||||
|
( now()-400d, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL )
|
||||||
|
( now()+{rows * 9}d, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL )
|
||||||
|
(
|
||||||
|
now()+{rows * 9-10}d, {pow(2,31)-pow(2,15)}, {pow(2,63)-pow(2,30)}, 32767, 127,
|
||||||
|
{ 3.3 * pow(10,38) }, { 1.3 * pow(10,308) }, { rows % 2 }, "binary_limit-1", "nachar_limit-1", now()-1d
|
||||||
|
)
|
||||||
|
(
|
||||||
|
now()+{rows * 9-20}d, {pow(2,31)-pow(2,16)}, {pow(2,63)-pow(2,31)}, 32766, 126,
|
||||||
|
{ 3.2 * pow(10,38) }, { 1.2 * pow(10,308) }, { (rows-1) % 2 }, "binary_limit-2", "nachar_limit-2", now()-2d
|
||||||
|
)
|
||||||
|
'''
|
||||||
|
)
|
||||||
|
|
||||||
|
tdSql.execute(
|
||||||
|
f'''insert into ct2 values
|
||||||
|
( now()-810d, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL )
|
||||||
|
( now()-400d, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL )
|
||||||
|
( now()+{rows * 9}d, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL )
|
||||||
|
(
|
||||||
|
now()+{rows * 9-10}d, { -1 * pow(2,31) + pow(2,15) }, { -1 * pow(2,63) + pow(2,30) }, -32766, -126,
|
||||||
|
{ -1 * 3.2 * pow(10,38) }, { -1.2 * pow(10,308) }, { rows % 2 }, "binary_limit-1", "nachar_limit-1", now()-1d
|
||||||
|
)
|
||||||
|
(
|
||||||
|
now()+{rows * 9-20}d, { -1 * pow(2,31) + pow(2,16) }, { -1 * pow(2,63) + pow(2,31) }, -32767, -127,
|
||||||
|
{ - 3.3 * pow(10,38) }, { -1.3 * pow(10,308) }, { (rows-1) % 2 }, "binary_limit-2", "nachar_limit-2", now()-2d
|
||||||
|
)
|
||||||
|
'''
|
||||||
|
)
|
||||||
|
|
||||||
|
for i in range(rows):
|
||||||
|
insert_data = f'''insert into t1 values
|
||||||
|
( now()-{i}h, {i}, {i}, { i % 32767 }, { i % 127}, { i * 1.11111 }, { i * 1000.1111 }, { i % 2},
|
||||||
|
"binary_{i}", "nchar_{i}", now()-{i}s )
|
||||||
|
'''
|
||||||
|
tdSql.execute(insert_data)
|
||||||
|
tdSql.execute(
|
||||||
|
f'''insert into t1 values
|
||||||
|
( now() + 3h, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL )
|
||||||
|
( now()-{ ( rows // 2 ) * 60 + 30 }m, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL )
|
||||||
|
( now()-{rows}h, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL )
|
||||||
|
( now() + 2h, { pow(2,31) - pow(2,15) }, { pow(2,63) - pow(2,30) }, 32767, 127,
|
||||||
|
{ 3.3 * pow(10,38) }, { 1.3 * pow(10,308) }, { rows % 2 },
|
||||||
|
"binary_limit-1", "nachar_limit-1", now()-1d
|
||||||
|
)
|
||||||
|
(
|
||||||
|
now() + 1h , { pow(2,31) - pow(2,16) }, { pow(2,63) - pow(2,31) }, 32766, 126,
|
||||||
|
{ 3.2 * pow(10,38) }, { 1.2 * pow(10,308) }, { (rows-1) % 2 },
|
||||||
|
"binary_limit-2", "nachar_limit-2", now()-2d
|
||||||
|
)
|
||||||
|
'''
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
tdSql.prepare()
|
||||||
|
|
||||||
|
tdLog.printNoPrefix("==========step1:create table")
|
||||||
|
self.__create_tb()
|
||||||
|
|
||||||
|
tdLog.printNoPrefix("==========step2:insert data")
|
||||||
|
self.__insert_data(100)
|
||||||
|
|
||||||
|
tdLog.printNoPrefix("==========step3:all check")
|
||||||
|
self.all_test()
|
||||||
|
|
||||||
|
# tdDnodes.stop(1)
|
||||||
|
# tdDnodes.start(1)
|
||||||
|
|
||||||
|
# tdSql.execute("use db")
|
||||||
|
|
||||||
|
# tdLog.printNoPrefix("==========step4:after wal, all check again ")
|
||||||
|
# self.all_test()
|
||||||
|
|
||||||
|
def stop(self):
|
||||||
|
tdSql.close()
|
||||||
|
tdLog.success(f"{__file__} successfully executed")
|
||||||
|
|
||||||
|
tdCases.addLinux(__file__, TDTestCase())
|
||||||
|
tdCases.addWindows(__file__, TDTestCase())
|
|
@ -2,6 +2,6 @@
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
#python3 ./test.py -f 2-query/between.py
|
#python3 ./test.py -f 2-query/between.py
|
||||||
python3 ./test.py -f 2-query/distinct.py
|
#python3 ./test.py -f 2-query/distinct.py
|
||||||
python3 ./test.py -f 2-query/varchar.py
|
python3 ./test.py -f 2-query/varchar.py
|
||||||
python3 ./test.py -f 2-query/cast.py
|
python3 ./test.py -f 2-query/cast.py
|
||||||
|
|
|
@ -125,13 +125,13 @@ void saveConfigToLogFile() {
|
||||||
for (int32_t i = 0; i < g_stConfInfo.numOfThread; i++) {
|
for (int32_t i = 0; i < g_stConfInfo.numOfThread; i++) {
|
||||||
taosFprintfFile(g_fp, "# consumer %d info:\n", g_stConfInfo.stThreads[i].consumerId);
|
taosFprintfFile(g_fp, "# consumer %d info:\n", g_stConfInfo.stThreads[i].consumerId);
|
||||||
taosFprintfFile(g_fp, " Topics: ");
|
taosFprintfFile(g_fp, " Topics: ");
|
||||||
for (int i = 0 ; i < g_stConfInfo.stThreads[i].numOfTopic; i++) {
|
for (int j = 0 ; j < g_stConfInfo.stThreads[i].numOfTopic; j++) {
|
||||||
taosFprintfFile(g_fp, "%s, ", g_stConfInfo.stThreads[i].topics[i]);
|
taosFprintfFile(g_fp, "%s, ", g_stConfInfo.stThreads[i].topics[j]);
|
||||||
}
|
}
|
||||||
taosFprintfFile(g_fp, "\n");
|
taosFprintfFile(g_fp, "\n");
|
||||||
taosFprintfFile(g_fp, " Key: ");
|
taosFprintfFile(g_fp, " Key: ");
|
||||||
for (int i = 0 ; i < g_stConfInfo.stThreads[i].numOfKey; i++) {
|
for (int k = 0 ; k < g_stConfInfo.stThreads[i].numOfKey; k++) {
|
||||||
taosFprintfFile(g_fp, "%s:%s, ", g_stConfInfo.stThreads[i].key[i], g_stConfInfo.stThreads[i].value[i]);
|
taosFprintfFile(g_fp, "%s:%s, ", g_stConfInfo.stThreads[i].key[k], g_stConfInfo.stThreads[i].value[k]);
|
||||||
}
|
}
|
||||||
taosFprintfFile(g_fp, "\n");
|
taosFprintfFile(g_fp, "\n");
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,93 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
|
|
||||||
*
|
|
||||||
* This program is free software: you can use, redistribute, and/or modify
|
|
||||||
* it under the terms of the GNU Affero General Public License, version 3
|
|
||||||
* or later ("AGPL"), as published by the Free Software Foundation.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Affero General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef _TD_SHELL_H_
|
|
||||||
#define _TD_SHELL_H_
|
|
||||||
|
|
||||||
#include "os.h"
|
|
||||||
|
|
||||||
#include "taos.h"
|
|
||||||
#include "taosdef.h"
|
|
||||||
|
|
||||||
#define MAX_USERNAME_SIZE 64
|
|
||||||
#define MAX_DBNAME_SIZE 64
|
|
||||||
#define MAX_IP_SIZE 20
|
|
||||||
#define MAX_HISTORY_SIZE 1000
|
|
||||||
#define MAX_COMMAND_SIZE 1048586
|
|
||||||
#define HISTORY_FILE ".taos_history"
|
|
||||||
|
|
||||||
#define DEFAULT_RES_SHOW_NUM 100
|
|
||||||
|
|
||||||
typedef struct SShellHistory {
|
|
||||||
char* hist[MAX_HISTORY_SIZE];
|
|
||||||
int hstart;
|
|
||||||
int hend;
|
|
||||||
} SShellHistory;
|
|
||||||
|
|
||||||
typedef struct SShellArguments {
|
|
||||||
char* host;
|
|
||||||
char* password;
|
|
||||||
char* user;
|
|
||||||
char* auth;
|
|
||||||
char* database;
|
|
||||||
char* timezone;
|
|
||||||
bool is_raw_time;
|
|
||||||
bool is_use_passwd;
|
|
||||||
bool dump_config;
|
|
||||||
char file[TSDB_FILENAME_LEN];
|
|
||||||
char dir[TSDB_FILENAME_LEN];
|
|
||||||
int threadNum;
|
|
||||||
int check;
|
|
||||||
bool status;
|
|
||||||
bool verbose;
|
|
||||||
char* commands;
|
|
||||||
int abort;
|
|
||||||
int port;
|
|
||||||
int pktLen;
|
|
||||||
int pktNum;
|
|
||||||
char* pktType;
|
|
||||||
char* netTestRole;
|
|
||||||
} SShellArguments;
|
|
||||||
|
|
||||||
/**************** Function declarations ****************/
|
|
||||||
extern void shellParseArgument(int argc, char* argv[], SShellArguments* arguments);
|
|
||||||
extern TAOS* shellInit(SShellArguments* args);
|
|
||||||
extern void* shellLoopQuery(void* arg);
|
|
||||||
extern void taos_error(TAOS_RES* tres, int64_t st);
|
|
||||||
extern int regex_match(const char* s, const char* reg, int cflags);
|
|
||||||
int32_t shellReadCommand(TAOS* con, char command[]);
|
|
||||||
int32_t shellRunCommand(TAOS* con, char* command);
|
|
||||||
void shellRunCommandOnServer(TAOS* con, char command[]);
|
|
||||||
void read_history();
|
|
||||||
void write_history();
|
|
||||||
void source_file(TAOS* con, char* fptr);
|
|
||||||
void source_dir(TAOS* con, SShellArguments* args);
|
|
||||||
void get_history_path(char* history);
|
|
||||||
void shellCheck(TAOS* con, SShellArguments* args);
|
|
||||||
void cleanup_handler(void* arg);
|
|
||||||
void exitShell();
|
|
||||||
int shellDumpResult(TAOS_RES* con, char* fname, int* error_no, bool printMode);
|
|
||||||
void shellGetGrantInfo(void *con);
|
|
||||||
int isCommentLine(char *line);
|
|
||||||
|
|
||||||
/**************** Global variable declarations ****************/
|
|
||||||
extern char PROMPT_HEADER[];
|
|
||||||
extern char CONTINUE_PROMPT[];
|
|
||||||
extern int prompt_size;
|
|
||||||
extern SShellHistory history;
|
|
||||||
extern SShellArguments args;
|
|
||||||
extern int64_t result;
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,55 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
|
|
||||||
*
|
|
||||||
* This program is free software: you can use, redistribute, and/or modify
|
|
||||||
* it under the terms of the GNU Affero General Public License, version 3
|
|
||||||
* or later ("AGPL"), as published by the Free Software Foundation.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Affero General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef _TD_SHELL_COMMAND_H_
|
|
||||||
#define _TD_SHELL_COMMAND_H_
|
|
||||||
|
|
||||||
#include "shell.h"
|
|
||||||
|
|
||||||
#define LEFT 1
|
|
||||||
#define RIGHT 2
|
|
||||||
#define UP 3
|
|
||||||
#define DOWN 4
|
|
||||||
|
|
||||||
typedef struct Command Command;
|
|
||||||
struct Command {
|
|
||||||
char * buffer;
|
|
||||||
char * command;
|
|
||||||
unsigned commandSize;
|
|
||||||
unsigned bufferSize;
|
|
||||||
unsigned cursorOffset;
|
|
||||||
unsigned screenOffset;
|
|
||||||
unsigned endOffset;
|
|
||||||
};
|
|
||||||
|
|
||||||
extern void backspaceChar(Command *cmd);
|
|
||||||
extern void clearLineBefore(Command *cmd);
|
|
||||||
extern void clearLineAfter(Command *cmd);
|
|
||||||
extern void deleteChar(Command *cmd);
|
|
||||||
extern void moveCursorLeft(Command *cmd);
|
|
||||||
extern void moveCursorRight(Command *cmd);
|
|
||||||
extern void positionCursorHome(Command *cmd);
|
|
||||||
extern void positionCursorEnd(Command *cmd);
|
|
||||||
extern void showOnScreen(Command *cmd);
|
|
||||||
extern void updateBuffer(Command *cmd);
|
|
||||||
extern int isReadyGo(Command *cmd);
|
|
||||||
extern void resetCommand(Command *cmd, const char s[]);
|
|
||||||
|
|
||||||
int countPrefixOnes(unsigned char c);
|
|
||||||
void clearScreen(int ecmd_pos, int cursor_pos);
|
|
||||||
void printChar(char c, int times);
|
|
||||||
void positionCursor(int step, int direction);
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -0,0 +1,117 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
|
||||||
|
*
|
||||||
|
* This program is free software: you can use, redistribute, and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License, version 3
|
||||||
|
* or later ("AGPL"), as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _TD_SHELL_INT_H_
|
||||||
|
#define _TD_SHELL_INT_H_
|
||||||
|
|
||||||
|
#include "os.h"
|
||||||
|
#include "taos.h"
|
||||||
|
#include "taosdef.h"
|
||||||
|
#include "taoserror.h"
|
||||||
|
#include "tconfig.h"
|
||||||
|
#include "tglobal.h"
|
||||||
|
#include "trpc.h"
|
||||||
|
#include "ttypes.h"
|
||||||
|
#include "tutil.h"
|
||||||
|
|
||||||
|
#define SHELL_MAX_HISTORY_SIZE 1000
|
||||||
|
#define SHELL_MAX_COMMAND_SIZE 1048586
|
||||||
|
#define SHELL_HISTORY_FILE ".taos_history"
|
||||||
|
#define SHELL_DEFAULT_RES_SHOW_NUM 100
|
||||||
|
#define SHELL_DEFAULT_MAX_BINARY_DISPLAY_WIDTH 30
|
||||||
|
#define SHELL_MAX_PKG_LEN 2 * 1024 * 1024
|
||||||
|
#define SHELL_MIN_PKG_LEN 1
|
||||||
|
#define SHELL_DEF_PKG_LEN 1024
|
||||||
|
#define SHELL_MAX_PKG_NUM 1 * 1024 * 1024
|
||||||
|
#define SHELL_MIN_PKG_NUM 1
|
||||||
|
#define SHELL_DEF_PKG_NUM 100
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
char* hist[SHELL_MAX_HISTORY_SIZE];
|
||||||
|
char file[TSDB_FILENAME_LEN];
|
||||||
|
int32_t hstart;
|
||||||
|
int32_t hend;
|
||||||
|
} SShellHistory;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
const char* host;
|
||||||
|
const char* user;
|
||||||
|
const char* auth;
|
||||||
|
const char* database;
|
||||||
|
const char* cfgdir;
|
||||||
|
const char* commands;
|
||||||
|
const char* netrole;
|
||||||
|
char file[PATH_MAX];
|
||||||
|
char password[TSDB_USET_PASSWORD_LEN];
|
||||||
|
bool is_gen_auth;
|
||||||
|
bool is_raw_time;
|
||||||
|
bool is_version;
|
||||||
|
bool is_dump_config;
|
||||||
|
bool is_check;
|
||||||
|
bool is_startup;
|
||||||
|
bool is_help;
|
||||||
|
uint16_t port;
|
||||||
|
int32_t pktLen;
|
||||||
|
int32_t pktNum;
|
||||||
|
int32_t displayWidth;
|
||||||
|
int32_t abort;
|
||||||
|
} SShellArgs;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
const char* clientVersion;
|
||||||
|
const char* promptHeader;
|
||||||
|
const char* promptContinue;
|
||||||
|
const char* osname;
|
||||||
|
int32_t promptSize;
|
||||||
|
char programVersion[32];
|
||||||
|
} SShellOsDetails;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
SShellArgs args;
|
||||||
|
SShellHistory history;
|
||||||
|
SShellOsDetails info;
|
||||||
|
TAOS* conn;
|
||||||
|
TdThread pid;
|
||||||
|
tsem_t cancelSem;
|
||||||
|
int64_t result;
|
||||||
|
} SShellObj;
|
||||||
|
|
||||||
|
// shellArguments.c
|
||||||
|
int32_t shellParseArgs(int32_t argc, char* argv[]);
|
||||||
|
|
||||||
|
// shellCommand.c
|
||||||
|
int32_t shellReadCommand(char* command);
|
||||||
|
|
||||||
|
// shellEngine.c
|
||||||
|
int32_t shellExecute();
|
||||||
|
|
||||||
|
// shellUtil.c
|
||||||
|
int32_t shellCheckIntSize();
|
||||||
|
void shellPrintVersion();
|
||||||
|
void shellPrintHelp();
|
||||||
|
void shellGenerateAuth();
|
||||||
|
void shellDumpConfig();
|
||||||
|
void shellCheckServerStatus();
|
||||||
|
bool shellRegexMatch(const char* s, const char* reg, int32_t cflags);
|
||||||
|
void shellExit();
|
||||||
|
|
||||||
|
// shellNettest.c
|
||||||
|
void shellTestNetWork();
|
||||||
|
|
||||||
|
// shellMain.c
|
||||||
|
extern SShellObj shell;
|
||||||
|
extern void taos_init();
|
||||||
|
|
||||||
|
#endif /*_TD_SHELL_INT_H_*/
|
|
@ -1,141 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
|
|
||||||
*
|
|
||||||
* This program is free software: you can use, redistribute, and/or modify
|
|
||||||
* it under the terms of the GNU Affero General Public License, version 3
|
|
||||||
* or later ("AGPL"), as published by the Free Software Foundation.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Affero General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef TDENGINE_SYNC_MSG_H
|
|
||||||
#define TDENGINE_SYNC_MSG_H
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
#include "tsync.h"
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
TAOS_SMSG_START = 0,
|
|
||||||
TAOS_SMSG_SYNC_DATA = 1,
|
|
||||||
TAOS_SMSG_SYNC_DATA_RSP = 2,
|
|
||||||
TAOS_SMSG_SYNC_FWD = 3,
|
|
||||||
TAOS_SMSG_SYNC_FWD_RSP = 4,
|
|
||||||
TAOS_SMSG_SYNC_REQ = 5,
|
|
||||||
TAOS_SMSG_SYNC_REQ_RSP = 6,
|
|
||||||
TAOS_SMSG_SYNC_MUST = 7,
|
|
||||||
TAOS_SMSG_SYNC_MUST_RSP = 8,
|
|
||||||
TAOS_SMSG_STATUS = 9,
|
|
||||||
TAOS_SMSG_STATUS_RSP = 10,
|
|
||||||
TAOS_SMSG_SETUP = 11,
|
|
||||||
TAOS_SMSG_SETUP_RSP = 12,
|
|
||||||
TAOS_SMSG_SYNC_FILE = 13,
|
|
||||||
TAOS_SMSG_SYNC_FILE_RSP = 14,
|
|
||||||
TAOS_SMSG_TEST = 15,
|
|
||||||
TAOS_SMSG_END = 16
|
|
||||||
} ESyncMsgType;
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
SYNC_STATUS_BROADCAST,
|
|
||||||
SYNC_STATUS_BROADCAST_RSP,
|
|
||||||
SYNC_STATUS_SETUP_CONN,
|
|
||||||
SYNC_STATUS_SETUP_CONN_RSP,
|
|
||||||
SYNC_STATUS_EXCHANGE_DATA,
|
|
||||||
SYNC_STATUS_EXCHANGE_DATA_RSP,
|
|
||||||
SYNC_STATUS_CHECK_ROLE,
|
|
||||||
SYNC_STATUS_CHECK_ROLE_RSP
|
|
||||||
} ESyncStatusType;
|
|
||||||
|
|
||||||
#pragma pack(push, 1)
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
int8_t type; // msg type
|
|
||||||
int8_t protocol; // protocol version
|
|
||||||
uint16_t signature; // fixed value
|
|
||||||
int32_t code; //
|
|
||||||
int32_t cId; // cluster Id
|
|
||||||
int32_t vgId; // vg ID
|
|
||||||
int32_t len; // content length, does not include head
|
|
||||||
uint32_t cksum;
|
|
||||||
} SSyncHead;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
SSyncHead head;
|
|
||||||
uint16_t port;
|
|
||||||
uint16_t tranId;
|
|
||||||
int32_t sourceId; // only for arbitrator
|
|
||||||
char fqdn[TSDB_FQDN_LEN];
|
|
||||||
} SSyncMsg;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
SSyncHead head;
|
|
||||||
int8_t sync;
|
|
||||||
int8_t reserved;
|
|
||||||
uint16_t tranId;
|
|
||||||
int8_t reserverd[4];
|
|
||||||
} SSyncRsp;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
int8_t role;
|
|
||||||
uint64_t version;
|
|
||||||
} SPeerStatus;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
SSyncHead head;
|
|
||||||
int8_t role;
|
|
||||||
int8_t ack;
|
|
||||||
int8_t type;
|
|
||||||
int8_t reserved[3];
|
|
||||||
uint16_t tranId;
|
|
||||||
uint64_t version;
|
|
||||||
SPeerStatus peersStatus[TAOS_SYNC_MAX_REPLICA];
|
|
||||||
} SPeersStatus;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
SSyncHead head;
|
|
||||||
uint64_t fversion;
|
|
||||||
} SFileVersion;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
SSyncHead head;
|
|
||||||
int8_t ack;
|
|
||||||
} SFileAck;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
SSyncHead head;
|
|
||||||
uint64_t version;
|
|
||||||
int32_t code;
|
|
||||||
} SFwdRsp;
|
|
||||||
|
|
||||||
#pragma pack(pop)
|
|
||||||
|
|
||||||
#define SYNC_PROTOCOL_VERSION 1
|
|
||||||
#define SYNC_SIGNATURE ((uint16_t)(0xCDEF))
|
|
||||||
|
|
||||||
extern char *statusType[];
|
|
||||||
|
|
||||||
uint16_t syncGenTranId();
|
|
||||||
int32_t syncCheckHead(SSyncHead *pHead);
|
|
||||||
|
|
||||||
void syncBuildSyncFwdMsg(SSyncHead *pHead, int32_t vgId, int32_t len);
|
|
||||||
void syncBuildSyncFwdRsp(SFwdRsp *pMsg, int32_t vgId, uint64_t version, int32_t code);
|
|
||||||
void syncBuildSyncReqMsg(SSyncMsg *pMsg, int32_t vgId);
|
|
||||||
void syncBuildSyncDataMsg(SSyncMsg *pMsg, int32_t vgId);
|
|
||||||
void syncBuildSyncSetupMsg(SSyncMsg *pMsg, int32_t vgId);
|
|
||||||
void syncBuildPeersStatus(SPeersStatus *pMsg, int32_t vgId);
|
|
||||||
void syncBuildSyncTestMsg(SSyncMsg *pMsg, int32_t vgId);
|
|
||||||
|
|
||||||
void syncBuildFileAck(SFileAck *pMsg, int32_t vgId);
|
|
||||||
void syncBuildFileVersion(SFileVersion *pMsg, int32_t vgId);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif // TDENGINE_VNODEPEER_H
|
|
|
@ -1,127 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
|
|
||||||
*
|
|
||||||
* This program is free software: you can use, redistribute, and/or modify
|
|
||||||
* it under the terms of the GNU Affero General Public License, version 3
|
|
||||||
* or later ("AGPL"), as published by the Free Software Foundation.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Affero General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef TDENGINE_SYNC_H
|
|
||||||
#define TDENGINE_SYNC_H
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define TAOS_SYNC_MAX_REPLICA 5
|
|
||||||
#define TAOS_SYNC_MAX_INDEX 0x7FFFFFFF
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
TAOS_SYNC_ROLE_OFFLINE = 0,
|
|
||||||
TAOS_SYNC_ROLE_UNSYNCED = 1,
|
|
||||||
TAOS_SYNC_ROLE_SYNCING = 2,
|
|
||||||
TAOS_SYNC_ROLE_SLAVE = 3,
|
|
||||||
TAOS_SYNC_ROLE_MASTER = 4
|
|
||||||
} ESyncRole;
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
TAOS_SYNC_STATUS_INIT = 0,
|
|
||||||
TAOS_SYNC_STATUS_START = 1,
|
|
||||||
TAOS_SYNC_STATUS_FILE = 2,
|
|
||||||
TAOS_SYNC_STATUS_CACHE = 3
|
|
||||||
} ESyncStatus;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
uint32_t nodeId; // node ID assigned by TDengine
|
|
||||||
uint16_t nodePort; // node sync Port
|
|
||||||
char nodeFqdn[TSDB_FQDN_LEN]; // node FQDN
|
|
||||||
} SNodeInfo;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
int8_t quorum; // number of confirms required, >=1
|
|
||||||
int8_t replica; // number of replications, >=1
|
|
||||||
SNodeInfo nodeInfo[TAOS_SYNC_MAX_REPLICA];
|
|
||||||
} SSyncCfg;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
int32_t selfIndex;
|
|
||||||
uint32_t nodeId[TAOS_SYNC_MAX_REPLICA];
|
|
||||||
int32_t role[TAOS_SYNC_MAX_REPLICA];
|
|
||||||
} SNodesRole;
|
|
||||||
|
|
||||||
// get the wal file from index or after
|
|
||||||
// return value, -1: error, 1:more wal files, 0:last WAL. if name[0]==0, no WAL file
|
|
||||||
typedef int32_t (*FGetWalInfo)(int32_t vgId, char *fileName, int64_t *fileId);
|
|
||||||
|
|
||||||
// when a forward pkt is received, call this to handle data
|
|
||||||
typedef int32_t (*FWriteToCache)(int32_t vgId, void *pHead, int32_t qtype, void *pMsg);
|
|
||||||
|
|
||||||
// when forward is confirmed by peer, master call this API to notify app
|
|
||||||
typedef void (*FConfirmForward)(int32_t vgId, void *mhandle, int32_t code);
|
|
||||||
|
|
||||||
// when role is changed, call this to notify app
|
|
||||||
typedef void (*FNotifyRole)(int32_t vgId, int8_t role);
|
|
||||||
|
|
||||||
// if a number of retrieving data failed, call this to start flow control
|
|
||||||
typedef void (*FNotifyFlowCtrl)(int32_t vgId, int32_t level);
|
|
||||||
|
|
||||||
// when data file is synced successfully, notity app
|
|
||||||
typedef void (*FStartSyncFile)(int32_t vgId);
|
|
||||||
typedef void (*FStopSyncFile)(int32_t vgId, uint64_t fversion);
|
|
||||||
|
|
||||||
// get file version
|
|
||||||
typedef int32_t (*FGetVersion)(int32_t vgId, uint64_t *fver, uint64_t *vver);
|
|
||||||
|
|
||||||
typedef int32_t (*FSendFile)(void *tsdb, SOCKET socketFd);
|
|
||||||
typedef int32_t (*FRecvFile)(void *tsdb, SOCKET socketFd);
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
int32_t vgId; // vgroup ID
|
|
||||||
uint64_t version; // initial version
|
|
||||||
SSyncCfg syncCfg; // configuration from mgmt
|
|
||||||
char path[TSDB_FILENAME_LEN]; // path to the file
|
|
||||||
void * pTsdb;
|
|
||||||
FGetWalInfo getWalInfoFp;
|
|
||||||
FWriteToCache writeToCacheFp;
|
|
||||||
FConfirmForward confirmForward;
|
|
||||||
FNotifyRole notifyRoleFp;
|
|
||||||
FNotifyFlowCtrl notifyFlowCtrlFp;
|
|
||||||
FStartSyncFile startSyncFileFp;
|
|
||||||
FStopSyncFile stopSyncFileFp;
|
|
||||||
FGetVersion getVersionFp;
|
|
||||||
FSendFile sendFileFp;
|
|
||||||
FRecvFile recvFileFp;
|
|
||||||
} SSyncInfo;
|
|
||||||
|
|
||||||
typedef void *tsync_h;
|
|
||||||
|
|
||||||
int32_t syncInit();
|
|
||||||
void syncCleanUp();
|
|
||||||
|
|
||||||
int64_t syncStart(const SSyncInfo *);
|
|
||||||
void syncStop(int64_t rid);
|
|
||||||
int32_t syncReconfig(int64_t rid, const SSyncCfg *);
|
|
||||||
int32_t syncForwardToPeer(int64_t rid, void *pHead, void *mhandle, int32_t qtype, bool force);
|
|
||||||
void syncConfirmForward(int64_t rid, uint64_t version, int32_t code, bool force);
|
|
||||||
void syncRecover(int64_t rid); // recover from other nodes:
|
|
||||||
int32_t syncGetNodesRole(int64_t rid, SNodesRole *);
|
|
||||||
|
|
||||||
extern char *syncRole[];
|
|
||||||
|
|
||||||
//global configurable parameters
|
|
||||||
extern int32_t sDebugFlag;
|
|
||||||
extern char tsArbitrator[];
|
|
||||||
extern uint16_t tsSyncPort;
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif // TDENGINE_SYNC_H
|
|
|
@ -1,202 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
|
|
||||||
*
|
|
||||||
* This program is free software: you can use, redistribute, and/or modify
|
|
||||||
* it under the terms of the GNU Affero General Public License, version 3
|
|
||||||
* or later ("AGPL"), as published by the Free Software Foundation.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Affero General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define _GNU_SOURCE
|
|
||||||
#define _XOPEN_SOURCE
|
|
||||||
#define _DEFAULT_SOURCE
|
|
||||||
|
|
||||||
#include "os.h"
|
|
||||||
#include "shell.h"
|
|
||||||
#include "shellCommand.h"
|
|
||||||
#include "tglobal.h"
|
|
||||||
#include "tutil.h"
|
|
||||||
|
|
||||||
#define SHELL_SQL_LEN 1024
|
|
||||||
static int32_t tbNum = 0;
|
|
||||||
static int32_t tbMallocNum = 0;
|
|
||||||
static char ** tbNames = NULL;
|
|
||||||
static int32_t checkedNum = 0;
|
|
||||||
static int32_t errorNum = 0;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
TdThread threadID;
|
|
||||||
int threadIndex;
|
|
||||||
int totalThreads;
|
|
||||||
void * taos;
|
|
||||||
char * db;
|
|
||||||
} ShellThreadObj;
|
|
||||||
|
|
||||||
static int32_t shellUseDb(TAOS *con, char *db) {
|
|
||||||
if (db == NULL) {
|
|
||||||
fprintf(stdout, "no dbname input\n");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
char sql[SHELL_SQL_LEN] = {0};
|
|
||||||
snprintf(sql, SHELL_SQL_LEN, "use %s", db);
|
|
||||||
|
|
||||||
TAOS_RES *pSql = taos_query(con, sql);
|
|
||||||
int32_t code = taos_errno(pSql);
|
|
||||||
if (code != 0) {
|
|
||||||
fprintf(stdout, "failed to execute sql:%s since %s", sql, taos_errstr(pSql));
|
|
||||||
}
|
|
||||||
|
|
||||||
taos_free_result(pSql);
|
|
||||||
return code;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int32_t shellShowTables(TAOS *con, char *db) {
|
|
||||||
char sql[SHELL_SQL_LEN] = {0};
|
|
||||||
snprintf(sql, SHELL_SQL_LEN, "show %s.tables", db);
|
|
||||||
|
|
||||||
TAOS_RES *pSql = taos_query(con, sql);
|
|
||||||
int32_t code = taos_errno(pSql);
|
|
||||||
|
|
||||||
if (code != 0) {
|
|
||||||
fprintf(stdout, "failed to execute sql:%s since %s\n", sql, taos_errstr(pSql));
|
|
||||||
} else {
|
|
||||||
TAOS_ROW row;
|
|
||||||
while ((row = taos_fetch_row(pSql))) {
|
|
||||||
int32_t tbIndex = tbNum++;
|
|
||||||
if (tbMallocNum < tbNum) {
|
|
||||||
tbMallocNum = (tbMallocNum * 2 + 1);
|
|
||||||
char** tbNames1 = taosMemoryRealloc(tbNames, tbMallocNum * sizeof(char *));
|
|
||||||
if (tbNames1 == NULL) {
|
|
||||||
fprintf(stdout, "failed to malloc tablenames, num:%d\n", tbMallocNum);
|
|
||||||
code = TSDB_CODE_TSC_OUT_OF_MEMORY;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
tbNames = tbNames1;
|
|
||||||
}
|
|
||||||
|
|
||||||
tbNames[tbIndex] = taosMemoryMalloc(TSDB_TABLE_NAME_LEN);
|
|
||||||
strncpy(tbNames[tbIndex], (const char *)row[0], TSDB_TABLE_NAME_LEN);
|
|
||||||
if (tbIndex % 100000 == 0 && tbIndex != 0) {
|
|
||||||
fprintf(stdout, "%d tablenames fetched\n", tbIndex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
taos_free_result(pSql);
|
|
||||||
|
|
||||||
fprintf(stdout, "total %d tablenames fetched, over\n", tbNum);
|
|
||||||
return code;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void shellFreeTbnames() {
|
|
||||||
for (int32_t i = 0; i < tbNum; ++i) {
|
|
||||||
taosMemoryFree(tbNames[i]);
|
|
||||||
}
|
|
||||||
taosMemoryFree(tbNames);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void *shellCheckThreadFp(void *arg) {
|
|
||||||
ShellThreadObj *pThread = (ShellThreadObj *)arg;
|
|
||||||
|
|
||||||
setThreadName("shellCheckThrd");
|
|
||||||
|
|
||||||
int32_t interval = tbNum / pThread->totalThreads + 1;
|
|
||||||
int32_t start = pThread->threadIndex * interval;
|
|
||||||
int32_t end = (pThread->threadIndex + 1) * interval;
|
|
||||||
|
|
||||||
if (end > tbNum) end = tbNum + 1;
|
|
||||||
|
|
||||||
char file[32] = {0};
|
|
||||||
snprintf(file, 32, "tb%d.txt", pThread->threadIndex);
|
|
||||||
|
|
||||||
TdFilePtr pFile = taosOpenFile(file, TD_FILE_CREATE | TD_FILE_WRITE | TD_FILE_TRUNC);
|
|
||||||
if (!fp) {
|
|
||||||
fprintf(stdout, "failed to open %s, reason:%s", file, strerror(errno));
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
char sql[SHELL_SQL_LEN];
|
|
||||||
for (int32_t t = start; t < end; ++t) {
|
|
||||||
char *tbname = tbNames[t];
|
|
||||||
if (tbname == NULL) break;
|
|
||||||
|
|
||||||
snprintf(sql, SHELL_SQL_LEN, "select * from %s limit 1", tbname);
|
|
||||||
|
|
||||||
TAOS_RES *pSql = taos_query(pThread->taos, sql);
|
|
||||||
int32_t code = taos_errno(pSql);
|
|
||||||
if (code != 0) {
|
|
||||||
int32_t len = snprintf(sql, SHELL_SQL_LEN, "drop table %s.%s;\n", pThread->db, tbname);
|
|
||||||
taosWriteFile(pFile, sql, len);
|
|
||||||
atomic_add_fetch_32(&errorNum, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
int32_t cnum = atomic_add_fetch_32(&checkedNum, 1);
|
|
||||||
if (cnum % 5000 == 0 && cnum != 0) {
|
|
||||||
fprintf(stdout, "%d tables checked\n", cnum);
|
|
||||||
}
|
|
||||||
|
|
||||||
taos_free_result(pSql);
|
|
||||||
}
|
|
||||||
|
|
||||||
taosFsync(pFile);
|
|
||||||
taosCloseFile(&pFile);
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void shellRunCheckThreads(TAOS *con, SShellArguments *_args) {
|
|
||||||
TdThreadAttr thattr;
|
|
||||||
ShellThreadObj *threadObj = (ShellThreadObj *)taosMemoryCalloc(_args->threadNum, sizeof(ShellThreadObj));
|
|
||||||
for (int t = 0; t < _args->threadNum; ++t) {
|
|
||||||
ShellThreadObj *pThread = threadObj + t;
|
|
||||||
pThread->threadIndex = t;
|
|
||||||
pThread->totalThreads = _args->threadNum;
|
|
||||||
pThread->taos = con;
|
|
||||||
pThread->db = _args->database;
|
|
||||||
|
|
||||||
taosThreadAttrInit(&thattr);
|
|
||||||
taosThreadAttrSetDetachState(&thattr, PTHREAD_CREATE_JOINABLE);
|
|
||||||
|
|
||||||
if (taosThreadCreate(&(pThread->threadID), &thattr, shellCheckThreadFp, (void *)pThread) != 0) {
|
|
||||||
fprintf(stderr, "ERROR: thread:%d failed to start\n", pThread->threadIndex);
|
|
||||||
exit(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int t = 0; t < _args->threadNum; ++t) {
|
|
||||||
taosThreadJoin(threadObj[t].threadID, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int t = 0; t < _args->threadNum; ++t) {
|
|
||||||
taos_close(threadObj[t].taos);
|
|
||||||
}
|
|
||||||
taosMemoryFree(threadObj);
|
|
||||||
}
|
|
||||||
|
|
||||||
void shellCheck(TAOS *con, SShellArguments *_args) {
|
|
||||||
int64_t start = taosGetTimestampMs();
|
|
||||||
|
|
||||||
if (shellUseDb(con, _args->database) != 0) {
|
|
||||||
shellFreeTbnames();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (shellShowTables(con, _args->database) != 0) {
|
|
||||||
shellFreeTbnames();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
fprintf(stdout, "total %d tables will be checked by %d threads\n", tbNum, _args->threadNum);
|
|
||||||
shellRunCheckThreads(con, _args);
|
|
||||||
|
|
||||||
int64_t end = taosGetTimestampMs();
|
|
||||||
fprintf(stdout, "total %d tables checked, failed:%d, time spent %.2f seconds\n", checkedNum, errorNum,
|
|
||||||
(end - start) / 1000.0);
|
|
||||||
}
|
|
|
@ -1,498 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
|
|
||||||
*
|
|
||||||
* This program is free software: you can use, redistribute, and/or modify
|
|
||||||
* it under the terms of the GNU Affero General Public License, version 3
|
|
||||||
* or later ("AGPL"), as published by the Free Software Foundation.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Affero General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define __USE_XOPEN
|
|
||||||
|
|
||||||
#include "os.h"
|
|
||||||
|
|
||||||
#include "shell.h"
|
|
||||||
#include "shellCommand.h"
|
|
||||||
#include "tbase64.h"
|
|
||||||
|
|
||||||
#include "tscLog.h"
|
|
||||||
|
|
||||||
#define OPT_ABORT 1 /* <20>Cabort */
|
|
||||||
|
|
||||||
int indicator = 1;
|
|
||||||
struct termios oldtio;
|
|
||||||
|
|
||||||
void insertChar(Command *cmd, char *c, int size);
|
|
||||||
|
|
||||||
|
|
||||||
void printHelp() {
|
|
||||||
char indent[10] = " ";
|
|
||||||
printf("taos shell is used to test the TDengine database\n");
|
|
||||||
|
|
||||||
printf("%s%s\n", indent, "-h");
|
|
||||||
printf("%s%s%s\n", indent, indent, "TDengine server IP address to connect. The default host is localhost.");
|
|
||||||
printf("%s%s\n", indent, "-p");
|
|
||||||
printf("%s%s%s\n", indent, indent, "The password to use when connecting to the server.");
|
|
||||||
printf("%s%s\n", indent, "-P");
|
|
||||||
printf("%s%s%s\n", indent, indent, "The TCP/IP port number to use for the connection");
|
|
||||||
printf("%s%s\n", indent, "-u");
|
|
||||||
printf("%s%s%s\n", indent, indent, "The user name to use when connecting to the server.");
|
|
||||||
printf("%s%s\n", indent, "-c");
|
|
||||||
printf("%s%s%s\n", indent, indent, "Configuration directory.");
|
|
||||||
printf("%s%s\n", indent, "-s");
|
|
||||||
printf("%s%s%s\n", indent, indent, "Commands to run without enter the shell.");
|
|
||||||
printf("%s%s\n", indent, "-r");
|
|
||||||
printf("%s%s%s\n", indent, indent, "Output time as unsigned long..");
|
|
||||||
printf("%s%s\n", indent, "-f");
|
|
||||||
printf("%s%s%s\n", indent, indent, "Script to run without enter the shell.");
|
|
||||||
printf("%s%s\n", indent, "-d");
|
|
||||||
printf("%s%s%s\n", indent, indent, "Database to use when connecting to the server.");
|
|
||||||
printf("%s%s\n", indent, "-t");
|
|
||||||
printf("%s%s%s\n", indent, indent, "Time zone of the shell, default is local.");
|
|
||||||
printf("%s%s\n", indent, "-D");
|
|
||||||
printf("%s%s%s\n", indent, indent, "Use multi-thread to import all SQL files in the directory separately.");
|
|
||||||
printf("%s%s\n", indent, "-T");
|
|
||||||
printf("%s%s%s\n", indent, indent, "Number of threads when using multi-thread to import data.");
|
|
||||||
|
|
||||||
exit(EXIT_SUCCESS);
|
|
||||||
}
|
|
||||||
|
|
||||||
char DARWINCLIENT_VERSION[] = "Welcome to the TDengine shell from %s, Client Version:%s\n"
|
|
||||||
"Copyright (c) 2020 by TAOS Data, Inc. All rights reserved.\n\n";
|
|
||||||
char g_password[SHELL_MAX_PASSWORD_LEN];
|
|
||||||
|
|
||||||
void shellParseArgument(int argc, char *argv[], SShellArguments *arguments) {
|
|
||||||
wordexp_t full_path;
|
|
||||||
for (int i = 1; i < argc; i++) {
|
|
||||||
// for host
|
|
||||||
if (strcmp(argv[i], "-h") == 0) {
|
|
||||||
if (i < argc - 1) {
|
|
||||||
arguments->host = argv[++i];
|
|
||||||
} else {
|
|
||||||
fprintf(stderr, "option -h requires an argument\n");
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// for password
|
|
||||||
else if ((strncmp(argv[i], "-p", 2) == 0)
|
|
||||||
|| (strncmp(argv[i], "--password", 10) == 0)) {
|
|
||||||
strcpy(tsOsName, "Darwin");
|
|
||||||
printf(DARWINCLIENT_VERSION, tsOsName, taos_get_client_info());
|
|
||||||
if ((strlen(argv[i]) == 2)
|
|
||||||
|| (strncmp(argv[i], "--password", 10) == 0)) {
|
|
||||||
printf("Enter password: ");
|
|
||||||
taosSetConsoleEcho(false);
|
|
||||||
if (scanf("%s", g_password) > 1) {
|
|
||||||
fprintf(stderr, "password read error\n");
|
|
||||||
}
|
|
||||||
taosSetConsoleEcho(true);
|
|
||||||
getchar();
|
|
||||||
} else {
|
|
||||||
tstrncpy(g_password, (char *)(argv[i] + 2), SHELL_MAX_PASSWORD_LEN);
|
|
||||||
}
|
|
||||||
arguments->password = g_password;
|
|
||||||
arguments->is_use_passwd = true;
|
|
||||||
strcpy(argv[i], "");
|
|
||||||
argc -= 1;
|
|
||||||
}
|
|
||||||
// for management port
|
|
||||||
else if (strcmp(argv[i], "-P") == 0) {
|
|
||||||
if (i < argc - 1) {
|
|
||||||
arguments->port = atoi(argv[++i]);
|
|
||||||
} else {
|
|
||||||
fprintf(stderr, "option -P requires an argument\n");
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// for user
|
|
||||||
else if (strcmp(argv[i], "-u") == 0) {
|
|
||||||
if (i < argc - 1) {
|
|
||||||
arguments->user = argv[++i];
|
|
||||||
} else {
|
|
||||||
fprintf(stderr, "option -u requires an argument\n");
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
} else if (strcmp(argv[i], "-c") == 0) {
|
|
||||||
if (i < argc - 1) {
|
|
||||||
if (strlen(argv[++i]) >= TSDB_FILENAME_LEN) {
|
|
||||||
fprintf(stderr, "config file path: %s overflow max len %d\n", argv[i], TSDB_FILENAME_LEN - 1);
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
strcpy(configDir, argv[i]);
|
|
||||||
} else {
|
|
||||||
fprintf(stderr, "Option -c requires an argument\n");
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
} else if (strcmp(argv[i], "-s") == 0) {
|
|
||||||
if (i < argc - 1) {
|
|
||||||
arguments->commands = argv[++i];
|
|
||||||
} else {
|
|
||||||
fprintf(stderr, "option -s requires an argument\n");
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
} else if (strcmp(argv[i], "-r") == 0) {
|
|
||||||
arguments->is_raw_time = true;
|
|
||||||
}
|
|
||||||
// For temperory batch commands to run TODO
|
|
||||||
else if (strcmp(argv[i], "-f") == 0) {
|
|
||||||
if (i < argc - 1) {
|
|
||||||
strcpy(arguments->file, argv[++i]);
|
|
||||||
} else {
|
|
||||||
fprintf(stderr, "option -f requires an argument\n");
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// for default database
|
|
||||||
else if (strcmp(argv[i], "-d") == 0) {
|
|
||||||
if (i < argc - 1) {
|
|
||||||
arguments->database = argv[++i];
|
|
||||||
} else {
|
|
||||||
fprintf(stderr, "option -d requires an argument\n");
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// For time zone
|
|
||||||
else if (strcmp(argv[i], "-t") == 0) {
|
|
||||||
if (i < argc - 1) {
|
|
||||||
arguments->timezone = argv[++i];
|
|
||||||
} else {
|
|
||||||
fprintf(stderr, "option -t requires an argument\n");
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// For import directory
|
|
||||||
else if (strcmp(argv[i], "-D") == 0) {
|
|
||||||
if (i < argc - 1) {
|
|
||||||
if (wordexp(argv[++i], &full_path, 0) != 0) {
|
|
||||||
fprintf(stderr, "Invalid path %s\n", argv[i]);
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
strcpy(arguments->dir, full_path.we_wordv[0]);
|
|
||||||
wordfree(&full_path);
|
|
||||||
} else {
|
|
||||||
fprintf(stderr, "option -D requires an argument\n");
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// For time zone
|
|
||||||
else if (strcmp(argv[i], "-T") == 0) {
|
|
||||||
if (i < argc - 1) {
|
|
||||||
arguments->threadNum = atoi(argv[++i]);
|
|
||||||
} else {
|
|
||||||
fprintf(stderr, "option -T requires an argument\n");
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// For temperory command TODO
|
|
||||||
else if (strcmp(argv[i], "--help") == 0) {
|
|
||||||
printHelp();
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
} else {
|
|
||||||
fprintf(stderr, "wrong options\n");
|
|
||||||
printHelp();
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int32_t shellReadCommand(TAOS *con, char *command) {
|
|
||||||
unsigned hist_counter = history.hend;
|
|
||||||
char utf8_array[10] = "\0";
|
|
||||||
Command cmd;
|
|
||||||
memset(&cmd, 0, sizeof(cmd));
|
|
||||||
cmd.buffer = (char *)taosMemoryCalloc(1, MAX_COMMAND_SIZE);
|
|
||||||
cmd.command = (char *)taosMemoryCalloc(1, MAX_COMMAND_SIZE);
|
|
||||||
showOnScreen(&cmd);
|
|
||||||
|
|
||||||
// Read input.
|
|
||||||
char c;
|
|
||||||
while (1) {
|
|
||||||
c = getchar();
|
|
||||||
|
|
||||||
if (c < 0) { // For UTF-8
|
|
||||||
int count = countPrefixOnes(c);
|
|
||||||
utf8_array[0] = c;
|
|
||||||
for (int k = 1; k < count; k++) {
|
|
||||||
c = getchar();
|
|
||||||
utf8_array[k] = c;
|
|
||||||
}
|
|
||||||
insertChar(&cmd, utf8_array, count);
|
|
||||||
} else if (c < '\033') {
|
|
||||||
// Ctrl keys. TODO: Implement ctrl combinations
|
|
||||||
switch (c) {
|
|
||||||
case 1: // ctrl A
|
|
||||||
positionCursorHome(&cmd);
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
printf("\n");
|
|
||||||
resetCommand(&cmd, "");
|
|
||||||
kill(0, SIGINT);
|
|
||||||
break;
|
|
||||||
case 4: // EOF or Ctrl+D
|
|
||||||
printf("\n");
|
|
||||||
taos_close(con);
|
|
||||||
// write the history
|
|
||||||
write_history();
|
|
||||||
exitShell();
|
|
||||||
break;
|
|
||||||
case 5: // ctrl E
|
|
||||||
positionCursorEnd(&cmd);
|
|
||||||
break;
|
|
||||||
case 8:
|
|
||||||
backspaceChar(&cmd);
|
|
||||||
break;
|
|
||||||
case '\n':
|
|
||||||
case '\r':
|
|
||||||
printf("\n");
|
|
||||||
if (isReadyGo(&cmd)) {
|
|
||||||
sprintf(command, "%s%s", cmd.buffer, cmd.command);
|
|
||||||
taosMemoryFreeClear(cmd.buffer);
|
|
||||||
taosMemoryFreeClear(cmd.command);
|
|
||||||
return 0;
|
|
||||||
} else {
|
|
||||||
updateBuffer(&cmd);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 11: // Ctrl + K;
|
|
||||||
clearLineAfter(&cmd);
|
|
||||||
break;
|
|
||||||
case 12: // Ctrl + L;
|
|
||||||
system("clear");
|
|
||||||
showOnScreen(&cmd);
|
|
||||||
break;
|
|
||||||
case 21: // Ctrl + U
|
|
||||||
clearLineBefore(&cmd);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} else if (c == '\033') {
|
|
||||||
c = getchar();
|
|
||||||
switch (c) {
|
|
||||||
case '[':
|
|
||||||
c = getchar();
|
|
||||||
switch (c) {
|
|
||||||
case 'A': // Up arrow
|
|
||||||
if (hist_counter != history.hstart) {
|
|
||||||
hist_counter = (hist_counter + MAX_HISTORY_SIZE - 1) % MAX_HISTORY_SIZE;
|
|
||||||
resetCommand(&cmd, (history.hist[hist_counter] == NULL) ? "" : history.hist[hist_counter]);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 'B': // Down arrow
|
|
||||||
if (hist_counter != history.hend) {
|
|
||||||
int next_hist = (hist_counter + 1) % MAX_HISTORY_SIZE;
|
|
||||||
|
|
||||||
if (next_hist != history.hend) {
|
|
||||||
resetCommand(&cmd, (history.hist[next_hist] == NULL) ? "" : history.hist[next_hist]);
|
|
||||||
} else {
|
|
||||||
resetCommand(&cmd, "");
|
|
||||||
}
|
|
||||||
hist_counter = next_hist;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 'C': // Right arrow
|
|
||||||
moveCursorRight(&cmd);
|
|
||||||
break;
|
|
||||||
case 'D': // Left arrow
|
|
||||||
moveCursorLeft(&cmd);
|
|
||||||
break;
|
|
||||||
case '1':
|
|
||||||
if ((c = getchar()) == '~') {
|
|
||||||
// Home key
|
|
||||||
positionCursorHome(&cmd);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case '2':
|
|
||||||
if ((c = getchar()) == '~') {
|
|
||||||
// Insert key
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case '3':
|
|
||||||
if ((c = getchar()) == '~') {
|
|
||||||
// Delete key
|
|
||||||
deleteChar(&cmd);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case '4':
|
|
||||||
if ((c = getchar()) == '~') {
|
|
||||||
// End key
|
|
||||||
positionCursorEnd(&cmd);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case '5':
|
|
||||||
if ((c = getchar()) == '~') {
|
|
||||||
// Page up key
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case '6':
|
|
||||||
if ((c = getchar()) == '~') {
|
|
||||||
// Page down key
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 72:
|
|
||||||
// Home key
|
|
||||||
positionCursorHome(&cmd);
|
|
||||||
break;
|
|
||||||
case 70:
|
|
||||||
// End key
|
|
||||||
positionCursorEnd(&cmd);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} else if (c == 0x7f) {
|
|
||||||
// press delete key
|
|
||||||
backspaceChar(&cmd);
|
|
||||||
} else {
|
|
||||||
insertChar(&cmd, &c, 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void *shellLoopQuery(void *arg) {
|
|
||||||
if (indicator) {
|
|
||||||
getOldTerminalMode();
|
|
||||||
indicator = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
TAOS *con = (TAOS *)arg;
|
|
||||||
|
|
||||||
setThreadName("shellLoopQuery");
|
|
||||||
|
|
||||||
taosThreadCleanupPush(cleanup_handler, NULL);
|
|
||||||
|
|
||||||
char *command = taosMemoryMalloc(MAX_COMMAND_SIZE);
|
|
||||||
if (command == NULL){
|
|
||||||
tscError("failed to malloc command");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
int32_t err = 0;
|
|
||||||
|
|
||||||
do {
|
|
||||||
// Read command from shell.
|
|
||||||
memset(command, 0, MAX_COMMAND_SIZE);
|
|
||||||
setTerminalMode();
|
|
||||||
err = shellReadCommand(con, command);
|
|
||||||
if (err) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
resetTerminalMode();
|
|
||||||
} while (shellRunCommand(con, command) == 0);
|
|
||||||
|
|
||||||
taosMemoryFreeClear(command);
|
|
||||||
exitShell();
|
|
||||||
|
|
||||||
taosThreadCleanupPop(1);
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
void get_history_path(char *history) { sprintf(history, "%s/%s", getpwuid(getuid())->pw_dir, HISTORY_FILE); }
|
|
||||||
|
|
||||||
void clearScreen(int ecmd_pos, int cursor_pos) {
|
|
||||||
struct winsize w;
|
|
||||||
if (ioctl(0, TIOCGWINSZ, &w) < 0 || w.ws_col == 0 || w.ws_row == 0) {
|
|
||||||
//fprintf(stderr, "No stream device, and use default value(col 120, row 30)\n");
|
|
||||||
w.ws_col = 120;
|
|
||||||
w.ws_row = 30;
|
|
||||||
}
|
|
||||||
|
|
||||||
int cursor_x = cursor_pos / w.ws_col;
|
|
||||||
int cursor_y = cursor_pos % w.ws_col;
|
|
||||||
int command_x = ecmd_pos / w.ws_col;
|
|
||||||
positionCursor(cursor_y, LEFT);
|
|
||||||
positionCursor(command_x - cursor_x, DOWN);
|
|
||||||
fprintf(stdout, "\033[2K");
|
|
||||||
for (int i = 0; i < command_x; i++) {
|
|
||||||
positionCursor(1, UP);
|
|
||||||
fprintf(stdout, "\033[2K");
|
|
||||||
}
|
|
||||||
fflush(stdout);
|
|
||||||
}
|
|
||||||
|
|
||||||
void showOnScreen(Command *cmd) {
|
|
||||||
struct winsize w;
|
|
||||||
if (ioctl(0, TIOCGWINSZ, &w) < 0 || w.ws_col == 0 || w.ws_row == 0) {
|
|
||||||
//fprintf(stderr, "No stream device\n");
|
|
||||||
w.ws_col = 120;
|
|
||||||
w.ws_row = 30;
|
|
||||||
}
|
|
||||||
|
|
||||||
TdWchar wc;
|
|
||||||
int size = 0;
|
|
||||||
|
|
||||||
// Print out the command.
|
|
||||||
char *total_string = taosMemoryMalloc(MAX_COMMAND_SIZE);
|
|
||||||
memset(total_string, '\0', MAX_COMMAND_SIZE);
|
|
||||||
if (strcmp(cmd->buffer, "") == 0) {
|
|
||||||
sprintf(total_string, "%s%s", PROMPT_HEADER, cmd->command);
|
|
||||||
} else {
|
|
||||||
sprintf(total_string, "%s%s", CONTINUE_PROMPT, cmd->command);
|
|
||||||
}
|
|
||||||
|
|
||||||
int remain_column = w.ws_col;
|
|
||||||
/* size = cmd->commandSize + prompt_size; */
|
|
||||||
for (char *str = total_string; size < cmd->commandSize + prompt_size;) {
|
|
||||||
int ret = taosMbToWchar(&wc, str, MB_CUR_MAX);
|
|
||||||
if (ret < 0) break;
|
|
||||||
size += ret;
|
|
||||||
/* assert(size >= 0); */
|
|
||||||
int width = taosWcharWidth(wc);
|
|
||||||
if (remain_column > width) {
|
|
||||||
printf("%lc", wc);
|
|
||||||
remain_column -= width;
|
|
||||||
} else {
|
|
||||||
if (remain_column == width) {
|
|
||||||
printf("%lc\n\r", wc);
|
|
||||||
remain_column = w.ws_col;
|
|
||||||
} else {
|
|
||||||
printf("\n\r%lc", wc);
|
|
||||||
remain_column = w.ws_col - width;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
str = total_string + size;
|
|
||||||
}
|
|
||||||
|
|
||||||
taosMemoryFree(total_string);
|
|
||||||
/* for (int i = 0; i < size; i++){ */
|
|
||||||
/* char c = total_string[i]; */
|
|
||||||
/* if (k % w.ws_col == 0) { */
|
|
||||||
/* printf("%c\n\r", c); */
|
|
||||||
/* } */
|
|
||||||
/* else { */
|
|
||||||
/* printf("%c", c); */
|
|
||||||
/* } */
|
|
||||||
/* k += 1; */
|
|
||||||
/* } */
|
|
||||||
|
|
||||||
// Position the cursor
|
|
||||||
int cursor_pos = cmd->screenOffset + prompt_size;
|
|
||||||
int ecmd_pos = cmd->endOffset + prompt_size;
|
|
||||||
|
|
||||||
int cursor_x = cursor_pos / w.ws_col;
|
|
||||||
int cursor_y = cursor_pos % w.ws_col;
|
|
||||||
// int cursor_y = cursor % w.ws_col;
|
|
||||||
int command_x = ecmd_pos / w.ws_col;
|
|
||||||
int command_y = ecmd_pos % w.ws_col;
|
|
||||||
// int command_y = (command.size() + prompt_size) % w.ws_col;
|
|
||||||
positionCursor(command_y, LEFT);
|
|
||||||
positionCursor(command_x, UP);
|
|
||||||
positionCursor(cursor_x, DOWN);
|
|
||||||
positionCursor(cursor_y, RIGHT);
|
|
||||||
fflush(stdout);
|
|
||||||
}
|
|
||||||
|
|
||||||
void cleanup_handler(void *arg) { resetTerminalMode(); }
|
|
||||||
|
|
||||||
void exitShell() {
|
|
||||||
resetTerminalMode();
|
|
||||||
exit(EXIT_SUCCESS);
|
|
||||||
}
|
|
|
@ -1,279 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
|
|
||||||
*
|
|
||||||
* This program is free software: you can use, redistribute, and/or modify
|
|
||||||
* it under the terms of the GNU Affero General Public License, version 3
|
|
||||||
* or later ("AGPL"), as published by the Free Software Foundation.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Affero General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define _GNU_SOURCE
|
|
||||||
#define _XOPEN_SOURCE
|
|
||||||
#define _DEFAULT_SOURCE
|
|
||||||
|
|
||||||
#include "os.h"
|
|
||||||
#include "shell.h"
|
|
||||||
#include "shellCommand.h"
|
|
||||||
#include "tglobal.h"
|
|
||||||
#include "tutil.h"
|
|
||||||
|
|
||||||
static char **shellSQLFiles = NULL;
|
|
||||||
static int32_t shellSQLFileNum = 0;
|
|
||||||
static char shellTablesSQLFile[TSDB_FILENAME_LEN] = {0};
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
TdThread threadID;
|
|
||||||
int threadIndex;
|
|
||||||
int totalThreads;
|
|
||||||
void *taos;
|
|
||||||
} ShellThreadObj;
|
|
||||||
|
|
||||||
static int shellGetFilesNum(const char *directoryName, const char *prefix)
|
|
||||||
{
|
|
||||||
char cmd[1024] = { 0 };
|
|
||||||
sprintf(cmd, "ls %s/*.%s | wc -l ", directoryName, prefix);
|
|
||||||
|
|
||||||
char buf[1024] = { 0 };
|
|
||||||
if (taosSystem(cmd, buf, sizeof(buf)) < 0) {
|
|
||||||
fprintf(stderr, "ERROR: failed to execute:%s, error:%s\n", cmd, strerror(errno));
|
|
||||||
exit(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
int fileNum = 0;
|
|
||||||
if (sscanf(buf, "%d", &fileNum) != 1) {
|
|
||||||
fprintf(stderr, "ERROR: failed to execute:%s, parse result error\n", cmd);
|
|
||||||
exit(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fileNum <= 0) {
|
|
||||||
fprintf(stderr, "ERROR: directory:%s is empry\n", directoryName);
|
|
||||||
exit(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
return fileNum;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void shellParseDirectory(const char *directoryName, const char *prefix, char **fileArray, int totalFiles)
|
|
||||||
{
|
|
||||||
char cmd[1024] = { 0 };
|
|
||||||
sprintf(cmd, "ls %s/*.%s | sort", directoryName, prefix);
|
|
||||||
|
|
||||||
char buf[1024] = { 0 };
|
|
||||||
if (taosSystem(cmd, buf, sizeof(buf)) < 0) {
|
|
||||||
fprintf(stderr, "ERROR: failed to execute:%s, error:%s\n", cmd, strerror(errno));
|
|
||||||
exit(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
int fileNum = 0;
|
|
||||||
while (sscanf(buf, "%128s", fileArray[fileNum++])) {
|
|
||||||
if (strcmp(fileArray[fileNum-1], shellTablesSQLFile) == 0) {
|
|
||||||
fileNum--;
|
|
||||||
}
|
|
||||||
if (fileNum >= totalFiles) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fileNum != totalFiles) {
|
|
||||||
fprintf(stderr, "ERROR: directory:%s changed while read\n", directoryName);
|
|
||||||
exit(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void shellCheckTablesSQLFile(const char *directoryName)
|
|
||||||
{
|
|
||||||
sprintf(shellTablesSQLFile, "%s/tables.sql", directoryName);
|
|
||||||
|
|
||||||
if (taosFStatFile(shellTablesSQLFile, NULL, NULL) < 0) {
|
|
||||||
shellTablesSQLFile[0] = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void shellMallocSQLFiles()
|
|
||||||
{
|
|
||||||
shellSQLFiles = (char**)taosMemoryCalloc(shellSQLFileNum, sizeof(char*));
|
|
||||||
for (int i = 0; i < shellSQLFileNum; i++) {
|
|
||||||
shellSQLFiles[i] = taosMemoryCalloc(1, TSDB_FILENAME_LEN);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void shellGetDirectoryFileList(char *inputDir)
|
|
||||||
{
|
|
||||||
if (!taosDirExist(inputDir)) {
|
|
||||||
fprintf(stderr, "ERROR: %s not exist\n", inputDir);
|
|
||||||
exit(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (taosIsDir(inputDir)) {
|
|
||||||
shellCheckTablesSQLFile(inputDir);
|
|
||||||
shellSQLFileNum = shellGetFilesNum(inputDir, "sql");
|
|
||||||
int totalSQLFileNum = shellSQLFileNum;
|
|
||||||
if (shellTablesSQLFile[0] != 0) {
|
|
||||||
shellSQLFileNum--;
|
|
||||||
}
|
|
||||||
shellMallocSQLFiles();
|
|
||||||
shellParseDirectory(inputDir, "sql", shellSQLFiles, shellSQLFileNum);
|
|
||||||
fprintf(stdout, "\nstart to dispose %d files in %s\n", totalSQLFileNum, inputDir);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
fprintf(stderr, "ERROR: %s is not a directory\n", inputDir);
|
|
||||||
exit(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void shellSourceFile(TAOS *con, char *fptr) {
|
|
||||||
wordexp_t full_path;
|
|
||||||
int read_len = 0;
|
|
||||||
char * cmd = taosMemoryMalloc(tsMaxSQLStringLen);
|
|
||||||
size_t cmd_len = 0;
|
|
||||||
char * line = NULL;
|
|
||||||
|
|
||||||
if (wordexp(fptr, &full_path, 0) != 0) {
|
|
||||||
fprintf(stderr, "ERROR: illegal file name\n");
|
|
||||||
taosMemoryFree(cmd);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
char *fname = full_path.we_wordv[0];
|
|
||||||
if (fname == NULL) {
|
|
||||||
fprintf(stderr, "ERROR: invalid filename\n");
|
|
||||||
taosMemoryFree(cmd);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
if (access(fname, F_OK) != 0) {
|
|
||||||
fprintf(stderr, "ERROR: file %s is not exist\n", fptr);
|
|
||||||
|
|
||||||
wordfree(&full_path);
|
|
||||||
taosMemoryFree(cmd);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (access(fname, R_OK) != 0) {
|
|
||||||
fprintf(stderr, "ERROR: file %s is not readable\n", fptr);
|
|
||||||
|
|
||||||
wordfree(&full_path);
|
|
||||||
taosMemoryFree(cmd);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
// FILE *f = fopen(fname, "r");
|
|
||||||
TdFilePtr pFile = taosOpenFile(fname, TD_FILE_READ | TD_FILE_STREAM);
|
|
||||||
if (pFile == NULL) {
|
|
||||||
fprintf(stderr, "ERROR: failed to open file %s\n", fname);
|
|
||||||
wordfree(&full_path);
|
|
||||||
taosMemoryFree(cmd);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
fprintf(stdout, "begin import file:%s\n", fname);
|
|
||||||
|
|
||||||
int lineNo = 0;
|
|
||||||
while ((read_len = taosGetLineFile(pFile, &line)) != -1) {
|
|
||||||
++lineNo;
|
|
||||||
if (read_len >= tsMaxSQLStringLen) continue;
|
|
||||||
line[--read_len] = '\0';
|
|
||||||
|
|
||||||
if (read_len == 0 || isCommentLine(line)) { // line starts with #
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (line[read_len - 1] == '\\') {
|
|
||||||
line[read_len - 1] = ' ';
|
|
||||||
memcpy(cmd + cmd_len, line, read_len);
|
|
||||||
cmd_len += read_len;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
memcpy(cmd + cmd_len, line, read_len);
|
|
||||||
|
|
||||||
TAOS_RES* pSql = taos_query(con, cmd);
|
|
||||||
int32_t code = taos_errno(pSql);
|
|
||||||
|
|
||||||
if (code != 0) {
|
|
||||||
fprintf(stderr, "DB error: %s: %s (%d)\n", taos_errstr(pSql), fname, lineNo);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* free local resouce: allocated memory/metric-meta refcnt */
|
|
||||||
taos_free_result(pSql);
|
|
||||||
|
|
||||||
memset(cmd, 0, MAX_COMMAND_SIZE);
|
|
||||||
cmd_len = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
taosMemoryFree(cmd);
|
|
||||||
if(line != NULL) taosMemoryFree(line);
|
|
||||||
wordfree(&full_path);
|
|
||||||
taosCloseFile(&pFile);
|
|
||||||
}
|
|
||||||
|
|
||||||
void* shellImportThreadFp(void *arg)
|
|
||||||
{
|
|
||||||
ShellThreadObj *pThread = (ShellThreadObj*)arg;
|
|
||||||
setThreadName("shellImportThrd");
|
|
||||||
|
|
||||||
for (int f = 0; f < shellSQLFileNum; ++f) {
|
|
||||||
if (f % pThread->totalThreads == pThread->threadIndex) {
|
|
||||||
char *SQLFileName = shellSQLFiles[f];
|
|
||||||
shellSourceFile(pThread->taos, SQLFileName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void shellRunImportThreads(SShellArguments* _args)
|
|
||||||
{
|
|
||||||
TdThreadAttr thattr;
|
|
||||||
ShellThreadObj *threadObj = (ShellThreadObj *)taosMemoryCalloc(_args->threadNum, sizeof(ShellThreadObj));
|
|
||||||
for (int t = 0; t < _args->threadNum; ++t) {
|
|
||||||
ShellThreadObj *pThread = threadObj + t;
|
|
||||||
pThread->threadIndex = t;
|
|
||||||
pThread->totalThreads = _args->threadNum;
|
|
||||||
pThread->taos = taos_connect(_args->host, _args->user, _args->password, _args->database, tsDnodeShellPort);
|
|
||||||
if (pThread->taos == NULL) {
|
|
||||||
fprintf(stderr, "ERROR: thread:%d failed connect to TDengine, error:%s\n", pThread->threadIndex, "null taos"/*taos_errstr(pThread->taos)*/);
|
|
||||||
exit(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
taosThreadAttrInit(&thattr);
|
|
||||||
taosThreadAttrSetDetachState(&thattr, PTHREAD_CREATE_JOINABLE);
|
|
||||||
|
|
||||||
if (taosThreadCreate(&(pThread->threadID), &thattr, shellImportThreadFp, (void*)pThread) != 0) {
|
|
||||||
fprintf(stderr, "ERROR: thread:%d failed to start\n", pThread->threadIndex);
|
|
||||||
exit(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int t = 0; t < _args->threadNum; ++t) {
|
|
||||||
taosThreadJoin(threadObj[t].threadID, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int t = 0; t < _args->threadNum; ++t) {
|
|
||||||
taos_close(threadObj[t].taos);
|
|
||||||
}
|
|
||||||
taosMemoryFree(threadObj);
|
|
||||||
}
|
|
||||||
|
|
||||||
void source_dir(TAOS* con, SShellArguments* _args) {
|
|
||||||
shellGetDirectoryFileList(_args->dir);
|
|
||||||
int64_t start = taosGetTimestampMs();
|
|
||||||
|
|
||||||
if (shellTablesSQLFile[0] != 0) {
|
|
||||||
shellSourceFile(con, shellTablesSQLFile);
|
|
||||||
int64_t end = taosGetTimestampMs();
|
|
||||||
fprintf(stdout, "import %s finished, time spent %.2f seconds\n", shellTablesSQLFile, (end - start) / 1000.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
shellRunImportThreads(_args);
|
|
||||||
int64_t end = taosGetTimestampMs();
|
|
||||||
fprintf(stdout, "import %s finished, time spent %.2f seconds\n", _args->dir, (end - start) / 1000.0);
|
|
||||||
}
|
|
|
@ -1,325 +0,0 @@
|
||||||
/*******************************************************************
|
|
||||||
* Copyright (c) 2017 by TAOS Technologies, Inc.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* This file is proprietary and confidential to TAOS Technologies.
|
|
||||||
* No part of this file may be reproduced, stored, transmitted,
|
|
||||||
* disclosed or used in any form or by any means other than as
|
|
||||||
* expressly provided by the written permission from Jianhui Tao
|
|
||||||
*
|
|
||||||
* ****************************************************************/
|
|
||||||
|
|
||||||
#include <assert.h>
|
|
||||||
#include <regex.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include "../../../../include/client/taos.h"
|
|
||||||
#include "os.h"
|
|
||||||
#include "shell.h"
|
|
||||||
#include "shellCommand.h"
|
|
||||||
|
|
||||||
extern char configDir[];
|
|
||||||
|
|
||||||
char WINCLIENT_VERSION[] = "Welcome to the TDengine shell from %s, Client Version:%s\n"
|
|
||||||
"Copyright (c) 2020 by TAOS Data, Inc. All rights reserved.\n\n";
|
|
||||||
|
|
||||||
void printVersion() {
|
|
||||||
printf("version: %s\n", version);
|
|
||||||
}
|
|
||||||
|
|
||||||
void printHelp() {
|
|
||||||
char indent[10] = " ";
|
|
||||||
printf("taos shell is used to test the TDengine database\n");
|
|
||||||
|
|
||||||
printf("%s%s\n", indent, "-h");
|
|
||||||
printf("%s%s%s\n", indent, indent, "TDengine server FQDN to connect. The default host is localhost.");
|
|
||||||
printf("%s%s\n", indent, "-p");
|
|
||||||
printf("%s%s%s\n", indent, indent, "The password to use when connecting to the server.");
|
|
||||||
printf("%s%s\n", indent, "-P");
|
|
||||||
printf("%s%s%s\n", indent, indent, "The TCP/IP port number to use for the connection");
|
|
||||||
printf("%s%s\n", indent, "-u");
|
|
||||||
printf("%s%s%s\n", indent, indent, "The user name to use when connecting to the server.");
|
|
||||||
printf("%s%s\n", indent, "-A");
|
|
||||||
printf("%s%s%s\n", indent, indent, "The user auth to use when connecting to the server.");
|
|
||||||
printf("%s%s\n", indent, "-c");
|
|
||||||
printf("%s%s%s\n", indent, indent, "Configuration directory.");
|
|
||||||
printf("%s%s\n", indent, "-C");
|
|
||||||
printf("%s%s%s\n", indent, indent, "Dump configuration.");
|
|
||||||
printf("%s%s\n", indent, "-s");
|
|
||||||
printf("%s%s%s\n", indent, indent, "Commands to run without enter the shell.");
|
|
||||||
printf("%s%s\n", indent, "-r");
|
|
||||||
printf("%s%s%s\n", indent, indent, "Output time as unsigned long..");
|
|
||||||
printf("%s%s\n", indent, "-f");
|
|
||||||
printf("%s%s%s\n", indent, indent, "Script to run without enter the shell.");
|
|
||||||
printf("%s%s\n", indent, "-d");
|
|
||||||
printf("%s%s%s\n", indent, indent, "Database to use when connecting to the server.");
|
|
||||||
printf("%s%s\n", indent, "-t");
|
|
||||||
printf("%s%s%s\n", indent, indent, "Time zone of the shell, default is local.");
|
|
||||||
printf("%s%s\n", indent, "-n");
|
|
||||||
printf("%s%s%s\n", indent, indent, "Net role when network connectivity test, default is startup, options: client|server|rpc|startup|sync|speed|fqdn.");
|
|
||||||
printf("%s%s\n", indent, "-l");
|
|
||||||
printf("%s%s%s\n", indent, indent, "Packet length used for net test, default is 1000 bytes.");
|
|
||||||
printf("%s%s\n", indent, "-N");
|
|
||||||
printf("%s%s%s\n", indent, indent, "Packet numbers used for net test, default is 100.");
|
|
||||||
printf("%s%s\n", indent, "-S");
|
|
||||||
printf("%s%s%s\n", indent, indent, "Packet type used for net test, default is TCP.");
|
|
||||||
printf("%s%s\n", indent, "-V");
|
|
||||||
printf("%s%s%s\n", indent, indent, "Print program version.");
|
|
||||||
|
|
||||||
exit(EXIT_SUCCESS);
|
|
||||||
}
|
|
||||||
|
|
||||||
char g_password[SHELL_MAX_PASSWORD_LEN];
|
|
||||||
|
|
||||||
void shellParseArgument(int argc, char *argv[], SShellArguments *arguments) {
|
|
||||||
for (int i = 1; i < argc; i++) {
|
|
||||||
// for host
|
|
||||||
if (strcmp(argv[i], "-h") == 0) {
|
|
||||||
if (i < argc - 1) {
|
|
||||||
arguments->host = argv[++i];
|
|
||||||
} else {
|
|
||||||
fprintf(stderr, "option -h requires an argument\n");
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// for password
|
|
||||||
else if ((strncmp(argv[i], "-p", 2) == 0)
|
|
||||||
|| (strncmp(argv[i], "--password", 10) == 0)) {
|
|
||||||
arguments->is_use_passwd = true;
|
|
||||||
strcpy(tsOsName, "Windows");
|
|
||||||
printf(WINCLIENT_VERSION, tsOsName, taos_get_client_info());
|
|
||||||
if ((strlen(argv[i]) == 2)
|
|
||||||
|| (strncmp(argv[i], "--password", 10) == 0)) {
|
|
||||||
printf("Enter password: ");
|
|
||||||
taosSetConsoleEcho(false);
|
|
||||||
if (scanf("%s", g_password) > 1) {
|
|
||||||
fprintf(stderr, "password read error!\n");
|
|
||||||
}
|
|
||||||
taosSetConsoleEcho(true);
|
|
||||||
getchar();
|
|
||||||
} else {
|
|
||||||
tstrncpy(g_password, (char *)(argv[i] + 2), SHELL_MAX_PASSWORD_LEN);
|
|
||||||
}
|
|
||||||
arguments->password = g_password;
|
|
||||||
strcpy(argv[i], "");
|
|
||||||
argc -= 1;
|
|
||||||
}
|
|
||||||
// for management port
|
|
||||||
else if (strcmp(argv[i], "-P") == 0) {
|
|
||||||
if (i < argc - 1) {
|
|
||||||
arguments->port = atoi(argv[++i]);
|
|
||||||
} else {
|
|
||||||
fprintf(stderr, "option -P requires an argument\n");
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// for user
|
|
||||||
else if (strcmp(argv[i], "-u") == 0) {
|
|
||||||
if (i < argc - 1) {
|
|
||||||
arguments->user = argv[++i];
|
|
||||||
} else {
|
|
||||||
fprintf(stderr, "option -u requires an argument\n");
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
} else if (strcmp(argv[i], "-A") == 0) {
|
|
||||||
if (i < argc - 1) {
|
|
||||||
arguments->auth = argv[++i];
|
|
||||||
} else {
|
|
||||||
fprintf(stderr, "option -A requires an argument\n");
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
} else if (strcmp(argv[i], "-c") == 0) {
|
|
||||||
if (i < argc - 1) {
|
|
||||||
char *tmp = argv[++i];
|
|
||||||
if (strlen(tmp) >= TSDB_FILENAME_LEN) {
|
|
||||||
fprintf(stderr, "config file path: %s overflow max len %d\n", tmp, TSDB_FILENAME_LEN - 1);
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
strcpy(configDir, tmp);
|
|
||||||
} else {
|
|
||||||
fprintf(stderr, "Option -c requires an argument\n");
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
} else if (strcmp(argv[i], "-C") == 0) {
|
|
||||||
arguments->dump_config = true;
|
|
||||||
} else if (strcmp(argv[i], "-s") == 0) {
|
|
||||||
if (i < argc - 1) {
|
|
||||||
arguments->commands = argv[++i];
|
|
||||||
} else {
|
|
||||||
fprintf(stderr, "option -s requires an argument\n");
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
} else if (strcmp(argv[i], "-r") == 0) {
|
|
||||||
arguments->is_raw_time = true;
|
|
||||||
}
|
|
||||||
// For temperory batch commands to run TODO
|
|
||||||
else if (strcmp(argv[i], "-f") == 0) {
|
|
||||||
if (i < argc - 1) {
|
|
||||||
strcpy(arguments->file, argv[++i]);
|
|
||||||
} else {
|
|
||||||
fprintf(stderr, "option -f requires an argument\n");
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// for default database
|
|
||||||
else if (strcmp(argv[i], "-d") == 0) {
|
|
||||||
if (i < argc - 1) {
|
|
||||||
arguments->database = argv[++i];
|
|
||||||
} else {
|
|
||||||
fprintf(stderr, "option -d requires an argument\n");
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// For time zone
|
|
||||||
else if (strcmp(argv[i], "-t") == 0) {
|
|
||||||
if (i < argc - 1) {
|
|
||||||
arguments->timezone = argv[++i];
|
|
||||||
} else {
|
|
||||||
fprintf(stderr, "option -t requires an argument\n");
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (strcmp(argv[i], "-n") == 0) {
|
|
||||||
if (i < argc - 1) {
|
|
||||||
arguments->netTestRole = argv[++i];
|
|
||||||
} else {
|
|
||||||
fprintf(stderr, "option -n requires an argument\n");
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (strcmp(argv[i], "-l") == 0) {
|
|
||||||
if (i < argc - 1) {
|
|
||||||
arguments->pktLen = atoi(argv[++i]);
|
|
||||||
} else {
|
|
||||||
fprintf(stderr, "option -l requires an argument\n");
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (strcmp(argv[i], "-N") == 0) {
|
|
||||||
if (i < argc - 1) {
|
|
||||||
arguments->pktNum = atoi(argv[++i]);
|
|
||||||
} else {
|
|
||||||
fprintf(stderr, "option -N requires an argument\n");
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (strcmp(argv[i], "-S") == 0) {
|
|
||||||
if (i < argc - 1) {
|
|
||||||
arguments->pktType = argv[++i];
|
|
||||||
} else {
|
|
||||||
fprintf(stderr, "option -S requires an argument\n");
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (strcmp(argv[i], "-V") == 0) {
|
|
||||||
printVersion();
|
|
||||||
exit(EXIT_SUCCESS);
|
|
||||||
}
|
|
||||||
// For temperory command TODO
|
|
||||||
else if (strcmp(argv[i], "--help") == 0) {
|
|
||||||
printHelp();
|
|
||||||
exit(EXIT_SUCCESS);
|
|
||||||
} else {
|
|
||||||
fprintf(stderr, "wrong options\n");
|
|
||||||
printHelp();
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void shellPrintContinuePrompt() { printf("%s", CONTINUE_PROMPT); }
|
|
||||||
|
|
||||||
void shellPrintPrompt() { printf("%s", PROMPT_HEADER); }
|
|
||||||
|
|
||||||
void updateBuffer(Command *cmd) {
|
|
||||||
if (regex_match(cmd->buffer, "(\\s+$)|(^$)", REG_EXTENDED)) strcat(cmd->command, " ");
|
|
||||||
strcat(cmd->buffer, cmd->command);
|
|
||||||
|
|
||||||
memset(cmd->command, 0, MAX_COMMAND_SIZE);
|
|
||||||
cmd->cursorOffset = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int isReadyGo(Command *cmd) {
|
|
||||||
char *total = taosMemoryMalloc(MAX_COMMAND_SIZE);
|
|
||||||
memset(total, 0, MAX_COMMAND_SIZE);
|
|
||||||
sprintf(total, "%s%s", cmd->buffer, cmd->command);
|
|
||||||
|
|
||||||
char *reg_str =
|
|
||||||
"(^.*;\\s*$)|(^\\s*$)|(^\\s*exit\\s*$)|(^\\s*q\\s*$)|(^\\s*quit\\s*$)|(^"
|
|
||||||
"\\s*clear\\s*$)";
|
|
||||||
if (regex_match(total, reg_str, REG_EXTENDED | REG_ICASE)) {
|
|
||||||
taosMemoryFree(total);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
taosMemoryFree(total);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void insertChar(Command *cmd, char c) {
|
|
||||||
// TODO: Check if the length enough.
|
|
||||||
if (cmd->cursorOffset >= MAX_COMMAND_SIZE) {
|
|
||||||
fprintf(stdout, "sql is larger than %d bytes", MAX_COMMAND_SIZE);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
cmd->command[cmd->cursorOffset++] = c;
|
|
||||||
}
|
|
||||||
|
|
||||||
int32_t shellReadCommand(TAOS *con, char command[]) {
|
|
||||||
Command cmd;
|
|
||||||
memset(&cmd, 0, sizeof(cmd));
|
|
||||||
cmd.buffer = (char *)taosMemoryCalloc(1, MAX_COMMAND_SIZE);
|
|
||||||
cmd.command = (char *)taosMemoryCalloc(1, MAX_COMMAND_SIZE);
|
|
||||||
|
|
||||||
// Read input.
|
|
||||||
char c;
|
|
||||||
while (1) {
|
|
||||||
c = getchar();
|
|
||||||
|
|
||||||
switch (c) {
|
|
||||||
case '\n':
|
|
||||||
case '\r':
|
|
||||||
if (isReadyGo(&cmd)) {
|
|
||||||
sprintf(command, "%s%s", cmd.buffer, cmd.command);
|
|
||||||
taosMemoryFree(cmd.buffer);
|
|
||||||
cmd.buffer = NULL;
|
|
||||||
taosMemoryFree(cmd.command);
|
|
||||||
cmd.command = NULL;
|
|
||||||
return 0;
|
|
||||||
} else {
|
|
||||||
shellPrintContinuePrompt();
|
|
||||||
updateBuffer(&cmd);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
insertChar(&cmd, c);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void *shellLoopQuery(void *arg) {
|
|
||||||
TAOS *con = (TAOS *)arg;
|
|
||||||
char *command = taosMemoryMalloc(MAX_COMMAND_SIZE);
|
|
||||||
if (command == NULL) return NULL;
|
|
||||||
|
|
||||||
int32_t err = 0;
|
|
||||||
|
|
||||||
do {
|
|
||||||
memset(command, 0, MAX_COMMAND_SIZE);
|
|
||||||
shellPrintPrompt();
|
|
||||||
|
|
||||||
// Read command from shell.
|
|
||||||
err = shellReadCommand(con, command);
|
|
||||||
if (err) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} while (shellRunCommand(con, command) == 0);
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
void get_history_path(char *history) { sprintf(history, "C:/TDengine/%s", HISTORY_FILE); }
|
|
||||||
|
|
||||||
void exitShell() { exit(EXIT_SUCCESS); }
|
|
|
@ -0,0 +1,354 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
|
||||||
|
*
|
||||||
|
* This program is free software: you can use, redistribute, and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License, version 3
|
||||||
|
* or later ("AGPL"), as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "shellInt.h"
|
||||||
|
|
||||||
|
#define SHELL_HOST "The auth string to use when connecting to the server."
|
||||||
|
#define SHELL_PORT "The TCP/IP port number to use for the connection."
|
||||||
|
#define SHELL_USER "The user name to use when connecting to the server."
|
||||||
|
#define SHELL_PASSWORD "The password to use when connecting to the server."
|
||||||
|
#define SHELL_AUTH "The auth string to use when connecting to the server."
|
||||||
|
#define SHELL_GEN_AUTH "Generate auth string from password."
|
||||||
|
#define SHELL_CFG_DIR "Configuration directory."
|
||||||
|
#define SHELL_DMP_CFG "Dump configuration."
|
||||||
|
#define SHELL_CMD "Commands to run without enter the shell."
|
||||||
|
#define SHELL_RAW_TIME "Output time as uint64_t."
|
||||||
|
#define SHELL_FILE "Script to run without enter the shell."
|
||||||
|
#define SHELL_DB "Database to use when connecting to the server."
|
||||||
|
#define SHELL_CHECK "Check the service status."
|
||||||
|
#define SHELL_STARTUP "Check the details of the service status."
|
||||||
|
#define SHELL_WIDTH "Set the default binary display width, default is 30."
|
||||||
|
#define SHELL_NET_ROLE "Net role when network connectivity test, options: client|server."
|
||||||
|
#define SHELL_PKG_LEN "Packet length used for net test, default is 1024 bytes."
|
||||||
|
#define SHELL_PKT_NUM "Packet numbers used for net test, default is 100."
|
||||||
|
#define SHELL_VERSION "Print program version."
|
||||||
|
#define SHELL_EMAIL "<support@taosdata.com>"
|
||||||
|
|
||||||
|
void shellPrintHelp() {
|
||||||
|
char indent[] = " ";
|
||||||
|
printf("Usage: taos [OPTION...] \n\n");
|
||||||
|
printf("%s%s%s%s\n", indent, "-a,", indent, SHELL_AUTH);
|
||||||
|
printf("%s%s%s%s\n", indent, "-A,", indent, SHELL_GEN_AUTH);
|
||||||
|
printf("%s%s%s%s\n", indent, "-c,", indent, SHELL_CFG_DIR);
|
||||||
|
printf("%s%s%s%s\n", indent, "-C,", indent, SHELL_DMP_CFG);
|
||||||
|
printf("%s%s%s%s\n", indent, "-d,", indent, SHELL_DB);
|
||||||
|
printf("%s%s%s%s\n", indent, "-f,", indent, SHELL_FILE);
|
||||||
|
printf("%s%s%s%s\n", indent, "-h,", indent, SHELL_HOST);
|
||||||
|
printf("%s%s%s%s\n", indent, "-k,", indent, SHELL_CHECK);
|
||||||
|
printf("%s%s%s%s\n", indent, "-l,", indent, SHELL_PKG_LEN);
|
||||||
|
printf("%s%s%s%s\n", indent, "-n,", indent, SHELL_NET_ROLE);
|
||||||
|
printf("%s%s%s%s\n", indent, "-N,", indent, SHELL_PKT_NUM);
|
||||||
|
printf("%s%s%s%s\n", indent, "-p,", indent, SHELL_PASSWORD);
|
||||||
|
printf("%s%s%s%s\n", indent, "-P,", indent, SHELL_PORT);
|
||||||
|
printf("%s%s%s%s\n", indent, "-r,", indent, SHELL_RAW_TIME);
|
||||||
|
printf("%s%s%s%s\n", indent, "-s,", indent, SHELL_CMD);
|
||||||
|
printf("%s%s%s%s\n", indent, "-t,", indent, SHELL_STARTUP);
|
||||||
|
printf("%s%s%s%s\n", indent, "-u,", indent, SHELL_USER);
|
||||||
|
printf("%s%s%s%s\n", indent, "-w,", indent, SHELL_WIDTH);
|
||||||
|
printf("%s%s%s%s\n", indent, "-V,", indent, SHELL_VERSION);
|
||||||
|
printf("\n\nReport bugs to %s.\n", SHELL_EMAIL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int32_t shellParseSingleOpt(int32_t key, char *arg) {
|
||||||
|
SShellArgs *pArgs = &shell.args;
|
||||||
|
|
||||||
|
switch (key) {
|
||||||
|
case 'h':
|
||||||
|
pArgs->host = arg;
|
||||||
|
break;
|
||||||
|
case 'P':
|
||||||
|
pArgs->port = atoi(arg);
|
||||||
|
break;
|
||||||
|
case 'u':
|
||||||
|
pArgs->user = arg;
|
||||||
|
break;
|
||||||
|
case 'p':
|
||||||
|
break;
|
||||||
|
case 'a':
|
||||||
|
pArgs->auth = arg;
|
||||||
|
break;
|
||||||
|
case 'A':
|
||||||
|
pArgs->is_gen_auth = true;
|
||||||
|
break;
|
||||||
|
case 'c':
|
||||||
|
pArgs->cfgdir = arg;
|
||||||
|
break;
|
||||||
|
case 'C':
|
||||||
|
pArgs->is_dump_config = true;
|
||||||
|
break;
|
||||||
|
case 's':
|
||||||
|
pArgs->commands = arg;
|
||||||
|
break;
|
||||||
|
case 'r':
|
||||||
|
pArgs->is_raw_time = true;
|
||||||
|
break;
|
||||||
|
case 'f':
|
||||||
|
tstrncpy(pArgs->file, arg, sizeof(pArgs->file));
|
||||||
|
break;
|
||||||
|
case 'd':
|
||||||
|
pArgs->database = arg;
|
||||||
|
break;
|
||||||
|
case 'k':
|
||||||
|
pArgs->is_check = true;
|
||||||
|
break;
|
||||||
|
case 't':
|
||||||
|
pArgs->is_startup = true;
|
||||||
|
break;
|
||||||
|
case 'w':
|
||||||
|
pArgs->displayWidth = atoi(arg);
|
||||||
|
break;
|
||||||
|
case 'n':
|
||||||
|
pArgs->netrole = arg;
|
||||||
|
break;
|
||||||
|
case 'l':
|
||||||
|
pArgs->pktLen = atoi(arg);
|
||||||
|
break;
|
||||||
|
case 'N':
|
||||||
|
pArgs->pktNum = atoi(arg);
|
||||||
|
break;
|
||||||
|
case 'V':
|
||||||
|
pArgs->is_version = true;
|
||||||
|
break;
|
||||||
|
case '?':
|
||||||
|
pArgs->is_help = true;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
pArgs->abort = 1;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return ARGP_ERR_UNKNOWN;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t shellParseArgsWithoutArgp(int argc, char *argv[]) {
|
||||||
|
SShellArgs *pArgs = &shell.args;
|
||||||
|
|
||||||
|
for (int i = 1; i < argc; i++) {
|
||||||
|
if (strcmp(argv[i], "--help") == 0 || strcmp(argv[i], "--usage") == 0 || strcmp(argv[i], "-?") == 0) {
|
||||||
|
shellParseSingleOpt('?', NULL);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *key = argv[i];
|
||||||
|
int32_t keyLen = strlen(key);
|
||||||
|
if (keyLen != 2) {
|
||||||
|
fprintf(stderr, "invalid option %s\n", key);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (key[0] != '-') {
|
||||||
|
fprintf(stderr, "invalid option %s\n", key);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (key[1] == 'h' || key[1] == 'P' || key[1] == 'u' || key[1] == 'a' || key[1] == 'c' || key[1] == 's' ||
|
||||||
|
key[1] == 'f' || key[1] == 'd' || key[1] == 'w' || key[1] == 'n' || key[1] == 'l' || key[1] == 'N') {
|
||||||
|
if (i + 1 >= argc) {
|
||||||
|
fprintf(stderr, "option %s requires an argument\n", key);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
char *val = argv[i + 1];
|
||||||
|
if (val[0] == '-') {
|
||||||
|
fprintf(stderr, "option %s requires an argument\n", key);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
shellParseSingleOpt(key[1], val);
|
||||||
|
i++;
|
||||||
|
} else if (key[1] == 'p' || key[1] == 'A' || key[1] == 'c' || key[1] == 'r' || key[1] == 'k' || key[1] == 't' ||
|
||||||
|
key[1] == 'V') {
|
||||||
|
shellParseSingleOpt(key[1], NULL);
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "invalid option %s\n", key);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef LINUX
|
||||||
|
#include <argp.h>
|
||||||
|
#include <termio.h>
|
||||||
|
|
||||||
|
const char *argp_program_version = version;
|
||||||
|
const char *argp_program_bug_address = SHELL_EMAIL;
|
||||||
|
|
||||||
|
static struct argp_option shellOptions[] = {
|
||||||
|
{"host", 'h', "HOST", 0, SHELL_HOST},
|
||||||
|
{"port", 'P', "PORT", 0, SHELL_PORT},
|
||||||
|
{"user", 'u', "USER", 0, SHELL_USER},
|
||||||
|
{0, 'p', 0, 0, SHELL_PASSWORD},
|
||||||
|
{"auth", 'a', "AUTH", 0, SHELL_AUTH},
|
||||||
|
{"generate-auth", 'A', 0, 0, SHELL_GEN_AUTH},
|
||||||
|
{"config-dir", 'c', "DIR", 0, SHELL_CFG_DIR},
|
||||||
|
{"dump-config", 'C', 0, 0, SHELL_DMP_CFG},
|
||||||
|
{"commands", 's', "COMMANDS", 0, SHELL_CMD},
|
||||||
|
{"raw-time", 'r', 0, 0, SHELL_RAW_TIME},
|
||||||
|
{"file", 'f', "FILE", 0, SHELL_FILE},
|
||||||
|
{"database", 'd', "DATABASE", 0, SHELL_DB},
|
||||||
|
{"check", 'k', 0, 0, SHELL_CHECK},
|
||||||
|
{"startup", 't', 0, 0, SHELL_STARTUP},
|
||||||
|
{"display-width", 'w', "WIDTH", 0, SHELL_WIDTH},
|
||||||
|
{"netrole", 'n', "NETROLE", 0, SHELL_NET_ROLE},
|
||||||
|
{"pktlen", 'l', "PKTLEN", 0, SHELL_PKG_LEN},
|
||||||
|
{"pktnum", 'N', "PKTNUM", 0, SHELL_PKT_NUM},
|
||||||
|
{0},
|
||||||
|
};
|
||||||
|
|
||||||
|
static error_t shellParseOpt(int32_t key, char *arg, struct argp_state *state) { return shellParseSingleOpt(key, arg); }
|
||||||
|
|
||||||
|
static struct argp shellArgp = {shellOptions, shellParseOpt, "", ""};
|
||||||
|
|
||||||
|
static void shellParseArgsUseArgp(int argc, char *argv[]) {
|
||||||
|
argp_program_version = shell.info.programVersion;
|
||||||
|
argp_parse(&shellArgp, argc, argv, 0, 0, &shell.args);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static void shellInitArgs(int argc, char *argv[]) {
|
||||||
|
for (int i = 1; i < argc; i++) {
|
||||||
|
if (strncmp(argv[i], "-p", 2) == 0) {
|
||||||
|
printf(shell.info.clientVersion, tsOsName, taos_get_client_info());
|
||||||
|
if (strlen(argv[i]) == 2) {
|
||||||
|
printf("Enter password: ");
|
||||||
|
taosSetConsoleEcho(false);
|
||||||
|
if (scanf("%20s", shell.args.password) > 1) {
|
||||||
|
fprintf(stderr, "password reading error\n");
|
||||||
|
}
|
||||||
|
taosSetConsoleEcho(true);
|
||||||
|
if (EOF == getchar()) {
|
||||||
|
fprintf(stderr, "getchar() return EOF\n");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
tstrncpy(shell.args.password, (char *)(argv[i] + 2), sizeof(shell.args.password));
|
||||||
|
strcpy(argv[i], "-p");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (strlen(shell.args.password) == 0) {
|
||||||
|
tstrncpy(shell.args.password, TSDB_DEFAULT_PASS, sizeof(shell.args.password));
|
||||||
|
}
|
||||||
|
|
||||||
|
SShellArgs *pArgs = &shell.args;
|
||||||
|
pArgs->user = TSDB_DEFAULT_USER;
|
||||||
|
pArgs->pktLen = SHELL_DEF_PKG_LEN;
|
||||||
|
pArgs->pktNum = SHELL_DEF_PKG_NUM;
|
||||||
|
pArgs->displayWidth = SHELL_DEFAULT_MAX_BINARY_DISPLAY_WIDTH;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int32_t shellCheckArgs() {
|
||||||
|
SShellArgs *pArgs = &shell.args;
|
||||||
|
if (pArgs->host != NULL && (strlen(pArgs->host) <= 0 || strlen(pArgs->host) > TSDB_FQDN_LEN)) {
|
||||||
|
printf("Invalid host:%s\n", pArgs->host);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pArgs->user != NULL && (strlen(pArgs->user) <= 0 || strlen(pArgs->user) > TSDB_USER_LEN)) {
|
||||||
|
printf("Invalid user:%s\n", pArgs->user);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pArgs->auth != NULL && (strlen(pArgs->auth) <= 0 || strlen(pArgs->auth) > TSDB_PASSWORD_LEN)) {
|
||||||
|
printf("Invalid auth:%s\n", pArgs->auth);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pArgs->database != NULL && (strlen(pArgs->database) <= 0 || strlen(pArgs->database) > TSDB_DB_NAME_LEN)) {
|
||||||
|
printf("Invalid database:%s\n", pArgs->database);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pArgs->file[0] != 0) {
|
||||||
|
char fullname[PATH_MAX] = {0};
|
||||||
|
if (taosExpandDir(pArgs->file, fullname, PATH_MAX) == 0) {
|
||||||
|
tstrncpy(pArgs->file, fullname, PATH_MAX);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pArgs->cfgdir != NULL) {
|
||||||
|
if (strlen(pArgs->cfgdir) <= 0 || strlen(pArgs->cfgdir) >= PATH_MAX) {
|
||||||
|
printf("Invalid cfgdir:%s\n", pArgs->cfgdir);
|
||||||
|
return -1;
|
||||||
|
} else {
|
||||||
|
if (taosExpandDir(pArgs->cfgdir, configDir, PATH_MAX) != 0) {
|
||||||
|
tstrncpy(configDir, pArgs->cfgdir, PATH_MAX);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pArgs->commands != NULL && (strlen(pArgs->commands) <= 0)) {
|
||||||
|
printf("Invalid commands:%s\n", pArgs->commands);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pArgs->netrole != NULL && !(strcmp(pArgs->netrole, "client") == 0 || strcmp(pArgs->netrole, "server") == 0)) {
|
||||||
|
printf("Invalid netrole:%s\n", pArgs->netrole);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pArgs->password != NULL && (strlen(pArgs->password) <= 0)) {
|
||||||
|
printf("Invalid password\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pArgs->pktLen < SHELL_MIN_PKG_LEN || pArgs->pktLen > SHELL_MAX_PKG_LEN) {
|
||||||
|
printf("Invalid pktLen:%d, range:[%d, %d]\n", pArgs->pktLen, SHELL_MIN_PKG_LEN, SHELL_MAX_PKG_LEN);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pArgs->pktNum < SHELL_MIN_PKG_NUM || pArgs->pktNum > SHELL_MAX_PKG_NUM) {
|
||||||
|
printf("Invalid pktNum:%d, range:[%d, %d]\n", pArgs->pktNum, SHELL_MIN_PKG_NUM, SHELL_MAX_PKG_NUM);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pArgs->displayWidth <= 0 || pArgs->displayWidth > 10 * 1024) {
|
||||||
|
printf("Invalid displayWidth:%d, range:[1, 10 * 1024]\n", pArgs->displayWidth);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t shellParseArgs(int32_t argc, char *argv[]) {
|
||||||
|
shellInitArgs(argc, argv);
|
||||||
|
shell.info.clientVersion =
|
||||||
|
"Welcome to the TDengine shell from %s, Client Version:%s\n"
|
||||||
|
"Copyright (c) 2020 by TAOS Data, Inc. All rights reserved.\n\n";
|
||||||
|
shell.info.promptHeader = "taos> ";
|
||||||
|
shell.info.promptContinue = " -> ";
|
||||||
|
shell.info.promptSize = 6;
|
||||||
|
snprintf(shell.info.programVersion, sizeof(shell.info.programVersion), "version: %s", version);
|
||||||
|
|
||||||
|
#if defined(_TD_WINDOWS_64) || defined(_TD_WINDOWS_32)
|
||||||
|
shell.info.osname = "Windows";
|
||||||
|
snprintf(shell.history.file, TSDB_FILENAME_LEN, "C:/TDengine/%s", SHELL_HISTORY_FILE);
|
||||||
|
if (shellParseArgsWithoutArgp(argc, argv) != 0) return -1;
|
||||||
|
#elif defined(_TD_DARWIN_64)
|
||||||
|
shell.info.osname = "Darwin";
|
||||||
|
snprintf(shell.history.file, TSDB_FILENAME_LEN, "%s/%s", getpwuid(getuid())->pw_dir, SHELL_HISTORY_FILE);
|
||||||
|
if (shellParseArgsWithoutArgp(argc, argv) != 0) return -1;
|
||||||
|
#else
|
||||||
|
shell.info.osname = "Linux";
|
||||||
|
snprintf(shell.history.file, TSDB_FILENAME_LEN, "%s/%s", getenv("HOME"), SHELL_HISTORY_FILE);
|
||||||
|
shellParseArgsUseArgp(argc, argv);
|
||||||
|
// if (shellParseArgsWithoutArgp(argc, argv) != 0) return -1;
|
||||||
|
if (shell.args.abort) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return shellCheckArgs();
|
||||||
|
}
|
|
@ -14,22 +14,122 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define __USE_XOPEN
|
#define __USE_XOPEN
|
||||||
|
#include "shellInt.h"
|
||||||
|
|
||||||
#include "shellCommand.h"
|
#define LEFT 1
|
||||||
#include "os.h"
|
#define RIGHT 2
|
||||||
#include "shell.h"
|
#define UP 3
|
||||||
|
#define DOWN 4
|
||||||
#include <regex.h>
|
#define PSIZE shell.info.promptSize
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
char widthInString;
|
char *buffer;
|
||||||
char widthOnScreen;
|
char *command;
|
||||||
} UTFCodeInfo;
|
uint32_t commandSize;
|
||||||
|
uint32_t bufferSize;
|
||||||
|
uint32_t cursorOffset;
|
||||||
|
uint32_t screenOffset;
|
||||||
|
uint32_t endOffset;
|
||||||
|
} SShellCmd;
|
||||||
|
|
||||||
int countPrefixOnes(unsigned char c) {
|
static int32_t shellCountPrefixOnes(uint8_t c);
|
||||||
unsigned char mask = 127;
|
static void shellGetPrevCharSize(const char *str, int32_t pos, int32_t *size, int32_t *width);
|
||||||
|
static void shellGetNextCharSize(const char *str, int32_t pos, int32_t *size, int32_t *width);
|
||||||
|
static void shellInsertChar(SShellCmd *cmd, char *c, int size);
|
||||||
|
static void shellBackspaceChar(SShellCmd *cmd);
|
||||||
|
static void shellClearLineBefore(SShellCmd *cmd);
|
||||||
|
static void shellClearLineAfter(SShellCmd *cmd);
|
||||||
|
static void shellDeleteChar(SShellCmd *cmd);
|
||||||
|
static void shellMoveCursorLeft(SShellCmd *cmd);
|
||||||
|
static void shellMoveCursorRight(SShellCmd *cmd);
|
||||||
|
static void shellPositionCursorHome(SShellCmd *cmd);
|
||||||
|
static void shellPositionCursorEnd(SShellCmd *cmd);
|
||||||
|
static void shellPrintChar(char c, int32_t times);
|
||||||
|
static void shellPositionCursor(int32_t step, int32_t direction);
|
||||||
|
static void shellUpdateBuffer(SShellCmd *cmd);
|
||||||
|
static int32_t shellIsReadyGo(SShellCmd *cmd);
|
||||||
|
static void shellGetMbSizeInfo(const char *str, int32_t *size, int32_t *width);
|
||||||
|
static void shellResetCommand(SShellCmd *cmd, const char s[]);
|
||||||
|
static void shellClearScreen(int32_t ecmd_pos, int32_t cursor_pos);
|
||||||
|
static void shellShowOnScreen(SShellCmd *cmd);
|
||||||
|
|
||||||
|
#if defined(_TD_WINDOWS_64) || defined(_TD_WINDOWS_32)
|
||||||
|
static void shellPrintContinuePrompt() { printf("%s", shell.args.promptContinue); }
|
||||||
|
static void shellPrintPrompt() { printf("%s", shell.args.promptHeader); }
|
||||||
|
|
||||||
|
void shellUpdateBuffer(SShellCmd *cmd) {
|
||||||
|
if (shellRegexMatch(cmd->buffer, "(\\s+$)|(^$)", REG_EXTENDED)) strcat(cmd->command, " ");
|
||||||
|
strcat(cmd->buffer, cmd->command);
|
||||||
|
|
||||||
|
memset(cmd->command, 0, SHELL_MAX_COMMAND_SIZE);
|
||||||
|
cmd->cursorOffset = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int shellIsReadyGo(SShellCmd *cmd) {
|
||||||
|
char *total = taosMemoryMalloc(SHELL_MAX_COMMAND_SIZE);
|
||||||
|
memset(total, 0, SHELL_MAX_COMMAND_SIZE);
|
||||||
|
sprintf(total, "%s%s", cmd->buffer, cmd->command);
|
||||||
|
|
||||||
|
char *reg_str =
|
||||||
|
"(^.*;\\s*$)|(^\\s*$)|(^\\s*exit\\s*$)|(^\\s*q\\s*$)|(^\\s*quit\\s*$)|(^"
|
||||||
|
"\\s*clear\\s*$)";
|
||||||
|
if (shellRegexMatch(total, reg_str, REG_EXTENDED | REG_ICASE)) {
|
||||||
|
taosMemoryFree(total);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
taosMemoryFree(total);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void shellInsertChar(SShellCmd *cmd, char c) {
|
||||||
|
if (cmd->cursorOffset >= SHELL_MAX_COMMAND_SIZE) {
|
||||||
|
fprintf(stdout, "sql is larger than %d bytes", SHELL_MAX_COMMAND_SIZE);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
cmd->command[cmd->cursorOffset++] = c;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t shellReadCommand(char command[]) {
|
||||||
|
SShellCmd cmd;
|
||||||
|
memset(&cmd, 0, sizeof(cmd));
|
||||||
|
cmd.buffer = (char *)taosMemoryCalloc(1, SHELL_MAX_COMMAND_SIZE);
|
||||||
|
cmd.command = (char *)taosMemoryCalloc(1, SHELL_MAX_COMMAND_SIZE);
|
||||||
|
|
||||||
|
// Read input.
|
||||||
|
char c;
|
||||||
|
while (1) {
|
||||||
|
c = getchar();
|
||||||
|
|
||||||
|
switch (c) {
|
||||||
|
case '\n':
|
||||||
|
case '\r':
|
||||||
|
if (shellIsReadyGo(&cmd)) {
|
||||||
|
sprintf(command, "%s%s", cmd.buffer, cmd.command);
|
||||||
|
taosMemoryFree(cmd.buffer);
|
||||||
|
cmd.buffer = NULL;
|
||||||
|
taosMemoryFree(cmd.command);
|
||||||
|
cmd.command = NULL;
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
shellPrintContinuePrompt();
|
||||||
|
shellUpdateBuffer(&cmd);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
shellInsertChar(&cmd, c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
int32_t shellCountPrefixOnes(uint8_t c) {
|
||||||
|
uint8_t mask = 127;
|
||||||
mask = ~mask;
|
mask = ~mask;
|
||||||
int ret = 0;
|
int32_t ret = 0;
|
||||||
while ((c & mask) != 0) {
|
while ((c & mask) != 0) {
|
||||||
ret++;
|
ret++;
|
||||||
c <<= 1;
|
c <<= 1;
|
||||||
|
@ -38,7 +138,7 @@ int countPrefixOnes(unsigned char c) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
void getPrevCharSize(const char *str, int pos, int *size, int *width) {
|
void shellGetPrevCharSize(const char *str, int32_t pos, int32_t *size, int32_t *width) {
|
||||||
assert(pos > 0);
|
assert(pos > 0);
|
||||||
|
|
||||||
TdWchar wc;
|
TdWchar wc;
|
||||||
|
@ -48,16 +148,16 @@ void getPrevCharSize(const char *str, int pos, int *size, int *width) {
|
||||||
while (--pos >= 0) {
|
while (--pos >= 0) {
|
||||||
*size += 1;
|
*size += 1;
|
||||||
|
|
||||||
if (str[pos] > 0 || countPrefixOnes((unsigned char)str[pos]) > 1) break;
|
if (str[pos] > 0 || shellCountPrefixOnes((uint8_t)str[pos]) > 1) break;
|
||||||
}
|
}
|
||||||
|
|
||||||
int rc = taosMbToWchar(&wc, str + pos, MB_CUR_MAX);
|
int32_t rc = taosMbToWchar(&wc, str + pos, MB_CUR_MAX);
|
||||||
assert(rc == *size);
|
assert(rc == *size);
|
||||||
|
|
||||||
*width = taosWcharWidth(wc);
|
*width = taosWcharWidth(wc);
|
||||||
}
|
}
|
||||||
|
|
||||||
void getNextCharSize(const char *str, int pos, int *size, int *width) {
|
void shellGetNextCharSize(const char *str, int32_t pos, int32_t *size, int32_t *width) {
|
||||||
assert(pos >= 0);
|
assert(pos >= 0);
|
||||||
|
|
||||||
TdWchar wc;
|
TdWchar wc;
|
||||||
|
@ -65,13 +165,13 @@ void getNextCharSize(const char *str, int pos, int *size, int *width) {
|
||||||
*width = taosWcharWidth(wc);
|
*width = taosWcharWidth(wc);
|
||||||
}
|
}
|
||||||
|
|
||||||
void insertChar(Command *cmd, char *c, int size) {
|
void shellInsertChar(SShellCmd *cmd, char *c, int32_t size) {
|
||||||
assert(cmd->cursorOffset <= cmd->commandSize && cmd->endOffset >= cmd->screenOffset);
|
assert(cmd->cursorOffset <= cmd->commandSize && cmd->endOffset >= cmd->screenOffset);
|
||||||
|
|
||||||
TdWchar wc;
|
TdWchar wc;
|
||||||
if (taosMbToWchar(&wc, c, size) < 0) return;
|
if (taosMbToWchar(&wc, c, size) < 0) return;
|
||||||
|
|
||||||
clearScreen(cmd->endOffset + prompt_size, cmd->screenOffset + prompt_size);
|
shellClearScreen(cmd->endOffset + PSIZE, cmd->screenOffset + PSIZE);
|
||||||
/* update the buffer */
|
/* update the buffer */
|
||||||
memmove(cmd->command + cmd->cursorOffset + size, cmd->command + cmd->cursorOffset,
|
memmove(cmd->command + cmd->cursorOffset + size, cmd->command + cmd->cursorOffset,
|
||||||
cmd->commandSize - cmd->cursorOffset);
|
cmd->commandSize - cmd->cursorOffset);
|
||||||
|
@ -81,122 +181,122 @@ void insertChar(Command *cmd, char *c, int size) {
|
||||||
cmd->cursorOffset += size;
|
cmd->cursorOffset += size;
|
||||||
cmd->screenOffset += taosWcharWidth(wc);
|
cmd->screenOffset += taosWcharWidth(wc);
|
||||||
cmd->endOffset += taosWcharWidth(wc);
|
cmd->endOffset += taosWcharWidth(wc);
|
||||||
showOnScreen(cmd);
|
shellShowOnScreen(cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
void backspaceChar(Command *cmd) {
|
void shellBackspaceChar(SShellCmd *cmd) {
|
||||||
assert(cmd->cursorOffset <= cmd->commandSize && cmd->endOffset >= cmd->screenOffset);
|
assert(cmd->cursorOffset <= cmd->commandSize && cmd->endOffset >= cmd->screenOffset);
|
||||||
|
|
||||||
if (cmd->cursorOffset > 0) {
|
if (cmd->cursorOffset > 0) {
|
||||||
clearScreen(cmd->endOffset + prompt_size, cmd->screenOffset + prompt_size);
|
shellClearScreen(cmd->endOffset + PSIZE, cmd->screenOffset + PSIZE);
|
||||||
int size = 0;
|
int32_t size = 0;
|
||||||
int width = 0;
|
int32_t width = 0;
|
||||||
getPrevCharSize(cmd->command, cmd->cursorOffset, &size, &width);
|
shellGetPrevCharSize(cmd->command, cmd->cursorOffset, &size, &width);
|
||||||
memmove(cmd->command + cmd->cursorOffset - size, cmd->command + cmd->cursorOffset,
|
memmove(cmd->command + cmd->cursorOffset - size, cmd->command + cmd->cursorOffset,
|
||||||
cmd->commandSize - cmd->cursorOffset);
|
cmd->commandSize - cmd->cursorOffset);
|
||||||
cmd->commandSize -= size;
|
cmd->commandSize -= size;
|
||||||
cmd->cursorOffset -= size;
|
cmd->cursorOffset -= size;
|
||||||
cmd->screenOffset -= width;
|
cmd->screenOffset -= width;
|
||||||
cmd->endOffset -= width;
|
cmd->endOffset -= width;
|
||||||
showOnScreen(cmd);
|
shellShowOnScreen(cmd);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void clearLineBefore(Command *cmd) {
|
void shellClearLineBefore(SShellCmd *cmd) {
|
||||||
assert(cmd->cursorOffset <= cmd->commandSize && cmd->endOffset >= cmd->screenOffset);
|
assert(cmd->cursorOffset <= cmd->commandSize && cmd->endOffset >= cmd->screenOffset);
|
||||||
|
|
||||||
clearScreen(cmd->endOffset + prompt_size, cmd->screenOffset + prompt_size);
|
shellClearScreen(cmd->endOffset + PSIZE, cmd->screenOffset + PSIZE);
|
||||||
memmove(cmd->command, cmd->command + cmd->cursorOffset, cmd->commandSize - cmd->cursorOffset);
|
memmove(cmd->command, cmd->command + cmd->cursorOffset, cmd->commandSize - cmd->cursorOffset);
|
||||||
cmd->commandSize -= cmd->cursorOffset;
|
cmd->commandSize -= cmd->cursorOffset;
|
||||||
cmd->cursorOffset = 0;
|
cmd->cursorOffset = 0;
|
||||||
cmd->screenOffset = 0;
|
cmd->screenOffset = 0;
|
||||||
cmd->endOffset = cmd->commandSize;
|
cmd->endOffset = cmd->commandSize;
|
||||||
showOnScreen(cmd);
|
shellShowOnScreen(cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
void clearLineAfter(Command *cmd) {
|
void shellClearLineAfter(SShellCmd *cmd) {
|
||||||
assert(cmd->cursorOffset <= cmd->commandSize && cmd->endOffset >= cmd->screenOffset);
|
assert(cmd->cursorOffset <= cmd->commandSize && cmd->endOffset >= cmd->screenOffset);
|
||||||
|
|
||||||
clearScreen(cmd->endOffset + prompt_size, cmd->screenOffset + prompt_size);
|
shellClearScreen(cmd->endOffset + PSIZE, cmd->screenOffset + PSIZE);
|
||||||
cmd->commandSize -= cmd->endOffset - cmd->cursorOffset;
|
cmd->commandSize -= cmd->endOffset - cmd->cursorOffset;
|
||||||
cmd->endOffset = cmd->cursorOffset;
|
cmd->endOffset = cmd->cursorOffset;
|
||||||
showOnScreen(cmd);
|
shellShowOnScreen(cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
void deleteChar(Command *cmd) {
|
void shellDeleteChar(SShellCmd *cmd) {
|
||||||
assert(cmd->cursorOffset <= cmd->commandSize && cmd->endOffset >= cmd->screenOffset);
|
assert(cmd->cursorOffset <= cmd->commandSize && cmd->endOffset >= cmd->screenOffset);
|
||||||
|
|
||||||
if (cmd->cursorOffset < cmd->commandSize) {
|
if (cmd->cursorOffset < cmd->commandSize) {
|
||||||
clearScreen(cmd->endOffset + prompt_size, cmd->screenOffset + prompt_size);
|
shellClearScreen(cmd->endOffset + PSIZE, cmd->screenOffset + PSIZE);
|
||||||
int size = 0;
|
int32_t size = 0;
|
||||||
int width = 0;
|
int32_t width = 0;
|
||||||
getNextCharSize(cmd->command, cmd->cursorOffset, &size, &width);
|
shellGetNextCharSize(cmd->command, cmd->cursorOffset, &size, &width);
|
||||||
memmove(cmd->command + cmd->cursorOffset, cmd->command + cmd->cursorOffset + size,
|
memmove(cmd->command + cmd->cursorOffset, cmd->command + cmd->cursorOffset + size,
|
||||||
cmd->commandSize - cmd->cursorOffset - size);
|
cmd->commandSize - cmd->cursorOffset - size);
|
||||||
cmd->commandSize -= size;
|
cmd->commandSize -= size;
|
||||||
cmd->endOffset -= width;
|
cmd->endOffset -= width;
|
||||||
showOnScreen(cmd);
|
shellShowOnScreen(cmd);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void moveCursorLeft(Command *cmd) {
|
void shellMoveCursorLeft(SShellCmd *cmd) {
|
||||||
assert(cmd->cursorOffset <= cmd->commandSize && cmd->endOffset >= cmd->screenOffset);
|
assert(cmd->cursorOffset <= cmd->commandSize && cmd->endOffset >= cmd->screenOffset);
|
||||||
|
|
||||||
if (cmd->cursorOffset > 0) {
|
if (cmd->cursorOffset > 0) {
|
||||||
clearScreen(cmd->endOffset + prompt_size, cmd->screenOffset + prompt_size);
|
shellClearScreen(cmd->endOffset + PSIZE, cmd->screenOffset + PSIZE);
|
||||||
int size = 0;
|
int32_t size = 0;
|
||||||
int width = 0;
|
int32_t width = 0;
|
||||||
getPrevCharSize(cmd->command, cmd->cursorOffset, &size, &width);
|
shellGetPrevCharSize(cmd->command, cmd->cursorOffset, &size, &width);
|
||||||
cmd->cursorOffset -= size;
|
cmd->cursorOffset -= size;
|
||||||
cmd->screenOffset -= width;
|
cmd->screenOffset -= width;
|
||||||
showOnScreen(cmd);
|
shellShowOnScreen(cmd);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void moveCursorRight(Command *cmd) {
|
void shellMoveCursorRight(SShellCmd *cmd) {
|
||||||
assert(cmd->cursorOffset <= cmd->commandSize && cmd->endOffset >= cmd->screenOffset);
|
assert(cmd->cursorOffset <= cmd->commandSize && cmd->endOffset >= cmd->screenOffset);
|
||||||
|
|
||||||
if (cmd->cursorOffset < cmd->commandSize) {
|
if (cmd->cursorOffset < cmd->commandSize) {
|
||||||
clearScreen(cmd->endOffset + prompt_size, cmd->screenOffset + prompt_size);
|
shellClearScreen(cmd->endOffset + PSIZE, cmd->screenOffset + PSIZE);
|
||||||
int size = 0;
|
int32_t size = 0;
|
||||||
int width = 0;
|
int32_t width = 0;
|
||||||
getNextCharSize(cmd->command, cmd->cursorOffset, &size, &width);
|
shellGetNextCharSize(cmd->command, cmd->cursorOffset, &size, &width);
|
||||||
cmd->cursorOffset += size;
|
cmd->cursorOffset += size;
|
||||||
cmd->screenOffset += width;
|
cmd->screenOffset += width;
|
||||||
showOnScreen(cmd);
|
shellShowOnScreen(cmd);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void positionCursorHome(Command *cmd) {
|
void shellPositionCursorHome(SShellCmd *cmd) {
|
||||||
assert(cmd->cursorOffset <= cmd->commandSize && cmd->endOffset >= cmd->screenOffset);
|
assert(cmd->cursorOffset <= cmd->commandSize && cmd->endOffset >= cmd->screenOffset);
|
||||||
|
|
||||||
if (cmd->cursorOffset > 0) {
|
if (cmd->cursorOffset > 0) {
|
||||||
clearScreen(cmd->endOffset + prompt_size, cmd->screenOffset + prompt_size);
|
shellClearScreen(cmd->endOffset + PSIZE, cmd->screenOffset + PSIZE);
|
||||||
cmd->cursorOffset = 0;
|
cmd->cursorOffset = 0;
|
||||||
cmd->screenOffset = 0;
|
cmd->screenOffset = 0;
|
||||||
showOnScreen(cmd);
|
shellShowOnScreen(cmd);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void positionCursorEnd(Command *cmd) {
|
void shellPositionCursorEnd(SShellCmd *cmd) {
|
||||||
assert(cmd->cursorOffset <= cmd->commandSize && cmd->endOffset >= cmd->screenOffset);
|
assert(cmd->cursorOffset <= cmd->commandSize && cmd->endOffset >= cmd->screenOffset);
|
||||||
|
|
||||||
if (cmd->cursorOffset < cmd->commandSize) {
|
if (cmd->cursorOffset < cmd->commandSize) {
|
||||||
clearScreen(cmd->endOffset + prompt_size, cmd->screenOffset + prompt_size);
|
shellClearScreen(cmd->endOffset + PSIZE, cmd->screenOffset + PSIZE);
|
||||||
cmd->cursorOffset = cmd->commandSize;
|
cmd->cursorOffset = cmd->commandSize;
|
||||||
cmd->screenOffset = cmd->endOffset;
|
cmd->screenOffset = cmd->endOffset;
|
||||||
showOnScreen(cmd);
|
shellShowOnScreen(cmd);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void printChar(char c, int times) {
|
void shellPrintChar(char c, int32_t times) {
|
||||||
for (int i = 0; i < times; i++) {
|
for (int32_t i = 0; i < times; i++) {
|
||||||
fprintf(stdout, "%c", c);
|
fprintf(stdout, "%c", c);
|
||||||
}
|
}
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
}
|
}
|
||||||
|
|
||||||
void positionCursor(int step, int direction) {
|
void shellPositionCursor(int32_t step, int32_t direction) {
|
||||||
if (step > 0) {
|
if (step > 0) {
|
||||||
if (direction == LEFT) {
|
if (direction == LEFT) {
|
||||||
fprintf(stdout, "\033[%dD", step);
|
fprintf(stdout, "\033[%dD", step);
|
||||||
|
@ -211,32 +311,32 @@ void positionCursor(int step, int direction) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void updateBuffer(Command *cmd) {
|
void shellUpdateBuffer(SShellCmd *cmd) {
|
||||||
assert(cmd->cursorOffset <= cmd->commandSize && cmd->endOffset >= cmd->screenOffset);
|
assert(cmd->cursorOffset <= cmd->commandSize && cmd->endOffset >= cmd->screenOffset);
|
||||||
|
|
||||||
if (regex_match(cmd->buffer, "(\\s+$)|(^$)", REG_EXTENDED)) strcat(cmd->command, " ");
|
if (shellRegexMatch(cmd->buffer, "(\\s+$)|(^$)", REG_EXTENDED)) strcat(cmd->command, " ");
|
||||||
strcat(cmd->buffer, cmd->command);
|
strcat(cmd->buffer, cmd->command);
|
||||||
cmd->bufferSize += cmd->commandSize;
|
cmd->bufferSize += cmd->commandSize;
|
||||||
|
|
||||||
memset(cmd->command, 0, MAX_COMMAND_SIZE);
|
memset(cmd->command, 0, SHELL_MAX_COMMAND_SIZE);
|
||||||
cmd->cursorOffset = 0;
|
cmd->cursorOffset = 0;
|
||||||
cmd->screenOffset = 0;
|
cmd->screenOffset = 0;
|
||||||
cmd->commandSize = 0;
|
cmd->commandSize = 0;
|
||||||
cmd->endOffset = 0;
|
cmd->endOffset = 0;
|
||||||
showOnScreen(cmd);
|
shellShowOnScreen(cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
int isReadyGo(Command *cmd) {
|
int32_t shellIsReadyGo(SShellCmd *cmd) {
|
||||||
assert(cmd->cursorOffset <= cmd->commandSize && cmd->endOffset >= cmd->screenOffset);
|
assert(cmd->cursorOffset <= cmd->commandSize && cmd->endOffset >= cmd->screenOffset);
|
||||||
|
|
||||||
char *total = (char *)taosMemoryCalloc(1, MAX_COMMAND_SIZE);
|
char *total = (char *)taosMemoryCalloc(1, SHELL_MAX_COMMAND_SIZE);
|
||||||
memset(cmd->command + cmd->commandSize, 0, MAX_COMMAND_SIZE - cmd->commandSize);
|
memset(cmd->command + cmd->commandSize, 0, SHELL_MAX_COMMAND_SIZE - cmd->commandSize);
|
||||||
sprintf(total, "%s%s", cmd->buffer, cmd->command);
|
sprintf(total, "%s%s", cmd->buffer, cmd->command);
|
||||||
|
|
||||||
char *reg_str =
|
char *reg_str =
|
||||||
"(^.*;\\s*$)|(^\\s*$)|(^\\s*exit\\s*$)|(^\\s*q\\s*$)|(^\\s*quit\\s*$)|(^"
|
"(^.*;\\s*$)|(^\\s*$)|(^\\s*exit\\s*$)|(^\\s*q\\s*$)|(^\\s*quit\\s*$)|(^"
|
||||||
"\\s*clear\\s*$)";
|
"\\s*clear\\s*$)";
|
||||||
if (regex_match(total, reg_str, REG_EXTENDED | REG_ICASE)) {
|
if (shellRegexMatch(total, reg_str, REG_EXTENDED | REG_ICASE)) {
|
||||||
taosMemoryFree(total);
|
taosMemoryFree(total);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
@ -245,28 +345,268 @@ int isReadyGo(Command *cmd) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void getMbSizeInfo(const char *str, int *size, int *width) {
|
void shellGetMbSizeInfo(const char *str, int32_t *size, int32_t *width) {
|
||||||
TdWchar *wc = (TdWchar *)taosMemoryCalloc(sizeof(TdWchar), MAX_COMMAND_SIZE);
|
TdWchar *wc = (TdWchar *)taosMemoryCalloc(sizeof(TdWchar), SHELL_MAX_COMMAND_SIZE);
|
||||||
*size = strlen(str);
|
*size = strlen(str);
|
||||||
taosMbsToWchars(wc, str, MAX_COMMAND_SIZE);
|
taosMbsToWchars(wc, str, SHELL_MAX_COMMAND_SIZE);
|
||||||
*width = taosWcharsWidth(wc, MAX_COMMAND_SIZE);
|
*width = taosWcharsWidth(wc, SHELL_MAX_COMMAND_SIZE);
|
||||||
taosMemoryFree(wc);
|
taosMemoryFree(wc);
|
||||||
}
|
}
|
||||||
|
|
||||||
void resetCommand(Command *cmd, const char s[]) {
|
void shellResetCommand(SShellCmd *cmd, const char s[]) {
|
||||||
assert(cmd->cursorOffset <= cmd->commandSize && cmd->endOffset >= cmd->screenOffset);
|
assert(cmd->cursorOffset <= cmd->commandSize && cmd->endOffset >= cmd->screenOffset);
|
||||||
|
|
||||||
clearScreen(cmd->endOffset + prompt_size, cmd->screenOffset + prompt_size);
|
shellClearScreen(cmd->endOffset + PSIZE, cmd->screenOffset + PSIZE);
|
||||||
memset(cmd->buffer, 0, MAX_COMMAND_SIZE);
|
memset(cmd->buffer, 0, SHELL_MAX_COMMAND_SIZE);
|
||||||
memset(cmd->command, 0, MAX_COMMAND_SIZE);
|
memset(cmd->command, 0, SHELL_MAX_COMMAND_SIZE);
|
||||||
strncpy(cmd->command, s, MAX_COMMAND_SIZE);
|
strncpy(cmd->command, s, SHELL_MAX_COMMAND_SIZE);
|
||||||
int size = 0;
|
int32_t size = 0;
|
||||||
int width = 0;
|
int32_t width = 0;
|
||||||
getMbSizeInfo(s, &size, &width);
|
shellGetMbSizeInfo(s, &size, &width);
|
||||||
cmd->bufferSize = 0;
|
cmd->bufferSize = 0;
|
||||||
cmd->commandSize = size;
|
cmd->commandSize = size;
|
||||||
cmd->cursorOffset = size;
|
cmd->cursorOffset = size;
|
||||||
cmd->screenOffset = width;
|
cmd->screenOffset = width;
|
||||||
cmd->endOffset = width;
|
cmd->endOffset = width;
|
||||||
showOnScreen(cmd);
|
shellShowOnScreen(cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void shellClearScreen(int32_t ecmd_pos, int32_t cursor_pos) {
|
||||||
|
struct winsize w;
|
||||||
|
if (ioctl(0, TIOCGWINSZ, &w) < 0 || w.ws_col == 0 || w.ws_row == 0) {
|
||||||
|
// fprintf(stderr, "No stream device, and use default value(col 120, row 30)\n");
|
||||||
|
w.ws_col = 120;
|
||||||
|
w.ws_row = 30;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t cursor_x = cursor_pos / w.ws_col;
|
||||||
|
int32_t cursor_y = cursor_pos % w.ws_col;
|
||||||
|
int32_t command_x = ecmd_pos / w.ws_col;
|
||||||
|
shellPositionCursor(cursor_y, LEFT);
|
||||||
|
shellPositionCursor(command_x - cursor_x, DOWN);
|
||||||
|
fprintf(stdout, "\033[2K");
|
||||||
|
for (int32_t i = 0; i < command_x; i++) {
|
||||||
|
shellPositionCursor(1, UP);
|
||||||
|
fprintf(stdout, "\033[2K");
|
||||||
|
}
|
||||||
|
fflush(stdout);
|
||||||
|
}
|
||||||
|
|
||||||
|
void shellShowOnScreen(SShellCmd *cmd) {
|
||||||
|
struct winsize w;
|
||||||
|
if (ioctl(0, TIOCGWINSZ, &w) < 0 || w.ws_col == 0 || w.ws_row == 0) {
|
||||||
|
fprintf(stderr, "No stream device\n");
|
||||||
|
w.ws_col = 120;
|
||||||
|
w.ws_row = 30;
|
||||||
|
}
|
||||||
|
|
||||||
|
TdWchar wc;
|
||||||
|
int32_t size = 0;
|
||||||
|
|
||||||
|
// Print out the command.
|
||||||
|
char *total_string = taosMemoryMalloc(SHELL_MAX_COMMAND_SIZE);
|
||||||
|
memset(total_string, '\0', SHELL_MAX_COMMAND_SIZE);
|
||||||
|
if (strcmp(cmd->buffer, "") == 0) {
|
||||||
|
sprintf(total_string, "%s%s", shell.info.promptHeader, cmd->command);
|
||||||
|
} else {
|
||||||
|
sprintf(total_string, "%s%s", shell.info.promptContinue, cmd->command);
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t remain_column = w.ws_col;
|
||||||
|
for (char *str = total_string; size < cmd->commandSize + PSIZE;) {
|
||||||
|
int32_t ret = taosMbToWchar(&wc, str, MB_CUR_MAX);
|
||||||
|
if (ret < 0) break;
|
||||||
|
size += ret;
|
||||||
|
/* assert(size >= 0); */
|
||||||
|
int32_t width = taosWcharWidth(wc);
|
||||||
|
if (remain_column > width) {
|
||||||
|
printf("%lc", wc);
|
||||||
|
remain_column -= width;
|
||||||
|
} else {
|
||||||
|
if (remain_column == width) {
|
||||||
|
printf("%lc\n\r", wc);
|
||||||
|
remain_column = w.ws_col;
|
||||||
|
} else {
|
||||||
|
printf("\n\r%lc", wc);
|
||||||
|
remain_column = w.ws_col - width;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
str = total_string + size;
|
||||||
|
}
|
||||||
|
|
||||||
|
taosMemoryFree(total_string);
|
||||||
|
|
||||||
|
// Position the cursor
|
||||||
|
int32_t cursor_pos = cmd->screenOffset + PSIZE;
|
||||||
|
int32_t ecmd_pos = cmd->endOffset + PSIZE;
|
||||||
|
|
||||||
|
int32_t cursor_x = cursor_pos / w.ws_col;
|
||||||
|
int32_t cursor_y = cursor_pos % w.ws_col;
|
||||||
|
// int32_t cursor_y = cursor % w.ws_col;
|
||||||
|
int32_t command_x = ecmd_pos / w.ws_col;
|
||||||
|
int32_t command_y = ecmd_pos % w.ws_col;
|
||||||
|
// int32_t command_y = (command.size() + PSIZE) % w.ws_col;
|
||||||
|
shellPositionCursor(command_y, LEFT);
|
||||||
|
shellPositionCursor(command_x, UP);
|
||||||
|
shellPositionCursor(cursor_x, DOWN);
|
||||||
|
shellPositionCursor(cursor_y, RIGHT);
|
||||||
|
fflush(stdout);
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t shellReadCommand(char *command) {
|
||||||
|
SShellHistory *pHistory = &shell.history;
|
||||||
|
SShellCmd cmd = {0};
|
||||||
|
uint32_t hist_counter = pHistory->hend;
|
||||||
|
char utf8_array[10] = "\0";
|
||||||
|
|
||||||
|
cmd.buffer = (char *)taosMemoryCalloc(1, SHELL_MAX_COMMAND_SIZE);
|
||||||
|
cmd.command = (char *)taosMemoryCalloc(1, SHELL_MAX_COMMAND_SIZE);
|
||||||
|
shellShowOnScreen(&cmd);
|
||||||
|
|
||||||
|
// Read input.
|
||||||
|
char c;
|
||||||
|
while (1) {
|
||||||
|
c = (char)getchar(); // getchar() return an 'int32_t' value
|
||||||
|
|
||||||
|
if (c == EOF) {
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c < 0) { // For UTF-8
|
||||||
|
int32_t count = shellCountPrefixOnes(c);
|
||||||
|
utf8_array[0] = c;
|
||||||
|
for (int32_t k = 1; k < count; k++) {
|
||||||
|
c = (char)getchar();
|
||||||
|
utf8_array[k] = c;
|
||||||
|
}
|
||||||
|
shellInsertChar(&cmd, utf8_array, count);
|
||||||
|
} else if (c < '\033') {
|
||||||
|
// Ctrl keys. TODO: Implement ctrl combinations
|
||||||
|
switch (c) {
|
||||||
|
case 1: // ctrl A
|
||||||
|
shellPositionCursorHome(&cmd);
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
printf("\n");
|
||||||
|
shellResetCommand(&cmd, "");
|
||||||
|
kill(0, SIGINT);
|
||||||
|
break;
|
||||||
|
case 4: // EOF or Ctrl+D
|
||||||
|
printf("\n");
|
||||||
|
return -1;
|
||||||
|
case 5: // ctrl E
|
||||||
|
shellPositionCursorEnd(&cmd);
|
||||||
|
break;
|
||||||
|
case 8:
|
||||||
|
shellBackspaceChar(&cmd);
|
||||||
|
break;
|
||||||
|
case '\n':
|
||||||
|
case '\r':
|
||||||
|
printf("\n");
|
||||||
|
if (shellIsReadyGo(&cmd)) {
|
||||||
|
sprintf(command, "%s%s", cmd.buffer, cmd.command);
|
||||||
|
taosMemoryFreeClear(cmd.buffer);
|
||||||
|
taosMemoryFreeClear(cmd.command);
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
shellUpdateBuffer(&cmd);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 11: // Ctrl + K;
|
||||||
|
shellClearLineAfter(&cmd);
|
||||||
|
break;
|
||||||
|
case 12: // Ctrl + L;
|
||||||
|
system("clear");
|
||||||
|
shellShowOnScreen(&cmd);
|
||||||
|
break;
|
||||||
|
case 21: // Ctrl + U;
|
||||||
|
shellClearLineBefore(&cmd);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else if (c == '\033') {
|
||||||
|
c = (char)getchar();
|
||||||
|
switch (c) {
|
||||||
|
case '[':
|
||||||
|
c = (char)getchar();
|
||||||
|
switch (c) {
|
||||||
|
case 'A': // Up arrow
|
||||||
|
if (hist_counter != pHistory->hstart) {
|
||||||
|
hist_counter = (hist_counter + SHELL_MAX_HISTORY_SIZE - 1) % SHELL_MAX_HISTORY_SIZE;
|
||||||
|
shellResetCommand(&cmd, (pHistory->hist[hist_counter] == NULL) ? "" : pHistory->hist[hist_counter]);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'B': // Down arrow
|
||||||
|
if (hist_counter != pHistory->hend) {
|
||||||
|
int32_t next_hist = (hist_counter + 1) % SHELL_MAX_HISTORY_SIZE;
|
||||||
|
|
||||||
|
if (next_hist != pHistory->hend) {
|
||||||
|
shellResetCommand(&cmd, (pHistory->hist[next_hist] == NULL) ? "" : pHistory->hist[next_hist]);
|
||||||
|
} else {
|
||||||
|
shellResetCommand(&cmd, "");
|
||||||
|
}
|
||||||
|
hist_counter = next_hist;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'C': // Right arrow
|
||||||
|
shellMoveCursorRight(&cmd);
|
||||||
|
break;
|
||||||
|
case 'D': // Left arrow
|
||||||
|
shellMoveCursorLeft(&cmd);
|
||||||
|
break;
|
||||||
|
case '1':
|
||||||
|
if ((c = (char)getchar()) == '~') {
|
||||||
|
// Home key
|
||||||
|
shellPositionCursorHome(&cmd);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case '2':
|
||||||
|
if ((c = (char)getchar()) == '~') {
|
||||||
|
// Insert key
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case '3':
|
||||||
|
if ((c = (char)getchar()) == '~') {
|
||||||
|
// Delete key
|
||||||
|
shellDeleteChar(&cmd);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case '4':
|
||||||
|
if ((c = (char)getchar()) == '~') {
|
||||||
|
// End key
|
||||||
|
shellPositionCursorEnd(&cmd);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case '5':
|
||||||
|
if ((c = (char)getchar()) == '~') {
|
||||||
|
// Page up key
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case '6':
|
||||||
|
if ((c = (char)getchar()) == '~') {
|
||||||
|
// Page down key
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 72:
|
||||||
|
// Home key
|
||||||
|
shellPositionCursorHome(&cmd);
|
||||||
|
break;
|
||||||
|
case 70:
|
||||||
|
// End key
|
||||||
|
shellPositionCursorEnd(&cmd);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else if (c == 0x7f) {
|
||||||
|
// press delete key
|
||||||
|
shellBackspaceChar(&cmd);
|
||||||
|
} else {
|
||||||
|
shellInsertChar(&cmd, &c, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
File diff suppressed because it is too large
Load Diff
|
@ -14,697 +14,53 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define __USE_XOPEN
|
#define __USE_XOPEN
|
||||||
#include "shellCommand.h"
|
#include "shellInt.h"
|
||||||
#include "tglobal.h"
|
|
||||||
#include "tlog.h"
|
|
||||||
|
|
||||||
#ifndef WINDOWS
|
SShellObj shell = {0};
|
||||||
#include <argp.h>
|
|
||||||
#include <termio.h>
|
|
||||||
#include <wordexp.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define OPT_ABORT 1 /* abort */
|
|
||||||
|
|
||||||
int indicator = 1;
|
|
||||||
|
|
||||||
void insertChar(Command *cmd, char *c, int size);
|
|
||||||
void taosNetTest(char *role, char *host, int32_t port, int32_t pkgLen, int32_t pkgNum, char *pkgType);
|
|
||||||
const char *argp_program_version = version;
|
|
||||||
const char *argp_program_bug_address = "<support@taosdata.com>";
|
|
||||||
static char doc[] = "";
|
|
||||||
static char args_doc[] = "";
|
|
||||||
|
|
||||||
TdThread pid;
|
|
||||||
static tsem_t cancelSem;
|
|
||||||
extern void taos_init();
|
|
||||||
|
|
||||||
#ifndef WINDOWS
|
|
||||||
static struct argp_option options[] = {
|
|
||||||
{"host", 'h', "HOST", 0, "TDengine server FQDN to connect. The default host is localhost."},
|
|
||||||
{"password", 'p', NULL, 0, "The password to use when connecting to the server."},
|
|
||||||
{"port", 'P', "PORT", 0, "The TCP/IP port number to use for the connection."},
|
|
||||||
{"user", 'u', "USER", 0, "The user name to use when connecting to the server."},
|
|
||||||
{"auth", 'A', "Auth", 0, "The auth string to use when connecting to the server."},
|
|
||||||
{"config-dir", 'c', "CONFIG_DIR", 0, "Configuration directory."},
|
|
||||||
{"dump-config",'C', NULL, 0, "Dump configuration."},
|
|
||||||
{"commands", 's', "COMMANDS", 0, "Commands to run without enter the shell."},
|
|
||||||
{"raw-time", 'r', NULL, 0, "Output time as uint64_t."},
|
|
||||||
{"file", 'f', "FILE", 0, "Script to run without enter the shell."},
|
|
||||||
{"directory", 'D', "DIRECTORY", 0, "Use multi-thread to import all SQL files in the directory separately."},
|
|
||||||
{"thread", 'T', "THREADNUM", 0, "Number of threads when using multi-thread to import data."},
|
|
||||||
{"check", 'k', "CHECK", 0, "Check tables."},
|
|
||||||
{"database", 'd', "DATABASE", 0, "Database to use when connecting to the server."},
|
|
||||||
{"timezone", 'z', "TIMEZONE", 0, "Time zone of the shell, default is local."},
|
|
||||||
{"status", 't', NULL, 0, "Check the service status."},
|
|
||||||
{"verbose", 'v', NULL, 0, "Check the details of the service status."},
|
|
||||||
{"netrole", 'n', "NETROLE", 0, "Net role when network connectivity test, default is startup, options: client|server|rpc|startup|sync|speed|fqdn."},
|
|
||||||
{"pktlen", 'l', "PKTLEN", 0, "Packet length used for net test, default is 1000 bytes."},
|
|
||||||
{"pktnum", 'N', "PKTNUM", 0, "Packet numbers used for net test, default is 100."},
|
|
||||||
// Shuduo: 3.0 does not support UDP any more
|
|
||||||
// {"pkttype", 'S', "PKTTYPE", 0, "Packet type used for net test, default is TCP."},
|
|
||||||
{0}};
|
|
||||||
|
|
||||||
static error_t parse_opt(int key, char *arg, struct argp_state *state) {
|
|
||||||
/* Get the input argument from argp_parse, which we
|
|
||||||
know is a pointer to our arguments structure. */
|
|
||||||
SShellArguments *arguments = state->input;
|
|
||||||
wordexp_t full_path;
|
|
||||||
|
|
||||||
switch (key) {
|
|
||||||
case 'h':
|
|
||||||
arguments->host = arg;
|
|
||||||
break;
|
|
||||||
case 'p':
|
|
||||||
break;
|
|
||||||
case 'P':
|
|
||||||
if (arg) {
|
|
||||||
arguments->port = atoi(arg);
|
|
||||||
} else {
|
|
||||||
fprintf(stderr, "Invalid port\n");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
case 'z':
|
|
||||||
arguments->timezone = arg;
|
|
||||||
break;
|
|
||||||
case 'u':
|
|
||||||
arguments->user = arg;
|
|
||||||
break;
|
|
||||||
case 'A':
|
|
||||||
arguments->auth = arg;
|
|
||||||
break;
|
|
||||||
case 'c':
|
|
||||||
if (wordexp(arg, &full_path, 0) != 0) {
|
|
||||||
fprintf(stderr, "Invalid path %s\n", arg);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (strlen(full_path.we_wordv[0]) >= TSDB_FILENAME_LEN) {
|
|
||||||
fprintf(stderr, "config file path: %s overflow max len %d\n", full_path.we_wordv[0], TSDB_FILENAME_LEN - 1);
|
|
||||||
wordfree(&full_path);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
tstrncpy(configDir, full_path.we_wordv[0], TSDB_FILENAME_LEN);
|
|
||||||
wordfree(&full_path);
|
|
||||||
break;
|
|
||||||
case 'C':
|
|
||||||
arguments->dump_config = true;
|
|
||||||
break;
|
|
||||||
case 's':
|
|
||||||
arguments->commands = arg;
|
|
||||||
break;
|
|
||||||
case 'r':
|
|
||||||
arguments->is_raw_time = true;
|
|
||||||
break;
|
|
||||||
case 'f':
|
|
||||||
if ((0 == strlen(arg)) || (wordexp(arg, &full_path, 0) != 0)) {
|
|
||||||
fprintf(stderr, "Invalid path %s\n", arg);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
tstrncpy(arguments->file, full_path.we_wordv[0], TSDB_FILENAME_LEN);
|
|
||||||
wordfree(&full_path);
|
|
||||||
break;
|
|
||||||
case 'D':
|
|
||||||
if (wordexp(arg, &full_path, 0) != 0) {
|
|
||||||
fprintf(stderr, "Invalid path %s\n", arg);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
tstrncpy(arguments->dir, full_path.we_wordv[0], TSDB_FILENAME_LEN);
|
|
||||||
wordfree(&full_path);
|
|
||||||
break;
|
|
||||||
case 'T':
|
|
||||||
if (arg) {
|
|
||||||
arguments->threadNum = atoi(arg);
|
|
||||||
} else {
|
|
||||||
fprintf(stderr, "Invalid number of threads\n");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 'k':
|
|
||||||
arguments->check = atoi(arg);
|
|
||||||
break;
|
|
||||||
case 't':
|
|
||||||
arguments->status = true;
|
|
||||||
break;
|
|
||||||
case 'v':
|
|
||||||
arguments->verbose = true;
|
|
||||||
break;
|
|
||||||
case 'd':
|
|
||||||
arguments->database = arg;
|
|
||||||
break;
|
|
||||||
case 'n':
|
|
||||||
arguments->netTestRole = arg;
|
|
||||||
break;
|
|
||||||
case 'l':
|
|
||||||
if (arg) {
|
|
||||||
arguments->pktLen = atoi(arg);
|
|
||||||
} else {
|
|
||||||
fprintf(stderr, "Invalid packet length\n");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 'N':
|
|
||||||
if (arg) {
|
|
||||||
arguments->pktNum = atoi(arg);
|
|
||||||
} else {
|
|
||||||
fprintf(stderr, "Invalid packet number\n");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 'S':
|
|
||||||
arguments->pktType = arg;
|
|
||||||
break;
|
|
||||||
case OPT_ABORT:
|
|
||||||
arguments->abort = 1;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return ARGP_ERR_UNKNOWN;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Our argp parser. */
|
|
||||||
static struct argp argp = {options, parse_opt, args_doc, doc};
|
|
||||||
|
|
||||||
char LINUXCLIENT_VERSION[] =
|
|
||||||
"Welcome to the TDengine shell from %s, Client Version:%s\n"
|
|
||||||
"Copyright (c) 2020 by TAOS Data, Inc. All rights reserved.\n\n";
|
|
||||||
char g_password[SHELL_MAX_PASSWORD_LEN];
|
|
||||||
|
|
||||||
static void parse_args(int argc, char *argv[], SShellArguments *arguments) {
|
|
||||||
for (int i = 1; i < argc; i++) {
|
|
||||||
if ((strncmp(argv[i], "-p", 2) == 0) || (strncmp(argv[i], "--password", 10) == 0)) {
|
|
||||||
printf(LINUXCLIENT_VERSION, tsOsName, taos_get_client_info());
|
|
||||||
if ((strlen(argv[i]) == 2) || (strncmp(argv[i], "--password", 10) == 0)) {
|
|
||||||
printf("Enter password: ");
|
|
||||||
taosSetConsoleEcho(false);
|
|
||||||
if (scanf("%20s", g_password) > 1) {
|
|
||||||
fprintf(stderr, "password reading error\n");
|
|
||||||
}
|
|
||||||
taosSetConsoleEcho(true);
|
|
||||||
if (EOF == getchar()) {
|
|
||||||
fprintf(stderr, "getchar() return EOF\n");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
tstrncpy(g_password, (char *)(argv[i] + 2), SHELL_MAX_PASSWORD_LEN);
|
|
||||||
strcpy(argv[i], "-p");
|
|
||||||
}
|
|
||||||
arguments->password = g_password;
|
|
||||||
arguments->is_use_passwd = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
void shellParseArgument(int argc, char *argv[], SShellArguments *arguments) {
|
|
||||||
#ifdef WINDOWS
|
|
||||||
#else
|
|
||||||
static char verType[32] = {0};
|
|
||||||
sprintf(verType, "version: %s\n", version);
|
|
||||||
|
|
||||||
argp_program_version = verType;
|
|
||||||
|
|
||||||
if (argc > 1) {
|
|
||||||
parse_args(argc, argv, arguments);
|
|
||||||
}
|
|
||||||
|
|
||||||
argp_parse(&argp, argc, argv, 0, 0, arguments);
|
|
||||||
if (arguments->abort) {
|
|
||||||
#ifndef _ALPINE
|
|
||||||
#if 0
|
|
||||||
error(10, 0, "ABORTED");
|
|
||||||
#endif
|
|
||||||
#else
|
|
||||||
abort();
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
int32_t shellReadCommand(TAOS *con, char *command) {
|
|
||||||
#ifdef WINDOWS
|
|
||||||
#else
|
|
||||||
unsigned hist_counter = history.hend;
|
|
||||||
char utf8_array[10] = "\0";
|
|
||||||
Command cmd;
|
|
||||||
memset(&cmd, 0, sizeof(cmd));
|
|
||||||
cmd.buffer = (char *)taosMemoryCalloc(1, MAX_COMMAND_SIZE);
|
|
||||||
cmd.command = (char *)taosMemoryCalloc(1, MAX_COMMAND_SIZE);
|
|
||||||
showOnScreen(&cmd);
|
|
||||||
|
|
||||||
// Read input.
|
|
||||||
char c;
|
|
||||||
while (1) {
|
|
||||||
c = (char)getchar(); // getchar() return an 'int' value
|
|
||||||
|
|
||||||
if (c == EOF) {
|
|
||||||
return c;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (c < 0) { // For UTF-8
|
|
||||||
int count = countPrefixOnes(c);
|
|
||||||
utf8_array[0] = c;
|
|
||||||
for (int k = 1; k < count; k++) {
|
|
||||||
c = (char)getchar();
|
|
||||||
utf8_array[k] = c;
|
|
||||||
}
|
|
||||||
insertChar(&cmd, utf8_array, count);
|
|
||||||
} else if (c < '\033') {
|
|
||||||
// Ctrl keys. TODO: Implement ctrl combinations
|
|
||||||
switch (c) {
|
|
||||||
case 1: // ctrl A
|
|
||||||
positionCursorHome(&cmd);
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
printf("\n");
|
|
||||||
resetCommand(&cmd, "");
|
|
||||||
kill(0, SIGINT);
|
|
||||||
break;
|
|
||||||
case 4: // EOF or Ctrl+D
|
|
||||||
printf("\n");
|
|
||||||
taos_close(con);
|
|
||||||
// write the history
|
|
||||||
write_history();
|
|
||||||
exitShell();
|
|
||||||
break;
|
|
||||||
case 5: // ctrl E
|
|
||||||
positionCursorEnd(&cmd);
|
|
||||||
break;
|
|
||||||
case 8:
|
|
||||||
backspaceChar(&cmd);
|
|
||||||
break;
|
|
||||||
case '\n':
|
|
||||||
case '\r':
|
|
||||||
printf("\n");
|
|
||||||
if (isReadyGo(&cmd)) {
|
|
||||||
sprintf(command, "%s%s", cmd.buffer, cmd.command);
|
|
||||||
taosMemoryFreeClear(cmd.buffer);
|
|
||||||
taosMemoryFreeClear(cmd.command);
|
|
||||||
return 0;
|
|
||||||
} else {
|
|
||||||
updateBuffer(&cmd);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 11: // Ctrl + K;
|
|
||||||
clearLineAfter(&cmd);
|
|
||||||
break;
|
|
||||||
case 12: // Ctrl + L;
|
|
||||||
system("clear");
|
|
||||||
showOnScreen(&cmd);
|
|
||||||
break;
|
|
||||||
case 21: // Ctrl + U;
|
|
||||||
clearLineBefore(&cmd);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} else if (c == '\033') {
|
|
||||||
c = (char)getchar();
|
|
||||||
switch (c) {
|
|
||||||
case '[':
|
|
||||||
c = (char)getchar();
|
|
||||||
switch (c) {
|
|
||||||
case 'A': // Up arrow
|
|
||||||
if (hist_counter != history.hstart) {
|
|
||||||
hist_counter = (hist_counter + MAX_HISTORY_SIZE - 1) % MAX_HISTORY_SIZE;
|
|
||||||
resetCommand(&cmd, (history.hist[hist_counter] == NULL) ? "" : history.hist[hist_counter]);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 'B': // Down arrow
|
|
||||||
if (hist_counter != history.hend) {
|
|
||||||
int next_hist = (hist_counter + 1) % MAX_HISTORY_SIZE;
|
|
||||||
|
|
||||||
if (next_hist != history.hend) {
|
|
||||||
resetCommand(&cmd, (history.hist[next_hist] == NULL) ? "" : history.hist[next_hist]);
|
|
||||||
} else {
|
|
||||||
resetCommand(&cmd, "");
|
|
||||||
}
|
|
||||||
hist_counter = next_hist;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 'C': // Right arrow
|
|
||||||
moveCursorRight(&cmd);
|
|
||||||
break;
|
|
||||||
case 'D': // Left arrow
|
|
||||||
moveCursorLeft(&cmd);
|
|
||||||
break;
|
|
||||||
case '1':
|
|
||||||
if ((c = (char)getchar()) == '~') {
|
|
||||||
// Home key
|
|
||||||
positionCursorHome(&cmd);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case '2':
|
|
||||||
if ((c = (char)getchar()) == '~') {
|
|
||||||
// Insert key
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case '3':
|
|
||||||
if ((c = (char)getchar()) == '~') {
|
|
||||||
// Delete key
|
|
||||||
deleteChar(&cmd);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case '4':
|
|
||||||
if ((c = (char)getchar()) == '~') {
|
|
||||||
// End key
|
|
||||||
positionCursorEnd(&cmd);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case '5':
|
|
||||||
if ((c = (char)getchar()) == '~') {
|
|
||||||
// Page up key
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case '6':
|
|
||||||
if ((c = (char)getchar()) == '~') {
|
|
||||||
// Page down key
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 72:
|
|
||||||
// Home key
|
|
||||||
positionCursorHome(&cmd);
|
|
||||||
break;
|
|
||||||
case 70:
|
|
||||||
// End key
|
|
||||||
positionCursorEnd(&cmd);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} else if (c == 0x7f) {
|
|
||||||
// press delete key
|
|
||||||
backspaceChar(&cmd);
|
|
||||||
} else {
|
|
||||||
insertChar(&cmd, &c, 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void *shellLoopQuery(void *arg) {
|
|
||||||
if (indicator) {
|
|
||||||
getOldTerminalMode();
|
|
||||||
indicator = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
TAOS *con = (TAOS *)arg;
|
|
||||||
|
|
||||||
setThreadName("shellLoopQuery");
|
|
||||||
|
|
||||||
taosThreadCleanupPush(cleanup_handler, NULL);
|
|
||||||
|
|
||||||
char *command = taosMemoryMalloc(MAX_COMMAND_SIZE);
|
|
||||||
if (command == NULL) {
|
|
||||||
uError("failed to malloc command");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
int32_t err = 0;
|
|
||||||
|
|
||||||
do {
|
|
||||||
// Read command from shell.
|
|
||||||
memset(command, 0, MAX_COMMAND_SIZE);
|
|
||||||
setTerminalMode();
|
|
||||||
err = shellReadCommand(con, command);
|
|
||||||
if (err) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
resetTerminalMode();
|
|
||||||
} while (shellRunCommand(con, command) == 0);
|
|
||||||
|
|
||||||
taosMemoryFreeClear(command);
|
|
||||||
exitShell();
|
|
||||||
|
|
||||||
taosThreadCleanupPop(1);
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
void get_history_path(char *_history) { snprintf(_history, TSDB_FILENAME_LEN, "%s/%s", getenv("HOME"), HISTORY_FILE); }
|
|
||||||
|
|
||||||
void clearScreen(int ecmd_pos, int cursor_pos) {
|
|
||||||
#ifdef WINDOWS
|
|
||||||
#else
|
|
||||||
struct winsize w;
|
|
||||||
if (ioctl(0, TIOCGWINSZ, &w) < 0 || w.ws_col == 0 || w.ws_row == 0) {
|
|
||||||
// fprintf(stderr, "No stream device, and use default value(col 120, row 30)\n");
|
|
||||||
w.ws_col = 120;
|
|
||||||
w.ws_row = 30;
|
|
||||||
}
|
|
||||||
|
|
||||||
int cursor_x = cursor_pos / w.ws_col;
|
|
||||||
int cursor_y = cursor_pos % w.ws_col;
|
|
||||||
int command_x = ecmd_pos / w.ws_col;
|
|
||||||
positionCursor(cursor_y, LEFT);
|
|
||||||
positionCursor(command_x - cursor_x, DOWN);
|
|
||||||
fprintf(stdout, "\033[2K");
|
|
||||||
for (int i = 0; i < command_x; i++) {
|
|
||||||
positionCursor(1, UP);
|
|
||||||
fprintf(stdout, "\033[2K");
|
|
||||||
}
|
|
||||||
fflush(stdout);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void showOnScreen(Command *cmd) {
|
|
||||||
#ifdef WINDOWS
|
|
||||||
#else
|
|
||||||
struct winsize w;
|
|
||||||
if (ioctl(0, TIOCGWINSZ, &w) < 0 || w.ws_col == 0 || w.ws_row == 0) {
|
|
||||||
// fprintf(stderr, "No stream device\n");
|
|
||||||
w.ws_col = 120;
|
|
||||||
w.ws_row = 30;
|
|
||||||
}
|
|
||||||
|
|
||||||
TdWchar wc;
|
|
||||||
int size = 0;
|
|
||||||
|
|
||||||
// Print out the command.
|
|
||||||
char *total_string = taosMemoryMalloc(MAX_COMMAND_SIZE);
|
|
||||||
memset(total_string, '\0', MAX_COMMAND_SIZE);
|
|
||||||
if (strcmp(cmd->buffer, "") == 0) {
|
|
||||||
sprintf(total_string, "%s%s", PROMPT_HEADER, cmd->command);
|
|
||||||
} else {
|
|
||||||
sprintf(total_string, "%s%s", CONTINUE_PROMPT, cmd->command);
|
|
||||||
}
|
|
||||||
|
|
||||||
int remain_column = w.ws_col;
|
|
||||||
/* size = cmd->commandSize + prompt_size; */
|
|
||||||
for (char *str = total_string; size < cmd->commandSize + prompt_size;) {
|
|
||||||
int ret = taosMbToWchar(&wc, str, MB_CUR_MAX);
|
|
||||||
if (ret < 0) break;
|
|
||||||
size += ret;
|
|
||||||
/* assert(size >= 0); */
|
|
||||||
int width = taosWcharWidth(wc);
|
|
||||||
if (remain_column > width) {
|
|
||||||
printf("%lc", wc);
|
|
||||||
remain_column -= width;
|
|
||||||
} else {
|
|
||||||
if (remain_column == width) {
|
|
||||||
printf("%lc\n\r", wc);
|
|
||||||
remain_column = w.ws_col;
|
|
||||||
} else {
|
|
||||||
printf("\n\r%lc", wc);
|
|
||||||
remain_column = w.ws_col - width;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
str = total_string + size;
|
|
||||||
}
|
|
||||||
|
|
||||||
taosMemoryFree(total_string);
|
|
||||||
/* for (int i = 0; i < size; i++){ */
|
|
||||||
/* char c = total_string[i]; */
|
|
||||||
/* if (k % w.ws_col == 0) { */
|
|
||||||
/* printf("%c\n\r", c); */
|
|
||||||
/* } */
|
|
||||||
/* else { */
|
|
||||||
/* printf("%c", c); */
|
|
||||||
/* } */
|
|
||||||
/* k += 1; */
|
|
||||||
/* } */
|
|
||||||
|
|
||||||
// Position the cursor
|
|
||||||
int cursor_pos = cmd->screenOffset + prompt_size;
|
|
||||||
int ecmd_pos = cmd->endOffset + prompt_size;
|
|
||||||
|
|
||||||
int cursor_x = cursor_pos / w.ws_col;
|
|
||||||
int cursor_y = cursor_pos % w.ws_col;
|
|
||||||
// int cursor_y = cursor % w.ws_col;
|
|
||||||
int command_x = ecmd_pos / w.ws_col;
|
|
||||||
int command_y = ecmd_pos % w.ws_col;
|
|
||||||
// int command_y = (command.size() + prompt_size) % w.ws_col;
|
|
||||||
positionCursor(command_y, LEFT);
|
|
||||||
positionCursor(command_x, UP);
|
|
||||||
positionCursor(cursor_x, DOWN);
|
|
||||||
positionCursor(cursor_y, RIGHT);
|
|
||||||
fflush(stdout);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void cleanup_handler(void *arg) { resetTerminalMode(); }
|
|
||||||
|
|
||||||
void exitShell() {
|
|
||||||
taos_cleanup();
|
|
||||||
exit(EXIT_SUCCESS);
|
|
||||||
}
|
|
||||||
|
|
||||||
void shellQueryInterruptHandler(int32_t signum, void *sigInfo, void *context) { tsem_post(&cancelSem); }
|
|
||||||
|
|
||||||
void *cancelHandler(void *arg) {
|
|
||||||
setThreadName("cancelHandler");
|
|
||||||
|
|
||||||
while (1) {
|
|
||||||
if (tsem_wait(&cancelSem) != 0) {
|
|
||||||
taosMsleep(10);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
resetTerminalMode();
|
|
||||||
printf("\nReceive ctrl+c or other signal, quit shell.\n");
|
|
||||||
exitShell();
|
|
||||||
}
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
int checkVersion() {
|
|
||||||
if (sizeof(int8_t) != 1) {
|
|
||||||
printf("taos int8 size is %d(!= 1)", (int)sizeof(int8_t));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if (sizeof(int16_t) != 2) {
|
|
||||||
printf("taos int16 size is %d(!= 2)", (int)sizeof(int16_t));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if (sizeof(int32_t) != 4) {
|
|
||||||
printf("taos int32 size is %d(!= 4)", (int)sizeof(int32_t));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if (sizeof(int64_t) != 8) {
|
|
||||||
printf("taos int64 size is %d(!= 8)", (int)sizeof(int64_t));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Global configurations
|
|
||||||
SShellArguments args = {
|
|
||||||
.host = NULL,
|
|
||||||
.user = NULL,
|
|
||||||
.database = NULL,
|
|
||||||
.timezone = NULL,
|
|
||||||
.is_raw_time = false,
|
|
||||||
.is_use_passwd = false,
|
|
||||||
.dump_config = false,
|
|
||||||
.file = "\0",
|
|
||||||
.dir = "\0",
|
|
||||||
.threadNum = 5,
|
|
||||||
.commands = NULL,
|
|
||||||
.pktLen = 1000,
|
|
||||||
.pktNum = 100,
|
|
||||||
.pktType = "TCP",
|
|
||||||
.netTestRole = NULL,
|
|
||||||
#ifndef TD_WINDOWS
|
|
||||||
.password = NULL,
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
void shellDumpConfig() {
|
|
||||||
if (!args.dump_config) return;
|
|
||||||
|
|
||||||
SConfig *pCfg = taosGetCfg();
|
|
||||||
if (NULL == pCfg) {
|
|
||||||
printf("TDengine read global config failed!\n");
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
cfgDumpCfg(pCfg, 0, 1);
|
|
||||||
exitShell();
|
|
||||||
}
|
|
||||||
|
|
||||||
void shellTestNetWork() {
|
|
||||||
if (args.netTestRole && args.netTestRole[0] != 0) {
|
|
||||||
taosNetTest(args.netTestRole, args.host, args.port, args.pktLen, args.pktNum, args.pktType);
|
|
||||||
exitShell();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void shellCheckServerStatus() {
|
|
||||||
if (!args.status && !args.verbose) return;
|
|
||||||
|
|
||||||
TSDB_SERVER_STATUS code;
|
|
||||||
do {
|
|
||||||
char details[1024] = {0};
|
|
||||||
code = taos_check_server_status(args.host, args.port, details, args.verbose ? 1024 : 0);
|
|
||||||
switch (code) {
|
|
||||||
case TSDB_SRV_STATUS_UNAVAILABLE:
|
|
||||||
printf("0: unavailable\n");
|
|
||||||
break;
|
|
||||||
case TSDB_SRV_STATUS_NETWORK_OK:
|
|
||||||
printf("1: network ok\n");
|
|
||||||
break;
|
|
||||||
case TSDB_SRV_STATUS_SERVICE_OK:
|
|
||||||
printf("2: service ok\n");
|
|
||||||
break;
|
|
||||||
case TSDB_SRV_STATUS_SERVICE_DEGRADED:
|
|
||||||
printf("3: service degraded\n");
|
|
||||||
break;
|
|
||||||
case TSDB_SRV_STATUS_EXTING:
|
|
||||||
printf("4: exiting\n");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (strlen(details) != 0) {
|
|
||||||
printf("%s\n\n", details);
|
|
||||||
}
|
|
||||||
if (code == TSDB_SRV_STATUS_NETWORK_OK && args.verbose) {
|
|
||||||
taosMsleep(1000);
|
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} while (1);
|
|
||||||
|
|
||||||
exitShell();
|
|
||||||
}
|
|
||||||
|
|
||||||
void shellExecute() {
|
|
||||||
TAOS *con = shellInit(&args);
|
|
||||||
if (con == NULL) {
|
|
||||||
exitShell();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tsem_init(&cancelSem, 0, 0) != 0) {
|
|
||||||
printf("failed to create cancel semphore\n");
|
|
||||||
exitShell();
|
|
||||||
}
|
|
||||||
|
|
||||||
TdThread spid;
|
|
||||||
taosThreadCreate(&spid, NULL, cancelHandler, NULL);
|
|
||||||
|
|
||||||
taosSetSignal(SIGTERM, shellQueryInterruptHandler);
|
|
||||||
taosSetSignal(SIGINT, shellQueryInterruptHandler);
|
|
||||||
taosSetSignal(SIGHUP, shellQueryInterruptHandler);
|
|
||||||
taosSetSignal(SIGABRT, shellQueryInterruptHandler);
|
|
||||||
|
|
||||||
shellGetGrantInfo(con);
|
|
||||||
|
|
||||||
while (1) {
|
|
||||||
taosThreadCreate(&pid, NULL, shellLoopQuery, con);
|
|
||||||
taosThreadJoin(pid, NULL);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
int main(int argc, char *argv[]) {
|
||||||
if (!checkVersion()) exitShell();
|
if (shellCheckIntSize() != 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
shellParseArgument(argc, argv, &args);
|
if (shellParseArgs(argc, argv) != 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shell.args.is_version) {
|
||||||
|
shellPrintVersion();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shell.args.is_gen_auth) {
|
||||||
|
shellGenerateAuth();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shell.args.is_help) {
|
||||||
|
shellPrintHelp();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
taos_init();
|
taos_init();
|
||||||
shellDumpConfig();
|
|
||||||
shellCheckServerStatus();
|
|
||||||
shellTestNetWork();
|
|
||||||
shellExecute();
|
|
||||||
|
|
||||||
return 0;
|
if (shell.args.is_dump_config) {
|
||||||
|
shellDumpConfig();
|
||||||
|
taos_cleanup();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shell.args.is_startup || shell.args.is_check) {
|
||||||
|
shellCheckServerStatus();
|
||||||
|
taos_cleanup();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shell.args.netrole != NULL) {
|
||||||
|
shellTestNetWork();
|
||||||
|
taos_cleanup();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return shellExecute();
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,141 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
|
||||||
|
*
|
||||||
|
* This program is free software: you can use, redistribute, and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License, version 3
|
||||||
|
* or later ("AGPL"), as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define _GNU_SOURCE
|
||||||
|
#include "shellInt.h"
|
||||||
|
|
||||||
|
static void shellWorkAsClient() {
|
||||||
|
SShellArgs *pArgs = &shell.args;
|
||||||
|
SRpcInit rpcInit = {0};
|
||||||
|
SEpSet epSet = {.inUse = 0, .numOfEps = 1};
|
||||||
|
SRpcMsg rpcRsp = {0};
|
||||||
|
void *clientRpc = NULL;
|
||||||
|
char pass[TSDB_PASSWORD_LEN + 1] = {0};
|
||||||
|
|
||||||
|
taosEncryptPass_c((uint8_t *)("_pwd"), strlen("_pwd"), pass);
|
||||||
|
rpcInit.label = "CHK";
|
||||||
|
rpcInit.numOfThreads = 1;
|
||||||
|
rpcInit.sessions = 16;
|
||||||
|
rpcInit.connType = TAOS_CONN_CLIENT;
|
||||||
|
rpcInit.idleTime = tsShellActivityTimer * 1000;
|
||||||
|
rpcInit.user = "_dnd";
|
||||||
|
rpcInit.ckey = "_key";
|
||||||
|
rpcInit.spi = 1;
|
||||||
|
rpcInit.secret = pass;
|
||||||
|
|
||||||
|
clientRpc = rpcOpen(&rpcInit);
|
||||||
|
if (clientRpc == NULL) {
|
||||||
|
printf("failed to init net test client since %s\n", terrstr());
|
||||||
|
goto _OVER;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pArgs->host == NULL) {
|
||||||
|
pArgs->host = tsFirst;
|
||||||
|
}
|
||||||
|
char fqdn[TSDB_FQDN_LEN] = {0};
|
||||||
|
tstrncpy(fqdn, pArgs->host, TSDB_FQDN_LEN);
|
||||||
|
strtok(fqdn, ":");
|
||||||
|
|
||||||
|
if (pArgs->port == 0) {
|
||||||
|
pArgs->port = tsServerPort;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("network test client is initialized, the server is %s:%u\n", fqdn, pArgs->port);
|
||||||
|
|
||||||
|
tstrncpy(epSet.eps[0].fqdn, fqdn, TSDB_FQDN_LEN);
|
||||||
|
epSet.eps[0].port = (uint16_t)pArgs->port;
|
||||||
|
|
||||||
|
int32_t totalSucc = 0;
|
||||||
|
uint64_t startTime = taosGetTimestampUs();
|
||||||
|
|
||||||
|
for (int32_t i = 0; i < pArgs->pktNum; ++i) {
|
||||||
|
SRpcMsg rpcMsg = {.ahandle = (void *)0x9525, .msgType = TDMT_DND_NET_TEST};
|
||||||
|
rpcMsg.pCont = rpcMallocCont(pArgs->pktLen);
|
||||||
|
rpcMsg.contLen = pArgs->pktLen;
|
||||||
|
|
||||||
|
printf("request is sent, size:%d\n", rpcMsg.contLen);
|
||||||
|
rpcSendRecv(clientRpc, &epSet, &rpcMsg, &rpcRsp);
|
||||||
|
if (rpcRsp.code == 0 &&rpcRsp.contLen == rpcMsg.contLen) {
|
||||||
|
printf("response is received, size:%d\n", rpcMsg.contLen);
|
||||||
|
if (rpcRsp.code == 0) totalSucc++;
|
||||||
|
} else {
|
||||||
|
printf("response not received since %s\n", tstrerror(rpcRsp.code));
|
||||||
|
}
|
||||||
|
|
||||||
|
rpcFreeCont(rpcRsp.pCont);
|
||||||
|
rpcRsp.pCont = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t endTime = taosGetTimestampUs();
|
||||||
|
uint64_t elT = endTime - startTime;
|
||||||
|
|
||||||
|
printf("\ntotal succ:%5d/%d\tcost:%8.2lf ms\tspeed:%8.2lf MB/s\n", totalSucc, pArgs->pktNum, elT / 1000.0,
|
||||||
|
pArgs->pktLen / (elT / 1000000.0) / 1024.0 / 1024.0 * totalSucc);
|
||||||
|
|
||||||
|
_OVER:
|
||||||
|
if (clientRpc != NULL) {
|
||||||
|
rpcClose(clientRpc);
|
||||||
|
}
|
||||||
|
if (rpcRsp.pCont != NULL) {
|
||||||
|
rpcFreeCont(rpcRsp.pCont);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void shellProcessMsg(void *p, SRpcMsg *pRpc, SEpSet *pEpSet) {
|
||||||
|
printf("request is received, size:%d\n", pRpc->contLen);
|
||||||
|
fflush(stdout);
|
||||||
|
SRpcMsg rsp = {.handle = pRpc->handle, .refId = pRpc->refId, .ahandle = pRpc->ahandle, .code = 0};
|
||||||
|
rsp.pCont = rpcMallocCont(shell.args.pktLen);
|
||||||
|
rsp.contLen = shell.args.pktLen;
|
||||||
|
rpcSendResponse(&rsp);
|
||||||
|
}
|
||||||
|
|
||||||
|
void shellNettestHandler(int32_t signum, void *sigInfo, void *context) { shellExit(); }
|
||||||
|
|
||||||
|
static void shellWorkAsServer() {
|
||||||
|
SShellArgs *pArgs = &shell.args;
|
||||||
|
|
||||||
|
if (pArgs->port == 0) {
|
||||||
|
pArgs->port = tsServerPort;
|
||||||
|
}
|
||||||
|
|
||||||
|
SRpcInit rpcInit = {0};
|
||||||
|
rpcInit.localPort = pArgs->port;
|
||||||
|
rpcInit.label = "CHK";
|
||||||
|
rpcInit.numOfThreads = tsNumOfRpcThreads;
|
||||||
|
rpcInit.cfp = (RpcCfp)shellProcessMsg;
|
||||||
|
rpcInit.sessions = 10;
|
||||||
|
rpcInit.connType = TAOS_CONN_SERVER;
|
||||||
|
rpcInit.idleTime = tsShellActivityTimer * 1000;
|
||||||
|
|
||||||
|
void *serverRpc = rpcOpen(&rpcInit);
|
||||||
|
if (serverRpc == NULL) {
|
||||||
|
printf("failed to init net test server since %s", terrstr());
|
||||||
|
} else {
|
||||||
|
printf("network test server is initialized, port:%u\n", pArgs->port);
|
||||||
|
taosSetSignal(SIGTERM, shellNettestHandler);
|
||||||
|
while (1) taosMsleep(10);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void shellTestNetWork() {
|
||||||
|
if (strcmp(shell.args.netrole, "client") == 0) {
|
||||||
|
shellWorkAsClient();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strcmp(shell.args.netrole, "server") == 0) {
|
||||||
|
shellWorkAsServer();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,132 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
|
||||||
|
*
|
||||||
|
* This program is free software: you can use, redistribute, and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License, version 3
|
||||||
|
* or later ("AGPL"), as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define _BSD_SOURCE
|
||||||
|
#define _GNU_SOURCE
|
||||||
|
#define _XOPEN_SOURCE
|
||||||
|
#define _DEFAULT_SOURCE
|
||||||
|
|
||||||
|
#include "shellInt.h"
|
||||||
|
|
||||||
|
bool shellRegexMatch(const char *s, const char *reg, int32_t cflags) {
|
||||||
|
regex_t regex = {0};
|
||||||
|
char msgbuf[100] = {0};
|
||||||
|
|
||||||
|
/* Compile regular expression */
|
||||||
|
if (regcomp(®ex, reg, cflags) != 0) {
|
||||||
|
fprintf(stderr, "Fail to compile regex");
|
||||||
|
shellExit();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Execute regular expression */
|
||||||
|
int32_t reti = regexec(®ex, s, 0, NULL, 0);
|
||||||
|
if (!reti) {
|
||||||
|
regfree(®ex);
|
||||||
|
return true;
|
||||||
|
} else if (reti == REG_NOMATCH) {
|
||||||
|
regfree(®ex);
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
regerror(reti, ®ex, msgbuf, sizeof(msgbuf));
|
||||||
|
fprintf(stderr, "Regex match failed: %s\n", msgbuf);
|
||||||
|
regfree(®ex);
|
||||||
|
shellExit();
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t shellCheckIntSize() {
|
||||||
|
if (sizeof(int8_t) != 1) {
|
||||||
|
printf("taos int8 size is %d(!= 1)", (int)sizeof(int8_t));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (sizeof(int16_t) != 2) {
|
||||||
|
printf("taos int16 size is %d(!= 2)", (int)sizeof(int16_t));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (sizeof(int32_t) != 4) {
|
||||||
|
printf("taos int32 size is %d(!= 4)", (int)sizeof(int32_t));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (sizeof(int64_t) != 8) {
|
||||||
|
printf("taos int64 size is %d(!= 8)", (int)sizeof(int64_t));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void shellPrintVersion() { printf("version: %s\n", version); }
|
||||||
|
|
||||||
|
void shellGenerateAuth() {
|
||||||
|
char secretEncrypt[TSDB_PASSWORD_LEN + 1] = {0};
|
||||||
|
taosEncryptPass_c((uint8_t *)shell.args.password, strlen(shell.args.password), secretEncrypt);
|
||||||
|
printf("%s\n", secretEncrypt);
|
||||||
|
fflush(stdout);
|
||||||
|
}
|
||||||
|
|
||||||
|
void shellDumpConfig() {
|
||||||
|
SConfig *pCfg = taosGetCfg();
|
||||||
|
if (pCfg == NULL) {
|
||||||
|
printf("TDengine read global config failed!\n");
|
||||||
|
} else {
|
||||||
|
cfgDumpCfg(pCfg, 1, true);
|
||||||
|
}
|
||||||
|
fflush(stdout);
|
||||||
|
}
|
||||||
|
|
||||||
|
void shellCheckServerStatus() {
|
||||||
|
TSDB_SERVER_STATUS code;
|
||||||
|
|
||||||
|
do {
|
||||||
|
char details[1024] = {0};
|
||||||
|
code = taos_check_server_status(shell.args.host, shell.args.port, details, 1024);
|
||||||
|
switch (code) {
|
||||||
|
case TSDB_SRV_STATUS_UNAVAILABLE:
|
||||||
|
printf("0: unavailable\n");
|
||||||
|
break;
|
||||||
|
case TSDB_SRV_STATUS_NETWORK_OK:
|
||||||
|
printf("1: network ok\n");
|
||||||
|
break;
|
||||||
|
case TSDB_SRV_STATUS_SERVICE_OK:
|
||||||
|
printf("2: service ok\n");
|
||||||
|
break;
|
||||||
|
case TSDB_SRV_STATUS_SERVICE_DEGRADED:
|
||||||
|
printf("3: service degraded\n");
|
||||||
|
break;
|
||||||
|
case TSDB_SRV_STATUS_EXTING:
|
||||||
|
printf("4: exiting\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (strlen(details) != 0) {
|
||||||
|
printf("%s\n\n", details);
|
||||||
|
}
|
||||||
|
fflush(stdout);
|
||||||
|
if (code == TSDB_SRV_STATUS_NETWORK_OK && shell.args.is_startup) {
|
||||||
|
taosMsleep(1000);
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} while (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void shellExit() {
|
||||||
|
if (shell.conn != NULL) {
|
||||||
|
taos_close(shell.conn);
|
||||||
|
shell.conn = NULL;
|
||||||
|
}
|
||||||
|
taos_cleanup();
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
|
@ -1,514 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
|
|
||||||
*
|
|
||||||
* This program is free software: you can use, redistribute, and/or modify
|
|
||||||
* it under the terms of the GNU Affero General Public License, version 3
|
|
||||||
* or later ("AGPL"), as published by the Free Software Foundation.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Affero General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define _DEFAULT_SOURCE
|
|
||||||
#define ALLOW_FORBID_FUNC
|
|
||||||
#include "os.h"
|
|
||||||
#include "taosdef.h"
|
|
||||||
#include "tmsg.h"
|
|
||||||
#include "taoserror.h"
|
|
||||||
#include "tlog.h"
|
|
||||||
#include "tglobal.h"
|
|
||||||
#include "trpc.h"
|
|
||||||
#include "rpcHead.h"
|
|
||||||
#include "tchecksum.h"
|
|
||||||
#include "syncMsg.h"
|
|
||||||
|
|
||||||
#include "osSocket.h"
|
|
||||||
|
|
||||||
#define MAX_PKG_LEN (64 * 1000)
|
|
||||||
#define MAX_SPEED_PKG_LEN (1024 * 1024 * 1024)
|
|
||||||
#define MIN_SPEED_PKG_LEN 1024
|
|
||||||
#define MAX_SPEED_PKG_NUM 10000
|
|
||||||
#define MIN_SPEED_PKG_NUM 1
|
|
||||||
#define BUFFER_SIZE (MAX_PKG_LEN + 1024)
|
|
||||||
|
|
||||||
extern int tsRpcMaxUdpSize;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
char * hostFqdn;
|
|
||||||
uint32_t hostIp;
|
|
||||||
int32_t port;
|
|
||||||
int32_t pktLen;
|
|
||||||
} STestInfo;
|
|
||||||
|
|
||||||
static void *taosNetBindUdpPort(void *sarg) {
|
|
||||||
STestInfo *pinfo = (STestInfo *)sarg;
|
|
||||||
int32_t port = pinfo->port;
|
|
||||||
SOCKET serverSocket;
|
|
||||||
char buffer[BUFFER_SIZE];
|
|
||||||
int32_t iDataNum;
|
|
||||||
socklen_t sin_size;
|
|
||||||
int32_t bufSize = 1024000;
|
|
||||||
|
|
||||||
struct sockaddr_in server_addr;
|
|
||||||
struct sockaddr_in clientAddr;
|
|
||||||
|
|
||||||
setThreadName("netBindUdpPort");
|
|
||||||
|
|
||||||
if ((serverSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
|
|
||||||
uError("failed to create UDP socket since %s", strerror(errno));
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
bzero(&server_addr, sizeof(server_addr));
|
|
||||||
server_addr.sin_family = AF_INET;
|
|
||||||
server_addr.sin_port = htons(port);
|
|
||||||
server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
|
|
||||||
|
|
||||||
if (bind(serverSocket, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) {
|
|
||||||
uError("failed to bind UDP port:%d since %s", port, strerror(errno));
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
TdSocketPtr pSocket = (TdSocketPtr)taosMemoryMalloc(sizeof(TdSocket));
|
|
||||||
if (pSocket == NULL) {
|
|
||||||
taosCloseSocketNoCheck1(serverSocket);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
pSocket->fd = serverSocket;
|
|
||||||
pSocket->refId = 0;
|
|
||||||
|
|
||||||
if (taosSetSockOpt(pSocket, SOL_SOCKET, SO_SNDBUF, (void *)&bufSize, sizeof(bufSize)) != 0) {
|
|
||||||
uError("failed to set the send buffer size for UDP socket\n");
|
|
||||||
taosCloseSocket(&pSocket);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (taosSetSockOpt(pSocket, SOL_SOCKET, SO_RCVBUF, (void *)&bufSize, sizeof(bufSize)) != 0) {
|
|
||||||
uError("failed to set the receive buffer size for UDP socket\n");
|
|
||||||
taosCloseSocket(&pSocket);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
uInfo("UDP server at port:%d is listening", port);
|
|
||||||
|
|
||||||
while (1) {
|
|
||||||
memset(buffer, 0, BUFFER_SIZE);
|
|
||||||
sin_size = sizeof(*(struct sockaddr *)&server_addr);
|
|
||||||
iDataNum = recvfrom(serverSocket, buffer, BUFFER_SIZE, 0, (struct sockaddr *)&clientAddr, &sin_size);
|
|
||||||
|
|
||||||
if (iDataNum < 0) {
|
|
||||||
uDebug("failed to perform recvfrom func at %d since %s", port, strerror(errno));
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
uInfo("UDP: recv:%d bytes from %s at %d", iDataNum, taosInetNtoa(clientAddr.sin_addr), port);
|
|
||||||
|
|
||||||
if (iDataNum > 0) {
|
|
||||||
iDataNum = taosSendto(pSocket, buffer, iDataNum, 0, (struct sockaddr *)&clientAddr, (int32_t)sin_size);
|
|
||||||
}
|
|
||||||
|
|
||||||
uInfo("UDP: send:%d bytes to %s at %d", iDataNum, taosInetNtoa(clientAddr.sin_addr), port);
|
|
||||||
}
|
|
||||||
|
|
||||||
taosCloseSocket(&pSocket);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void *taosNetBindTcpPort(void *sarg) {
|
|
||||||
struct sockaddr_in server_addr;
|
|
||||||
struct sockaddr_in clientAddr;
|
|
||||||
|
|
||||||
STestInfo *pinfo = sarg;
|
|
||||||
int32_t port = pinfo->port;
|
|
||||||
SOCKET serverSocket;
|
|
||||||
int32_t addr_len = sizeof(clientAddr);
|
|
||||||
SOCKET client;
|
|
||||||
char buffer[BUFFER_SIZE];
|
|
||||||
|
|
||||||
setThreadName("netBindTcpPort");
|
|
||||||
|
|
||||||
if ((serverSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
|
|
||||||
uError("failed to create TCP socket since %s", strerror(errno));
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
bzero(&server_addr, sizeof(server_addr));
|
|
||||||
server_addr.sin_family = AF_INET;
|
|
||||||
server_addr.sin_port = htons(port);
|
|
||||||
server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
|
|
||||||
|
|
||||||
int32_t reuse = 1;
|
|
||||||
TdSocketPtr pSocket = (TdSocketPtr)taosMemoryMalloc(sizeof(TdSocket));
|
|
||||||
if (pSocket == NULL) {
|
|
||||||
taosCloseSocketNoCheck1(serverSocket);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
pSocket->fd = serverSocket;
|
|
||||||
pSocket->refId = 0;
|
|
||||||
|
|
||||||
if (taosSetSockOpt(pSocket, SOL_SOCKET, SO_REUSEADDR, (void *)&reuse, sizeof(reuse)) < 0) {
|
|
||||||
uError("setsockopt SO_REUSEADDR failed: %d (%s)", errno, strerror(errno));
|
|
||||||
taosCloseSocket(&pSocket);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (bind(serverSocket, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) {
|
|
||||||
uError("failed to bind TCP port:%d since %s", port, strerror(errno));
|
|
||||||
taosCloseSocket(&pSocket);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (taosKeepTcpAlive(pSocket) < 0) {
|
|
||||||
uError("failed to set tcp server keep-alive option since %s", strerror(errno));
|
|
||||||
taosCloseSocket(&pSocket);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (listen(serverSocket, 10) < 0) {
|
|
||||||
uError("failed to listen TCP port:%d since %s", port, strerror(errno));
|
|
||||||
taosCloseSocket(&pSocket);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
uInfo("TCP server at port:%d is listening", port);
|
|
||||||
|
|
||||||
while (1) {
|
|
||||||
client = accept(serverSocket, (struct sockaddr *)&clientAddr, (socklen_t *)&addr_len);
|
|
||||||
if (client < 0) {
|
|
||||||
uDebug("TCP: failed to accept at port:%d since %s", port, strerror(errno));
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
int32_t ret = taosReadMsg(pSocket, buffer, pinfo->pktLen);
|
|
||||||
if (ret < 0 || ret != pinfo->pktLen) {
|
|
||||||
uError("TCP: failed to read %d bytes at port:%d since %s", pinfo->pktLen, port, strerror(errno));
|
|
||||||
taosCloseSocket(&pSocket);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
uInfo("TCP: read:%d bytes from %s at %d", pinfo->pktLen, taosInetNtoa(clientAddr.sin_addr), port);
|
|
||||||
|
|
||||||
ret = taosWriteMsg(pSocket, buffer, pinfo->pktLen);
|
|
||||||
if (ret < 0) {
|
|
||||||
uError("TCP: failed to write %d bytes at %d since %s", pinfo->pktLen, port, strerror(errno));
|
|
||||||
taosCloseSocket(&pSocket);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
uInfo("TCP: write:%d bytes to %s at %d", pinfo->pktLen, taosInetNtoa(clientAddr.sin_addr), port);
|
|
||||||
}
|
|
||||||
|
|
||||||
taosCloseSocket(&pSocket);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int32_t taosNetCheckTcpPort(STestInfo *info) {
|
|
||||||
SOCKET clientSocket;
|
|
||||||
char buffer[BUFFER_SIZE] = {0};
|
|
||||||
|
|
||||||
if ((clientSocket = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
|
|
||||||
uError("failed to create TCP client socket since %s", strerror(errno));
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int32_t reuse = 1;
|
|
||||||
TdSocketPtr pSocket = (TdSocketPtr)taosMemoryMalloc(sizeof(TdSocket));
|
|
||||||
if (pSocket == NULL) {
|
|
||||||
taosCloseSocketNoCheck1(clientSocket);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
pSocket->fd = clientSocket;
|
|
||||||
pSocket->refId = 0;
|
|
||||||
|
|
||||||
if (taosSetSockOpt(pSocket, SOL_SOCKET, SO_REUSEADDR, (void *)&reuse, sizeof(reuse)) < 0) {
|
|
||||||
uError("setsockopt SO_REUSEADDR failed: %d (%s)", errno, strerror(errno));
|
|
||||||
taosCloseSocket(&pSocket);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct sockaddr_in serverAddr;
|
|
||||||
memset((char *)&serverAddr, 0, sizeof(serverAddr));
|
|
||||||
serverAddr.sin_family = AF_INET;
|
|
||||||
serverAddr.sin_port = (uint16_t)htons((uint16_t)info->port);
|
|
||||||
serverAddr.sin_addr.s_addr = info->hostIp;
|
|
||||||
|
|
||||||
if (connect(clientSocket, (struct sockaddr *)&serverAddr, sizeof(serverAddr)) < 0) {
|
|
||||||
uError("TCP: failed to connect port %s:%d since %s", taosIpStr(info->hostIp), info->port, strerror(errno));
|
|
||||||
taosCloseSocket(&pSocket);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
taosKeepTcpAlive(pSocket);
|
|
||||||
|
|
||||||
sprintf(buffer, "client send TCP pkg to %s:%d, content: 1122334455", taosIpStr(info->hostIp), info->port);
|
|
||||||
sprintf(buffer + info->pktLen - 16, "1122334455667788");
|
|
||||||
|
|
||||||
int32_t ret = taosWriteMsg(pSocket, buffer, info->pktLen);
|
|
||||||
if (ret < 0) {
|
|
||||||
uError("TCP: failed to write msg to %s:%d since %s", taosIpStr(info->hostIp), info->port, strerror(errno));
|
|
||||||
taosCloseSocket(&pSocket);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = taosReadMsg(pSocket, buffer, info->pktLen);
|
|
||||||
if (ret < 0) {
|
|
||||||
uError("TCP: failed to read msg from %s:%d since %s", taosIpStr(info->hostIp), info->port, strerror(errno));
|
|
||||||
taosCloseSocket(&pSocket);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
taosCloseSocket(&pSocket);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int32_t taosNetCheckUdpPort(STestInfo *info) {
|
|
||||||
SOCKET clientSocket;
|
|
||||||
char buffer[BUFFER_SIZE] = {0};
|
|
||||||
int32_t iDataNum = 0;
|
|
||||||
int32_t bufSize = 1024000;
|
|
||||||
|
|
||||||
struct sockaddr_in serverAddr;
|
|
||||||
|
|
||||||
if ((clientSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
|
|
||||||
uError("failed to create udp client socket since %s", strerror(errno));
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
TdSocketPtr pSocket = (TdSocketPtr)taosMemoryMalloc(sizeof(TdSocket));
|
|
||||||
if (pSocket == NULL) {
|
|
||||||
taosCloseSocketNoCheck1(clientSocket);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
pSocket->fd = clientSocket;
|
|
||||||
pSocket->refId = 0;
|
|
||||||
|
|
||||||
if (taosSetSockOpt(pSocket, SOL_SOCKET, SO_SNDBUF, (void *)&bufSize, sizeof(bufSize)) != 0) {
|
|
||||||
uError("failed to set the send buffer size for UDP socket\n");
|
|
||||||
taosCloseSocket(&pSocket);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (taosSetSockOpt(pSocket, SOL_SOCKET, SO_RCVBUF, (void *)&bufSize, sizeof(bufSize)) != 0) {
|
|
||||||
uError("failed to set the receive buffer size for UDP socket\n");
|
|
||||||
taosCloseSocket(&pSocket);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
serverAddr.sin_family = AF_INET;
|
|
||||||
serverAddr.sin_port = htons(info->port);
|
|
||||||
serverAddr.sin_addr.s_addr = info->hostIp;
|
|
||||||
|
|
||||||
struct in_addr ipStr;
|
|
||||||
memcpy(&ipStr, &info->hostIp, 4);
|
|
||||||
sprintf(buffer, "client send udp pkg to %s:%d, content: 1122334455", taosInetNtoa(ipStr), info->port);
|
|
||||||
sprintf(buffer + info->pktLen - 16, "1122334455667788");
|
|
||||||
|
|
||||||
socklen_t sin_size = sizeof(*(struct sockaddr *)&serverAddr);
|
|
||||||
|
|
||||||
iDataNum = taosSendto(pSocket, buffer, info->pktLen, 0, (struct sockaddr *)&serverAddr, (int32_t)sin_size);
|
|
||||||
if (iDataNum < 0 || iDataNum != info->pktLen) {
|
|
||||||
uError("UDP: failed to perform sendto func since %s", strerror(errno));
|
|
||||||
taosCloseSocket(&pSocket);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
memset(buffer, 0, BUFFER_SIZE);
|
|
||||||
sin_size = sizeof(*(struct sockaddr *)&serverAddr);
|
|
||||||
iDataNum = recvfrom(clientSocket, buffer, BUFFER_SIZE, 0, (struct sockaddr *)&serverAddr, &sin_size);
|
|
||||||
|
|
||||||
if (iDataNum < 0 || iDataNum != info->pktLen) {
|
|
||||||
uError("UDP: received ack:%d bytes(expect:%d) from port:%d since %s", iDataNum, info->pktLen, info->port, strerror(errno));
|
|
||||||
taosCloseSocket(&pSocket);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
taosCloseSocket(&pSocket);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void taosNetCheckPort(uint32_t hostIp, int32_t startPort, int32_t endPort, int32_t pktLen) {
|
|
||||||
int32_t ret;
|
|
||||||
STestInfo info;
|
|
||||||
|
|
||||||
memset(&info, 0, sizeof(STestInfo));
|
|
||||||
info.hostIp = hostIp;
|
|
||||||
info.pktLen = pktLen;
|
|
||||||
|
|
||||||
for (int32_t port = startPort; port <= endPort; port++) {
|
|
||||||
info.port = port;
|
|
||||||
ret = taosNetCheckTcpPort(&info);
|
|
||||||
if (ret != 0) {
|
|
||||||
printf("failed to test TCP port:%d\n", port);
|
|
||||||
} else {
|
|
||||||
printf("successed to test TCP port:%d\n", port);
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = taosNetCheckUdpPort(&info);
|
|
||||||
if (ret != 0) {
|
|
||||||
printf("failed to test UDP port:%d\n", port);
|
|
||||||
} else {
|
|
||||||
printf("successed to test UDP port:%d\n", port);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void taosNetTestClient(char *host, int32_t startPort, int32_t pkgLen) {
|
|
||||||
uInfo("work as client, host:%s Port:%d pkgLen:%d\n", host, startPort, pkgLen);
|
|
||||||
|
|
||||||
uint32_t serverIp = taosGetIpv4FromFqdn(host);
|
|
||||||
if (serverIp == 0xFFFFFFFF) {
|
|
||||||
uError("failed to resolve fqdn:%s", host);
|
|
||||||
exit(-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
uInfo("server ip:%s is resolved from host:%s", taosIpStr(serverIp), host);
|
|
||||||
taosNetCheckPort(serverIp, startPort, startPort, pkgLen);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void taosNetTestServer(char *host, int32_t startPort, int32_t pkgLen) {
|
|
||||||
uInfo("work as server, host:%s Port:%d pkgLen:%d\n", host, startPort, pkgLen);
|
|
||||||
|
|
||||||
int32_t port = startPort;
|
|
||||||
int32_t num = 1;
|
|
||||||
if (num < 0) num = 1;
|
|
||||||
|
|
||||||
TdThread *pids = taosMemoryMalloc(2 * num * sizeof(TdThread));
|
|
||||||
STestInfo *tinfos = taosMemoryMalloc(num * sizeof(STestInfo));
|
|
||||||
STestInfo *uinfos = taosMemoryMalloc(num * sizeof(STestInfo));
|
|
||||||
|
|
||||||
for (int32_t i = 0; i < num; i++) {
|
|
||||||
STestInfo *tcpInfo = tinfos + i;
|
|
||||||
tcpInfo->port = port + i;
|
|
||||||
tcpInfo->pktLen = pkgLen;
|
|
||||||
|
|
||||||
if (taosThreadCreate(pids + i, NULL, taosNetBindTcpPort, tcpInfo) != 0) {
|
|
||||||
uInfo("failed to create TCP test thread, %s:%d", tcpInfo->hostFqdn, tcpInfo->port);
|
|
||||||
exit(-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
STestInfo *udpInfo = uinfos + i;
|
|
||||||
udpInfo->port = port + i;
|
|
||||||
tcpInfo->pktLen = pkgLen;
|
|
||||||
if (taosThreadCreate(pids + num + i, NULL, taosNetBindUdpPort, udpInfo) != 0) {
|
|
||||||
uInfo("failed to create UDP test thread, %s:%d", tcpInfo->hostFqdn, tcpInfo->port);
|
|
||||||
exit(-1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int32_t i = 0; i < num; i++) {
|
|
||||||
taosThreadJoin(pids[i], NULL);
|
|
||||||
taosThreadJoin(pids[(num + i)], NULL);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void taosNetCheckSpeed(char *host, int32_t port, int32_t pkgLen,
|
|
||||||
int32_t pkgNum, char *pkgType) {
|
|
||||||
#if 0
|
|
||||||
|
|
||||||
// record config
|
|
||||||
int32_t compressTmp = tsCompressMsgSize;
|
|
||||||
int32_t maxUdpSize = tsRpcMaxUdpSize;
|
|
||||||
int32_t forceTcp = tsRpcForceTcp;
|
|
||||||
|
|
||||||
if (0 == strcmp("tcp", pkgType)){
|
|
||||||
tsRpcForceTcp = 1;
|
|
||||||
tsRpcMaxUdpSize = 0; // force tcp
|
|
||||||
} else {
|
|
||||||
tsRpcForceTcp = 0;
|
|
||||||
tsRpcMaxUdpSize = INT_MAX;
|
|
||||||
}
|
|
||||||
tsCompressMsgSize = -1;
|
|
||||||
|
|
||||||
SEpSet epSet;
|
|
||||||
SRpcMsg reqMsg;
|
|
||||||
SRpcMsg rspMsg;
|
|
||||||
void * pRpcConn;
|
|
||||||
char secretEncrypt[32] = {0};
|
|
||||||
char spi = 0;
|
|
||||||
pRpcConn = taosNetInitRpc(secretEncrypt, spi);
|
|
||||||
if (NULL == pRpcConn) {
|
|
||||||
uError("failed to init client rpc");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
printf("check net spend, host:%s port:%d pkgLen:%d pkgNum:%d pkgType:%s\n\n", host, port, pkgLen, pkgNum, pkgType);
|
|
||||||
int32_t totalSucc = 0;
|
|
||||||
uint64_t startT = taosGetTimestampUs();
|
|
||||||
for (int32_t i = 1; i <= pkgNum; i++) {
|
|
||||||
uint64_t startTime = taosGetTimestampUs();
|
|
||||||
|
|
||||||
memset(&epSet, 0, sizeof(SEpSet));
|
|
||||||
strcpy(epSet.eps[0].fqdn, host);
|
|
||||||
epSet.eps[0].port = port;
|
|
||||||
epSet.numOfEps = 1;
|
|
||||||
|
|
||||||
reqMsg.msgType = TDMT_DND_NETWORK_TEST;
|
|
||||||
reqMsg.pCont = rpcMallocCont(pkgLen);
|
|
||||||
reqMsg.contLen = pkgLen;
|
|
||||||
reqMsg.code = 0;
|
|
||||||
reqMsg.handle = NULL; // rpc handle returned to app
|
|
||||||
reqMsg.ahandle = NULL; // app handle set by client
|
|
||||||
strcpy(reqMsg.pCont, "nettest speed");
|
|
||||||
|
|
||||||
rpcSendRecv(pRpcConn, &epSet, &reqMsg, &rspMsg);
|
|
||||||
|
|
||||||
int code = 0;
|
|
||||||
if ((rspMsg.code != 0) || (rspMsg.msgType != TDMT_DND_NETWORK_TEST + 1)) {
|
|
||||||
uError("ret code 0x%x %s", rspMsg.code, tstrerror(rspMsg.code));
|
|
||||||
code = -1;
|
|
||||||
}else{
|
|
||||||
totalSucc ++;
|
|
||||||
}
|
|
||||||
|
|
||||||
rpcFreeCont(rspMsg.pCont);
|
|
||||||
|
|
||||||
uint64_t endTime = taosGetTimestampUs();
|
|
||||||
uint64_t el = endTime - startTime;
|
|
||||||
printf("progress:%5d/%d\tstatus:%d\tcost:%8.2lf ms\tspeed:%8.2lf MB/s\n", i, pkgNum, code, el/1000.0, pkgLen/(el/1000000.0)/1024.0/1024.0);
|
|
||||||
}
|
|
||||||
int64_t endT = taosGetTimestampUs();
|
|
||||||
uint64_t elT = endT - startT;
|
|
||||||
printf("\ntotal succ:%5d/%d\tcost:%8.2lf ms\tspeed:%8.2lf MB/s\n", totalSucc, pkgNum, elT/1000.0, pkgLen/(elT/1000000.0)/1024.0/1024.0*totalSucc);
|
|
||||||
|
|
||||||
rpcClose(pRpcConn);
|
|
||||||
|
|
||||||
// return config
|
|
||||||
tsCompressMsgSize = compressTmp;
|
|
||||||
tsRpcMaxUdpSize = maxUdpSize;
|
|
||||||
tsRpcForceTcp = forceTcp;
|
|
||||||
return;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void taosNetTest(char *role, char *host, int32_t port, int32_t pkgLen, int32_t pkgNum, char *pkgType) {
|
|
||||||
tsLogEmbedded = 1;
|
|
||||||
if (host == NULL) host = tsLocalFqdn;
|
|
||||||
if (port == 0) port = tsServerPort;
|
|
||||||
if (0 == strcmp("speed", role)) {
|
|
||||||
if (pkgLen <= MIN_SPEED_PKG_LEN) pkgLen = MIN_SPEED_PKG_LEN;
|
|
||||||
if (pkgLen > MAX_SPEED_PKG_LEN) pkgLen = MAX_SPEED_PKG_LEN;
|
|
||||||
if (pkgNum <= MIN_SPEED_PKG_NUM) pkgNum = MIN_SPEED_PKG_NUM;
|
|
||||||
if (pkgNum > MAX_SPEED_PKG_NUM) pkgNum = MAX_SPEED_PKG_NUM;
|
|
||||||
} else {
|
|
||||||
if (pkgLen <= 10) pkgLen = 1000;
|
|
||||||
if (pkgLen > MAX_PKG_LEN) pkgLen = MAX_PKG_LEN;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (0 == strcmp("client", role)) {
|
|
||||||
taosNetTestClient(host, port, pkgLen);
|
|
||||||
} else if (0 == strcmp("server", role)) {
|
|
||||||
taosNetTestServer(host, port, pkgLen);
|
|
||||||
} else if (0 == strcmp("speed", role)) {
|
|
||||||
tsLogEmbedded = 0;
|
|
||||||
char type[10] = {0};
|
|
||||||
taosNetCheckSpeed(host, port, pkgLen, pkgNum, strtolower(type, pkgType));
|
|
||||||
} else {
|
|
||||||
TASSERT(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
tsLogEmbedded = 0;
|
|
||||||
}
|
|
Loading…
Reference in New Issue