未验证 提交 a9dbf73d 编写于 作者: S Shengliang Guan 提交者: GitHub

Merge pull request #2052 from taosdata/feature/td-342

td-342: shell multiple statements support
......@@ -2,6 +2,8 @@
TDengine provides many connectors for development, including C/C++, JAVA, Python, RESTful, Go, Node.JS, etc.
NOTE: All APIs which require a SQL string as parameter, including but not limit to `taos_query`, `taos_query_a`, `taos_subscribe` in the C/C++ Connector and their counterparts in other connectors, can ONLY process one SQL statement at a time. If more than one SQL statements are provided, their behaviors are undefined.
## C/C++ API
C/C++ APIs are similar to the MySQL APIs. Applications should include TDengine head file _taos.h_ to use C/C++ APIs by adding the following line in code:
......
......@@ -2,6 +2,8 @@
TDengine提供了丰富的应用程序开发接口,其中包括C/C++、JAVA、Python、RESTful、Go等,便于用户快速开发应用。
注意:所以执行 SQL 语句的 API,例如 C/C++ Connector 中的 `tao_query``taos_query_a``taos_subscribe` 等,以及其它语言中与它们对应的API,每次都只能执行一条 SQL 语句,如果实际参数中包含了多条语句,它们的行为是未定义的。
## C/C++ Connector
C/C++的API类似于MySQL的C API。应用程序使用时,需要包含TDengine头文件 _taos.h_(安装后,位于 _/usr/local/taos/include_):
......
......@@ -335,17 +335,14 @@ void *shellLoopQuery(void *arg) {
tscError("failed to malloc command");
return NULL;
}
while (1) {
// Read command from shell.
do {
// Read command from shell.
memset(command, 0, MAX_COMMAND_SIZE);
set_terminal_mode();
shellReadCommand(con, command);
reset_terminal_mode();
// Run the command
shellRunCommand(con, command);
}
} while (shellRunCommand(con, command) == 0);
pthread_cleanup_pop(1);
......
......@@ -82,20 +82,15 @@ TAOS *shellInit(SShellArguments *args) {
// Check if it is temperory run
if (args->commands != NULL || args->file[0] != 0) {
if (args->commands != NULL) {
char *token;
token = strtok(args->commands, ";");
while (token != NULL) {
printf("%s%s\n", PROMPT_HEADER, token);
shellRunCommand(con, token);
token = strtok(NULL, ";");
}
printf("%s%s\n", PROMPT_HEADER, args->commands);
shellRunCommand(con, args->commands);
}
if (args->file[0] != 0) {
source_file(con, args->file);
}
taos_close(con);
taos_close(con);
write_history();
exit(EXIT_SUCCESS);
}
......@@ -111,96 +106,37 @@ TAOS *shellInit(SShellArguments *args) {
return con;
}
void shellReplaceCtrlChar(char *str) {
_Bool ctrlOn = false;
char *pstr = NULL;
char quote = 0;
for (pstr = str; *str != '\0'; ++str) {
if (ctrlOn) {
switch (*str) {
case 'n':
*pstr = '\n';
pstr++;
break;
case 'r':
*pstr = '\r';
pstr++;
break;
case 't':
*pstr = '\t';
pstr++;
break;
case 'G':
*pstr++ = '\\';
*pstr++ = *str;
break;
case '\\':
*pstr = '\\';
pstr++;
break;
case '\'':
case '"':
if (quote) {
*pstr++ = '\\';
*pstr++ = *str;
}
break;
default:
*pstr = *str;
pstr++;
break;
}
ctrlOn = false;
} else {
if (*str == '\\') {
ctrlOn = true;
} else {
if (quote == *str) {
quote = 0;
} else if (*str == '\'' || *str == '"') {
quote = *str;
}
*pstr = *str;
pstr++;
}
static bool isEmptyCommand(const char* cmd) {
for (char c = *cmd++; c != 0; c = *cmd++) {
if (c != ' ' && c != '\t' && c != ';') {
return false;
}
}
*pstr = '\0';
return true;
}
int32_t shellRunCommand(TAOS *con, char *command) {
static int32_t shellRunSingleCommand(TAOS *con, char *command) {
/* If command is empty just return */
if (regex_match(command, "^[ \t;]*$", REG_EXTENDED)) {
if (isEmptyCommand(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) {
tfree(history.hist[history.hend]);
}
history.hist[history.hend] = strdup(command);
history.hend = (history.hend + 1) % MAX_HISTORY_SIZE;
if (history.hend == history.hstart) {
history.hstart = (history.hstart + 1) % MAX_HISTORY_SIZE;
}
}
shellReplaceCtrlChar(command);
// Analyse the command.
if (regex_match(command, "^[ \t]*(quit|q|exit)[ \t;]*$", REG_EXTENDED | REG_ICASE)) {
taos_close(con);
write_history();
return -1;
} else if (regex_match(command, "^[\t ]*clear[ \t;]*$", REG_EXTENDED | REG_ICASE)) {
}
if (regex_match(command, "^[\t ]*clear[ \t;]*$", REG_EXTENDED | REG_ICASE)) {
// If clear the screen.
system("clear");
} else if (regex_match(command, "^[\t ]*set[ \t]+max_binary_display_width[ \t]+(default|[1-9][0-9]*)[ \t;]*$", REG_EXTENDED | REG_ICASE)) {
return 0;
}
if (regex_match(command, "^[\t ]*set[ \t]+max_binary_display_width[ \t]+(default|[1-9][0-9]*)[ \t;]*$", REG_EXTENDED | REG_ICASE)) {
strtok(command, " \t");
strtok(NULL, " \t");
char* p = strtok(NULL, " \t");
......@@ -209,21 +145,102 @@ int32_t shellRunCommand(TAOS *con, char *command) {
} else {
tsMaxBinaryDisplayWidth = atoi(p);
}
} else if (regex_match(command, "^[ \t]*source[\t ]+[^ ]+[ \t;]*$", REG_EXTENDED | REG_ICASE)) {
return 0;
}
if (regex_match(command, "^[ \t]*source[\t ]+[^ ]+[ \t;]*$", REG_EXTENDED | REG_ICASE)) {
/* If source file. */
char *c_ptr = strtok(command, " ;");
assert(c_ptr != NULL);
c_ptr = strtok(NULL, " ;");
assert(c_ptr != NULL);
source_file(con, c_ptr);
} else {
shellRunCommandOnServer(con, command);
return 0;
}
shellRunCommandOnServer(con, command);
return 0;
}
int32_t shellRunCommand(TAOS* con, char* command) {
/* If command is empty just return */
if (isEmptyCommand(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) {
tfree(history.hist[history.hend]);
}
history.hist[history.hend] = strdup(command);
history.hend = (history.hend + 1) % MAX_HISTORY_SIZE;
if (history.hend == history.hstart) {
history.hstart = (history.hstart + 1) % MAX_HISTORY_SIZE;
}
}
bool esc = false;
char quote = 0, *cmd = command, *p = command;
for (char c = *command++; c != 0; c = *command++) {
if (esc) {
switch (c) {
case 'n':
c = '\n';
break;
case 'r':
c = '\r';
break;
case 't':
c = '\t';
break;
case 'G':
*p++ = '\\';
break;
case '\'':
case '"':
if (quote) {
*p++ = '\\';
}
break;
}
*p++ = c;
esc = false;
continue;
}
if (c == '\\') {
esc = true;
continue;
}
if (quote == c) {
quote = 0;
} else if (c == '\'' || c == '"') {
quote = c;
}
*p++ = c;
if (c == ';') {
c = *p;
*p = 0;
if (shellRunSingleCommand(con, cmd) < 0) {
return -1;
}
*p = c;
p = cmd;
}
}
*p = 0;
return shellRunSingleCommand(con, cmd);
}
void shellRunCommandOnServer(TAOS *con, char command[]) {
int64_t st, et;
wordexp_t full_path;
......
......@@ -307,19 +307,13 @@ void *shellLoopQuery(void *arg) {
return NULL;
}
while (1) {
do {
// Read command from shell.
memset(command, 0, MAX_COMMAND_SIZE);
set_terminal_mode();
shellReadCommand(con, command);
reset_terminal_mode();
// Run the command
if (shellRunCommand(con, command) != 0) {
break;
}
}
} while (shellRunCommand(con, command) == 0);
tfree(command);
exitShell();
......
......@@ -203,16 +203,13 @@ void *shellLoopQuery(void *arg) {
char *command = malloc(MAX_COMMAND_SIZE);
if (command == NULL) return NULL;
while (1) {
do {
memset(command, 0, MAX_COMMAND_SIZE);
shellPrintPrompt();
// Read command from shell.
shellReadCommand(con, command);
// Run the command
shellRunCommand(con, command);
}
} while (shellRunCommand(con, command) == 0);
return NULL;
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册