Merge pull request #2028 from taosdata/feature/td-407
TD-407: add config for binary column display width
This commit is contained in:
commit
5513e3a738
|
@ -202,6 +202,8 @@ char tsTimezone[64] = {0};
|
||||||
char tsLocale[TSDB_LOCALE_LEN] = {0};
|
char tsLocale[TSDB_LOCALE_LEN] = {0};
|
||||||
char tsCharset[TSDB_LOCALE_LEN] = {0}; // default encode string
|
char tsCharset[TSDB_LOCALE_LEN] = {0}; // default encode string
|
||||||
|
|
||||||
|
int32_t tsMaxBinaryDisplayWidth = 30;
|
||||||
|
|
||||||
static pthread_once_t tsInitGlobalCfgOnce = PTHREAD_ONCE_INIT;
|
static pthread_once_t tsInitGlobalCfgOnce = PTHREAD_ONCE_INIT;
|
||||||
|
|
||||||
void taosSetAllDebugFlag() {
|
void taosSetAllDebugFlag() {
|
||||||
|
@ -1227,6 +1229,16 @@ static void doInitGlobalConfig() {
|
||||||
cfg.ptrLength = 0;
|
cfg.ptrLength = 0;
|
||||||
cfg.unitType = TAOS_CFG_UTYPE_NONE;
|
cfg.unitType = TAOS_CFG_UTYPE_NONE;
|
||||||
taosInitConfigOption(cfg);
|
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() {
|
void taosInitGlobalCfg() {
|
||||||
|
|
|
@ -29,18 +29,6 @@
|
||||||
#define MAX_COMMAND_SIZE 65536
|
#define MAX_COMMAND_SIZE 65536
|
||||||
#define HISTORY_FILE ".taos_history"
|
#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 {
|
typedef struct SShellHistory {
|
||||||
char* hist[MAX_HISTORY_SIZE];
|
char* hist[MAX_HISTORY_SIZE];
|
||||||
int hstart;
|
int hstart;
|
||||||
|
@ -80,7 +68,7 @@ void get_history_path(char* history);
|
||||||
void cleanup_handler(void* arg);
|
void cleanup_handler(void* arg);
|
||||||
void exitShell();
|
void exitShell();
|
||||||
int shellDumpResult(TAOS* con, char* fname, int* error_no, bool printMode);
|
int shellDumpResult(TAOS* con, char* fname, int* error_no, bool printMode);
|
||||||
void shellPrintNChar(char* str, int width, bool printMode);
|
void shellPrintNChar(const char* str, int length, int width);
|
||||||
void shellGetGrantInfo(void *con);
|
void shellGetGrantInfo(void *con);
|
||||||
int isCommentLine(char *line);
|
int isCommentLine(char *line);
|
||||||
|
|
||||||
|
|
|
@ -352,37 +352,31 @@ void *shellLoopQuery(void *arg) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void shellPrintNChar(char *str, int width, bool printMode) {
|
void shellPrintNChar(const char *str, int length, int width) {
|
||||||
int col_left = width;
|
int pos = 0, cols = 0;
|
||||||
wchar_t wc;
|
while (pos < length) {
|
||||||
while (col_left > 0) {
|
wchar_t wc;
|
||||||
if (*str == '\0') break;
|
pos += mbtowc(&wc, str + pos, MB_CUR_MAX);
|
||||||
char *tstr = str;
|
if (pos > length) {
|
||||||
int byte_width = mbtowc(&wc, tstr, MB_CUR_MAX);
|
break;
|
||||||
if (byte_width <= 0) break;
|
}
|
||||||
int col_width = wcwidth(wc);
|
|
||||||
if (col_width <= 0) {
|
int w = wcwidth(wc);
|
||||||
str += byte_width;
|
if (w > 0) {
|
||||||
continue;
|
if (width > 0 && cols + w > width) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
printf("%lc", wc);
|
||||||
|
cols += w;
|
||||||
}
|
}
|
||||||
if (col_left < col_width) break;
|
|
||||||
printf("%lc", wc);
|
|
||||||
str += byte_width;
|
|
||||||
col_left -= col_width;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
while (col_left > 0) {
|
for (; cols < width; cols++) {
|
||||||
printf(" ");
|
putchar(' ');
|
||||||
col_left--;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!printMode) {
|
|
||||||
printf("|");
|
|
||||||
} else {
|
|
||||||
printf("\n");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int get_old_terminal_mode(struct termios *tio) {
|
int get_old_terminal_mode(struct termios *tio) {
|
||||||
/* Make sure stdin is a terminal. */
|
/* Make sure stdin is a terminal. */
|
||||||
if (!isatty(STDIN_FILENO)) {
|
if (!isatty(STDIN_FILENO)) {
|
||||||
|
|
|
@ -35,6 +35,9 @@ int prompt_size = 6;
|
||||||
TAOS_RES *result = NULL;
|
TAOS_RES *result = NULL;
|
||||||
SShellHistory history;
|
SShellHistory history;
|
||||||
|
|
||||||
|
#define DEFAULT_MAX_BINARY_DISPLAY_WIDTH 30
|
||||||
|
extern int32_t tsMaxBinaryDisplayWidth;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* FUNCTION: Initialize the shell.
|
* 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)) {
|
} else if (regex_match(command, "^[\t ]*clear[ \t;]*$", REG_EXTENDED | REG_ICASE)) {
|
||||||
// If clear the screen.
|
// If clear the screen.
|
||||||
system("clear");
|
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)) {
|
} else if (regex_match(command, "^[ \t]*source[\t ]+[^ ]+[ \t;]*$", REG_EXTENDED | REG_ICASE)) {
|
||||||
/* If source file. */
|
/* If source file. */
|
||||||
char *c_ptr = strtok(command, " ;");
|
char *c_ptr = strtok(command, " ;");
|
||||||
|
@ -310,360 +321,347 @@ int regex_match(const char *s, const char *reg, int cflags) {
|
||||||
return 0;
|
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);
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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:
|
||||||
|
shellPrintNChar(val, length, width);
|
||||||
|
break;
|
||||||
|
case TSDB_DATA_TYPE_TIMESTAMP:
|
||||||
|
formatTimestamp(buf, *(int64_t*)val, precision);
|
||||||
|
printf("%s", buf);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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);
|
||||||
|
int precision = taos_result_precision(result);
|
||||||
|
|
||||||
|
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 {
|
||||||
|
return MAX(field->bytes, width);
|
||||||
|
}
|
||||||
|
|
||||||
|
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'
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
assert(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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) {
|
if (result == NULL) {
|
||||||
taos_error(con);
|
taos_error(con);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fname != NULL) {
|
if (fname != NULL) {
|
||||||
if (wordexp(fname, &full_path, 0) != 0) {
|
numOfRows = dumpResultToFile(fname, result);
|
||||||
fprintf(stderr, "ERROR: invalid file name: %s\n", fname);
|
} else if(vertical) {
|
||||||
return -1;
|
numOfRows = verticalPrintResult(result);
|
||||||
}
|
} else {
|
||||||
|
numOfRows = horizontalPrintResult(result);
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
TAOS_FIELD *fields = taos_fetch_fields(result);
|
|
||||||
|
|
||||||
row = taos_fetch_row(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 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");
|
|
||||||
} else {
|
|
||||||
for (int col = 0; col < num_fields; col++) {
|
|
||||||
if (strlen(fields[col].name) > maxLenColumnName) maxLenColumnName = strlen(fields[col].name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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)));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
*error_no = taos_errno(con);
|
*error_no = taos_errno(con);
|
||||||
|
|
||||||
taos_free_result(result);
|
taos_free_result(result);
|
||||||
result = NULL;
|
|
||||||
|
|
||||||
if (fname != NULL) {
|
|
||||||
fclose(fp);
|
|
||||||
}
|
|
||||||
|
|
||||||
return numOfRows;
|
return numOfRows;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void read_history() {
|
void read_history() {
|
||||||
// Initialize history
|
// Initialize history
|
||||||
memset(history.hist, 0, sizeof(char *) * MAX_HISTORY_SIZE);
|
memset(history.hist, 0, sizeof(char *) * MAX_HISTORY_SIZE);
|
||||||
|
|
|
@ -329,34 +329,27 @@ void *shellLoopQuery(void *arg) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void shellPrintNChar(char *str, int width, bool printMode) {
|
void shellPrintNChar(const char *str, int length, int width) {
|
||||||
int col_left = width;
|
int pos = 0, cols = 0;
|
||||||
wchar_t wc;
|
while (pos < length) {
|
||||||
while (col_left > 0) {
|
wchar_t wc;
|
||||||
if (*str == '\0') break;
|
pos += mbtowc(&wc, str + pos, MB_CUR_MAX);
|
||||||
char *tstr = str;
|
if (pos > length) {
|
||||||
int byte_width = mbtowc(&wc, tstr, MB_CUR_MAX);
|
break;
|
||||||
if (byte_width <= 0) break;
|
}
|
||||||
int col_width = wcwidth(wc);
|
|
||||||
if (col_width <= 0) {
|
int w = wcwidth(wc);
|
||||||
str += byte_width;
|
if (w > 0) {
|
||||||
continue;
|
if (width > 0 && cols + w > width) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
printf("%lc", wc);
|
||||||
|
cols += w;
|
||||||
}
|
}
|
||||||
if (col_left < col_width) break;
|
|
||||||
printf("%lc", wc);
|
|
||||||
str += byte_width;
|
|
||||||
col_left -= col_width;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
while (col_left > 0) {
|
for (; cols < width; cols++) {
|
||||||
printf(" ");
|
putchar(' ');
|
||||||
col_left--;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!printMode) {
|
|
||||||
printf("|");
|
|
||||||
} else {
|
|
||||||
printf("\n");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,6 @@
|
||||||
|
|
||||||
TAOS* con;
|
TAOS* con;
|
||||||
pthread_t pid;
|
pthread_t pid;
|
||||||
int32_t TIMESTAMP_OUTPUT_LENGTH = 22;
|
|
||||||
|
|
||||||
// TODO: IMPLEMENT INTERRUPT HANDLER.
|
// TODO: IMPLEMENT INTERRUPT HANDLER.
|
||||||
void interruptHandler(int signum) {
|
void interruptHandler(int signum) {
|
||||||
|
|
|
@ -217,32 +217,32 @@ void *shellLoopQuery(void *arg) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void shellPrintNChar(char *str, int width, bool printMode) {
|
void shellPrintNChar(const char *str, int length, int width) {
|
||||||
int col_left = width;
|
int pos = 0, cols = 0;
|
||||||
wchar_t wc;
|
while (pos < length) {
|
||||||
while (col_left > 0) {
|
wchar_t wc;
|
||||||
if (*str == '\0') break;
|
int bytes = mbtowc(&wc, str + pos, MB_CUR_MAX);
|
||||||
char *tstr = str;
|
pos += bytes;
|
||||||
int byte_width = mbtowc(&wc, tstr, MB_CUR_MAX);
|
if (pos > length) {
|
||||||
int col_width = byte_width;
|
break;
|
||||||
if (col_left < col_width) break;
|
}
|
||||||
printf("%lc", wc);
|
|
||||||
str += byte_width;
|
int w = bytes;
|
||||||
col_left -= col_width;
|
if (w > 0) {
|
||||||
|
if (width > 0 && cols + w > width) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
printf("%lc", wc);
|
||||||
|
cols += w;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
while (col_left > 0) {
|
for (; cols < width; cols++) {
|
||||||
printf(" ");
|
putchar(' ');
|
||||||
col_left--;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!printMode) {
|
|
||||||
printf("|");
|
|
||||||
} else {
|
|
||||||
printf("\n");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void get_history_path(char *history) { sprintf(history, "%s/%s", ".", HISTORY_FILE); }
|
void get_history_path(char *history) { sprintf(history, "%s/%s", ".", HISTORY_FILE); }
|
||||||
|
|
||||||
void exitShell() { exit(EXIT_SUCCESS); }
|
void exitShell() { exit(EXIT_SUCCESS); }
|
||||||
|
|
Loading…
Reference in New Issue