Merge pull request #2052 from taosdata/feature/td-342
td-342: shell multiple statements support
This commit is contained in:
commit
a9dbf73d34
|
@ -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,67 +106,66 @@ 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;
|
||||
}
|
||||
|
||||
// Analyse the command.
|
||||
if (regex_match(command, "^[ \t]*(quit|q|exit)[ \t;]*$", REG_EXTENDED | REG_ICASE)) {
|
||||
taos_close(con);
|
||||
write_history();
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (regex_match(command, "^[\t ]*clear[ \t;]*$", REG_EXTENDED | REG_ICASE)) {
|
||||
// If clear the screen.
|
||||
system("clear");
|
||||
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");
|
||||
if (strcasecmp(p, "default") == 0) {
|
||||
tsMaxBinaryDisplayWidth = DEFAULT_MAX_BINARY_DISPLAY_WIDTH;
|
||||
} else {
|
||||
tsMaxBinaryDisplayWidth = atoi(p);
|
||||
}
|
||||
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);
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -190,40 +184,63 @@ int32_t shellRunCommand(TAOS *con, char *command) {
|
|||
}
|
||||
}
|
||||
|
||||
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 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)) {
|
||||
strtok(command, " \t");
|
||||
strtok(NULL, " \t");
|
||||
char* p = strtok(NULL, " \t");
|
||||
if (strcasecmp(p, "default") == 0) {
|
||||
tsMaxBinaryDisplayWidth = DEFAULT_MAX_BINARY_DISPLAY_WIDTH;
|
||||
} else {
|
||||
tsMaxBinaryDisplayWidth = atoi(p);
|
||||
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;
|
||||
}
|
||||
} else 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);
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
*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;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue