提交 d2d51961 编写于 作者: S Shengliang Guan

refactor(tools): refact shell codes

上级 2d94f8a8
......@@ -31,19 +31,19 @@ extern "C" {
typedef struct TdCmd *TdCmdPtr;
TdCmdPtr taosOpenCmd(const char *cmd);
int64_t taosGetLineCmd(TdCmdPtr pCmd, char ** __restrict ptrBuf);
TdCmdPtr taosOpenCmd(const char* cmd);
int64_t taosGetLineCmd(TdCmdPtr pCmd, char** __restrict ptrBuf);
int32_t taosEOFCmd(TdCmdPtr pCmd);
int64_t taosCloseCmd(TdCmdPtr *ppCmd);
int64_t taosCloseCmd(TdCmdPtr* ppCmd);
void* taosLoadDll(const char* filename);
void* taosLoadSym(void* handle, char* name);
void taosCloseDll(void* handle);
int32_t taosSetConsoleEcho(bool on);
void setTerminalMode();
int32_t getOldTerminalMode();
void resetTerminalMode();
void taosSetTerminalMode();
int32_t taosGetOldTerminalMode();
void taosResetTerminalMode();
#ifdef __cplusplus
}
......
......@@ -76,8 +76,6 @@ extern const int32_t TYPE_BYTES[15];
#define TSDB_DEFAULT_PASS "taosdata"
#endif
#define SHELL_MAX_PASSWORD_LEN 20
#define TSDB_TRUE 1
#define TSDB_FALSE 0
#define TSDB_OK 0
......
......@@ -119,7 +119,7 @@ int taosSetConsoleEcho(bool on) {
#endif
}
void setTerminalMode() {
void taosSetTerminalMode() {
#if defined(WINDOWS)
#else
......@@ -152,7 +152,7 @@ void setTerminalMode() {
#endif
}
int32_t getOldTerminalMode() {
int32_t taosGetOldTerminalMode() {
#if defined(WINDOWS)
#else
......@@ -170,7 +170,7 @@ int32_t getOldTerminalMode() {
#endif
}
void resetTerminalMode() {
void taosResetTerminalMode() {
#if defined(WINDOWS)
#else
......
/*
* 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 "shellInt.h"
#define LEFT 1
#define RIGHT 2
#define UP 3
#define DOWN 4
typedef struct {
char *buffer;
char *command;
unsigned commandSize;
unsigned bufferSize;
unsigned cursorOffset;
unsigned screenOffset;
unsigned endOffset;
} Command;
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 /*_TD_SHELL_COMMAND_H_*/
......@@ -19,34 +19,37 @@
#include "os.h"
#include "taos.h"
#include "taosdef.h"
#include "taoserror.h"
#include "tconfig.h"
#include "tglobal.h"
#include "ttypes.h"
#include "tutil.h"
#include <regex.h>
#include <wordexp.h>
#define MAX_HISTORY_SIZE 1000
#define MAX_COMMAND_SIZE 1048586
#define HISTORY_FILE ".taos_history"
#define DEFAULT_RES_SHOW_NUM 100
#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
typedef struct {
char* hist[MAX_HISTORY_SIZE];
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* password;
const char* user;
const char* auth;
const char* database;
const char* file;
const char* cfgdir;
const char* commands;
const char* netrole;
char password[TSDB_USET_PASSWORD_LEN];
bool is_gen_auth;
bool is_raw_time;
bool is_client;
bool is_server;
bool is_version;
bool is_dump_config;
bool is_check;
......@@ -55,38 +58,51 @@ typedef struct {
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[]);
int32_t shellInit();
void shellCleanup(void* arg);
void shellExit();
void* shellThreadLoop(void* arg);
void shellPrintError(TAOS_RES* tres, int64_t st);
int32_t shellRegexMatch(const char* s, const char* reg, int32_t cflags);
void shellGetGrantInfo();
void shellReadHistory();
void shellWriteHistory();
void shellHistoryPath(char* history);
// shellCommand.c
int32_t shellReadCommand(char* command);
// shellEngine.c
int32_t shellExecute();
// shellUtil.c
int32_t shellCheckIntSize();
void shellPrintVersion();
void shellGenerateAuth();
void shellDumpConfig();
void shellCheckServerStatus();
bool shellRegexMatch(const char* s, const char* reg, int32_t cflags);
int32_t shellReadCommand(char command[]);
int32_t shellRunCommand(char* command);
void shellRunCommandImp(char command[]);
void shellSourceFile(TAOS* con, char* fptr);
int32_t shellDumpResult(TAOS_RES* con, char* fname, int32_t* error_no, bool printMode);
// shellNettest.c
void shellTestNetWork();
extern char PROMPT_HEADER[];
extern char CONTINUE_PROMPT[];
extern int32_t prompt_size;
// shellMain.c
extern SShellObj shell;
extern void taos_init();
#endif /*_TD_SHELL_INT_H_*/
/*
* 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 "shellInt.h"
#include "shellCommand.h"
#include "tbase64.h"
#include "tscLog.h"
#define OPT_ABORT 1 /* �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 shellParseArgs(int argc, char *argv[], SShellArgs *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
shellWriteHistory();
shellExit();
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 *shellThreadLoop(void *arg) {
if (indicator) {
getOldTerminalMode();
indicator = 0;
}
TAOS *con = (TAOS *)arg;
setThreadName("shellThreadLoop");
taosThreadCleanupPush(shellCleanup, 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);
shellExit();
taosThreadCleanupPop(1);
return NULL;
}
void shellHistoryPath(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 shellCleanup(void *arg) { resetTerminalMode(); }
void shellExit() {
resetTerminalMode();
exit(EXIT_SUCCESS);
}
/*******************************************************************
* 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
*
* ****************************************************************/
/*
* 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 <assert.h>
#include <regex.h>
#include <stdio.h>
#include "../../../../include/client/taos.h"
#include "os.h"
#include "shellInt.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() {
#if defined(_TD_WINDOWS_64) || defined(_TD_WINDOWS_32) || defined(_TD_DARWIN_64)
void shellPrintHelp() {
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\n", indent, "-p");
printf("%s%s%s\n", indent, indent, "The password 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, "-A");
printf("%s%s%s\n", indent, indent, "Generate auth string from password.");
printf("%s%s\n", indent, "-c");
printf("%s%s%s\n", indent, indent, "Configuration directory.");
printf("%s%s\n", indent, "-C");
......@@ -52,27 +43,24 @@ void printHelp() {
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, "-k");
printf("%s%s%s\n", indent, indent, "Check the service status.");
printf("%s%s\n", indent, "-t");
printf("%s%s%s\n", indent, indent, "Time zone of the shell, default is local.");
printf("%s%s%s\n", indent, indent, "Check the details of the service status.");
printf("%s%s\n", indent, "-w");
printf("%s%s%s\n", indent, indent, "Set the default binary display width.");
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%s\n", indent, indent, "Net role when network connectivity test, options: client|server.");
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 shellParseArgs(int argc, char *argv[], SShellArgs *arguments) {
void shellParseArgsInWindows(int argc, char *argv[]) {
for (int i = 1; i < argc; i++) {
// for host
if (strcmp(argv[i], "-h") == 0) {
if (i < argc - 1) {
arguments->host = argv[++i];
......@@ -80,67 +68,40 @@ void shellParseArgs(int argc, char *argv[], SShellArgs *arguments) {
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) {
} 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) {
} 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) {
} else if ((strncmp(argv[i], "-p", 2) == 0) || (strncmp(argv[i], "--password", 10) == 0)) {
continue;
} else if (strcmp(argv[i], "-a") == 0) {
if (i < argc - 1) {
arguments->auth = argv[++i];
} else {
fprintf(stderr, "option -A requires an argument\n");
fprintf(stderr, "option -a requires an argument\n");
exit(EXIT_FAILURE);
}
} else if (strcmp(argv[i], "-A") == 0) {
arguments->is_gen_auth = true;
} 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);
arguments->cfgdir = argv[++i];
} else {
fprintf(stderr, "Option -c requires an argument\n");
exit(EXIT_FAILURE);
}
} else if (strcmp(argv[i], "-C") == 0) {
arguments->dump_config = true;
arguments->is_dump_config = true;
} else if (strcmp(argv[i], "-s") == 0) {
if (i < argc - 1) {
arguments->commands = argv[++i];
......@@ -150,176 +111,238 @@ void shellParseArgs(int argc, char *argv[], SShellArgs *arguments) {
}
} 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) {
} 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) {
} 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) {
} else if (strcmp(argv[i], "-k") == 0) {
arguments->is_check = true;
} else if (strcmp(argv[i], "-t") == 0) {
arguments->is_startup = true;
} else if (strcmp(argv[i], "-w") == 0) {
if (i < argc - 1) {
arguments->timezone = argv[++i];
arguments->displayWidth = argv[++i];
} else {
fprintf(stderr, "option -t requires an argument\n");
fprintf(stderr, "option -w requires an argument\n");
exit(EXIT_FAILURE);
}
}
else if (strcmp(argv[i], "-n") == 0) {
} 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) {
} 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) {
} 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) {
} 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 if (strcmp(argv[i], "-V") == 0) {
arguments->is_version = true;
} else if (strcmp(argv[i], "--help") == 0) {
arguments->is_help = true;
} else {
fprintf(stderr, "wrong options\n");
printHelp();
exit(EXIT_FAILURE);
arguments->is_help = true;
}
}
}
void shellPrintContinuePrompt() { printf("%s", CONTINUE_PROMPT); }
#else
void shellPrintPrompt() { printf("%s", PROMPT_HEADER); }
#include <argp.h>
#include <termio.h>
const char *argp_program_version = version;
const char *argp_program_bug_address = "<support@taosdata.com>";
void updateBuffer(Command *cmd) {
if (shellRegexMatch(cmd->buffer, "(\\s+$)|(^$)", REG_EXTENDED)) strcat(cmd->command, " ");
strcat(cmd->buffer, cmd->command);
static struct argp_option shellOptions[] = {
{"host", 'h', "HOST", 0, "TDengine server FQDN to connect. The default host is localhost."},
{"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."},
{"password", 'p', "PASSWORD", 0, "The password to use when connecting to the server."},
{"auth", 'a', "AUTH", 0, "The auth string to use when connecting to the server."},
{"generate-auth", 'A', 0, 0, "Generate auth string from password."},
{"config-dir", 'c', "CONFIG_DIR", 0, "Configuration directory."},
{"dump-config", 'C', 0, 0, "Dump configuration."},
{"commands", 's', "COMMANDS", 0, "Commands to run without enter the shell."},
{"raw-time", 'r', 0, 0, "Output time as uint64_t."},
{"file", 'f', "FILE", 0, "Script to run without enter the shell."},
{"database", 'd', "DATABASE", 0, "Database to use when connecting to the server."},
{"check", 'k', 0, 0, "Check the service status."},
{"startup", 't', 0, 0, "Check the details of the service status."},
{"display-width", 'w', 0, 0, "Set the default binary display width."},
{"netrole", 'n', "NETROLE", 0, "Net role when network connectivity test, options: client|server."},
{"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."},
{"version", 'V', 0, 0, "Print client version number."},
{0},
};
memset(cmd->command, 0, MAX_COMMAND_SIZE);
cmd->cursorOffset = 0;
}
static error_t shellParseOpt(int32_t key, char *arg, struct argp_state *state) {
SShellArgs *arguments = &shell.args;
wordexp_t full_path = {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 (shellRegexMatch(total, reg_str, REG_EXTENDED | REG_ICASE)) {
taosMemoryFree(total);
return 1;
switch (key) {
case 'h':
arguments->host = arg;
break;
case 'P':
arguments->port = atoi(arg);
break;
case 'u':
arguments->user = arg;
break;
case 'p':
break;
case 'a':
arguments->auth = arg;
break;
case 'A':
arguments->is_gen_auth = true;
break;
case 'c':
arguments->cfgdir = arg;
break;
case 'C':
arguments->is_dump_config = true;
break;
case 's':
arguments->commands = arg;
break;
case 'r':
arguments->is_raw_time = true;
break;
case 'f':
arguments->file = arg;
break;
case 'd':
arguments->database = arg;
break;
case 'k':
arguments->is_check = true;
break;
case 't':
arguments->is_startup = true;
break;
case 'w':
arguments->displayWidth = atoi(arg);
break;
case 'n':
arguments->netrole = arg;
break;
case 'l':
arguments->pktLen = atoi(arg);
break;
case 'N':
arguments->pktNum = atoi(arg);
break;
case 'V':
arguments->is_version = true;
break;
case 1:
arguments->abort = 1;
break;
default:
return ARGP_ERR_UNKNOWN;
}
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;
}
static struct argp shellArgp = {shellOptions, shellParseOpt, "", ""};
cmd->command[cmd->cursorOffset++] = c;
static void shellParseArgsInLinux(int argc, char *argv[]) {
argp_program_version = shell.info.programVersion;
argp_parse(&shellArgp, argc, argv, 0, 0, NULL);
}
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);
#endif
// 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;
static void shellInitArgs(int argc, char *argv[]) {
for (int i = 1; i < argc; i++) {
if ((strncmp(argv[i], "-p", 2) == 0) || (strncmp(argv[i], "--password", 10) == 0)) {
printf(shell.info.clientVersion, tsOsName, taos_get_client_info());
if ((strlen(argv[i]) == 2) || (strncmp(argv[i], "--password", 10) == 0)) {
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 {
shellPrintContinuePrompt();
updateBuffer(&cmd);
tstrncpy(shell.args.password, (char *)(argv[i] + 2), sizeof(shell.args.password));
strcpy(argv[i], "-p");
}
break;
default:
insertChar(&cmd, c);
}
}
if (strlen(shell.args.password) == 0) {
tstrncpy(shell.args.password, TSDB_DEFAULT_PASS, sizeof(shell.args.password));
}
return 0;
shell.args.pktLen = 1024;
shell.args.pktNum = 100;
shell.args.displayWidth = SHELL_DEFAULT_MAX_BINARY_DISPLAY_WIDTH;
shell.args.user = TSDB_DEFAULT_USER;
}
void *shellThreadLoop(void *arg) {
TAOS *con = (TAOS *)arg;
char *command = taosMemoryMalloc(MAX_COMMAND_SIZE);
if (command == NULL) return NULL;
static int32_t shellCheckArgs() { return 0; }
int32_t err = 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\n", version);
do {
memset(command, 0, MAX_COMMAND_SIZE);
shellPrintPrompt();
#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);
shellParseArgsInLinuxAndDarwin();
#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);
shellParseArgsInLinuxAndDarwin();
#else
shell.info.osname = "Linux";
snprintf(shell.history.file, TSDB_FILENAME_LEN, "%s/%s", getenv("HOME"), SHELL_HISTORY_FILE);
shellParseArgsInLinux(argc, argv);
#endif
// Read command from shell.
err = shellReadCommand(con, command);
if (err) {
break;
if (shell.args.abort) {
return -1;
}
} while (shellRunCommand(con, command) == 0);
return NULL;
return shellCheckArgs();
}
void shellHistoryPath(char *history) { sprintf(history, "C:/TDengine/%s", HISTORY_FILE); }
void shellExit() { exit(EXIT_SUCCESS); }
......@@ -14,21 +14,122 @@
*/
#define __USE_XOPEN
#include "shellCommand.h"
#include "os.h"
#include "shellInt.h"
#define LEFT 1
#define RIGHT 2
#define UP 3
#define DOWN 4
#define PSIZE shell.info.promptSize
typedef struct {
char widthInString;
char widthOnScreen;
} UTFCodeInfo;
char *buffer;
char *command;
uint32_t commandSize;
uint32_t bufferSize;
uint32_t cursorOffset;
uint32_t screenOffset;
uint32_t endOffset;
} SShellCmd;
static int32_t shellCountPrefixOnes(uint8_t c);
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;
}
int countPrefixOnes(unsigned char c) {
unsigned char mask = 127;
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;
int ret = 0;
int32_t ret = 0;
while ((c & mask) != 0) {
ret++;
c <<= 1;
......@@ -37,7 +138,7 @@ int countPrefixOnes(unsigned char c) {
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);
TdWchar wc;
......@@ -47,16 +148,16 @@ void getPrevCharSize(const char *str, int pos, int *size, int *width) {
while (--pos >= 0) {
*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);
*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);
TdWchar wc;
......@@ -64,13 +165,13 @@ void getNextCharSize(const char *str, int pos, int *size, int *width) {
*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);
TdWchar wc;
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 */
memmove(cmd->command + cmd->cursorOffset + size, cmd->command + cmd->cursorOffset,
cmd->commandSize - cmd->cursorOffset);
......@@ -80,122 +181,122 @@ void insertChar(Command *cmd, char *c, int size) {
cmd->cursorOffset += size;
cmd->screenOffset += 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);
if (cmd->cursorOffset > 0) {
clearScreen(cmd->endOffset + prompt_size, cmd->screenOffset + prompt_size);
int size = 0;
int width = 0;
getPrevCharSize(cmd->command, cmd->cursorOffset, &size, &width);
shellClearScreen(cmd->endOffset + PSIZE, cmd->screenOffset + PSIZE);
int32_t size = 0;
int32_t width = 0;
shellGetPrevCharSize(cmd->command, cmd->cursorOffset, &size, &width);
memmove(cmd->command + cmd->cursorOffset - size, cmd->command + cmd->cursorOffset,
cmd->commandSize - cmd->cursorOffset);
cmd->commandSize -= size;
cmd->cursorOffset -= size;
cmd->screenOffset -= 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);
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);
cmd->commandSize -= cmd->cursorOffset;
cmd->cursorOffset = 0;
cmd->screenOffset = 0;
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);
clearScreen(cmd->endOffset + prompt_size, cmd->screenOffset + prompt_size);
shellClearScreen(cmd->endOffset + PSIZE, cmd->screenOffset + PSIZE);
cmd->commandSize -= 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);
if (cmd->cursorOffset < cmd->commandSize) {
clearScreen(cmd->endOffset + prompt_size, cmd->screenOffset + prompt_size);
int size = 0;
int width = 0;
getNextCharSize(cmd->command, cmd->cursorOffset, &size, &width);
shellClearScreen(cmd->endOffset + PSIZE, cmd->screenOffset + PSIZE);
int32_t size = 0;
int32_t width = 0;
shellGetNextCharSize(cmd->command, cmd->cursorOffset, &size, &width);
memmove(cmd->command + cmd->cursorOffset, cmd->command + cmd->cursorOffset + size,
cmd->commandSize - cmd->cursorOffset - size);
cmd->commandSize -= size;
cmd->endOffset -= width;
showOnScreen(cmd);
shellShowOnScreen(cmd);
}
}
void moveCursorLeft(Command *cmd) {
void shellMoveCursorLeft(SShellCmd *cmd) {
assert(cmd->cursorOffset <= cmd->commandSize && cmd->endOffset >= cmd->screenOffset);
if (cmd->cursorOffset > 0) {
clearScreen(cmd->endOffset + prompt_size, cmd->screenOffset + prompt_size);
int size = 0;
int width = 0;
getPrevCharSize(cmd->command, cmd->cursorOffset, &size, &width);
shellClearScreen(cmd->endOffset + PSIZE, cmd->screenOffset + PSIZE);
int32_t size = 0;
int32_t width = 0;
shellGetPrevCharSize(cmd->command, cmd->cursorOffset, &size, &width);
cmd->cursorOffset -= size;
cmd->screenOffset -= width;
showOnScreen(cmd);
shellShowOnScreen(cmd);
}
}
void moveCursorRight(Command *cmd) {
void shellMoveCursorRight(SShellCmd *cmd) {
assert(cmd->cursorOffset <= cmd->commandSize && cmd->endOffset >= cmd->screenOffset);
if (cmd->cursorOffset < cmd->commandSize) {
clearScreen(cmd->endOffset + prompt_size, cmd->screenOffset + prompt_size);
int size = 0;
int width = 0;
getNextCharSize(cmd->command, cmd->cursorOffset, &size, &width);
shellClearScreen(cmd->endOffset + PSIZE, cmd->screenOffset + PSIZE);
int32_t size = 0;
int32_t width = 0;
shellGetNextCharSize(cmd->command, cmd->cursorOffset, &size, &width);
cmd->cursorOffset += size;
cmd->screenOffset += width;
showOnScreen(cmd);
shellShowOnScreen(cmd);
}
}
void positionCursorHome(Command *cmd) {
void shellPositionCursorHome(SShellCmd *cmd) {
assert(cmd->cursorOffset <= cmd->commandSize && cmd->endOffset >= cmd->screenOffset);
if (cmd->cursorOffset > 0) {
clearScreen(cmd->endOffset + prompt_size, cmd->screenOffset + prompt_size);
shellClearScreen(cmd->endOffset + PSIZE, cmd->screenOffset + PSIZE);
cmd->cursorOffset = 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);
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->screenOffset = cmd->endOffset;
showOnScreen(cmd);
shellShowOnScreen(cmd);
}
}
void printChar(char c, int times) {
for (int i = 0; i < times; i++) {
void shellPrintChar(char c, int32_t times) {
for (int32_t i = 0; i < times; i++) {
fprintf(stdout, "%c", c);
}
fflush(stdout);
}
void positionCursor(int step, int direction) {
void shellPositionCursor(int32_t step, int32_t direction) {
if (step > 0) {
if (direction == LEFT) {
fprintf(stdout, "\033[%dD", step);
......@@ -210,26 +311,26 @@ void positionCursor(int step, int direction) {
}
}
void updateBuffer(Command *cmd) {
void shellUpdateBuffer(SShellCmd *cmd) {
assert(cmd->cursorOffset <= cmd->commandSize && cmd->endOffset >= cmd->screenOffset);
if (shellRegexMatch(cmd->buffer, "(\\s+$)|(^$)", REG_EXTENDED)) strcat(cmd->command, " ");
strcat(cmd->buffer, cmd->command);
cmd->bufferSize += cmd->commandSize;
memset(cmd->command, 0, MAX_COMMAND_SIZE);
memset(cmd->command, 0, SHELL_MAX_COMMAND_SIZE);
cmd->cursorOffset = 0;
cmd->screenOffset = 0;
cmd->commandSize = 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);
char *total = (char *)taosMemoryCalloc(1, MAX_COMMAND_SIZE);
memset(cmd->command + cmd->commandSize, 0, MAX_COMMAND_SIZE - cmd->commandSize);
char *total = (char *)taosMemoryCalloc(1, SHELL_MAX_COMMAND_SIZE);
memset(cmd->command + cmd->commandSize, 0, SHELL_MAX_COMMAND_SIZE - cmd->commandSize);
sprintf(total, "%s%s", cmd->buffer, cmd->command);
char *reg_str =
......@@ -244,28 +345,268 @@ int isReadyGo(Command *cmd) {
return 0;
}
void getMbSizeInfo(const char *str, int *size, int *width) {
TdWchar *wc = (TdWchar *)taosMemoryCalloc(sizeof(TdWchar), MAX_COMMAND_SIZE);
void shellGetMbSizeInfo(const char *str, int32_t *size, int32_t *width) {
TdWchar *wc = (TdWchar *)taosMemoryCalloc(sizeof(TdWchar), SHELL_MAX_COMMAND_SIZE);
*size = strlen(str);
taosMbsToWchars(wc, str, MAX_COMMAND_SIZE);
*width = taosWcharsWidth(wc, MAX_COMMAND_SIZE);
taosMbsToWchars(wc, str, SHELL_MAX_COMMAND_SIZE);
*width = taosWcharsWidth(wc, SHELL_MAX_COMMAND_SIZE);
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);
clearScreen(cmd->endOffset + prompt_size, cmd->screenOffset + prompt_size);
memset(cmd->buffer, 0, MAX_COMMAND_SIZE);
memset(cmd->command, 0, MAX_COMMAND_SIZE);
strncpy(cmd->command, s, MAX_COMMAND_SIZE);
int size = 0;
int width = 0;
getMbSizeInfo(s, &size, &width);
shellClearScreen(cmd->endOffset + PSIZE, cmd->screenOffset + PSIZE);
memset(cmd->buffer, 0, SHELL_MAX_COMMAND_SIZE);
memset(cmd->command, 0, SHELL_MAX_COMMAND_SIZE);
strncpy(cmd->command, s, SHELL_MAX_COMMAND_SIZE);
int32_t size = 0;
int32_t width = 0;
shellGetMbSizeInfo(s, &size, &width);
cmd->bufferSize = 0;
cmd->commandSize = size;
cmd->cursorOffset = size;
cmd->screenOffset = 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
\ No newline at end of file
......@@ -17,118 +17,35 @@
#define _GNU_SOURCE
#define _XOPEN_SOURCE
#define _DEFAULT_SOURCE
#include "os.h"
#include "shellInt.h"
#include "shellCommand.h"
#include "taosdef.h"
#include "taoserror.h"
#include "tconfig.h"
#include "tglobal.h"
#include "ttypes.h"
#include "tutil.h"
/**************** Global variables ****************/
#ifdef _TD_POWER_
char CLIENT_VERSION[] =
"Welcome to the PowerDB shell from %s, Client Version:%s\n"
"Copyright (c) 2020 by PowerDB, Inc. All rights reserved.\n\n";
char PROMPT_HEADER[] = "power> ";
char CONTINUE_PROMPT[] = " -> ";
int prompt_size = 7;
#elif (_TD_TQ_ == true)
char CLIENT_VERSION[] =
"Welcome to the TQ shell from %s, Client Version:%s\n"
"Copyright (c) 2020 by TQ, Inc. All rights reserved.\n\n";
char PROMPT_HEADER[] = "tq> ";
char CONTINUE_PROMPT[] = " -> ";
int prompt_size = 4;
#else
char CLIENT_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 PROMPT_HEADER[] = "taos> ";
char CONTINUE_PROMPT[] = " -> ";
int prompt_size = 6;
#endif
int64_t result = 0;
SShellHistory history;
#define DEFAULT_MAX_BINARY_DISPLAY_WIDTH 30
extern int32_t tsMaxBinaryDisplayWidth;
extern TAOS *taos_connect_auth(const char *ip, const char *user, const char *auth, const char *db, uint16_t port);
/*
* FUNCTION: Initialize the shell.
*/
TAOS *shellInit(SShellArgs *_args) {
printf("\n");
if (!_args->is_use_passwd) {
#ifdef TD_WINDOWS
strcpy(tsOsName, "Windows");
#elif defined(TD_DARWIN)
strcpy(tsOsName, "Darwin");
#endif
printf(CLIENT_VERSION, tsOsName, taos_get_client_info());
}
fflush(stdout);
// set options before initializing
if (_args->timezone != NULL) {
taos_options(TSDB_OPTION_TIMEZONE, _args->timezone);
}
if (!_args->is_use_passwd) {
_args->password = TSDB_DEFAULT_PASS;
}
if (_args->user == NULL) {
_args->user = TSDB_DEFAULT_USER;
}
// Connect to the database.
TAOS *con = NULL;
if (_args->auth == NULL) {
con = taos_connect(_args->host, _args->user, _args->password, _args->database, _args->port);
} else {
con = taos_connect_auth(_args->host, _args->user, _args->auth, _args->database, _args->port);
}
if (con == NULL) {
fflush(stdout);
return con;
}
/* Read history TODO : release resources here*/
shellReadHistory();
// Check if it is temperory run
if (_args->commands != NULL || _args->file[0] != 0) {
if (_args->commands != NULL) {
printf("%s%s\n", PROMPT_HEADER, _args->commands);
shellRunCommand(con, _args->commands);
}
if (_args->file[0] != 0) {
shellSourceFile(con, _args->file);
}
taos_close(con);
shellWriteHistory();
exit(EXIT_SUCCESS);
}
return con;
}
static bool isEmptyCommand(const char *cmd) {
static bool shellIsEmptyCommand(const char *cmd);
static int32_t shellRunSingleCommand(char *command);
static int32_t shellRunCommand(char *command);
static void shellRunSingleCommandImp(char *command);
static char *shellFormatTimestamp(char *buf, int64_t val, int32_t precision);
static void shellDumpFieldToFile(TdFilePtr pFile, const char *val, TAOS_FIELD *field, int32_t length,
int32_t precision);
static int32_t shellDumpResultToFile(const char *fname, TAOS_RES *tres);
static void shellPrintNChar(const char *str, int32_t length, int32_t width);
static void shellPrintField(const char *val, TAOS_FIELD *field, int32_t width, int32_t length, int32_t precision);
static int32_t shellVerticalPrintResult(TAOS_RES *tres);
static int32_t shellCalcColWidth(TAOS_FIELD *field, int32_t precision);
static void shellPrintHeader(TAOS_FIELD *fields, int32_t *width, int32_t num_fields);
static int32_t shellHorizontalPrintResult(TAOS_RES *tres);
static int32_t shellDumpResult(TAOS_RES *tres, char *fname, int32_t *error_no, bool vertical);
static void shellReadHistory();
static void shellWriteHistory();
static void shellPrintError(TAOS_RES *tres, int64_t st);
static bool shellIsCommentLine(char *line);
static void shellSourceFile(const char *file);
static void shellGetGrantInfo();
static void shellQueryInterruptHandler(int32_t signum, void *sigInfo, void *context);
static void shellCleanup(void *arg);
static void *shellCancelHandler(void *arg);
static void *shellThreadLoop(void *arg);
bool shellIsEmptyCommand(const char *cmd) {
for (char c = *cmd++; c != 0; c = *cmd++) {
if (c != ' ' && c != '\t' && c != ';') {
return false;
......@@ -137,24 +54,17 @@ static bool isEmptyCommand(const char *cmd) {
return true;
}
static int32_t shellRunSingleCommand(TAOS *con, char *command) {
/* If command is empty just return */
if (isEmptyCommand(command)) {
int32_t shellRunSingleCommand(char *command) {
if (shellIsEmptyCommand(command)) {
return 0;
}
// Analyse the command.
if (shellRegexMatch(command, "^[ \t]*(quit|q|exit)[ \t;]*$", REG_EXTENDED | REG_ICASE)) {
taos_close(con);
shellWriteHistory();
#ifdef WINDOWS
exit(EXIT_SUCCESS);
#endif
return -1;
}
if (shellRegexMatch(command, "^[\t ]*clear[ \t;]*$", REG_EXTENDED | REG_ICASE)) {
// If clear the screen.
system("clear");
return 0;
}
......@@ -165,9 +75,9 @@ static int32_t shellRunSingleCommand(TAOS *con, char *command) {
strtok(NULL, " \t");
char *p = strtok(NULL, " \t");
if (strcasecmp(p, "default") == 0) {
tsMaxBinaryDisplayWidth = DEFAULT_MAX_BINARY_DISPLAY_WIDTH;
shell.args.displayWidth = SHELL_DEFAULT_MAX_BINARY_DISPLAY_WIDTH;
} else {
tsMaxBinaryDisplayWidth = atoi(p);
shell.args.displayWidth = atoi(p);
}
return 0;
}
......@@ -178,32 +88,31 @@ static int32_t shellRunSingleCommand(TAOS *con, char *command) {
assert(c_ptr != NULL);
c_ptr = strtok(NULL, " ;");
assert(c_ptr != NULL);
shellSourceFile(con, c_ptr);
shellSourceFile(c_ptr);
return 0;
}
shellRunCommandImp(con, command);
shellRunSingleCommandImp(command);
return 0;
}
int32_t shellRunCommand(TAOS *con, char *command) {
/* If command is empty just return */
if (isEmptyCommand(command)) {
int32_t shellRunCommand(char *command) {
if (shellIsEmptyCommand(command)) {
return 0;
}
/* Update the history vector. */
if (history.hstart == history.hend ||
history.hist[(history.hend + MAX_HISTORY_SIZE - 1) % MAX_HISTORY_SIZE] == NULL ||
strcmp(command, history.hist[(history.hend + MAX_HISTORY_SIZE - 1) % MAX_HISTORY_SIZE]) != 0) {
if (history.hist[history.hend] != NULL) {
taosMemoryFreeClear(history.hist[history.hend]);
SShellHistory *pHistory = &shell.history;
if (pHistory->hstart == pHistory->hend ||
pHistory->hist[(pHistory->hend + SHELL_MAX_HISTORY_SIZE - 1) % SHELL_MAX_HISTORY_SIZE] == NULL ||
strcmp(command, pHistory->hist[(pHistory->hend + SHELL_MAX_HISTORY_SIZE - 1) % SHELL_MAX_HISTORY_SIZE]) != 0) {
if (pHistory->hist[pHistory->hend] != NULL) {
taosMemoryFreeClear(pHistory->hist[pHistory->hend]);
}
history.hist[history.hend] = strdup(command);
pHistory->hist[pHistory->hend] = strdup(command);
history.hend = (history.hend + 1) % MAX_HISTORY_SIZE;
if (history.hend == history.hstart) {
history.hstart = (history.hstart + 1) % MAX_HISTORY_SIZE;
pHistory->hend = (pHistory->hend + 1) % SHELL_MAX_HISTORY_SIZE;
if (pHistory->hend == pHistory->hstart) {
pHistory->hstart = (pHistory->hstart + 1) % SHELL_MAX_HISTORY_SIZE;
}
}
......@@ -255,7 +164,7 @@ int32_t shellRunCommand(TAOS *con, char *command) {
if (c == ';' && quote == 0) {
c = *p;
*p = 0;
if (shellRunSingleCommand(con, cmd) < 0) {
if (shellRunSingleCommand(cmd) < 0) {
return -1;
}
*p = c;
......@@ -264,20 +173,10 @@ int32_t shellRunCommand(TAOS *con, char *command) {
}
*p = 0;
return shellRunSingleCommand(con, cmd);
}
void freeResultWithRid(int64_t rid) {
#if 0
SSqlObj* pSql = taosAcquireRef(tscObjRef, rid);
if(pSql){
taos_free_result(pSql);
taosReleaseRef(tscObjRef, rid);
}
#endif
return shellRunSingleCommand(cmd);
}
void shellRunCommandImp(TAOS *con, char command[]) {
void shellRunSingleCommandImp(char *command) {
int64_t st, et;
wordexp_t full_path;
char *sptr = NULL;
......@@ -291,12 +190,8 @@ void shellRunCommandImp(TAOS *con, char command[]) {
*cptr = '\0';
}
if (wordexp(sptr + 2, &full_path, 0) != 0) {
fprintf(stderr, "ERROR: invalid filename: %s\n", sptr + 2);
return;
}
fname = sptr + 2;
*sptr = '\0';
fname = full_path.we_wordv[0];
}
if ((sptr = strstr(command, "\\G")) != NULL) {
......@@ -311,20 +206,19 @@ void shellRunCommandImp(TAOS *con, char command[]) {
st = taosGetTimestampUs();
TAOS_RES *pSql = taos_query(con, command);
TAOS_RES *pSql = taos_query(shell.conn, command);
if (taos_errno(pSql)) {
shellPrintError(pSql, st);
return;
}
int64_t oresult = atomic_load_64(&result);
int64_t oresult = atomic_load_64(&shell.result);
if (shellRegexMatch(command, "^\\s*use\\s+[a-zA-Z0-9_]+\\s*;\\s*$", REG_EXTENDED | REG_ICASE)) {
fprintf(stdout, "Database changed.\n\n");
fflush(stdout);
atomic_store_64(&result, 0);
freeResultWithRid(oresult);
atomic_store_64(&shell.result, 0);
taos_free_result(pSql);
return;
......@@ -332,12 +226,11 @@ void shellRunCommandImp(TAOS *con, char command[]) {
TAOS_FIELD *pFields = taos_fetch_fields(pSql);
if (pFields != NULL) { // select and show kinds of commands
int error_no = 0;
int32_t error_no = 0;
int numOfRows = shellDumpResult(pSql, fname, &error_no, printMode);
int32_t numOfRows = shellDumpResult(pSql, fname, &error_no, printMode);
if (numOfRows < 0) {
atomic_store_64(&result, 0);
freeResultWithRid(oresult);
atomic_store_64(&shell.result, 0);
return;
}
......@@ -349,7 +242,7 @@ void shellRunCommandImp(TAOS *con, char command[]) {
}
taos_free_result(pSql);
} else {
int num_rows_affacted = taos_affected_rows(pSql);
int32_t num_rows_affacted = taos_affected_rows(pSql);
taos_free_result(pSql);
et = taosGetTimestampUs();
printf("Query OK, %d of %d row(s) in database (%.6fs)\n", num_rows_affacted, num_rows_affacted, (et - st) / 1E6);
......@@ -361,41 +254,11 @@ void shellRunCommandImp(TAOS *con, char command[]) {
wordfree(&full_path);
}
atomic_store_64(&result, 0);
freeResultWithRid(oresult);
}
/* Function to do regular expression check */
int shellRegexMatch(const char *s, const char *reg, int cflags) {
regex_t regex;
char msgbuf[100] = {0};
/* Compile regular expression */
if (regcomp(&regex, reg, cflags) != 0) {
fprintf(stderr, "Fail to compile regex");
shellExit();
}
/* Execute regular expression */
int reti = regexec(&regex, s, 0, NULL, 0);
if (!reti) {
regfree(&regex);
return 1;
} else if (reti == REG_NOMATCH) {
regfree(&regex);
return 0;
} else {
regerror(reti, &regex, msgbuf, sizeof(msgbuf));
fprintf(stderr, "Regex match failed: %s\n", msgbuf);
regfree(&regex);
shellExit();
}
return 0;
atomic_store_64(&shell.result, 0);
}
static char *formatTimestamp(char *buf, int64_t val, int precision) {
if (args.is_raw_time) {
char *shellFormatTimestamp(char *buf, int64_t val, int32_t precision) {
if (shell.args.is_raw_time) {
sprintf(buf, "%" PRId64, val);
return buf;
}
......@@ -413,7 +276,8 @@ static char *formatTimestamp(char *buf, int64_t val, int precision) {
ms = val % 1000;
}
/* comment out as it make testcases like select_with_tags.sim fail.
/*
comment out as it make testcases like select_with_tags.sim fail.
but in windows, this may cause the call to localtime crash if tt < 0,
need to find a better solution.
if (tt < 0) {
......@@ -449,7 +313,7 @@ static char *formatTimestamp(char *buf, int64_t val, int precision) {
return buf;
}
static void dumpFieldToFile(TdFilePtr pFile, const char *val, TAOS_FIELD *field, int32_t length, int precision) {
void shellDumpFieldToFile(TdFilePtr pFile, const char *val, TAOS_FIELD *field, int32_t length, int32_t precision) {
if (val == NULL) {
taosFprintfFile(pFile, "%s", TSDB_DATA_NULL_STR);
return;
......@@ -485,7 +349,7 @@ static void dumpFieldToFile(TdFilePtr pFile, const char *val, TAOS_FIELD *field,
taosFprintfFile(pFile, "\'%s\'", buf);
break;
case TSDB_DATA_TYPE_TIMESTAMP:
formatTimestamp(buf, *(int64_t *)val, precision);
shellFormatTimestamp(buf, *(int64_t *)val, precision);
taosFprintfFile(pFile, "'%s'", buf);
break;
default:
......@@ -493,35 +357,23 @@ static void dumpFieldToFile(TdFilePtr pFile, const char *val, TAOS_FIELD *field,
}
}
static int dumpResultToFile(const char *fname, TAOS_RES *tres) {
int32_t shellDumpResultToFile(const char *fname, TAOS_RES *tres) {
TAOS_ROW row = taos_fetch_row(tres);
if (row == NULL) {
return 0;
}
wordexp_t full_path;
if (wordexp((char *)fname, &full_path, 0) != 0) {
fprintf(stderr, "ERROR: invalid file name: %s\n", fname);
return -1;
}
// FILE *fp = fopen(full_path.we_wordv[0], "w");
TdFilePtr pFile =
taosOpenFile(full_path.we_wordv[0], TD_FILE_CREATE | TD_FILE_WRITE | TD_FILE_TRUNC | TD_FILE_STREAM);
TdFilePtr pFile = taosOpenFile(fname, TD_FILE_CREATE | TD_FILE_WRITE | TD_FILE_TRUNC | TD_FILE_STREAM);
if (pFile == NULL) {
fprintf(stderr, "ERROR: failed to open file: %s\n", full_path.we_wordv[0]);
wordfree(&full_path);
fprintf(stderr, "ERROR: failed to open file: %s\n", fname);
return -1;
}
wordfree(&full_path);
int num_fields = taos_num_fields(tres);
TAOS_FIELD *fields = taos_fetch_fields(tres);
int precision = taos_result_precision(tres);
int32_t num_fields = taos_num_fields(tres);
int32_t precision = taos_result_precision(tres);
for (int col = 0; col < num_fields; col++) {
for (int32_t col = 0; col < num_fields; col++) {
if (col > 0) {
taosFprintfFile(pFile, ",");
}
......@@ -529,14 +381,14 @@ static int dumpResultToFile(const char *fname, TAOS_RES *tres) {
}
taosFprintfFile(pFile, "\n");
int numOfRows = 0;
int32_t numOfRows = 0;
do {
int32_t *length = taos_fetch_lengths(tres);
for (int i = 0; i < num_fields; i++) {
for (int32_t i = 0; i < num_fields; i++) {
if (i > 0) {
taosFprintfFile(pFile, "\n");
}
dumpFieldToFile(pFile, (const char *)row[i], fields + i, length[i], precision);
shellDumpFieldToFile(pFile, (const char *)row[i], fields + i, length[i], precision);
}
taosFprintfFile(pFile, "\n");
......@@ -544,19 +396,19 @@ static int dumpResultToFile(const char *fname, TAOS_RES *tres) {
row = taos_fetch_row(tres);
} while (row != NULL);
result = 0;
shell.result = 0;
taosCloseFile(&pFile);
return numOfRows;
}
static void shellPrintNChar(const char *str, int length, int width) {
void shellPrintNChar(const char *str, int32_t length, int32_t width) {
TdWchar tail[3];
int pos = 0, cols = 0, totalCols = 0, tailLen = 0;
int32_t pos = 0, cols = 0, totalCols = 0, tailLen = 0;
while (pos < length) {
TdWchar wc;
int bytes = taosMbToWchar(&wc, str + pos, MB_CUR_MAX);
int32_t bytes = taosMbToWchar(&wc, str + pos, MB_CUR_MAX);
if (bytes == 0) {
break;
}
......@@ -566,9 +418,9 @@ static void shellPrintNChar(const char *str, int length, int width) {
}
#ifdef WINDOWS
int w = bytes;
int32_t w = bytes;
#else
int w = taosWcharWidth(wc);
int32_t w = taosWcharWidth(wc);
#endif
if (w <= 0) {
continue;
......@@ -594,7 +446,7 @@ static void shellPrintNChar(const char *str, int length, int width) {
if (totalCols > width) {
// width could be 1 or 2, so printf("...") cannot be used
for (int i = 0; i < 3; i++) {
for (int32_t i = 0; i < 3; i++) {
if (cols >= width) {
break;
}
......@@ -602,7 +454,7 @@ static void shellPrintNChar(const char *str, int length, int width) {
++cols;
}
} else {
for (int i = 0; i < tailLen; i++) {
for (int32_t i = 0; i < tailLen; i++) {
printf("%lc", tail[i]);
}
cols = totalCols;
......@@ -613,9 +465,9 @@ static void shellPrintNChar(const char *str, int length, int width) {
}
}
static void printField(const char *val, TAOS_FIELD *field, int width, int32_t length, int precision) {
void shellPrintField(const char *val, TAOS_FIELD *field, int32_t width, int32_t length, int32_t precision) {
if (val == NULL) {
int w = width;
int32_t w = width;
if (field->type < TSDB_DATA_TYPE_TINYINT || field->type > TSDB_DATA_TYPE_DOUBLE) {
w = 0;
}
......@@ -666,7 +518,7 @@ static void printField(const char *val, TAOS_FIELD *field, int width, int32_t le
shellPrintNChar(val, length, width);
break;
case TSDB_DATA_TYPE_TIMESTAMP:
formatTimestamp(buf, *(int64_t *)val, precision);
shellFormatTimestamp(buf, *(int64_t *)val, precision);
printf("%s", buf);
break;
default:
......@@ -674,30 +526,19 @@ static void printField(const char *val, TAOS_FIELD *field, int width, int32_t le
}
}
bool isSelectQuery(TAOS_RES *tres) {
#if 0
char *sql = tscGetSqlStr(tres);
if (shellRegexMatch(sql, "^[\t ]*select[ \t]*", REG_EXTENDED | REG_ICASE)) {
return true;
}
#endif
return false;
}
static int verticalPrintResult(TAOS_RES *tres) {
int32_t shellVerticalPrintResult(TAOS_RES *tres) {
TAOS_ROW row = taos_fetch_row(tres);
if (row == NULL) {
return 0;
}
int num_fields = taos_num_fields(tres);
int32_t num_fields = taos_num_fields(tres);
TAOS_FIELD *fields = taos_fetch_fields(tres);
int precision = taos_result_precision(tres);
int32_t precision = taos_result_precision(tres);
int maxColNameLen = 0;
for (int col = 0; col < num_fields; col++) {
int len = (int)strlen(fields[col].name);
int32_t maxColNameLen = 0;
for (int32_t col = 0; col < num_fields; col++) {
int32_t len = (int32_t)strlen(fields[col].name);
if (len > maxColNameLen) {
maxColNameLen = len;
}
......@@ -705,25 +546,25 @@ static int verticalPrintResult(TAOS_RES *tres) {
uint64_t resShowMaxNum = UINT64_MAX;
if (args.commands == NULL && args.file[0] == 0 && isSelectQuery(tres) /*&& !tscIsQueryWithLimit(tres)*/) {
resShowMaxNum = DEFAULT_RES_SHOW_NUM;
if (shell.args.commands == NULL && shell.args.file[0] == 0) {
resShowMaxNum = SHELL_DEFAULT_RES_SHOW_NUM;
}
int numOfRows = 0;
int showMore = 1;
int32_t numOfRows = 0;
int32_t showMore = 1;
do {
if (numOfRows < resShowMaxNum) {
printf("*************************** %d.row ***************************\n", numOfRows + 1);
int32_t *length = taos_fetch_lengths(tres);
for (int i = 0; i < num_fields; i++) {
for (int32_t i = 0; i < num_fields; i++) {
TAOS_FIELD *field = fields + i;
int padding = (int)(maxColNameLen - strlen(field->name));
int32_t padding = (int32_t)(maxColNameLen - strlen(field->name));
printf("%*.s%s: ", padding, " ", field->name);
printField((const char *)row[i], field, 0, length[i], precision);
shellPrintField((const char *)row[i], field, 0, length[i], precision);
putchar('\n');
}
} else if (showMore) {
......@@ -739,8 +580,8 @@ static int verticalPrintResult(TAOS_RES *tres) {
return numOfRows;
}
static int calcColWidth(TAOS_FIELD *field, int precision) {
int width = (int)strlen(field->name);
int32_t shellCalcColWidth(TAOS_FIELD *field, int32_t precision) {
int32_t width = (int32_t)strlen(field->name);
switch (field->type) {
case TSDB_DATA_TYPE_BOOL:
......@@ -769,23 +610,23 @@ static int calcColWidth(TAOS_FIELD *field, int precision) {
return TMAX(25, width);
case TSDB_DATA_TYPE_BINARY:
if (field->bytes > tsMaxBinaryDisplayWidth) {
return TMAX(tsMaxBinaryDisplayWidth, width);
if (field->bytes > shell.args.displayWidth) {
return TMAX(shell.args.displayWidth, width);
} else {
return TMAX(field->bytes, width);
}
case TSDB_DATA_TYPE_NCHAR: {
int16_t bytes = field->bytes * TSDB_NCHAR_SIZE;
if (bytes > tsMaxBinaryDisplayWidth) {
return TMAX(tsMaxBinaryDisplayWidth, width);
if (bytes > shell.args.displayWidth) {
return TMAX(shell.args.displayWidth, width);
} else {
return TMAX(bytes, width);
}
}
case TSDB_DATA_TYPE_TIMESTAMP:
if (args.is_raw_time) {
if (shell.args.is_raw_time) {
return TMAX(14, width);
}
if (precision == TSDB_TIME_PRECISION_NANO) {
......@@ -803,55 +644,55 @@ static int calcColWidth(TAOS_FIELD *field, int precision) {
return 0;
}
static void printHeader(TAOS_FIELD *fields, int *width, int num_fields) {
int rowWidth = 0;
for (int col = 0; col < num_fields; col++) {
void shellPrintHeader(TAOS_FIELD *fields, int32_t *width, int32_t num_fields) {
int32_t rowWidth = 0;
for (int32_t col = 0; col < num_fields; col++) {
TAOS_FIELD *field = fields + col;
int padding = (int)(width[col] - strlen(field->name));
int left = padding / 2;
int32_t padding = (int32_t)(width[col] - strlen(field->name));
int32_t left = padding / 2;
printf(" %*.s%s%*.s |", left, " ", field->name, padding - left, " ");
rowWidth += width[col] + 3;
}
putchar('\n');
for (int i = 0; i < rowWidth; i++) {
for (int32_t i = 0; i < rowWidth; i++) {
putchar('=');
}
putchar('\n');
}
static int horizontalPrintResult(TAOS_RES *tres) {
int32_t shellHorizontalPrintResult(TAOS_RES *tres) {
TAOS_ROW row = taos_fetch_row(tres);
if (row == NULL) {
return 0;
}
int num_fields = taos_num_fields(tres);
int32_t num_fields = taos_num_fields(tres);
TAOS_FIELD *fields = taos_fetch_fields(tres);
int precision = taos_result_precision(tres);
int32_t precision = taos_result_precision(tres);
int width[TSDB_MAX_COLUMNS];
for (int col = 0; col < num_fields; col++) {
width[col] = calcColWidth(fields + col, precision);
int32_t width[TSDB_MAX_COLUMNS];
for (int32_t col = 0; col < num_fields; col++) {
width[col] = shellCalcColWidth(fields + col, precision);
}
printHeader(fields, width, num_fields);
shellPrintHeader(fields, width, num_fields);
uint64_t resShowMaxNum = UINT64_MAX;
if (args.commands == NULL && args.file[0] == 0 && isSelectQuery(tres) /* && !tscIsQueryWithLimit(tres)*/) {
resShowMaxNum = DEFAULT_RES_SHOW_NUM;
if (shell.args.commands == NULL && shell.args.file[0] == 0) {
resShowMaxNum = SHELL_DEFAULT_RES_SHOW_NUM;
}
int numOfRows = 0;
int showMore = 1;
int32_t numOfRows = 0;
int32_t showMore = 1;
do {
int32_t *length = taos_fetch_lengths(tres);
if (numOfRows < resShowMaxNum) {
for (int i = 0; i < num_fields; i++) {
for (int32_t i = 0; i < num_fields; i++) {
putchar(' ');
printField((const char *)row[i], fields + i, width[i], length[i], precision);
shellPrintField((const char *)row[i], fields + i, width[i], length[i], precision);
putchar(' ');
putchar('|');
}
......@@ -869,14 +710,14 @@ static int horizontalPrintResult(TAOS_RES *tres) {
return numOfRows;
}
int shellDumpResult(TAOS_RES *tres, char *fname, int *error_no, bool vertical) {
int numOfRows = 0;
int32_t shellDumpResult(TAOS_RES *tres, char *fname, int32_t *error_no, bool vertical) {
int32_t numOfRows = 0;
if (fname != NULL) {
numOfRows = dumpResultToFile(fname, tres);
numOfRows = shellDumpResultToFile(fname, tres);
} else if (vertical) {
numOfRows = verticalPrintResult(tres);
numOfRows = shellVerticalPrintResult(tres);
} else {
numOfRows = horizontalPrintResult(tres);
numOfRows = shellHorizontalPrintResult(tres);
}
*error_no = taos_errno(tres);
......@@ -884,35 +725,20 @@ int shellDumpResult(TAOS_RES *tres, char *fname, int *error_no, bool vertical) {
}
void shellReadHistory() {
// Initialize history
memset(history.hist, 0, sizeof(char *) * MAX_HISTORY_SIZE);
history.hstart = 0;
history.hend = 0;
char *line = NULL;
int read_size = 0;
char f_history[TSDB_FILENAME_LEN];
shellHistoryPath(f_history);
// FILE *f = fopen(f_history, "r");
TdFilePtr pFile = taosOpenFile(f_history, TD_FILE_READ | TD_FILE_STREAM);
if (pFile == NULL) {
#ifndef WINDOWS
if (errno != ENOENT) {
fprintf(stderr, "Failed to open file %s, reason:%s\n", f_history, strerror(errno));
}
#endif
return;
}
SShellHistory *pHistory = &shell.history;
TdFilePtr pFile = taosOpenFile(pHistory->file, TD_FILE_READ | TD_FILE_STREAM);
if (pFile == NULL) return;
char *line = NULL;
int32_t read_size = 0;
while ((read_size = taosGetLineFile(pFile, &line)) != -1) {
line[read_size - 1] = '\0';
history.hist[history.hend] = strdup(line);
pHistory->hist[pHistory->hend] = strdup(line);
history.hend = (history.hend + 1) % MAX_HISTORY_SIZE;
pHistory->hend = (pHistory->hend + 1) % SHELL_MAX_HISTORY_SIZE;
if (history.hend == history.hstart) {
history.hstart = (history.hstart + 1) % MAX_HISTORY_SIZE;
if (pHistory->hend == pHistory->hstart) {
pHistory->hstart = (pHistory->hstart + 1) % SHELL_MAX_HISTORY_SIZE;
}
}
......@@ -921,71 +747,41 @@ void shellReadHistory() {
}
void shellWriteHistory() {
char f_history[TSDB_FILENAME_LEN];
shellHistoryPath(f_history);
// FILE *f = fopen(f_history, "w");
TdFilePtr pFile = taosOpenFile(f_history, TD_FILE_CREATE | TD_FILE_WRITE | TD_FILE_TRUNC | TD_FILE_STREAM);
if (pFile == NULL) {
#ifndef WINDOWS
fprintf(stderr, "Failed to open file %s for write, reason:%s\n", f_history, strerror(errno));
#endif
return;
}
SShellHistory *pHistory = &shell.history;
TdFilePtr pFile = taosOpenFile(pHistory->file, TD_FILE_CREATE | TD_FILE_WRITE | TD_FILE_TRUNC | TD_FILE_STREAM);
if (pFile == NULL) return;
for (int i = history.hstart; i != history.hend;) {
if (history.hist[i] != NULL) {
taosFprintfFile(pFile, "%s\n", history.hist[i]);
taosMemoryFreeClear(history.hist[i]);
for (int32_t i = pHistory->hstart; i != pHistory->hend;) {
if (pHistory->hist[i] != NULL) {
taosFprintfFile(pFile, "%s\n", pHistory->hist[i]);
taosMemoryFreeClear(pHistory->hist[i]);
}
i = (i + 1) % MAX_HISTORY_SIZE;
i = (i + 1) % SHELL_MAX_HISTORY_SIZE;
}
taosCloseFile(&pFile);
}
void shellPrintError(TAOS_RES *tres, int64_t st) {
int64_t et = taosGetTimestampUs();
atomic_store_ptr(&result, 0);
atomic_store_ptr(&shell.result, 0);
fprintf(stderr, "\nDB error: %s (%.6fs)\n", taos_errstr(tres), (et - st) / 1E6);
taos_free_result(tres);
}
int isCommentLine(char *line) {
if (line == NULL) return 1;
bool shellIsCommentLine(char *line) {
if (line == NULL) return true;
return shellRegexMatch(line, "^\\s*#.*", REG_EXTENDED);
}
void shellSourceFile(TAOS *con, char *fptr) {
wordexp_t full_path;
int read_len = 0;
void shellSourceFile(const char *file) {
int32_t read_len = 0;
char *cmd = taosMemoryCalloc(1, TSDB_MAX_ALLOWED_SQL_LEN + 1);
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 (access(fname, F_OK) != 0) {
fprintf(stderr, "ERROR: file %s is not exist\n", fptr);
wordfree(&full_path);
taosMemoryFree(cmd);
return;
}
*/
// FILE *f = fopen(fname, "r");
TdFilePtr pFile = taosOpenFile(fname, TD_FILE_READ | TD_FILE_STREAM);
TdFilePtr pFile = taosOpenFile(file, TD_FILE_READ | TD_FILE_STREAM);
if (pFile == NULL) {
fprintf(stderr, "ERROR: failed to open file %s\n", fname);
wordfree(&full_path);
fprintf(stderr, "ERROR: failed to open file %s\n", file);
taosMemoryFree(cmd);
return;
}
......@@ -994,7 +790,7 @@ void shellSourceFile(TAOS *con, char *fptr) {
if (read_len >= TSDB_MAX_ALLOWED_SQL_LEN) continue;
line[--read_len] = '\0';
if (read_len == 0 || isCommentLine(line)) { // line starts with #
if (read_len == 0 || shellIsCommentLine(line)) { // line starts with #
continue;
}
......@@ -1006,36 +802,34 @@ void shellSourceFile(TAOS *con, char *fptr) {
}
memcpy(cmd + cmd_len, line, read_len);
printf("%s%s\n", PROMPT_HEADER, cmd);
shellRunCommand(con, cmd);
printf("%s%s\n", shell.info.promptHeader, cmd);
shellRunCommand(cmd);
memset(cmd, 0, TSDB_MAX_ALLOWED_SQL_LEN);
cmd_len = 0;
}
taosMemoryFree(cmd);
if (line != NULL) taosMemoryFree(line);
wordfree(&full_path);
taosCloseFile(&pFile);
}
void shellGetGrantInfo(void *con) {
return;
#if 0
void shellGetGrantInfo() {
char sql[] = "show grants";
TAOS_RES* tres = taos_query(con, sql);
TAOS_RES *tres = taos_query(shell.conn, sql);
int code = taos_errno(tres);
int32_t code = taos_errno(tres);
if (code != TSDB_CODE_SUCCESS) {
if (code == TSDB_CODE_COM_OPS_NOT_SUPPORT) {
fprintf(stdout, "Server is Community Edition, version is %s\n\n", taos_get_server_info(con));
if (code == TSDB_CODE_OPS_NOT_SUPPORT) {
fprintf(stdout, "Server is Community Edition, version is %s\n\n", taos_get_server_info(shell.conn));
} else {
fprintf(stderr, "Failed to check Server Edition, Reason:%d:%s\n\n", taos_errno(con), taos_errstr(con));
fprintf(stderr, "Failed to check Server Edition, Reason:%d:%s\n\n", taos_errno(shell.conn),
taos_errstr(shell.conn));
}
return;
}
int num_fields = taos_field_count(tres);
int32_t num_fields = taos_field_count(tres);
if (num_fields == 0) {
fprintf(stderr, "\nInvalid grant information.\n");
exit(0);
......@@ -1061,15 +855,120 @@ void shellGetGrantInfo(void *con) {
memcpy(expired, row[2], fields[2].bytes);
if (strcmp(expiretime, "unlimited") == 0) {
fprintf(stdout, "Server is Enterprise %s Edition, version is %s and will never expire.\n", serverVersion, taos_get_server_info(con));
fprintf(stdout, "Server is Enterprise %s Edition, version is %s and will never expire.\n", serverVersion,
taos_get_server_info(shell.conn));
} else {
fprintf(stdout, "Server is Enterprise %s Edition, version is %s and will expire at %s.\n", serverVersion, taos_get_server_info(con), expiretime);
fprintf(stdout, "Server is Enterprise %s Edition, version is %s and will expire at %s.\n", serverVersion,
taos_get_server_info(shell.conn), expiretime);
}
result = NULL;
shell.result = 0;
taos_free_result(tres);
}
fprintf(stdout, "\n");
#endif
}
void shellQueryInterruptHandler(int32_t signum, void *sigInfo, void *context) { tsem_post(&shell.cancelSem); }
void shellCleanup(void *arg) { taosResetTerminalMode(); }
void *shellCancelHandler(void *arg) {
setThreadName("shellCancelHandler");
while (1) {
if (tsem_wait(&shell.cancelSem) != 0) {
taosMsleep(10);
continue;
}
taosResetTerminalMode();
printf("\nReceive ctrl+c or other signal, quit shell.\n");
// shellExit();
}
return NULL;
}
void *shellThreadLoop(void *arg) {
setThreadName("shellThreadLoop");
taosGetOldTerminalMode();
taosThreadCleanupPush(shellCleanup, NULL);
char *command = taosMemoryMalloc(SHELL_MAX_COMMAND_SIZE);
if (command == NULL) {
printf("failed to malloc command\n");
return NULL;
}
do {
memset(command, 0, SHELL_MAX_COMMAND_SIZE);
taosSetTerminalMode();
if (shellReadCommand(command) != 0) {
break;
}
taosResetTerminalMode();
} while (shellRunCommand(command) == 0);
taosMemoryFreeClear(command);
taosThreadCleanupPop(1);
return NULL;
}
int32_t shellExecute() {
printf(shell.info.clientVersion, shell.info.osname, taos_get_client_info());
fflush(stdout);
SShellArgs *pArgs = &shell.args;
if (shell.args.auth == NULL) {
shell.conn = taos_connect(pArgs->host, pArgs->user, pArgs->password, pArgs->database, pArgs->port);
} else {
shell.conn = taos_connect_auth(pArgs->host, pArgs->user, pArgs->auth, pArgs->database, pArgs->port);
}
if (shell.conn == NULL) {
fflush(stdout);
return -1;
}
if (pArgs->commands != NULL || pArgs->file[0] != 0) {
if (pArgs->commands != NULL) {
printf("%s%s\n", shell.info.promptHeader, pArgs->commands);
char *cmd = strdup(pArgs->commands);
shellRunCommand(cmd);
taosMemoryFree(cmd);
}
if (pArgs->file[0] != 0) {
shellSourceFile(pArgs->file);
}
taos_close(shell.conn);
shellWriteHistory();
return 0;
}
if (tsem_init(&shell.cancelSem, 0, 0) != 0) {
printf("failed to create cancel semphore\n");
return -1;
}
TdThread spid = {0};
taosThreadCreate(&spid, NULL, shellCancelHandler, NULL);
taosSetSignal(SIGTERM, shellQueryInterruptHandler);
taosSetSignal(SIGINT, shellQueryInterruptHandler);
taosSetSignal(SIGHUP, shellQueryInterruptHandler);
taosSetSignal(SIGABRT, shellQueryInterruptHandler);
shellGetGrantInfo(shell.conn);
shellReadHistory();
while (1) {
taosThreadCreate(&shell.pid, NULL, shellThreadLoop, shell.conn);
taosThreadJoin(shell.pid, NULL);
}
return 0;
}
......@@ -14,682 +14,52 @@
*/
#define __USE_XOPEN
#include "shellCommand.h"
#include "tglobal.h"
#include "shellInt.h"
#include <argp.h>
#include <termio.h>
#include <wordexp.h>
SShellObj shell = {0};
#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();
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. */
SShellArgs *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;
}
int main(int argc, char *argv[]) {
if (shellCheckIntSize() != 0) {
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[], SShellArgs *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;
}
}
}
int32_t shellParseArgs(int argc, char *argv[], SShellArgs *arguments) {
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
}
if (shellParseArgs(argc, argv) != 0) {
return 0;
}
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 = (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
shellWriteHistory();
shellExit();
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);
if (shell.args.is_version) {
shellPrintVersion();
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);
}
}
if (shell.args.is_gen_auth) {
shellGenerateAuth();
return 0;
}
void *shellThreadLoop(void *arg) {
if (indicator) {
getOldTerminalMode();
indicator = 0;
}
TAOS *con = (TAOS *)arg;
setThreadName("shellThreadLoop");
taosThreadCleanupPush(shellCleanup, NULL);
char *command = taosMemoryMalloc(MAX_COMMAND_SIZE);
if (command == NULL) {
printf("failed to malloc command\n");
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);
shellExit();
taosThreadCleanupPop(1);
return NULL;
}
void shellHistoryPath(char *_history) { snprintf(_history, TSDB_FILENAME_LEN, "%s/%s", getenv("HOME"), 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;
if (shell.args.is_help) {
return 0;
}
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 shellCleanup(void *arg) { resetTerminalMode(); }
taos_init();
void shellExit() {
if (shell.args.is_dump_config) {
shellDumpConfig();
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");
shellExit();
}
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
SShellArgs 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);
shellExit();
}
void shellTestNetWork() {
if (args.netTestRole && args.netTestRole[0] != 0) {
taosNetTest(args.netTestRole, args.host, args.port, args.pktLen, args.pktNum, args.pktType);
shellExit();
}
}
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);
shellExit();
}
void shellExecute() {
TAOS *con = shellInit(&args);
if (con == NULL) {
shellExit();
}
if (tsem_init(&cancelSem, 0, 0) != 0) {
printf("failed to create cancel semphore\n");
shellExit();
}
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, shellThreadLoop, con);
taosThreadJoin(pid, NULL);
if (shell.args.is_startup || shell.args.is_check) {
shellCheckServerStatus();
taos_cleanup();
return 0;
}
}
int main(int argc, char *argv[]) {
if (!checkVersion()) shellExit();
shellParseArgs(argc, argv, &args);
taos_init();
shellDumpConfig();
shellCheckServerStatus();
if (strcmp(shell.args.netrole, "client") == 0 || strcmp(shell.args.netrole, "server") == 0) {
shellTestNetWork();
shellExecute();
taos_cleanup();
return 0;
}
return shellExecute();
}
......@@ -13,18 +13,23 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#define _DEFAULT_SOURCE
#define _GNU_SOURCE
#include "shellInt.h"
void shellTestNetWork() {}
#if 0
#define ALLOW_FORBID_FUNC
#include "os.h"
#include "rpcHead.h"
#include "syncMsg.h"
#include "taosdef.h"
#include "tmsg.h"
#include "taoserror.h"
#include "tlog.h"
#include "tchecksum.h"
#include "tglobal.h"
#include "tlog.h"
#include "tmsg.h"
#include "trpc.h"
#include "rpcHead.h"
#include "tchecksum.h"
#include "syncMsg.h"
#include "osSocket.h"
......@@ -321,9 +326,8 @@ static int32_t taosNetCheckUdpPort(STestInfo *info) {
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;
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);
......@@ -468,11 +472,13 @@ static void taosNetCheckSpeed(char *host, int32_t port, int32_t pkgLen,
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);
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);
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);
......@@ -512,3 +518,5 @@ void taosNetTest(char *role, char *host, int32_t port, int32_t pkgLen, int32_t p
tsLogEmbedded = 0;
}
#endif
\ No newline at end of file
/*
* 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;
char msgbuf[100] = {0};
/* Compile regular expression */
if (regcomp(&regex, reg, cflags) != 0) {
fprintf(stderr, "Fail to compile regex");
return false;
}
/* Execute regular expression */
int32_t reti = regexec(&regex, s, 0, NULL, 0);
if (!reti) {
regfree(&regex);
return true;
} else if (reti == REG_NOMATCH) {
regfree(&regex);
return false;
} else {
regerror(reti, &regex, msgbuf, sizeof(msgbuf));
fprintf(stderr, "Regex match failed: %s\n", msgbuf);
regfree(&regex);
return false;
}
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() {}
void shellDumpConfig() {
SConfig *pCfg = taosGetCfg();
if (pCfg == NULL) {
printf("TDengine read global config failed!\n");
} else {
cfgDumpCfg(pCfg, 1, 1);
}
}
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);
}
if (code == TSDB_SRV_STATUS_NETWORK_OK && shell.args.is_startup) {
taosMsleep(1000);
} else {
break;
}
} while (1);
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册