From 3a650da645b6859c164d751bde957f1530436d8b Mon Sep 17 00:00:00 2001 From: Bomin Zhang Date: Mon, 25 May 2020 17:16:18 +0800 Subject: [PATCH] TD-407: add config for binary column display width --- src/common/src/tglobal.c | 12 + src/kit/shell/inc/shell.h | 14 +- src/kit/shell/src/shellDarwin.c | 42 +- src/kit/shell/src/shellEngine.c | 652 +++++++++++++++---------------- src/kit/shell/src/shellLinux.c | 41 +- src/kit/shell/src/shellMain.c | 1 - src/kit/shell/src/shellWindows.c | 42 +- 7 files changed, 392 insertions(+), 412 deletions(-) diff --git a/src/common/src/tglobal.c b/src/common/src/tglobal.c index faf15c4215..763b3f5c22 100644 --- a/src/common/src/tglobal.c +++ b/src/common/src/tglobal.c @@ -202,6 +202,8 @@ char tsTimezone[64] = {0}; char tsLocale[TSDB_LOCALE_LEN] = {0}; char tsCharset[TSDB_LOCALE_LEN] = {0}; // default encode string +int32_t tsMaxBinaryDisplayWidth = 30; + static pthread_once_t tsInitGlobalCfgOnce = PTHREAD_ONCE_INIT; void taosSetAllDebugFlag() { @@ -1227,6 +1229,16 @@ static void doInitGlobalConfig() { cfg.ptrLength = 0; cfg.unitType = TAOS_CFG_UTYPE_NONE; taosInitConfigOption(cfg); + + cfg.option = "maxBinaryDisplayWidth"; + cfg.ptr = &tsMaxBinaryDisplayWidth; + cfg.valType = TAOS_CFG_VTYPE_INT32; + cfg.cfgType = TSDB_CFG_CTYPE_B_CONFIG | TSDB_CFG_CTYPE_B_CLIENT; + cfg.minValue = 1; + cfg.maxValue = 0x7fffffff; + cfg.ptrLength = 0; + cfg.unitType = TAOS_CFG_UTYPE_NONE; + taosInitConfigOption(cfg); } void taosInitGlobalCfg() { diff --git a/src/kit/shell/inc/shell.h b/src/kit/shell/inc/shell.h index 549b0ef977..51bd1c1102 100644 --- a/src/kit/shell/inc/shell.h +++ b/src/kit/shell/inc/shell.h @@ -29,18 +29,6 @@ #define MAX_COMMAND_SIZE 65536 #define HISTORY_FILE ".taos_history" -#define BOOL_OUTPUT_LENGTH 6 -#define TINYINT_OUTPUT_LENGTH 6 -#define SMALLINT_OUTPUT_LENGTH 7 -#define INT_OUTPUT_LENGTH 11 -#define BIGINT_OUTPUT_LENGTH 21 -#define FLOAT_OUTPUT_LENGTH 20 -#define DOUBLE_OUTPUT_LENGTH 25 -#define BINARY_OUTPUT_LENGTH 20 - -// dynamic config timestamp width according to maximum time precision -extern int32_t TIMESTAMP_OUTPUT_LENGTH; - typedef struct SShellHistory { char* hist[MAX_HISTORY_SIZE]; int hstart; @@ -80,7 +68,7 @@ void get_history_path(char* history); void cleanup_handler(void* arg); void exitShell(); int shellDumpResult(TAOS* con, char* fname, int* error_no, bool printMode); -void shellPrintNChar(char* str, int width, bool printMode); +int shellPrintNChar(const char* str, int length, int width); void shellGetGrantInfo(void *con); int isCommentLine(char *line); diff --git a/src/kit/shell/src/shellDarwin.c b/src/kit/shell/src/shellDarwin.c index cd2fe6df33..2f5d1f421d 100644 --- a/src/kit/shell/src/shellDarwin.c +++ b/src/kit/shell/src/shellDarwin.c @@ -352,37 +352,29 @@ void *shellLoopQuery(void *arg) { return NULL; } -void shellPrintNChar(char *str, int width, bool printMode) { - int col_left = width; - wchar_t wc; - while (col_left > 0) { - if (*str == '\0') break; - char *tstr = str; - int byte_width = mbtowc(&wc, tstr, MB_CUR_MAX); - if (byte_width <= 0) break; - int col_width = wcwidth(wc); - if (col_width <= 0) { - str += byte_width; - continue; +int shellPrintNChar(const char *str, int length, int width) { + int pos = 0, cols = 0; + while (pos < length) { + wchar_t wc; + pos += mbtowc(&wc, str + pos, MB_CUR_MAX); + if (pos > length) { + break; } - if (col_left < col_width) break; - printf("%lc", wc); - str += byte_width; - col_left -= col_width; - } - while (col_left > 0) { - printf(" "); - col_left--; + int w = wcwidth(wc); + if (w > 0) { + if (width > 0 && cols + w > width) { + break; + } + printf("%lc", wc); + cols += w; + } } - if (!printMode) { - printf("|"); - } else { - printf("\n"); - } + return cols; } + int get_old_terminal_mode(struct termios *tio) { /* Make sure stdin is a terminal. */ if (!isatty(STDIN_FILENO)) { diff --git a/src/kit/shell/src/shellEngine.c b/src/kit/shell/src/shellEngine.c index dbb05f6a35..b4103ab331 100644 --- a/src/kit/shell/src/shellEngine.c +++ b/src/kit/shell/src/shellEngine.c @@ -35,6 +35,9 @@ int prompt_size = 6; TAOS_RES *result = NULL; SShellHistory history; +#define DEFAULT_MAX_BINARY_DISPLAY_WIDTH 30 +extern int32_t tsMaxBinaryDisplayWidth; + /* * FUNCTION: Initialize the shell. */ @@ -195,7 +198,15 @@ int32_t shellRunCommand(TAOS *con, char *command) { } else if (regex_match(command, "^[\t ]*clear[ \t;]*$", REG_EXTENDED | REG_ICASE)) { // If clear the screen. system("clear"); - return 0; + } 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); + } } else if (regex_match(command, "^[ \t]*source[\t ]+[^ ]+[ \t;]*$", REG_EXTENDED | REG_ICASE)) { /* If source file. */ char *c_ptr = strtok(command, " ;"); @@ -310,360 +321,349 @@ int regex_match(const char *s, const char *reg, int cflags) { return 0; } -int shellDumpResult(TAOS *con, char *fname, int *error_no, bool printMode) { - TAOS_ROW row = NULL; - int numOfRows = 0; - time_t tt; - char buf[25] = "\0"; - struct tm *ptm; - int output_bytes = 0; - FILE * fp = NULL; - int num_fields = taos_field_count(con); - wordexp_t full_path; - assert(num_fields != 0); +static char* formatTimestamp(char* buf, int64_t val, int precision) { + if (args.is_raw_time) { + sprintf(buf, "%" PRId64, val); + return buf; + } - result = taos_use_result(con); - if (result == NULL) { - taos_error(con); + time_t tt; + if (precision == TSDB_TIME_PRECISION_MICRO) { + tt = (time_t)(val / 1000000); + } else { + tt = (time_t)(val / 1000); + } + + struct tm* ptm = localtime(&tt); + size_t pos = strftime(buf, 32, "%Y-%m-%d %H:%M:%S", ptm); + + if (precision == TSDB_TIME_PRECISION_MICRO) { + sprintf(buf + pos, ".%06d", (int)(val % 1000000)); + } else { + sprintf(buf + pos, ".%03d", (int)(val % 1000)); + } + + return buf; +} + + +static void dumpFieldToFile(FILE* fp, const char* val, TAOS_FIELD* field, int32_t length, int precision) { + if (val == NULL) { + fprintf(fp, "%s", TSDB_DATA_NULL_STR); + return; + } + + char buf[TSDB_MAX_BYTES_PER_ROW]; + switch (field->type) { + case TSDB_DATA_TYPE_BOOL: + fprintf(fp, "%d", ((((int)(*((char *)val))) == 1) ? 1 : 0)); + break; + case TSDB_DATA_TYPE_TINYINT: + fprintf(fp, "%d", (int)(*((char *)val))); + break; + case TSDB_DATA_TYPE_SMALLINT: + fprintf(fp, "%d", (int)(*((short *)val))); + break; + case TSDB_DATA_TYPE_INT: + fprintf(fp, "%d", *((int *)val)); + break; + case TSDB_DATA_TYPE_BIGINT: + fprintf(fp, "%" PRId64, *((int64_t *)val)); + break; + case TSDB_DATA_TYPE_FLOAT: + fprintf(fp, "%.5f", GET_FLOAT_VAL(val)); + break; + case TSDB_DATA_TYPE_DOUBLE: + fprintf(fp, "%.9f", GET_DOUBLE_VAL(val)); + break; + case TSDB_DATA_TYPE_BINARY: + case TSDB_DATA_TYPE_NCHAR: + memcpy(buf, val, length); + buf[length] = 0; + fprintf(fp, "\'%s\'", buf); + break; + case TSDB_DATA_TYPE_TIMESTAMP: + formatTimestamp(buf, *(int64_t*)val, precision); + fprintf(fp, "'%s'", buf); + break; + default: + break; + } +} + +static int dumpResultToFile(const char* fname, TAOS_RES* result) { + TAOS_ROW row = taos_fetch_row(result); + if (row == NULL) { + return 0; + } + + wordexp_t full_path; + + if (wordexp(fname, &full_path, 0) != 0) { + fprintf(stderr, "ERROR: invalid file name: %s\n", fname); return -1; } - if (fname != NULL) { - if (wordexp(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"); + if (fp == NULL) { + fprintf(stderr, "ERROR: failed to open file: %s\n", full_path.we_wordv[0]); + wordfree(&full_path); + return -1; + } + + wordfree(&full_path); + + int num_fields = taos_num_fields(result); + TAOS_FIELD *fields = taos_fetch_fields(result); + int32_t* length = taos_fetch_lengths(result); + int precision = taos_result_precision(result); + + for (int col = 0; col < num_fields; col++) { + if (col > 0) { + fprintf(fp, ","); + } + fprintf(fp, "%s", fields[col].name); + } + fputc('\n', fp); + + int numOfRows = 0; + do { + for (int i = 0; i < num_fields; i++) { + if (i > 0) { + fputc(',', fp); + } + dumpFieldToFile(fp, row[i], fields +i, length[i], precision); } + fputc('\n', fp); + + numOfRows++; + row = taos_fetch_row(result); + } while( row != NULL); + + fclose(fp); + return numOfRows; +} - fp = fopen(full_path.we_wordv[0], "w"); - if (fp == NULL) { - fprintf(stderr, "ERROR: failed to open file: %s\n", full_path.we_wordv[0]); - wordfree(&full_path); - return -1; + +static void printField(const char* val, TAOS_FIELD* field, int width, int32_t length, int precision) { + if (val == NULL) { + int w = width; + if (field->type < TSDB_DATA_TYPE_TINYINT || field->type > TSDB_DATA_TYPE_DOUBLE) { + w = 0; + } + w = printf("%*s", w, TSDB_DATA_NULL_STR); + for (; w < width; w++) { + putchar(' '); } + return; + } - wordfree(&full_path); + char buf[TSDB_MAX_BYTES_PER_ROW]; + switch (field->type) { + case TSDB_DATA_TYPE_BOOL: + printf("%*s", width, ((((int)(*((char *)val))) == 1) ? "true" : "false")); + break; + case TSDB_DATA_TYPE_TINYINT: + printf("%*d", width, (int)(*((char *)val))); + break; + case TSDB_DATA_TYPE_SMALLINT: + printf("%*d", width, (int)(*((short *)val))); + break; + case TSDB_DATA_TYPE_INT: + printf("%*d", width, *((int *)val)); + break; + case TSDB_DATA_TYPE_BIGINT: + printf("%*" PRId64, width, *((int64_t *)val)); + break; + case TSDB_DATA_TYPE_FLOAT: + printf("%*.5f", width, GET_FLOAT_VAL(val)); + break; + case TSDB_DATA_TYPE_DOUBLE: + printf("%*.9f", width, GET_DOUBLE_VAL(val)); + break; + case TSDB_DATA_TYPE_BINARY: + case TSDB_DATA_TYPE_NCHAR: + for (int w = shellPrintNChar(val, length, width); w < width; w++) { + putchar(' '); + } + break; + case TSDB_DATA_TYPE_TIMESTAMP: + formatTimestamp(buf, *(int64_t*)val, precision); + printf("%s", buf); + break; + default: + break; } +} - TAOS_FIELD *fields = taos_fetch_fields(result); - row = taos_fetch_row(result); +static int verticalPrintResult(TAOS_RES* result) { + TAOS_ROW row = taos_fetch_row(result); + if (row == NULL) { + return 0; + } + + int num_fields = taos_num_fields(result); + TAOS_FIELD *fields = taos_fetch_fields(result); int32_t* length = taos_fetch_lengths(result); - - char t_str[TSDB_MAX_BYTES_PER_ROW] = "\0"; - int l[TSDB_MAX_COLUMNS] = {0}; - int maxLenColumnName = 0; - - if (row) { - // Print the header indicator - if (fname == NULL) { // print to standard output - if (!printMode) { - for (int col = 0; col < num_fields; col++) { - switch (fields[col].type) { - case TSDB_DATA_TYPE_BOOL: - l[col] = MAX(BOOL_OUTPUT_LENGTH, strlen(fields[col].name)); - break; - case TSDB_DATA_TYPE_TINYINT: - l[col] = MAX(TINYINT_OUTPUT_LENGTH, strlen(fields[col].name)); - break; - case TSDB_DATA_TYPE_SMALLINT: - l[col] = MAX(SMALLINT_OUTPUT_LENGTH, strlen(fields[col].name)); - break; - case TSDB_DATA_TYPE_INT: - l[col] = MAX(INT_OUTPUT_LENGTH, strlen(fields[col].name)); - break; - case TSDB_DATA_TYPE_BIGINT: - l[col] = MAX(BIGINT_OUTPUT_LENGTH, strlen(fields[col].name)); - break; - case TSDB_DATA_TYPE_FLOAT: - l[col] = MAX(FLOAT_OUTPUT_LENGTH, strlen(fields[col].name)); - break; - case TSDB_DATA_TYPE_DOUBLE: - l[col] = MAX(DOUBLE_OUTPUT_LENGTH, strlen(fields[col].name)); - break; - case TSDB_DATA_TYPE_BINARY: - case TSDB_DATA_TYPE_NCHAR: - l[col] = MAX(fields[col].bytes, strlen(fields[col].name)); - /* l[col] = max(BINARY_OUTPUT_LENGTH, strlen(fields[col].name)); */ - break; - case TSDB_DATA_TYPE_TIMESTAMP: { - int32_t defaultWidth = TIMESTAMP_OUTPUT_LENGTH; - if (args.is_raw_time) { - defaultWidth = 14; - } - if (taos_result_precision(result) == TSDB_TIME_PRECISION_MICRO) { - defaultWidth += 3; - } - l[col] = MAX(defaultWidth, strlen(fields[col].name)); - - break; - } - default: - break; - } + int precision = taos_result_precision(result); - int spaces = (int)(l[col] - strlen(fields[col].name)); - int left_space = spaces / 2; - int right_space = (spaces % 2 ? left_space + 1 : left_space); - printf("%*.s%s%*.s|", left_space, " ", fields[col].name, right_space, " "); - output_bytes += (l[col] + 1); - } - printf("\n"); - for (int k = 0; k < output_bytes; k++) printf("="); - printf("\n"); + int maxColNameLen = 0; + for (int col = 0; col < num_fields; col++) { + int len = strlen(fields[col].name); + if (len > maxColNameLen) { + maxColNameLen = len; + } + } + + int numOfRows = 0; + do { + printf("*************************** %d.row ***************************\n", numOfRows + 1); + for (int i = 0; i < num_fields; i++) { + TAOS_FIELD* field = fields + i; + + int padding = (int)(maxColNameLen - strlen(field->name)); + printf("%*.s%s: ", padding, " ", field->name); + + printField(row[i], field, 0, length[i], precision); + putchar('\n'); + } + + numOfRows++; + row = taos_fetch_row(result); + } while(row != NULL); + + return numOfRows; +} + + +static int calcColWidth(TAOS_FIELD* field, int precision) { + int width = strlen(field->name); + + switch (field->type) { + case TSDB_DATA_TYPE_BOOL: + return MAX(5, width); // 'false' + + case TSDB_DATA_TYPE_TINYINT: + return MAX(4, width); // '-127' + + case TSDB_DATA_TYPE_SMALLINT: + return MAX(6, width); // '-32767' + + case TSDB_DATA_TYPE_INT: + return MAX(11, width); // '-2147483648' + + case TSDB_DATA_TYPE_BIGINT: + return MAX(21, width); // '-9223372036854775807' + + case TSDB_DATA_TYPE_FLOAT: + return MAX(20, width); + + case TSDB_DATA_TYPE_DOUBLE: + return MAX(25, width); + + case TSDB_DATA_TYPE_BINARY: + case TSDB_DATA_TYPE_NCHAR: + if (field->bytes > tsMaxBinaryDisplayWidth) { + return MAX(tsMaxBinaryDisplayWidth, width); } else { - for (int col = 0; col < num_fields; col++) { - if (strlen(fields[col].name) > maxLenColumnName) maxLenColumnName = strlen(fields[col].name); - } + return MAX(field->bytes, width); } - // print the elements - do { - if (!printMode) { - for (int i = 0; i < num_fields; i++) { - if (row[i] == NULL) { - printf("%*s|", l[i], TSDB_DATA_NULL_STR); - continue; - } - - switch (fields[i].type) { - case TSDB_DATA_TYPE_BOOL: - printf("%*s|", l[i], ((((int)(*((char *)row[i]))) == 1) ? "true" : "false")); - break; - case TSDB_DATA_TYPE_TINYINT: - printf("%*d|", l[i], (int)(*((char *)row[i]))); - break; - case TSDB_DATA_TYPE_SMALLINT: - printf("%*d|", l[i], (int)(*((short *)row[i]))); - break; - case TSDB_DATA_TYPE_INT: - printf("%*d|", l[i], *((int *)row[i])); - break; - case TSDB_DATA_TYPE_BIGINT: - printf("%*" PRId64 "|", l[i], *((int64_t *)row[i])); - break; - case TSDB_DATA_TYPE_FLOAT: { - float fv = 0; - fv = GET_FLOAT_VAL(row[i]); - printf("%*.5f|", l[i], fv); - } - break; - case TSDB_DATA_TYPE_DOUBLE: { - double dv = 0; - dv = GET_DOUBLE_VAL(row[i]); - printf("%*.9f|", l[i], dv); - } - break; - case TSDB_DATA_TYPE_BINARY: - case TSDB_DATA_TYPE_NCHAR: - memset(t_str, 0, TSDB_MAX_BYTES_PER_ROW); - memcpy(t_str, row[i], length[i]); - /* printf("%-*s|",max(fields[i].bytes, strlen(fields[i].name)), - * t_str); */ - /* printf("%-*s|", l[i], t_str); */ - shellPrintNChar(t_str, l[i], printMode); - break; - case TSDB_DATA_TYPE_TIMESTAMP: - if (args.is_raw_time) { - printf(" %" PRId64 "|", *(int64_t *)row[i]); - } else { - if (taos_result_precision(result) == TSDB_TIME_PRECISION_MICRO) { - tt = (time_t)((*(int64_t *)row[i]) / 1000000); - } else { - tt = (time_t)((*(int64_t *)row[i]) / 1000); - } - - ptm = localtime(&tt); - strftime(buf, 64, "%y-%m-%d %H:%M:%S", ptm); - - if (taos_result_precision(result) == TSDB_TIME_PRECISION_MICRO) { - printf(" %s.%06d|", buf, (int)(*(int64_t *)row[i] % 1000000)); - } else { - printf(" %s.%03d|", buf, (int)(*(int64_t *)row[i] % 1000)); - } - } - break; - default: - break; - } - } - printf("\n"); - } else { - printf("*************************** %d.row ***************************\n", numOfRows + 1); - for (int i = 0; i < num_fields; i++) { - // 1. print column name - int left_space = (int)(maxLenColumnName - strlen(fields[i].name)); - printf("%*.s%s: ", left_space, " ", fields[i].name); - - // 2. print column value - if (row[i] == NULL) { - printf("%s\n", TSDB_DATA_NULL_STR); - continue; - } - - switch (fields[i].type) { - case TSDB_DATA_TYPE_BOOL: - printf("%s\n", ((((int)(*((char *)row[i]))) == 1) ? "true" : "false")); - break; - case TSDB_DATA_TYPE_TINYINT: - printf("%d\n", (int)(*((char *)row[i]))); - break; - case TSDB_DATA_TYPE_SMALLINT: - printf("%d\n", (int)(*((short *)row[i]))); - break; - case TSDB_DATA_TYPE_INT: - printf("%d\n", *((int *)row[i])); - break; - case TSDB_DATA_TYPE_BIGINT: - printf("%" PRId64 "\n", *((int64_t *)row[i])); - break; - case TSDB_DATA_TYPE_FLOAT: { - float fv = 0; - fv = GET_FLOAT_VAL(row[i]); - printf("%.5f\n", fv); - } - break; - case TSDB_DATA_TYPE_DOUBLE: { - double dv = 0; - dv = GET_DOUBLE_VAL(row[i]); - printf("%.9f\n", dv); - } - break; - case TSDB_DATA_TYPE_BINARY: - case TSDB_DATA_TYPE_NCHAR: - memset(t_str, 0, TSDB_MAX_BYTES_PER_ROW); - memcpy(t_str, row[i], length[i]); - - l[i] = MAX(fields[i].bytes, strlen(fields[i].name)); - shellPrintNChar(t_str, l[i], printMode); - break; - case TSDB_DATA_TYPE_TIMESTAMP: - if (args.is_raw_time) { - printf("%" PRId64 "\n", *(int64_t *)row[i]); - } else { - if (taos_result_precision(result) == TSDB_TIME_PRECISION_MICRO) { - tt = (time_t)((*(int64_t *)row[i]) / 1000000); - } else { - tt = (time_t)((*(int64_t *)row[i]) / 1000); - } - - ptm = localtime(&tt); - strftime(buf, 64, "%y-%m-%d %H:%M:%S", ptm); - - if (taos_result_precision(result) == TSDB_TIME_PRECISION_MICRO) { - printf("%s.%06d\n", buf, (int)(*(int64_t *)row[i] % 1000000)); - } else { - printf("%s.%03d\n", buf, (int)(*(int64_t *)row[i] % 1000)); - } - } - break; - default: - break; - } - } - } - - numOfRows++; - } while ((row = taos_fetch_row(result))); - - } else { // dump to file - // first write column - for (int col = 0; col < num_fields; col++) { - fprintf(fp, "%s", fields[col].name); - if (col < num_fields - 1) { - fprintf(fp, ","); - } else { - fprintf(fp, "\n"); - } + case TSDB_DATA_TYPE_TIMESTAMP: + if (args.is_raw_time) { + return MAX(14, width); + } else if (precision == TSDB_TIME_PRECISION_MICRO) { + return MAX(26, width); // '2020-01-01 00:00:00.000000' + } else { + return MAX(23, width); // '2020-01-01 00:00:00.000' } - - do { - for (int i = 0; i < num_fields; i++) { - if (row[i]) { - switch (fields[i].type) { - case TSDB_DATA_TYPE_BOOL: - fprintf(fp, "%d", ((((int)(*((char *)row[i]))) == 1) ? 1 : 0)); - break; - case TSDB_DATA_TYPE_TINYINT: - fprintf(fp, "%d", (int)(*((char *)row[i]))); - break; - case TSDB_DATA_TYPE_SMALLINT: - fprintf(fp, "%d", (int)(*((short *)row[i]))); - break; - case TSDB_DATA_TYPE_INT: - fprintf(fp, "%d", *((int *)row[i])); - break; - case TSDB_DATA_TYPE_BIGINT: - fprintf(fp, "%" PRId64, *((int64_t *)row[i])); - break; - case TSDB_DATA_TYPE_FLOAT: { - float fv = 0; - fv = GET_FLOAT_VAL(row[i]); - fprintf(fp, "%.5f", fv); - } - break; - case TSDB_DATA_TYPE_DOUBLE: { - double dv = 0; - dv = GET_DOUBLE_VAL(row[i]); - fprintf(fp, "%.9f", dv); - } - break; - case TSDB_DATA_TYPE_BINARY: - case TSDB_DATA_TYPE_NCHAR: - memset(t_str, 0, TSDB_MAX_BYTES_PER_ROW); - memcpy(t_str, row[i], length[i]); - fprintf(fp, "\'%s\'", t_str); - break; - case TSDB_DATA_TYPE_TIMESTAMP: - if (args.is_raw_time) { - fprintf(fp, "%" PRId64, *(int64_t *)row[i]); - } else { - if (taos_result_precision(result) == TSDB_TIME_PRECISION_MICRO) { - tt = (time_t)((*(int64_t *)row[i]) / 1000000); - } else { - tt = (time_t)((*(int64_t *)row[i]) / 1000); - } - - ptm = localtime(&tt); - strftime(buf, 64, "%Y-%m-%d %H:%M:%S", ptm); - - if (taos_result_precision(result) == TSDB_TIME_PRECISION_MICRO) { - fprintf(fp, "\'%s.%06d\'", buf, (int)(*(int64_t *)row[i] % 1000000)); - } else { - fprintf(fp, "\'%s.%03d\'", buf, (int)(*(int64_t *)row[i] % 1000)); - } - } - break; - default: - break; - } - } else { - fprintf(fp, "%s", TSDB_DATA_NULL_STR); - } - if (i < num_fields - 1) { - fprintf(fp, ","); - } else { - fprintf(fp, "\n"); - } - } - numOfRows++; - } while ((row = taos_fetch_row(result))); - } + default: + assert(false); } - *error_no = taos_errno(con); + return 0; +} - taos_free_result(result); - result = NULL; + +static void printHeader(TAOS_FIELD* fields, int* width, int num_fields) { + int rowWidth = 0; + for (int col = 0; col < num_fields; col++) { + TAOS_FIELD* field = fields + col; + int padding = (int)(width[col] - strlen(field->name)); + int 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++) { + putchar('='); + } + putchar('\n'); +} + + +static int horizontalPrintResult(TAOS_RES* result) { + TAOS_ROW row = taos_fetch_row(result); + if (row == NULL) { + return 0; + } + + int num_fields = taos_num_fields(result); + TAOS_FIELD *fields = taos_fetch_fields(result); + int32_t* length = taos_fetch_lengths(result); + int precision = taos_result_precision(result); + + int width[TSDB_MAX_COLUMNS]; + for (int col = 0; col < num_fields; col++) { + width[col] = calcColWidth(fields + col, precision); + } + + printHeader(fields, width, num_fields); + + int numOfRows = 0; + do { + for (int i = 0; i < num_fields; i++) { + putchar(' '); + printField(row[i], fields + i, width[i], length[i], precision); + putchar(' '); + putchar('|'); + } + putchar('\n'); + numOfRows++; + row = taos_fetch_row(result); + } while(row != NULL); + + return numOfRows; +} + + +int shellDumpResult(TAOS *con, char *fname, int *error_no, bool vertical) { + int numOfRows = 0; + + TAOS_RES* result = taos_use_result(con); + if (result == NULL) { + taos_error(con); + return -1; + } if (fname != NULL) { - fclose(fp); + numOfRows = dumpResultToFile(fname, result); + } else if(vertical) { + numOfRows = verticalPrintResult(result); + } else { + numOfRows = horizontalPrintResult(result); } + *error_no = taos_errno(con); + taos_free_result(result); return numOfRows; } + void read_history() { // Initialize history memset(history.hist, 0, sizeof(char *) * MAX_HISTORY_SIZE); diff --git a/src/kit/shell/src/shellLinux.c b/src/kit/shell/src/shellLinux.c index da2bd94814..37c08d7ae9 100644 --- a/src/kit/shell/src/shellLinux.c +++ b/src/kit/shell/src/shellLinux.c @@ -329,35 +329,26 @@ void *shellLoopQuery(void *arg) { return NULL; } -void shellPrintNChar(char *str, int width, bool printMode) { - int col_left = width; - wchar_t wc; - while (col_left > 0) { - if (*str == '\0') break; - char *tstr = str; - int byte_width = mbtowc(&wc, tstr, MB_CUR_MAX); - if (byte_width <= 0) break; - int col_width = wcwidth(wc); - if (col_width <= 0) { - str += byte_width; - continue; +int shellPrintNChar(const char *str, int length, int width) { + int pos = 0, cols = 0; + while (pos < length) { + wchar_t wc; + pos += mbtowc(&wc, str + pos, MB_CUR_MAX); + if (pos > length) { + break; } - if (col_left < col_width) break; - printf("%lc", wc); - str += byte_width; - col_left -= col_width; - } - while (col_left > 0) { - printf(" "); - col_left--; + int w = wcwidth(wc); + if (w > 0) { + if (width > 0 && cols + w > width) { + break; + } + printf("%lc", wc); + cols += w; + } } - if (!printMode) { - printf("|"); - } else { - printf("\n"); - } + return cols; } int get_old_terminal_mode(struct termios *tio) { diff --git a/src/kit/shell/src/shellMain.c b/src/kit/shell/src/shellMain.c index f8010b84cd..3485a964d7 100644 --- a/src/kit/shell/src/shellMain.c +++ b/src/kit/shell/src/shellMain.c @@ -20,7 +20,6 @@ TAOS* con; pthread_t pid; -int32_t TIMESTAMP_OUTPUT_LENGTH = 22; // TODO: IMPLEMENT INTERRUPT HANDLER. void interruptHandler(int signum) { diff --git a/src/kit/shell/src/shellWindows.c b/src/kit/shell/src/shellWindows.c index ac04c593fb..8c7f24ef52 100644 --- a/src/kit/shell/src/shellWindows.c +++ b/src/kit/shell/src/shellWindows.c @@ -217,32 +217,30 @@ void *shellLoopQuery(void *arg) { return NULL; } -void shellPrintNChar(char *str, int width, bool printMode) { - int col_left = width; - wchar_t wc; - while (col_left > 0) { - if (*str == '\0') break; - char *tstr = str; - int byte_width = mbtowc(&wc, tstr, MB_CUR_MAX); - int col_width = byte_width; - if (col_left < col_width) break; - printf("%lc", wc); - str += byte_width; - col_left -= col_width; - } +int shellPrintNChar(const char *str, int length, int width) { + int pos = 0, cols = 0; + while (pos < length) { + wchar_t wc; + int bytes = mbtowc(&wc, str + pos, MB_CUR_MAX); + pos += bytes; + if (pos > length) { + break; + } - while (col_left > 0) { - printf(" "); - col_left--; - } - - if (!printMode) { - printf("|"); - } else { - printf("\n"); + int w = bytes; + if (w > 0) { + if (width > 0 && cols + w > width) { + break; + } + printf("%lc", wc); + cols += w; + } } + + return cols; } + void get_history_path(char *history) { sprintf(history, "%s/%s", ".", HISTORY_FILE); } void exitShell() { exit(EXIT_SUCCESS); } -- GitLab