• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

taosdata / TDengine / #3831

02 Apr 2025 01:14AM UTC coverage: 34.081% (-0.02%) from 34.097%
#3831

push

travis-ci

happyguoxy
test:alter gcda dir

148596 of 599532 branches covered (24.79%)

Branch coverage included in aggregate %.

222550 of 489473 relevant lines covered (45.47%)

1589752.67 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

19.15
/tools/shell/src/shellAuto.c
1
/*
2
 * Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
3
 *
4
 * This program is free software: you can use, redistribute, and/or modify
5
 * it under the terms of the GNU Affero General Public License, version 3
6
 * or later ("AGPL"), as published by the Free Software Foundation.
7
 *
8
 * This program is distributed in the hope that it will be useful, but WITHOUT
9
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10
 * FITNESS FOR A PARTICULAR PURPOSE.
11
 *
12
 * You should have received a copy of the GNU Affero General Public License
13
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
14
 */
15

16
#define __USE_XOPEN
17

18
#include "shellAuto.h"
19
#include "shellInt.h"
20
#include "shellTire.h"
21
#include "tthread.h"
22

23
//
24
// ------------- define area  ---------------
25
//
26
#define UNION_ALL " union all "
27

28
// extern function
29
void  shellClearScreen(int32_t ecmd_pos, int32_t cursor_pos);
30
void  shellGetPrevCharSize(const char* str, int32_t pos, int32_t* size, int32_t* width);
31
void  shellShowOnScreen(SShellCmd* cmd);
32
void  shellInsertChar(SShellCmd* cmd, char* c, int size);
33
void  shellInsertStr(SShellCmd* cmd, char* str, int size);
34
bool  appendAfterSelect(TAOS* con, SShellCmd* cmd, char* p, int32_t len);
35
char* tireSearchWord(int type, char* pre);
36
bool  updateTireValue(int type, bool autoFill);
37

38
typedef struct SAutoPtr {
39
  STire* p;
40
  int    ref;
41
} SAutoPtr;
42

43
typedef struct SWord {
44
  int           type;  // word type , see WT_ define
45
  char*         word;
46
  int32_t       len;
47
  struct SWord* next;
48
  bool          free;  // if true need free
49
  bool          end;   // if true is last keyword
50
} SWord;
51

52
typedef struct {
53
  char*   source;
54
  int32_t source_len;  // valid data length in source
55
  int32_t count;
56
  SWord*  head;
57
  // matched information
58
  int32_t matchIndex;  // matched word index in words
59
  int32_t matchLen;    // matched length at matched word
60
} SWords;
61

62
SWords shellCommands[] = {
63
    {"alter database <db_name> <alter_db_options> <anyword> <alter_db_options> <anyword> <alter_db_options> <anyword> "
64
     "<alter_db_options> <anyword> <alter_db_options> <anyword> ;",
65
     0, 0, NULL},
66
    {"alter dnode <dnode_id> \"resetlog\";", 0, 0, NULL},
67
    {"alter dnode <dnode_id> \"debugFlag\" \"141\";", 0, 0, NULL},
68
    {"alter dnode <dnode_id> \"monitor\" \"0\";", 0, 0, NULL},
69
    {"alter dnode <dnode_id> \"monitor\" \"1\";", 0, 0, NULL},
70
    {"alter dnode <dnode_id> \"asynclog\" \"0\";", 0, 0, NULL},
71
    {"alter dnode <dnode_id> \"asynclog\" \"1\";", 0, 0, NULL},
72
    {"alter all dnodes \"resetlog\";", 0, 0, NULL},
73
    {"alter all dnodes \"debugFlag\" \"141\";", 0, 0, NULL},
74
    {"alter all dnodes \"monitor\" \"0\";", 0, 0, NULL},
75
    {"alter all dnodes \"monitor\" \"1\";", 0, 0, NULL},
76
    {"alter table <tb_name> <tb_actions> <anyword> ;", 0, 0, NULL},
77
    {"alter local \"resetlog\";", 0, 0, NULL},
78
    {"alter local \"DebugFlag\" \"143\";", 0, 0, NULL},
79
    {"alter local \"cDebugFlag\" \"143\";", 0, 0, NULL},
80
    {"alter local \"uDebugFlag\" \"143\";", 0, 0, NULL},
81
    {"alter local \"rpcDebugFlag\" \"143\";", 0, 0, NULL},
82
    {"alter local \"tmrDebugFlag\" \"143\";", 0, 0, NULL},
83
    {"alter local \"asynclog\" \"0\";", 0, 0, NULL},
84
    {"alter local \"asynclog\" \"1\";", 0, 0, NULL},
85
    {"alter topic", 0, 0, NULL},
86
    {"alter user <user_name> <user_actions> <anyword> ;", 0, 0, NULL},
87
#ifdef TD_ENTERPRISE
88
    {"balance vgroup ;", 0, 0, NULL},
89
    {"balance vgroup leader on <vgroup_id>", 0, 0, NULL},
90
#endif
91

92
    // 20
93
    {"create table <anyword> using <stb_name> tags(", 0, 0, NULL},
94
    {"create database <anyword> <db_options> <anyword> <db_options> <anyword> <db_options> <anyword> <db_options> "
95
     "<anyword> <db_options> <anyword> <db_options> <anyword> <db_options> <anyword> <db_options> <anyword> "
96
     "<db_options> <anyword> <db_options> <anyword> ;", 0, 0, NULL},
97
    {"create dnode <anyword>", 0, 0, NULL},
98
    {"create index <anyword> on <stb_name> ()", 0, 0, NULL},
99
    {"create mnode on dnode <dnode_id>;", 0, 0, NULL},
100
    {"create qnode on dnode <dnode_id>;", 0, 0, NULL},
101
    {"create stream <anyword> into <anyword> as select", 0, 0, NULL},  // 26 append sub sql
102
    {"create topic <anyword> as select", 0, 0, NULL},                  // 27 append sub sql
103
    {"create tsma <anyword> on <all_table> function", 0, 0, NULL},
104
    {"create recursive tsma <anyword> on <tsma_name> interval(", 0, 0, NULL},
105
    {"create function <anyword> as <anyword> outputtype <data_types> language <udf_language>;", 0, 0, NULL},
106
    {"create or replace <anyword> as <anyword> outputtype <data_types> language <udf_language>;", 0, 0, NULL},
107
    {"create aggregate function  <anyword> as <anyword> outputtype <data_types> bufsize <anyword> language <udf_language>;", 0, 0, NULL},
108
    {"create or replace aggregate function  <anyword> as <anyword> outputtype <data_types> bufsize <anyword> language <udf_language>;", 0, 0, NULL},
109
    {"create user <anyword> pass <anyword> sysinfo 0;", 0, 0, NULL},
110
    {"create user <anyword> pass <anyword> sysinfo 1;", 0, 0, NULL},
111
#ifdef TD_ENTERPRISE    
112
    {"create view <anyword> as select", 0, 0, NULL},
113
    {"compact database <db_name>", 0, 0, NULL},
114
#endif
115
    {"desc <all_table>;", 0, 0, NULL},
116
    {"describe <all_table>;", 0, 0, NULL},
117
    {"delete from <all_table> where ", 0, 0, NULL},
118
    {"drop database <db_name>;", 0, 0, NULL},
119
    {"drop index <anyword>;", 0, 0, NULL},
120
    {"drop table <all_table>;", 0, 0, NULL},
121
    {"drop dnode <dnode_id>;", 0, 0, NULL},
122
    {"drop mnode on dnode <dnode_id>;", 0, 0, NULL},
123
    {"drop qnode on dnode <dnode_id>;", 0, 0, NULL},
124
    {"drop user <user_name>;", 0, 0, NULL},
125
    // 40
126
    {"drop function <udf_name>;", 0, 0, NULL},
127
    {"drop consumer group <anyword> on ", 0, 0, NULL},
128
    {"drop topic <topic_name>;", 0, 0, NULL},
129
    {"drop stream <stream_name>;", 0, 0, NULL},
130
    {"drop tsma <tsma_name>;", 0, 0, NULL},
131
    {"explain select ", 0, 0, NULL},  // 44 append sub sql
132
    {"flush database <db_name>;", 0, 0, NULL},
133
    {"help;", 0, 0, NULL},
134
    {"grant all on <anyword> to <user_name>;", 0, 0, NULL},
135
    {"grant read on <anyword> to <user_name>;", 0, 0, NULL},
136
    {"grant write on <anyword> to <user_name>;", 0, 0, NULL},
137
    {"kill connection <anyword>;", 0, 0, NULL},
138
    {"kill query ", 0, 0, NULL},
139
    {"kill transaction ", 0, 0, NULL},
140
#ifdef TD_ENTERPRISE
141
    {"merge vgroup <vgroup_id> <vgroup_id>;", 0, 0, NULL},
142
#endif
143
    {"pause stream <stream_name>;", 0, 0, NULL},
144
#ifdef TD_ENTERPRISE
145
    {"redistribute vgroup <vgroup_id> dnode <dnode_id>;", 0, 0, NULL},
146
#endif
147
    {"resume stream <stream_name>;", 0, 0, NULL},
148
    {"reset query cache;", 0, 0, NULL},
149
    {"restore dnode <dnode_id>;", 0, 0, NULL},
150
    {"restore vnode on dnode <dnode_id>;", 0, 0, NULL},
151
    {"restore mnode on dnode <dnode_id>;", 0, 0, NULL},
152
    {"restore qnode on dnode <dnode_id>;", 0, 0, NULL},
153
    {"revoke all on <anyword> from <user_name>;", 0, 0, NULL},
154
    {"revoke read on <anyword> from <user_name>;", 0, 0, NULL},
155
    {"revoke write on <anyword> from <user_name>;", 0, 0, NULL},
156
    {"select * from <all_table>", 0, 0, NULL},
157
    {"select client_version();", 0, 0, NULL},
158
    // 60
159
    {"select current_user();", 0, 0, NULL},
160
    {"select database();", 0, 0, NULL},
161
    {"select server_version();", 0, 0, NULL},
162
    {"select server_status();", 0, 0, NULL},
163
    {"select now();", 0, 0, NULL},
164
    {"select today();", 0, 0, NULL},
165
    {"select timezone();", 0, 0, NULL},
166
    {"set max_binary_display_width ", 0, 0, NULL},
167
    {"show apps;", 0, 0, NULL},
168
    {"show alive;", 0, 0, NULL},
169
    {"show create database <db_name> \\G;", 0, 0, NULL},
170
    {"show create stable <stb_name> \\G;", 0, 0, NULL},
171
    {"show create table <tb_name> \\G;", 0, 0, NULL},
172
#ifdef TD_ENTERPRISE    
173
    {"show create view <all_table> \\G;", 0, 0, NULL},
174
    {"show compact", 0, 0, NULL},
175
    {"show compacts;", 0, 0, NULL},
176

177
#endif
178
    {"show connections;", 0, 0, NULL},
179
    {"show cluster;", 0, 0, NULL},
180
    {"show cluster alive;", 0, 0, NULL},
181
    {"show cluster machines;", 0, 0, NULL},
182
    {"show databases;", 0, 0, NULL},
183
    {"show dnodes;", 0, 0, NULL},
184
    {"show dnode <dnode_id> variables;", 0, 0, NULL},
185
    {"show functions;", 0, 0, NULL},
186
    {"show licences;", 0, 0, NULL},
187
    {"show mnodes;", 0, 0, NULL},
188
    {"show queries;", 0, 0, NULL},
189
    // 80
190
    {"show query <anyword> ;", 0, 0, NULL},
191
    {"show qnodes;", 0, 0, NULL},
192
    {"show stables;", 0, 0, NULL},
193
    {"show stables like ", 0, 0, NULL},
194
    {"show streams;", 0, 0, NULL},
195
    {"show scores;", 0, 0, NULL},
196
    {"show snodes;", 0, 0, NULL},
197
    {"show subscriptions;", 0, 0, NULL},
198
    {"show tables;", 0, 0, NULL},
199
    {"show tables like", 0, 0, NULL},
200
    {"show table distributed <all_table>;", 0, 0, NULL},
201
    {"show tags from <tb_name>;", 0, 0, NULL},
202
    {"show table tags from <all_table>;", 0, 0, NULL},
203
    {"show topics;", 0, 0, NULL},
204
    {"show transactions;", 0, 0, NULL},
205
    {"show tsmas;", 0, 0, NULL},
206
    {"show users;", 0, 0, NULL},
207
    {"show variables;", 0, 0, NULL},
208
    {"show local variables;", 0, 0, NULL},
209
    {"show vnodes;", 0, 0, NULL},
210
    {"show vnodes on dnode <dnode_id>;", 0, 0, NULL},
211
    {"show vgroups;", 0, 0, NULL},
212
    {"show consumers;", 0, 0, NULL},
213
    {"show grants;", 0, 0, NULL},
214
    {"show grants full;", 0, 0, NULL},
215
    {"show grants logs;", 0, 0, NULL},
216
#ifdef TD_ENTERPRISE
217
    {"show views;", 0, 0, NULL},
218
    {"show arbgroups;", 0, 0, NULL},
219
    {"split vgroup <vgroup_id>;", 0, 0, NULL},
220
    {"s3migrate database <db_name>;", 0, 0, NULL},
221
#endif
222
    {"insert into <tb_name> values(", 0, 0, NULL},
223
    {"insert into <tb_name> using <stb_name> tags(", 0, 0, NULL},
224
    {"insert into <tb_name> using <stb_name> <anyword> values(", 0, 0, NULL},
225
    {"insert into <tb_name> file ", 0, 0, NULL},
226
    {"trim database <db_name>;", 0, 0, NULL},
227
    {"use <db_name>;", 0, 0, NULL},
228
    {"quit", 0, 0, NULL}};
229

230
// where keyword
231
char* keywords[] = {
232
    "where ",       "and ",      "asc ",      "desc ",    "from ",         "fill(",     "limit ",
233
    "interval(",    "order by ", "order by ", "offset ",  "or ",           "group by ", "now()",
234
    "session(",     "sliding ",  "slimit ",   "soffset ", "state_window(", "today() ",  "union all select ",
235
    "partition by ", "match",    "nmatch ",    "between ",  "like ",           "is null ",   "is not null ",
236
    "event_window ",  "count_window("
237
};
238

239
char* functions[] = {
240
    "count(",         "sum(",
241
    "avg(",           "last(",
242
    "last_row(",      "top(",
243
    "interp(",        "max(",
244
    "min(",           "now()",
245
    "today()",        "percentile(",
246
    "tail(",          "pow(",
247
    "abs(",           "atan(",
248
    "acos(",          "asin(",
249
    "apercentile(",   "bottom(",
250
    "cast(",          "ceil(",
251
    "char_length(",   "cos(",
252
    "concat(",        "concat_ws(",
253
    "csum(",          "diff(",
254
    "derivative(",    "elapsed(",
255
    "first(",         "floor(",
256
    "hyperloglog(",   "histogram(",
257
    "irate(",         "leastsquares(",
258
    "length(",        "log(",
259
    "lower(",         "ltrim(",
260
    "mavg(",          "mode(",
261
    "tan(",           "round(",
262
    "rtrim(",         "sample(",
263
    "sin(",           "spread(",
264
    "substr(",        "statecount(",
265
    "stateduration(", "stddev(",
266
    "sqrt(",          "timediff(",
267
    "timezone(",      "timetruncate(",
268
    "twa(",           "to_unixtimestamp(",
269
    "unique(",        "upper(",
270
    "pi(",            "round(",
271
    "truncate(",      "exp(",
272
    "ln(",            "mod(",
273
    "rand(",          "sign(",
274
    "degrees(",       "radians(",
275
    "greatest(",      "least(",
276
    "char_length(",   "char(",
277
    "ascii(",         "position(",
278
    "trim(",           "replace(",
279
    "repeat(",         "substring(",
280
    "substring_index(","timediff(",
281
    "week(",           "weekday(",
282
    "weekofyear(",     "dayofweek(",
283
    "stddev_pop(",     "var_pop("
284
};
285

286
char* tb_actions[] = {
287
    "add column ", "modify column ", "drop column ", "rename column ", "add tag ",
288
    "modify tag ", "drop tag ",      "rename tag ",  "set tag ",
289
};
290

291
char* user_actions[] = {"pass ", "enable ", "sysinfo "};
292

293
char* tb_options[] = {"comment ", "watermark ", "max_delay ", "ttl ", "rollup(", "sma("};
294

295
char* db_options[] = {"keep ",
296
                      "replica ",
297
                      "precision ",
298
                      "strict ",
299
                      "buffer ",
300
                      "cachemodel ",
301
                      "cachesize ",
302
                      "comp ",
303
                      "duration ",
304
                      "wal_fsync_period ",
305
                      "maxrows ",
306
                      "minrows ",
307
                      "pages ",
308
                      "pagesize ",
309
                      "retentions ",
310
                      "wal_level ",
311
                      "vgroups ",
312
                      "single_stable ",
313
                      "s3_chunksize ",
314
                      "s3_keeplocal ",
315
                      "s3_compact ",
316
                      "wal_retention_period ",
317
                      "wal_roll_period ",
318
                      "wal_retention_size ",
319
#ifdef TD_ENTERPRISE                      
320
                      "encrypt_algorithm "
321
#endif
322
                      "keep_time_offset ",
323
                      "wal_segment_size "
324
};
325

326
char* alter_db_options[] = {"cachemodel ", "replica ", "keep ", "stt_trigger ",
327
                            "wal_retention_period ", "wal_retention_size ", "cachesize ", 
328
                                              "s3_keeplocal ", "s3_compact ",
329
                            "wal_fsync_period ", "buffer ", "pages " ,"wal_level "};
330

331
char* data_types[] = {"timestamp",    "int",
332
                      "int unsigned", "varchar(16)",
333
                      "float",        "double",
334
                      "binary(16)",   "nchar(16)",
335
                      "bigint",       "bigint unsigned",
336
                      "smallint",     "smallint unsigned",
337
                      "tinyint",      "tinyint unsigned",
338
                      "geometry(64)", "varbinary(16)",
339
                      "bool",         "json"};
340

341
char* key_tags[] = {"tags("};
342

343
char* key_select[] = {"select "};
344

345
char* key_systable[] = {
346
    "ins_dnodes",        "ins_mnodes",     "ins_modules",      "ins_qnodes",  "ins_snodes",          "ins_cluster",
347
    "ins_databases",     "ins_functions",  "ins_indexes",      "ins_stables", "ins_tables",          "ins_tags",
348
    "ins_users",         "ins_grants",     "ins_vgroups",      "ins_configs", "ins_dnode_variables", "ins_topics",
349
    "ins_subscriptions", "ins_streams",    "ins_stream_tasks", "ins_vnodes",  "ins_user_privileges", "perf_connections",
350
    "perf_queries",      "perf_consumers", "perf_trans",       "perf_apps"};
351

352
char* udf_language[] = {"\'Python\'", "\'C\'"};
353

354
char* field_options[] = {
355
    "encode ", "compress ", "level ", 
356
    "\'lz4\' ", "\'zlib\' ", "\'zstd\' ", "\'xz\' ", "\'tsz\' ", "\'disabled\' ", // compress
357
    "\'simple8b\' ", "\'delta-i\' ", "\'delta-d\' ", "\'bit-packing\' ",
358
    "\'high\' ", "\'medium\' ", "\'low\' ",
359
    "comment ",
360
    "primary key "
361
};
362

363
// global keys can tips on anywhere
364
char* global_keys[] = {
365
    "tbname",         
366
    "now",
367
    "vgroups",
368
    "_wstart",      
369
    "_wend",
370
    "_wduration",
371
    "_qstart",          
372
    "_qend",
373
    "_qduration",
374
    "_qtag",
375
    "_isfilled"
376
  };
377

378
//
379
//  ------- global variant define ---------
380
//
381
int32_t firstMatchIndex = -1;  // first match shellCommands index
382
int32_t lastMatchIndex = -1;   // last match shellCommands index
383
int32_t curMatchIndex = -1;    // current match shellCommands index
384
int32_t lastWordBytes = -1;    // printShow last word length
385
bool    waitAutoFill = false;
386

387
//
388
//   ----------- global var array define -----------
389
//
390
#define WT_VAR_DBNAME         0
391
#define WT_VAR_STABLE         1
392
#define WT_VAR_TABLE          2
393
#define WT_VAR_DNODEID        3
394
#define WT_VAR_USERNAME       4
395
#define WT_VAR_TOPIC          5
396
#define WT_VAR_STREAM         6
397
#define WT_VAR_UDFNAME        7
398
#define WT_VAR_VGROUPID       8
399
#define WT_VAR_TSMA           9
400

401
#define WT_FROM_DB_MAX        9  // max get content from db
402
#define WT_FROM_DB_CNT (WT_FROM_DB_MAX + 1)
403

404
#define WT_VAR_ALLTABLE       10
405
#define WT_VAR_FUNC           11
406
#define WT_VAR_KEYWORD        12
407
#define WT_VAR_TBACTION       13
408
#define WT_VAR_DBOPTION       14
409
#define WT_VAR_ALTER_DBOPTION 15
410
#define WT_VAR_DATATYPE       16
411
#define WT_VAR_KEYTAGS        17
412
#define WT_VAR_ANYWORD        18
413
#define WT_VAR_TBOPTION       19
414
#define WT_VAR_USERACTION     20
415
#define WT_VAR_KEYSELECT      21
416
#define WT_VAR_SYSTABLE       22
417
#define WT_VAR_LANGUAGE       23
418
#define WT_VAR_GLOBALKEYS     24
419
#define WT_VAR_FIELD_OPTIONS  25
420

421
#define WT_VAR_CNT 26
422

423

424
#define WT_TEXT 0xFF
425

426
char dbName[256] = "";  // save use database name;
427
// tire array
428
STire*        tires[WT_VAR_CNT];
429
TdThreadMutex tiresMutex;
430
// save thread handle obtain var name from db server
431
TdThread* threads[WT_FROM_DB_CNT];
432
// obtain var name  with sql from server
433
char varTypes[WT_VAR_CNT][64] = {
434
    // get from db
435
    "<db_name>",    "<stb_name>",  "<tb_name>",  "<dnode_id>",  "<user_name>",    "<topic_name>", "<stream_name>",
436
    "<udf_name>",   "<vgroup_id>", "<tsma_name>",
437
    // get from code
438
    "<all_table>",  "<function>",  "<keyword>",  "<tb_actions>",   "<db_options>", "<alter_db_options>",
439
    "<data_types>", "<key_tags>",  "<anyword>",  "<tb_options>", "<user_actions>", "<key_select>", "<sys_table>", 
440
    "<udf_language>", "<global_keys>", "<field_options>"};
441

442
char varSqls[WT_FROM_DB_CNT][64] = {"show databases;", "show stables;", "show tables;", "show dnodes;",
443
                                    "show users;",     "show topics;",  "show streams;", "show functions;", 
444
                                    "show vgroups;",   "show tsmas;"};
445

446
// var words current cursor, if user press any one key except tab, cursorVar can be reset to -1
447
int  cursorVar = -1;
448
bool varMode = false;  // enter var names list mode
449

450
TAOS*      varCon = NULL;
451
SShellCmd* varCmd = NULL;
452
bool       varRunOnce = false;
453
SMatch*    lastMatch = NULL;  // save last match result
454
int        cntDel = 0;        // delete byte count after next press tab
455

456
// show auto tab introduction
457
void printfIntroduction(EVersionType type) {
×
458
  printf("  *********************************  Tab Completion  *************************************\n");
×
459
  char secondLine[160] = "\0";
×
460
  sprintf(secondLine, "  *   The %s CLI supports tab completion for a variety of items, ", shell.info.cusName);
×
461
  printf("%s", secondLine);
×
462
  int secondLineLen = strlen(secondLine);
×
463
  while (89 - (secondLineLen++) > 0) {
×
464
    printf(" ");
×
465
  }
466
  printf("*\n");
×
467
  printf("  *   including database names, table names, function names and keywords.                *\n");
×
468
  printf("  *   The full list of shortcut keys is as follows:                                      *\n");
×
469
  printf("  *    [ TAB ]        ......  complete the current word                                  *\n");
×
470
  printf("  *                   ......  if used on a blank line, display all supported commands    *\n");
×
471
  printf("  *    [ Ctrl + A ]   ......  move cursor to the st[A]rt of the line                     *\n");
×
472
  printf("  *    [ Ctrl + E ]   ......  move cursor to the [E]nd of the line                       *\n");
×
473
  printf("  *    [ Ctrl + W ]   ......  move cursor to the middle of the line                      *\n");
×
474
  printf("  *    [ Ctrl + L ]   ......  clear the entire screen                                    *\n");
×
475
  printf("  *    [ Ctrl + K ]   ......  clear the screen after the cursor                          *\n");
×
476
  printf("  *    [ Ctrl + U ]   ......  clear the screen before the cursor                         *\n");
×
477
  if (type == TSDB_VERSION_OSS) {
×
478
    printf("  * ------------------------------------------------------------------------------------ *\n");
×
479
    printf("  *   You are using TDengine OSS. To experience advanced features, like backup/restore,  *\n");
×
480
    printf("  *   privilege control and more, or receive 7x24 technical support, try TDengine        *\n");
×
481
    printf("  *   Enterprise or TDengine Cloud. Learn more at https://tdengine.com                   *\n");
×
482
  }
483
  printf("  ****************************************************************************************\n\n");
×
484
}
×
485

486
// show enterprise AD
487
void showAD(bool end) {
×
488
  printf("  You are using TDengine OSS. To experience advanced features, like backup/restore,  \n");
×
489
  printf("  privilege control and more, or receive 7x24 technical support, try TDengine Enterprise \n");
×
490
  printf("  or TDengine Cloud. Learn more at https://tdengine.com   \n");
×
491
  printf("  \n");
×
492
}
×
493

494
void showHelp() {
×
495
  printf("\nThe %s CLI supports the following commands:", shell.info.cusName);
×
496
  printf(
×
497
      "\n\
498
  ----- A ----- \n\
499
    alter database <db_name> <db_options> \n\
500
    alter dnode <dnode_id> 'resetlog';\n\
501
    alter dnode <dnode_id> 'monitor' '0';\n\
502
    alter dnode <dnode_id> 'monitor' \"1\";\n\
503
    alter dnode <dnode_id> \"debugflag\" \"143\";\n\
504
    alter dnode <dnode_id> 'asynclog' '0';\n\
505
    alter dnode <dnode_id> 'asynclog' \"1\";\n\
506
    alter all dnodes \"monitor\" \"0\";\n\
507
    alter all dnodes \"monitor\" \"1\";\n\
508
    alter all dnodes \"resetlog\";\n\
509
    alter all dnodes \"debugFlag\" \n\
510
    alter all dnodes \"asynclog\" \"0\";\n\
511
    alter all dnodes \"asynclog\" \"1\";\n\
512
    alter table <tb_name> <tb_actions> ;\n\
513
    alter local \"resetlog\";\n\
514
    alter local \"DebugFlag\" \"143\";\n\
515
    alter local \"asynclog\" \"0\";\n\
516
    alter local \"asynclog\" \"1\";\n\
517
    alter topic\n\
518
    alter user <user_name> <user_actions> ...\n\
519
  ----- C ----- \n\
520
    create table <tb_name> using <stb_name> tags ...\n\
521
    create database <db_name> <db_options>  ...\n\
522
    create dnode \"fqdn:port\" ...\n\
523
    create index <index_name> on <stb_name> (tag_column_name);\n\
524
    create mnode on dnode <dnode_id> ;\n\
525
    create qnode on dnode <dnode_id> ;\n\
526
    create stream <stream_name> into <stb_name> as select ...\n\
527
    create topic <topic_name> as select ...\n\
528
    create function <udf_name> as <file_name> outputtype <data_types> language \'C\' | \'Python\' ;\n\
529
    create aggregate function  <udf_name> as <file_name> outputtype <data_types> bufsize <bufsize_bytes> language \'C\' | \'Python\';\n\
530
    create user <user_name> pass <password> ...\n\
531
  ----- D ----- \n\
532
    describe <all_table>\n\
533
    delete from <all_table> where ...\n\
534
    drop database <db_name>;\n\
535
    drop table <all_table>;\n\
536
    drop dnode <dnode_id>;\n\
537
    drop mnode on dnode <dnode_id> ;\n\
538
    drop qnode on dnode <dnode_id> ;\n\
539
    drop user <user_name> ;\n\
540
    drop function <udf_name>;\n\
541
    drop consumer group ... \n\
542
    drop topic <topic_name> ;\n\
543
    drop stream <stream_name> ;\n\
544
    drop index <index_name>;\n\
545
  ----- E ----- \n\
546
    explain select clause ...\n\
547
  ----- F ----- \n\
548
    flush database <db_name>;\n\
549
  ----- H ----- \n\
550
    help;\n\
551
  ----- I ----- \n\
552
    insert into <tb_name> values(...) ;\n\
553
    insert into <tb_name> using <stb_name> tags(...) values(...) ;\n\
554
  ----- G ----- \n\
555
    grant all   on <priv_level> to <user_name> ;\n\
556
    grant read  on <priv_level> to <user_name> ;\n\
557
    grant write on <priv_level> to <user_name> ;\n\
558
  ----- K ----- \n\
559
    kill connection <connection_id>; \n\
560
    kill query <query_id>; \n\
561
    kill transaction <transaction_id>;\n\
562
  ----- P ----- \n\
563
    pause stream <stream_name>;\n\
564
  ----- R ----- \n\
565
    resume stream <stream_name>;\n\
566
    reset query cache;\n\
567
    restore dnode <dnode_id> ;\n\
568
    restore vnode on dnode <dnode_id> ;\n\
569
    restore mnode on dnode <dnode_id> ;\n\
570
    restore qnode on dnode <dnode_id> ;\n\
571
    revoke all   on <priv_level> from <user_name> ;\n\
572
    revoke read  on <priv_level> from <user_name> ;\n\
573
    revoke write on <priv_level> from <user_name> ;\n\
574
  ----- S ----- \n\
575
    select * from <all_table> where ... \n\
576
    select client_version();\n\
577
    select current_user();\n\
578
    select database();\n\
579
    select server_version();\n\
580
    select server_status();\n\
581
    select now();\n\
582
    select today();\n\
583
    select timezone();\n\
584
    set max_binary_display_width ...\n\
585
    show apps;\n\
586
    show alive;\n\
587
    show create database <db_name>;\n\
588
    show create stable <stb_name>;\n\
589
    show create table <tb_name>;\n\
590
    show connections;\n\
591
    show cluster;\n\
592
    show cluster alive;\n\
593
    show cluster machines;\n\
594
    show databases;\n\
595
    show dnodes;\n\
596
    show dnode <dnode_id> variables;\n\
597
    show functions;\n\
598
    show licences;\n\
599
    show mnodes;\n\
600
    show queries;\n\
601
    show query <query_id> ;\n\
602
    show qnodes;\n\
603
    show snodes;\n\
604
    show stables;\n\
605
    show stables like \n\
606
    show streams;\n\
607
    show scores;\n\
608
    show subscriptions;\n\
609
    show tables;\n\
610
    show tables like\n\
611
    show table distributed <all_table>;\n\
612
    show tags from <tb_name>\n\
613
    show tags from <db_name>\n\
614
    show table tags from <all_table>\n\
615
    show topics;\n\
616
    show transactions;\n\
617
    show users;\n\
618
    show variables;\n\
619
    show local variables;\n\
620
    show vnodes;\n\
621
    show vnodes on dnode <dnode_id>;\n\
622
    show vgroups;\n\
623
    show consumers;\n\
624
    show grants;\n\
625
    show grants full;\n\
626
    show grants logs;\n\
627
  ----- T ----- \n\
628
    trim database <db_name>;\n\
629
  ----- U ----- \n\
630
    use <db_name>;");
631

632
#ifdef TD_ENTERPRISE
633
  printf(
×
634
      "\n\n\
635
  ----- special commands on enterpise version ----- \n\
636
    balance vgroup ;\n\
637
    balance vgroup leader on <vgroup_id> \n\
638
    compact database <db_name>; \n\
639
    create view <view_name> as select ...\n\
640
    redistribute vgroup <vgroup_id> dnode <dnode_id> ;\n\
641
    split vgroup <vgroup_id>;\n\
642
    s3migrate database <db_name>;\n\
643
    show compacts;\n\
644
    show compact \n\
645
    show arbgroups;\n\
646
    show views;\n\
647
    show create view <all_table>;");
648
#endif
649

650
  printf("\n\n");
×
651
  // define in getDuration() function
652
  printf(
×
653
      "\
654
  Timestamp expression Format:\n\
655
    b - nanosecond \n\
656
    u - microsecond \n\
657
    a - millisecond \n\
658
    s - second \n\
659
    m - minute \n\
660
    h - hour \n\
661
    d - day \n\
662
    w - week \n\
663
    now - current time \n\
664
  Example : \n\
665
    select * from t1 where ts > now - 2w + 3d and ts <= now - 1w -2h ;\n");
666
  printf(ERROR_CODE_DETAIL);
×
667
  printf("\n");
×
668
}
×
669

670
//
671
//  -------------------  parse words --------------------------
672
//
673

674
#define SHELL_COMMAND_COUNT() (sizeof(shellCommands) / sizeof(SWords))
675

676
// get at
677
SWord* atWord(SWords* command, int32_t index) {
×
678
  SWord* word = command->head;
×
679
  for (int32_t i = 0; i < index; i++) {
×
680
    if (word == NULL) return NULL;
×
681
    word = word->next;
×
682
  }
683

684
  return word;
×
685
}
686

687
#define MATCH_WORD(x) atWord(x, x->matchIndex)
688

689
int wordType(const char* p, int32_t len) {
237,222✔
690
  for (int i = 0; i < WT_VAR_CNT; i++) {
5,462,316✔
691
    if (strncmp(p, varTypes[i], len) == 0) return i;
5,287,194✔
692
  }
693
  return WT_TEXT;
175,122✔
694
}
695

696
// add word
697
SWord* addWord(const char* p, int32_t len, bool pattern) {
240,534✔
698
  SWord* word = (SWord*)taosMemoryMalloc(sizeof(SWord));
240,534!
699
  memset(word, 0, sizeof(SWord));
240,534✔
700
  word->word = (char*)p;
240,534✔
701
  word->len = len;
240,534✔
702

703
  // check format
704
  if (pattern && len > 0) {
240,534!
705
    if (p[len - 1] == ';') {
237,222✔
706
      word->type = wordType(p, len - 1);
48,852✔
707
      word->end = true;
48,852✔
708
    } else {
709
      word->type = wordType(p, len);
188,370✔
710
    }
711
  } else {
712
    word->type = WT_TEXT;
3,312✔
713
  }
714

715
  return word;
240,534✔
716
}
717

718
// parse one command
719
void parseCommand(SWords* command, bool pattern) {
59,616✔
720
  char*   p = command->source;
59,616✔
721
  int32_t start = 0;
59,616✔
722
  int32_t size = command->source_len > 0 ? command->source_len : strlen(p);
59,616!
723

724
  bool lastBlank = false;
59,616✔
725
  for (int i = 0; i <= size; i++) {
1,937,520✔
726
    if (p[i] == ' ' || i == size) {
1,877,904✔
727
      // check continue blank like '    '
728
      if (p[i] == ' ') {
241,362✔
729
        if (lastBlank) {
181,746✔
730
          start++;
828✔
731
          continue;
828✔
732
        }
733
        if (i == 0) {  // first blank
180,918!
734
          lastBlank = true;
×
735
          start++;
×
736
          continue;
×
737
        }
738
        lastBlank = true;
180,918✔
739
      }
740

741
      // found split or string end , append word
742
      if (command->head == NULL) {
240,534✔
743
        command->head = addWord(p + start, i - start, pattern);
59,616✔
744
        command->count = 1;
59,616✔
745
      } else {
746
        SWord* word = command->head;
180,918✔
747
        while (word->next) {
585,810✔
748
          word = word->next;
404,892✔
749
        }
750
        word->next = addWord(p + start, i - start, pattern);
180,918✔
751
        command->count++;
180,918✔
752
      }
753
      start = i + 1;
240,534✔
754
    } else {
755
      lastBlank = false;
1,636,542✔
756
    }
757
  }
758
}
59,616✔
759

760
// free SShellCmd
761
void freeCommand(SWords* command) {
59,616✔
762
  SWord* item = command->head;
59,616✔
763
  command->head = NULL;
59,616✔
764
  // loop
765
  while (item) {
300,150✔
766
    SWord* tmp = item;
240,534✔
767
    item = item->next;
240,534✔
768
    // if malloc need free
769
    if (tmp->free && tmp->word) taosMemoryFree(tmp->word);
240,534!
770
    taosMemoryFree(tmp);
240,534!
771
  }
772
}
59,616✔
773

774
void GenerateVarType(int type, char** p, int count) {
5,796✔
775
  STire* tire = createTire(TIRE_LIST);
5,796✔
776
  for (int i = 0; i < count; i++) {
110,952✔
777
    insertWord(tire, p[i]);
105,156✔
778
  }
779

780
  taosThreadMutexLock(&tiresMutex);
5,796✔
781
  tires[type] = tire;
5,796✔
782
  taosThreadMutexUnlock(&tiresMutex);
5,796✔
783
}
5,796✔
784

785
//
786
//  -------------------- shell auto ----------------
787
//
788

789
// init shell auto function , shell start call once
790
void shellAutoInit() {
414✔
791
  // command
792
  int32_t count = SHELL_COMMAND_COUNT();
414✔
793
  for (int32_t i = 0; i < count; i++) {
60,030✔
794
    parseCommand(shellCommands + i, true);
59,616✔
795
  }
796

797
  // tires
798
  memset(tires, 0, sizeof(STire*) * WT_VAR_CNT);
414✔
799
  taosThreadMutexInit(&tiresMutex, NULL);
414✔
800

801
  // threads
802
  memset(threads, 0, sizeof(TdThread*) * WT_FROM_DB_CNT);
414✔
803

804
  // generate varType
805
  GenerateVarType(WT_VAR_FUNC, functions, sizeof(functions) / sizeof(char*));
414✔
806
  GenerateVarType(WT_VAR_KEYWORD, keywords, sizeof(keywords) / sizeof(char*));
414✔
807
  GenerateVarType(WT_VAR_TBACTION, tb_actions, sizeof(tb_actions) / sizeof(char*));
414✔
808
  GenerateVarType(WT_VAR_DBOPTION, db_options, sizeof(db_options) / sizeof(char*));
414✔
809
  GenerateVarType(WT_VAR_ALTER_DBOPTION, alter_db_options, sizeof(alter_db_options) / sizeof(char*));
414✔
810
  GenerateVarType(WT_VAR_DATATYPE, data_types, sizeof(data_types) / sizeof(char*));
414✔
811
  GenerateVarType(WT_VAR_KEYTAGS, key_tags, sizeof(key_tags) / sizeof(char*));
414✔
812
  GenerateVarType(WT_VAR_TBOPTION, tb_options, sizeof(tb_options) / sizeof(char*));
414✔
813
  GenerateVarType(WT_VAR_USERACTION, user_actions, sizeof(user_actions) / sizeof(char*));
414✔
814
  GenerateVarType(WT_VAR_KEYSELECT, key_select, sizeof(key_select) / sizeof(char*));
414✔
815
  GenerateVarType(WT_VAR_SYSTABLE, key_systable, sizeof(key_systable) / sizeof(char*));
414✔
816
  GenerateVarType(WT_VAR_LANGUAGE, udf_language, sizeof(udf_language) / sizeof(char*));
414✔
817
  GenerateVarType(WT_VAR_GLOBALKEYS, global_keys, sizeof(global_keys) / sizeof(char*));
414✔
818
  GenerateVarType(WT_VAR_FIELD_OPTIONS, field_options, sizeof(field_options) / sizeof(char*));
414✔
819
}
414✔
820

821
// set conn
822
void shellSetConn(TAOS* conn, bool runOnce) {
378✔
823
  varCon = conn;
378✔
824
  varRunOnce = runOnce;
378✔
825
  // init database and stable
826
  if (!runOnce) updateTireValue(WT_VAR_DBNAME, false);
378!
827
}
378✔
828

829
// exit shell auto function, shell exit call once
830
void shellAutoExit() {
414✔
831
  // free command
832
  int32_t count = SHELL_COMMAND_COUNT();
414✔
833
  for (int32_t i = 0; i < count; i++) {
60,030✔
834
    freeCommand(shellCommands + i);
59,616✔
835
  }
836

837
  // free tires
838
  taosThreadMutexLock(&tiresMutex);
414✔
839
  for (int32_t i = 0; i < WT_VAR_CNT; i++) {
11,178✔
840
    if (tires[i]) {
10,764✔
841
      freeTire(tires[i]);
5,796✔
842
      tires[i] = NULL;
5,796✔
843
    }
844
  }
845
  taosThreadMutexUnlock(&tiresMutex);
414✔
846
  // destroy
847
  taosThreadMutexDestroy(&tiresMutex);
414✔
848

849
  // free threads
850
  for (int32_t i = 0; i < WT_FROM_DB_CNT; i++) {
4,554✔
851
    if (threads[i]) {
4,140!
852
      taosDestroyThread(threads[i]);
×
853
      threads[i] = NULL;
×
854
    }
855
  }
856

857
  // free lastMatch
858
  if (lastMatch) {
414!
859
    freeMatch(lastMatch);
×
860
    lastMatch = NULL;
×
861
  }
862
}
414✔
863

864
//
865
//  -------------------  auto ptr for tires --------------------------
866
//
867
bool setNewAutoPtr(int type, STire* pNew) {
×
868
  if (pNew == NULL) return false;
×
869

870
  taosThreadMutexLock(&tiresMutex);
×
871
  STire* pOld = tires[type];
×
872
  if (pOld != NULL) {
×
873
    // previous have value, release self ref count
874
    if (--pOld->ref == 0) {
×
875
      freeTire(pOld);
×
876
    }
877
  }
878

879
  // set new
880
  tires[type] = pNew;
×
881
  tires[type]->ref = 1;
×
882
  taosThreadMutexUnlock(&tiresMutex);
×
883

884
  return true;
×
885
}
886

887
// get ptr
888
STire* getAutoPtr(int type) {
×
889
  if (tires[type] == NULL) {
×
890
    return NULL;
×
891
  }
892

893
  taosThreadMutexLock(&tiresMutex);
×
894
  tires[type]->ref++;
×
895
  taosThreadMutexUnlock(&tiresMutex);
×
896

897
  return tires[type];
×
898
}
899

900
// put back tire to tires[type], if tire not equal tires[type].p, need free tire
901
void putBackAutoPtr(int type, STire* tire) {
×
902
  if (tire == NULL) {
×
903
    return;
×
904
  }
905

906
  taosThreadMutexLock(&tiresMutex);
×
907
  if (tires[type] != tire) {
×
908
    // update by out,  can't put back , so free
909
    if (--tire->ref == 1) {
×
910
      // support multi thread getAutoPtr
911
      freeTire(tire);
×
912
    }
913

914
  } else {
915
    tires[type]->ref--;
×
916
    ASSERT(tires[type]->ref > 0);
×
917
  }
918
  taosThreadMutexUnlock(&tiresMutex);
×
919

920
  return;
×
921
}
922

923
//
924
//  -------------------  var Word --------------------------
925
//
926

927
#define MAX_CACHED_CNT 100000  // max cached rows 10w
928
// write sql result to var name, return write rows cnt
929
int writeVarNames(int type, TAOS_RES* tres) {
×
930
  // fetch row
931
  TAOS_ROW row = taos_fetch_row(tres);
×
932
  if (row == NULL) {
×
933
    return 0;
×
934
  }
935

936
  TAOS_FIELD* fields = taos_fetch_fields(tres);
×
937
  // create new tires
938
  char   tireType = type == WT_VAR_TABLE ? TIRE_TREE : TIRE_LIST;
×
939
  STire* tire = createTire(tireType);
×
940

941
  // enum rows
942
  char name[1024];
943
  int  numOfRows = 0;
×
944
  do {
945
    int32_t* lengths = taos_fetch_lengths(tres);
×
946
    int32_t  bytes = lengths[0];
×
947
    if (fields[0].type == TSDB_DATA_TYPE_INT) {
×
948
      sprintf(name, "%d", *(int16_t*)row[0]);
×
949
    } else {
950
      memcpy(name, row[0], bytes);
×
951
    }
952

953
    name[bytes] = 0;  // set string end
×
954
    // insert to tire
955
    insertWord(tire, name);
×
956

957
    if (++numOfRows > MAX_CACHED_CNT) {
×
958
      break;
×
959
    }
960

961
    row = taos_fetch_row(tres);
×
962
  } while (row != NULL);
×
963

964
  // replace old tire
965
  setNewAutoPtr(type, tire);
×
966

967
  return numOfRows;
×
968
}
969

970
void setThreadNull(int type) {
×
971
  taosThreadMutexLock(&tiresMutex);
×
972
  if (threads[type]) {
×
973
    taosMemoryFree(threads[type]);
×
974
  }
975
  threads[type] = NULL;
×
976
  taosThreadMutexUnlock(&tiresMutex);
×
977
}
×
978

979
bool firstMatchCommand(TAOS* con, SShellCmd* cmd);
980
//
981
//  thread obtain var thread from db server
982
//
983
void* varObtainThread(void* param) {
×
984
  int type = *(int*)param;
×
985
  taosMemoryFree(param);
×
986

987
  if (varCon == NULL || type > WT_FROM_DB_MAX) {
×
988
    return NULL;
×
989
  }
990

991
  TAOS_RES* pSql = taos_query(varCon, varSqls[type]);
×
992
  if (taos_errno(pSql)) {
×
993
    taos_free_result(pSql);
×
994
    setThreadNull(type);
×
995
    return NULL;
×
996
  }
997

998
  // write var names from pSql
999
  int cnt = writeVarNames(type, pSql);
×
1000

1001
  // free sql
1002
  taos_free_result(pSql);
×
1003

1004
  // check need call auto tab
1005
  if (cnt > 0 && waitAutoFill) {
×
1006
    // press tab key by program
1007
    firstMatchCommand(varCon, varCmd);
×
1008
  }
1009

1010
  setThreadNull(type);
×
1011
  return NULL;
×
1012
}
1013

1014
// return true is need update value by async
1015
bool updateTireValue(int type, bool autoFill) {
×
1016
  // TYPE CONTEXT GET FROM DB
1017
  taosThreadMutexLock(&tiresMutex);
×
1018

1019
  // check need obtain from server
1020
  if (tires[type] == NULL) {
×
1021
    waitAutoFill = autoFill;
×
1022
    // need async obtain var names from db sever
1023
    if (threads[type] != NULL) {
×
1024
      if (taosThreadRunning(threads[type])) {
×
1025
        // thread running , need not obtain again, return
1026
        taosThreadMutexUnlock(&tiresMutex);
×
1027
        return NULL;
×
1028
      }
1029
      // destroy previous thread handle for new create thread handle
1030
      taosDestroyThread(threads[type]);
×
1031
      threads[type] = NULL;
×
1032
    }
1033

1034
    // create new
1035
    void* param = taosMemoryMalloc(sizeof(int));
×
1036
    *((int*)param) = type;
×
1037
    threads[type] = taosCreateThread(varObtainThread, param);
×
1038
    taosThreadMutexUnlock(&tiresMutex);
×
1039
    return true;
×
1040
  }
1041
  taosThreadMutexUnlock(&tiresMutex);
×
1042

1043
  return false;
×
1044
}
1045

1046
// only match next one word from all match words, return valuue must free by caller
1047
char* matchNextPrefix(STire* tire, char* pre) {
×
1048
  SMatch* match = NULL;
×
1049
  if (tire == NULL) return NULL;
×
1050

1051
  // re-use last result
1052
  if (lastMatch) {
×
1053
    if (strcmp(pre, lastMatch->pre) == 0) {
×
1054
      // same pre
1055
      match = lastMatch;
×
1056
    }
1057
  }
1058

1059
  if (match == NULL) {
×
1060
    // not same with last result
1061
    if (pre[0] == 0) {
×
1062
      // EMPTY PRE
1063
      match = enumAll(tire);
×
1064
    } else {
1065
      // NOT EMPTY
1066
      match = (SMatch*)taosMemoryMalloc(sizeof(SMatch));
×
1067
      memset(match, 0, sizeof(SMatch));
×
1068
      matchPrefix(tire, pre, match);
×
1069
    }
1070

1071
    // save to lastMatch
1072
    if (match) {
×
1073
      if (lastMatch) freeMatch(lastMatch);
×
1074
      lastMatch = match;
×
1075
    }
1076
  }
1077

1078
  // check valid
1079
  if (match == NULL || match->head == NULL) {
×
1080
    // no one matched
1081
    return NULL;
×
1082
  }
1083

1084
  if (cursorVar == -1) {
×
1085
    // first
1086
    cursorVar = 0;
×
1087
    return taosStrdup(match->head->word);
×
1088
  }
1089

1090
  // according to cursorVar , calculate next one
1091
  int         i = 0;
×
1092
  SMatchNode* item = match->head;
×
1093
  while (item) {
×
1094
    if (i == cursorVar + 1) {
×
1095
      // found next position ok
1096
      if (item->next == NULL) {
×
1097
        // match last item, reset cursorVar to head
1098
        cursorVar = -1;
×
1099
      } else {
1100
        cursorVar = i;
×
1101
      }
1102

1103
      return taosStrdup(item->word);
×
1104
    }
1105

1106
    // check end item
1107
    if (item->next == NULL) {
×
1108
      // if cursorVar > var list count, return last and reset cursorVar
1109
      cursorVar = -1;
×
1110

1111
      return taosStrdup(item->word);
×
1112
    }
1113

1114
    // move next
1115
    item = item->next;
×
1116
    i++;
×
1117
  }
1118

1119
  return NULL;
×
1120
}
1121

1122
// search pre word from tire tree, return value must free by caller
1123
char* tireSearchWord(int type, char* pre) {
×
1124
  if (type == WT_TEXT) {
×
1125
    return NULL;
×
1126
  }
1127

1128
  if (type > WT_FROM_DB_MAX) {
×
1129
    // NOT FROM DB , tires[type] alwary not null
1130
    STire* tire = tires[type];
×
1131
    if (tire == NULL) return NULL;
×
1132
    return matchNextPrefix(tire, pre);
×
1133
  }
1134

1135
  if (updateTireValue(type, true)) {
×
1136
    return NULL;
×
1137
  }
1138

1139
  // can obtain var names from local
1140
  STire* tire = getAutoPtr(type);
×
1141
  if (tire == NULL) {
×
1142
    return NULL;
×
1143
  }
1144

1145
  char* str = matchNextPrefix(tire, pre);
×
1146
  // used finish, put back pointer to autoptr array
1147
  putBackAutoPtr(type, tire);
×
1148

1149
  return str;
×
1150
}
1151

1152
// match var word, word1 is pattern , word2 is input from shell
1153
bool matchVarWord(SWord* word1, SWord* word2) {
×
1154
  // search input word from tire tree
1155
  char pre[512];
1156
  memcpy(pre, word2->word, word2->len);
×
1157
  pre[word2->len] = 0;
×
1158

1159
  char* str = NULL;
×
1160
  if (word1->type == WT_VAR_ALLTABLE) {
×
1161
    // ALL_TABLE
1162
    str = tireSearchWord(WT_VAR_STABLE, pre);
×
1163
    if (str == NULL) {
×
1164
      str = tireSearchWord(WT_VAR_TABLE, pre);
×
1165
      if (str == NULL) return false;
×
1166
    }
1167
  } else {
1168
    // OTHER
1169
    str = tireSearchWord(word1->type, pre);
×
1170
    if (str == NULL) {
×
1171
      // not found or word1->type variable list not obtain from server, return not match
1172
      return false;
×
1173
    }
1174
  }
1175

1176
  // free previous malloc
1177
  if (word1->free && word1->word) {
×
1178
    taosMemoryFree(word1->word);
×
1179
  }
1180

1181
  // save
1182
  word1->word = str;
×
1183
  word1->len = strlen(str);
×
1184
  word1->free = true;  // need free
×
1185

1186
  return true;
×
1187
}
1188

1189
//
1190
//  -------------------  match words --------------------------
1191
//
1192

1193
// compare command cmdPattern come from shellCommands , cmdInput come from user input
1194
int32_t compareCommand(SWords* cmdPattern, SWords* cmdInput) {
×
1195
  SWord* wordPattern = cmdPattern->head;
×
1196
  SWord* wordInput = cmdInput->head;
×
1197

1198
  if (wordPattern == NULL || wordInput == NULL) {
×
1199
    return -1;
×
1200
  }
1201

1202
  for (int32_t i = 0; i < cmdPattern->count; i++) {
×
1203
    if (wordPattern->type == WT_TEXT) {
×
1204
      // WT_TEXT match
1205
      if (wordPattern->len == wordInput->len) {
×
1206
        if (strncasecmp(wordPattern->word, wordInput->word, wordPattern->len) != 0) return -1;
×
1207
      } else if (wordPattern->len < wordInput->len) {
×
1208
        return -1;
×
1209
      } else {
1210
        // wordPattern->len > wordInput->len
1211
        if (strncasecmp(wordPattern->word, wordInput->word, wordInput->len) == 0) {
×
1212
          if (i + 1 == cmdInput->count) {
×
1213
            // last word return match
1214
            cmdPattern->matchIndex = i;
×
1215
            cmdPattern->matchLen = wordInput->len;
×
1216
            return i;
×
1217
          } else {
1218
            return -1;
×
1219
          }
1220
        } else {
1221
          return -1;
×
1222
        }
1223
      }
1224
    } else {
1225
      // WT_VAR auto match any one word
1226
      if (wordInput->next == NULL) {  // input words last one
×
1227
        if (matchVarWord(wordPattern, wordInput)) {
×
1228
          cmdPattern->matchIndex = i;
×
1229
          cmdPattern->matchLen = wordInput->len;
×
1230
          varMode = true;
×
1231
          return i;
×
1232
        }
1233
        return -1;
×
1234
      }
1235
    }
1236

1237
    // move next
1238
    wordPattern = wordPattern->next;
×
1239
    wordInput = wordInput->next;
×
1240
    if (wordPattern == NULL || wordInput == NULL) {
×
1241
      return -1;
×
1242
    }
1243
  }
1244

1245
  return -1;
×
1246
}
1247

1248
// match command
1249
SWords* matchCommand(SWords* input, bool continueSearch) {
×
1250
  int32_t count = SHELL_COMMAND_COUNT();
×
1251
  for (int32_t i = 0; i < count; i++) {
×
1252
    SWords* shellCommand = shellCommands + i;
×
1253
    if (continueSearch && lastMatchIndex != -1 && i <= lastMatchIndex) {
×
1254
      // new match must greater than lastMatchIndex
1255
      if (varMode && i == lastMatchIndex) {
×
1256
        // do nothing, var match on lastMatchIndex
1257
      } else {
1258
        continue;
×
1259
      }
1260
    }
1261

1262
    // command is large
1263
    if (input->count > shellCommand->count) {
×
1264
      continue;
×
1265
    }
1266

1267
    // compare
1268
    int32_t index = compareCommand(shellCommand, input);
×
1269
    if (index != -1) {
×
1270
      if (firstMatchIndex == -1) firstMatchIndex = i;
×
1271
      curMatchIndex = i;
×
1272
      return &shellCommands[i];
×
1273
    }
1274
  }
1275

1276
  // not match
1277
  return NULL;
×
1278
}
1279

1280
//
1281
//  -------------------  print screen --------------------------
1282
//
1283

1284
// delete char count
1285
void deleteCount(SShellCmd* cmd, int count) {
×
1286
  int size = 0;
×
1287
  int width = 0;
×
1288
  int prompt_size = 6;
×
1289
  shellClearScreen(cmd->endOffset + prompt_size, cmd->screenOffset + prompt_size);
×
1290

1291
  // loop delete
1292
  while (--count >= 0 && cmd->cursorOffset > 0) {
×
1293
    shellGetPrevCharSize(cmd->command, cmd->cursorOffset, &size, &width);
×
1294
    memmove(cmd->command + cmd->cursorOffset - size, cmd->command + cmd->cursorOffset,
×
1295
            cmd->commandSize - cmd->cursorOffset);
×
1296
    cmd->commandSize -= size;
×
1297
    cmd->cursorOffset -= size;
×
1298
    cmd->screenOffset -= width;
×
1299
    cmd->endOffset -= width;
×
1300
  }
1301
}
×
1302

1303
// show screen
1304
void printScreen(TAOS* con, SShellCmd* cmd, SWords* match) {
×
1305
  // modify SShellCmd
1306
  if (firstMatchIndex == -1 || curMatchIndex == -1) {
×
1307
    // no match
1308
    return;
×
1309
  }
1310

1311
  // first tab press
1312
  const char* str = NULL;
×
1313
  int         strLen = 0;
×
1314

1315
  SWord* word = MATCH_WORD(match);
×
1316
  if (firstMatchIndex == curMatchIndex && lastWordBytes == -1) {
×
1317
    // first press tab
1318
    str = word->word + match->matchLen;
×
1319
    strLen = word->len - match->matchLen;
×
1320
    lastMatchIndex = firstMatchIndex;
×
1321
    lastWordBytes = word->len;
×
1322
  } else {
1323
    if (lastWordBytes == -1) return;
×
1324
    deleteCount(cmd, lastWordBytes);
×
1325
    str = word->word;
×
1326
    strLen = word->len;
×
1327
    // set current to last
1328
    lastMatchIndex = curMatchIndex;
×
1329
    lastWordBytes = word->len;
×
1330
  }
1331

1332
  if (word->end && str[strLen - 1] != ';') {
×
1333
    // append end ';'
1334
    char* p = taosMemoryCalloc(strLen + 8, 1);
×
1335
    if (p) {
×
1336
      tstrncpy(p, str, strLen + 1);
×
1337
      tstrncpy(p + strLen, ";", 1 + 1);
×
1338
      lastWordBytes += 1;
×
1339
      shellInsertStr(cmd, (char*)p, strLen + 1);
×
1340
      taosMemoryFree(p);
×
1341
    } else {
1342
      shellInsertStr(cmd, (char*)str, strLen);
×
1343
    }
1344
  } else {
1345
    // insert new
1346
    shellInsertStr(cmd, (char*)str, strLen);
×
1347
  }
1348
}
1349

1350
// main key press tab , matched return true else false
1351
bool firstMatchCommand(TAOS* con, SShellCmd* cmd) {
×
1352
  if (con == NULL || cmd == NULL) return false;
×
1353
  // parse command
1354
  SWords* input = (SWords*)taosMemoryMalloc(sizeof(SWords));
×
1355
  memset(input, 0, sizeof(SWords));
×
1356
  input->source = cmd->command;
×
1357
  input->source_len = cmd->commandSize;
×
1358
  parseCommand(input, false);
×
1359

1360
  // if have many , default match first, if press tab again , switch to next
1361
  curMatchIndex = -1;
×
1362
  lastMatchIndex = -1;
×
1363
  SWords* match = matchCommand(input, true);
×
1364
  if (match == NULL) {
×
1365
    // not match , nothing to do
1366
    freeCommand(input);
×
1367
    taosMemoryFree(input);
×
1368
    return false;
×
1369
  }
1370

1371
  // print to screen
1372
  printScreen(con, cmd, match);
×
1373
#ifdef WINDOWS
1374
  printf("\r");
1375
  shellShowOnScreen(cmd);
1376
#endif
1377
  freeCommand(input);
×
1378
  taosMemoryFree(input);
×
1379
  return true;
×
1380
}
1381

1382
// create input source
1383
void createInputFromFirst(SWords* input, SWords* firstMatch) {
×
1384
  //
1385
  // if next pressTabKey , input context come from firstMatch, set matched length with source_len
1386
  //
1387
  input->source = (char*)taosMemoryMalloc(1024);
×
1388
  memset((void*)input->source, 0, 1024);
×
1389

1390
  SWord* word = firstMatch->head;
×
1391

1392
  // source_len = full match word->len + half match with firstMatch->matchLen
1393
  for (int i = 0; i < firstMatch->matchIndex && word; i++) {
×
1394
    // combine source from each word
1395
    strncpy(input->source + input->source_len, word->word, word->len);
×
1396
    strcat(input->source, " ");          // append blank space
×
1397
    input->source_len += word->len + 1;  // 1 is blank length
×
1398
    // move next
1399
    word = word->next;
×
1400
  }
1401
  // appand half matched word for last
1402
  if (word) {
×
1403
    strncpy(input->source + input->source_len, word->word, firstMatch->matchLen);
×
1404
    input->source_len += firstMatch->matchLen;
×
1405
  }
1406
}
×
1407

1408
// user press Tabkey again is named next , matched return true else false
1409
bool nextMatchCommand(TAOS* con, SShellCmd* cmd, SWords* firstMatch) {
×
1410
  if (firstMatch == NULL || firstMatch->head == NULL) {
×
1411
    return false;
×
1412
  }
1413
  SWords* input = (SWords*)taosMemoryMalloc(sizeof(SWords));
×
1414
  memset(input, 0, sizeof(SWords));
×
1415

1416
  // create input from firstMatch
1417
  createInputFromFirst(input, firstMatch);
×
1418

1419
  // parse input
1420
  parseCommand(input, false);
×
1421

1422
  // if have many , default match first, if press tab again , switch to next
1423
  SWords* match = matchCommand(input, true);
×
1424
  if (match == NULL) {
×
1425
    // if not match , reset all index
1426
    firstMatchIndex = -1;
×
1427
    curMatchIndex = -1;
×
1428
    match = matchCommand(input, false);
×
1429
    if (match == NULL) {
×
1430
      freeCommand(input);
×
1431
      if (input->source) taosMemoryFree(input->source);
×
1432
      taosMemoryFree(input);
×
1433
      return false;
×
1434
    }
1435
  }
1436

1437
  // print to screen
1438
  printScreen(con, cmd, match);
×
1439
#ifdef WINDOWS
1440
  printf("\r");
1441
  shellShowOnScreen(cmd);
1442
#endif
1443

1444
  // free
1445
  freeCommand(input);
×
1446
  if (input->source) {
×
1447
    taosMemoryFree(input->source);
×
1448
    input->source = NULL;
×
1449
  }
1450
  taosMemoryFree(input);
×
1451

1452
  return true;
×
1453
}
1454

1455
// fill with type
1456
bool fillWithType(TAOS* con, SShellCmd* cmd, char* pre, int type) {
×
1457
  // get type
1458
  STire* tire = tires[type];
×
1459
  char*  str = matchNextPrefix(tire, pre);
×
1460
  if (str == NULL) {
×
1461
    return false;
×
1462
  }
1463

1464
  // need insert part string
1465
  char* part = str + strlen(pre);
×
1466

1467
  // show
1468
  int count = strlen(part);
×
1469
  shellInsertStr(cmd, part, count);
×
1470
  cntDel = count;  // next press tab delete current append count
×
1471

1472
  taosMemoryFree(str);
×
1473
  return true;
×
1474
}
1475

1476
// fill with type
1477
bool fillTableName(TAOS* con, SShellCmd* cmd, char* pre) {
×
1478
  // search stable and table
1479
  char* str = tireSearchWord(WT_VAR_STABLE, pre);
×
1480
  if (str == NULL) {
×
1481
    str = tireSearchWord(WT_VAR_TABLE, pre);
×
1482
    if (str == NULL) return false;
×
1483
  }
1484

1485
  // need insert part string
1486
  char* part = str + strlen(pre);
×
1487

1488
  // delete autofill count last append
1489
  if (cntDel > 0) {
×
1490
    deleteCount(cmd, cntDel);
×
1491
    cntDel = 0;
×
1492
  }
1493

1494
  // show
1495
  int count = strlen(part);
×
1496
  shellInsertStr(cmd, part, count);
×
1497
  cntDel = count;  // next press tab delete current append count
×
1498

1499
  taosMemoryFree(str);
×
1500
  return true;
×
1501
}
1502

1503
//
1504
// find last word from sql select clause
1505
//  example :
1506
//  1 select cou -> press tab  select count(
1507
//  2 select count(*),su -> select count(*), sum(
1508
//  3 select count(*), su -> select count(*), sum(
1509
//
1510
char* lastWord(char* p) {
×
1511
  // get near from end revert find ' ' and ','
1512
  char* p1 = strrchr(p, ' ');
×
1513
  char* p2 = strrchr(p, ',');
×
1514

1515
  if (p1 && p2) {
×
1516
    return p1 > p2 ? p1 + 1 : p2 + 1;
×
1517
  } else if (p1) {
×
1518
    return p1 + 1;
×
1519
  } else if (p2) {
×
1520
    return p2 + 1;
×
1521
  } else {
1522
    return p;
×
1523
  }
1524
}
1525

1526
bool fieldsInputEnd(char* sql) {
×
1527
  // not in '()'
1528
  char* p1 = strrchr(sql, '(');
×
1529
  char* p2 = strrchr(sql, ')');
×
1530
  if (p1 && p2 == NULL) {
×
1531
    // like select count( '  '
1532
    return false;
×
1533
  } else if (p1 && p2 && p1 > p2) {
×
1534
    // like select sum(age), count( ' '
1535
    return false;
×
1536
  }
1537

1538
  // not in ','
1539
  char* p3 = strrchr(sql, ',');
×
1540
  char* p = p3;
×
1541
  // like select ts, age,'    '
1542
  if (p) {
×
1543
    ++p;
×
1544
    bool  allBlank = true;  // after last ','  all char is blank
×
1545
    int   cnt = 0;          // blank count , like '    ' as one blank
×
1546
    char* plast = NULL;     // last blank position
×
1547
    while (*p) {
×
1548
      if (*p == ' ') {
×
1549
        plast = p;
×
1550
        cnt++;
×
1551
      } else {
1552
        allBlank = false;
×
1553
      }
1554
      ++p;
×
1555
    }
1556

1557
    // any one word is not blank
1558
    if (allBlank) {
×
1559
      return false;
×
1560
    }
1561

1562
    // like 'select count(*),sum(age) fr' need return true
1563
    if (plast && plast > p3 && p2 > p1 && plast > p2 && p1 > p3) {
×
1564
      return true;
×
1565
    }
1566

1567
    // if last char not ' ', then not end field, like 'select count(*), su' can fill sum(
1568
    if (sql[strlen(sql) - 1] != ' ' && cnt <= 1) {
×
1569
      return false;
×
1570
    }
1571
  }
1572

1573
  char* p4 = strrchr(sql, ' ');
×
1574
  if (p4 == NULL) {
×
1575
    // only one word
1576
    return false;
×
1577
  }
1578

1579
  return true;
×
1580
}
1581

1582
// need insert from
1583
bool needInsertFrom(char* sql, int len) {
×
1584
  // last is blank
1585
  if (sql[len - 1] != ' ') {
×
1586
    // insert from keyword
1587
    return false;
×
1588
  }
1589

1590
  //  select fields input is end
1591
  if (!fieldsInputEnd(sql)) {
×
1592
    return false;
×
1593
  }
1594

1595
  // can insert from keyword
1596
  return true;
×
1597
}
1598

1599
// p is string following select keyword
1600
bool appendAfterSelect(TAOS* con, SShellCmd* cmd, char* sql, int32_t len) {
×
1601
  char* p = taosStrndup(sql, len);
×
1602

1603
  // union all
1604
  char* p1;
1605
  do {
1606
    p1 = strstr(p, UNION_ALL);
×
1607
    if (p1) {
×
1608
      p = p1 + strlen(UNION_ALL);
×
1609
    }
1610
  } while (p1);
×
1611

1612
  char* from = strstr(p, " from ");
×
1613
  // last word , maybe empty string or some letters of a string
1614
  char* last = lastWord(p);
×
1615
  bool  ret = false;
×
1616
  if (from == NULL) {
×
1617
    bool fieldEnd = fieldsInputEnd(p);
×
1618
    // check fields input end then insert from keyword
1619
    if (fieldEnd && p[len - 1] == ' ') {
×
1620
      shellInsertStr(cmd, "from", 4);
×
1621
      taosMemoryFree(p);
×
1622
      return true;
×
1623
    }
1624

1625
    // fill function
1626
    if (fieldEnd) {
×
1627
      // fields is end , need match keyword
1628
      ret = fillWithType(con, cmd, last, WT_VAR_KEYWORD);
×
1629
    } else {
1630
      ret = fillWithType(con, cmd, last, WT_VAR_FUNC);
×
1631
    }
1632

1633
    taosMemoryFree(p);
×
1634
    return ret;
×
1635
  }
1636

1637
  // have from
1638
  char* blank = strstr(from + 6, " ");
×
1639
  if (blank == NULL) {
×
1640
    // no table name, need fill
1641
    ret = fillTableName(con, cmd, last);
×
1642
  } else {
1643
    ret = fillWithType(con, cmd, last, WT_VAR_KEYWORD);
×
1644
  }
1645

1646
  taosMemoryFree(p);
×
1647
  return ret;
×
1648
}
1649

1650
int32_t searchAfterSelect(char* p, int32_t len) {
×
1651
  // select * from st;
1652
  if (strncasecmp(p, "select ", 7) == 0) {
×
1653
    // check nest query
1654
    char* p1 = p + 7;
×
1655
    while (1) {
×
1656
      char* p2 = strstr(p1, "select ");
×
1657
      if (p2 == NULL) break;
×
1658
      p1 = p2 + 7;
×
1659
    }
1660

1661
    return p1 - p;
×
1662
  }
1663

1664
  // explain as select * from st;
1665
  if (strncasecmp(p, "explain select ", 15) == 0) {
×
1666
    return 15;
×
1667
  }
1668

1669
  char* as_pos_end = strstr(p, " as select ");
×
1670
  if (as_pos_end == NULL) return -1;
×
1671
  as_pos_end += 11;
×
1672

1673
  // create stream <stream_name> as select
1674
  if (strncasecmp(p, "create stream ", 14) == 0) {
×
1675
    return as_pos_end - p;
×
1676
    ;
1677
  }
1678

1679
  // create topic <topic_name> as select
1680
  if (strncasecmp(p, "create topic ", 13) == 0) {
×
1681
    return as_pos_end - p;
×
1682
  }
1683

1684
  return -1;
×
1685
}
1686

1687
bool matchSelectQuery(TAOS* con, SShellCmd* cmd) {
×
1688
  // if continue press Tab , delete bytes by previous autofill
1689
  if (cntDel > 0) {
×
1690
    deleteCount(cmd, cntDel);
×
1691
    cntDel = 0;
×
1692
  }
1693

1694
  // match select ...
1695
  int   len = cmd->commandSize;
×
1696
  char* p = cmd->command;
×
1697

1698
  // remove prefix blank
1699
  while (p[0] == ' ' && len > 0) {
×
1700
    p++;
×
1701
    len--;
×
1702
  }
1703

1704
  // special range
1705
  if (len < 7 || len > 512) {
×
1706
    return false;
×
1707
  }
1708

1709
  // search
1710
  char*   sql_cp = taosStrndup(p, len);
×
1711
  int32_t n = searchAfterSelect(sql_cp, len);
×
1712
  taosMemoryFree(sql_cp);
×
1713
  if (n == -1 || n > len) return false;
×
1714
  p += n;
×
1715
  len -= n;
×
1716

1717
  // append
1718
  return appendAfterSelect(con, cmd, p, len);
×
1719
}
1720

1721
// is fields option area
1722
bool fieldOptionsArea(char* p) {
84✔
1723
  char* p1 = strrchr(p, '(');
84✔
1724
  char* p2 = strrchr(p, ',');
84✔
1725
  if (p1 == NULL && p2 == NULL) {
84!
1726
    return false;
×
1727
  }
1728

1729
  // find tags
1730
  if (strstr(p, " tags") != NULL) {
84✔
1731
    return false;
24✔
1732
  }
1733

1734
  if (p2 == NULL) {
60✔
1735
    // first field area
1736
    p2 = p1;
6✔
1737
  }
1738

1739
  // find blank count
1740
  int32_t cnt = 0;
60✔
1741
  while (p2) {
285✔
1742
    p2 = strchr(p2, ' ');
225✔
1743
    if (p2) {
225✔
1744
      // get prev char
1745
      char prec = *(p2 - 1);
165✔
1746
      if (prec != ',' && prec != '(') {
165✔
1747
        // blank if before comma, not calc count.  like st(ts timestamp,  age int + BLANK + TAB only two blank
1748
        cnt++;
123✔
1749
      }
1750

1751
      // continue blank is one blank
1752
      while (p2[1] != 0 && p2[1] == ' ') {
204✔
1753
        // move next if blank again
1754
        p2 += 1;
39✔
1755
      }
1756
      p2 += 1;
165✔
1757
    }
1758
  }
1759

1760
  // like  create table st(ts timestamp TAB-KEY or  st(ts timestamp , age int TAB-KEY
1761
  return cnt >= 2;
60✔
1762
}
1763

1764
// if is input create fields or tags area, return true
1765
bool isCreateFieldsArea(char* p) {
84✔
1766
  int32_t n = 0;  // count
84✔
1767
  char*  p1 = p;
84✔
1768
  while (*p1 != 0) {
6,672✔
1769
    switch (*p1) {
6,588✔
1770
      case '(':
243✔
1771
        ++n;
243✔
1772
        break;
243✔
1773
      case ')':
201✔
1774
        --n;
201✔
1775
        break;
201✔
1776
      default:
6,144✔
1777
        break;
6,144✔
1778
    }
1779
    // move next
1780
    ++p1;
6,588✔
1781
  }
1782

1783
  return n > 0;
84✔
1784
}
1785

1786
bool matchCreateTable(TAOS* con, SShellCmd* cmd) {
×
1787
  // if continue press Tab , delete bytes by previous autofill
1788
  if (cntDel > 0) {
×
1789
    deleteCount(cmd, cntDel);
×
1790
    cntDel = 0;
×
1791
  }
1792

1793
  // match select ...
1794
  int   len = cmd->commandSize;
×
1795
  char* p = cmd->command;
×
1796

1797
  // remove prefix blank
1798
  while (p[0] == ' ' && len > 0) {
×
1799
    p++;
×
1800
    len--;
×
1801
  }
1802

1803
  // special range
1804
  if (len < 7 || len > 1024) {
×
1805
    return false;
×
1806
  }
1807

1808
  // select and from
1809
  if (strncasecmp(p, "create table ", 13) != 0) {
×
1810
    // not select query clause
1811
    return false;
×
1812
  }
1813
  p += 13;
×
1814
  len -= 13;
×
1815

1816
  char* ps = taosStrndup(p, len);
×
1817
  bool  ret = false;
×
1818
  char* last = lastWord(ps);
×
1819

1820
  // check in create fields or tags input area
1821
  if (isCreateFieldsArea(ps)) {
×
1822
    if (fieldOptionsArea(ps)) {
×
1823
      // fill field options
1824
      ret = fillWithType(con, cmd, last, WT_VAR_FIELD_OPTIONS);
×
1825
    } else {
1826
      // fill field
1827
      ret = fillWithType(con, cmd, last, WT_VAR_DATATYPE);
×
1828
    }
1829
  }
1830

1831
  // tags
1832
  if (!ret) {
×
1833
    // find only one ')' , can insert tags
1834
    char* p1 = strchr(ps, ')');
×
1835
    if (p1) {
×
1836
      if (strstr(p1 + 1, "tags") == NULL) {
×
1837
        // can insert tags keyword
1838
        ret = fillWithType(con, cmd, last, WT_VAR_KEYTAGS);
×
1839
      }
1840
    }
1841
  }
1842

1843
  // tb options
1844
  if (!ret) {
×
1845
    // find like create table st (...) tags(..)  <here is fill tb option area>
1846
    char* p1 = strchr(ps, ')');  // first ')' end
×
1847
    if (p1) {
×
1848
      if (strchr(p1 + 1, ')')) {  // second ')' end
×
1849
        // here is tb options area, can insert option
1850
        ret = fillWithType(con, cmd, last, WT_VAR_TBOPTION);
×
1851
      }
1852
    }
1853
  }
1854

1855
  taosMemoryFree(ps);
×
1856
  return ret;
×
1857
}
1858

1859
bool matchOther(TAOS* con, SShellCmd* cmd) {
×
1860
  int   len = cmd->commandSize;
×
1861
  char* p = cmd->command;
×
1862

1863
  // '\\'
1864
  if (p[len - 1] == '\\') {
×
1865
    // append '\G'
1866
    char a[] = "G;";
×
1867
    shellInsertStr(cmd, a, 2);
×
1868
    return true;
×
1869
  }
1870

1871
  // too small
1872
  if (len < 8) return false;
×
1873

1874
  // like 'from ( '
1875
  char* sql = taosStrndup(p, len);
×
1876
  char* last = lastWord(sql);
×
1877

1878
  if (strcmp(last, "from(") == 0) {
×
1879
    fillWithType(con, cmd, "", WT_VAR_KEYSELECT);
×
1880
    taosMemoryFree(sql);
×
1881
    return true;
×
1882
  }
1883
  if (strncmp(last, "(", 1) == 0) {
×
1884
    last += 1;
×
1885
  }
1886

1887
  char* from = strstr(sql, " from");
×
1888
  // find last ' from'
1889
  while (from) {
×
1890
    char* p1 = strstr(from + 5, " from");
×
1891
    if (p1 == NULL) break;
×
1892
    from = p1;
×
1893
  }
1894

1895
  if (from) {
×
1896
    // find next is '('
1897
    char* p2 = from + 5;
×
1898
    bool  found = false;   // found 'from ... ( ...'  ... is any count of blank
×
1899
    bool  found1 = false;  // found '('
×
1900
    while (1) {
1901
      if (p2 == last || *p2 == '\0') {
×
1902
        // last word or string end
1903
        if (found1) {
×
1904
          found = true;
×
1905
        }
1906
        break;
×
1907
      } else if (*p2 == '(') {
×
1908
        found1 = true;
×
1909
      } else if (*p2 == ' ') {
×
1910
        // do nothing
1911
      } else {
1912
        // have any other char
1913
        break;
×
1914
      }
1915

1916
      // move next
1917
      p2++;
×
1918
    }
1919

1920
    if (found) {
×
1921
      fillWithType(con, cmd, last, WT_VAR_KEYSELECT);
×
1922
      taosMemoryFree(sql);
×
1923
      return true;
×
1924
    }
1925
  }
1926

1927
  // INSERT
1928

1929
  taosMemoryFree(sql);
×
1930

1931
  return false;
×
1932
}
1933

1934
// last match if nothing matched
1935
bool matchEnd(TAOS* con, SShellCmd* cmd) {
×
1936
  // str dump
1937
  bool  ret = false;
×
1938
  char* ps = taosStrndup(cmd->command, cmd->commandSize);
×
1939
  char* last = lastWord(ps);
×
1940
  char* elast = strrchr(last, '.');  // find end last
×
1941
  if (elast) {
×
1942
    last = elast + 1;
×
1943
  }
1944

1945
  // less one char can match
1946
  if (strlen(last) == 0) {
×
1947
    goto _return;
×
1948
  }
1949
  if (strcmp(last, " ") == 0) {
×
1950
    goto _return;
×
1951
  }
1952

1953
  // match database
1954
  if (elast == NULL) {
×
1955
    // dot need not completed with dbname
1956
    if (fillWithType(con, cmd, last, WT_VAR_DBNAME)) {
×
1957
      ret = true;
×
1958
      goto _return;
×
1959
    }
1960
  }
1961

1962
  if (fillWithType(con, cmd, last, WT_VAR_SYSTABLE)) {
×
1963
    ret = true;
×
1964
    goto _return;
×
1965
  }
1966

1967
  // global keys
1968
  if (fillWithType(con, cmd, last, WT_VAR_GLOBALKEYS)) {
×
1969
    ret = true;
×
1970
    goto _return;
×
1971
  }
1972

1973

1974
_return:
×
1975
  taosMemoryFree(ps);
×
1976
  return ret;
×
1977
}
1978

1979
// main key press tab
1980
void pressTabKey(SShellCmd* cmd) {
×
1981
#ifdef WINDOWS
1982
  return ;
1983
#endif
1984
  // check empty tab key
1985
  if (cmd->commandSize == 0) {
×
1986
    // have multi line tab key
1987
    if (cmd->bufferSize == 0) {
×
1988
      showHelp();
×
1989
    }
1990
    shellShowOnScreen(cmd);
×
1991
    return;
×
1992
  }
1993

1994
  // save connection to global
1995
  varCmd = cmd;
×
1996
  bool matched = false;
×
1997

1998
  // manual match like create table st( ...
1999
  matched = matchCreateTable(varCon, cmd);
×
2000
  if (matched) return;
×
2001

2002
  // shellCommands match
2003
  if (firstMatchIndex == -1) {
×
2004
    matched = firstMatchCommand(varCon, cmd);
×
2005
  } else {
2006
    matched = nextMatchCommand(varCon, cmd, &shellCommands[firstMatchIndex]);
×
2007
  }
2008
  if (matched) return;
×
2009

2010
  // NOT MATCHED ANYONE
2011
  // match other like '\G' ...
2012
  matched = matchOther(varCon, cmd);
×
2013
  if (matched) return;
×
2014

2015
  // manual match like select * from ...
2016
  matched = matchSelectQuery(varCon, cmd);
×
2017
  if (matched) return;
×
2018

2019
  // match end
2020
  matched = matchEnd(varCon, cmd);
×
2021

2022
  return;
×
2023
}
2024

2025
// press othr key
2026
void pressOtherKey(char c) {
×
2027
#ifdef WINDOWS
2028
  return ;
2029
#endif
2030

2031
  // reset global variant
2032
  firstMatchIndex = -1;
×
2033
  lastMatchIndex = -1;
×
2034
  curMatchIndex = -1;
×
2035
  lastWordBytes = -1;
×
2036

2037
  // var names
2038
  cursorVar = -1;
×
2039
  varMode = false;
×
2040
  waitAutoFill = false;
×
2041
  cntDel = 0;
×
2042

2043
  if (lastMatch) {
×
2044
    freeMatch(lastMatch);
×
2045
    lastMatch = NULL;
×
2046
  }
2047
}
×
2048

2049
// put name into name, return name length
2050
int getWordName(char* p, char* name, int nameLen) {
348✔
2051
  // remove prefix blank
2052
  while (*p == ' ') {
522✔
2053
    p++;
174✔
2054
  }
2055

2056
  // get databases name;
2057
  int i = 0;
348✔
2058
  while (p[i] != 0 && i < nameLen - 1) {
1,746!
2059
    name[i] = p[i];
1,725✔
2060
    i++;
1,725✔
2061
    if (p[i] == ' ' || p[i] == ';' || p[i] == '(') {
1,725!
2062
      // name end
2063
      break;
2064
    }
2065
  }
2066
  name[i] = 0;
348✔
2067

2068
  return i;
348✔
2069
}
2070

2071
// deal use db, if have  'use' return true
2072
bool dealUseDB(char* sql) {
210✔
2073
  // check use keyword
2074
  if (strncasecmp(sql, "use ", 4) != 0) {
210!
2075
    return false;
210✔
2076
  }
2077

2078
  char  db[256];
2079
  char* p = sql + 4;
×
2080
  if (getWordName(p, db, sizeof(db)) == 0) {
×
2081
    // no name , return
2082
    return true;
×
2083
  }
2084

2085
  //  dbName is previous use open db name
2086
  if (strcasecmp(db, dbName) == 0) {
×
2087
    // same , no need switch
2088
    return true;
×
2089
  }
2090

2091
  // switch new db
2092
  taosThreadMutexLock(&tiresMutex);
×
2093
  // STABLE set null
2094
  STire* tire = tires[WT_VAR_STABLE];
×
2095
  tires[WT_VAR_STABLE] = NULL;
×
2096
  if (tire) {
×
2097
    freeTire(tire);
×
2098
  }
2099
  // TABLE set null
2100
  tire = tires[WT_VAR_TABLE];
×
2101
  tires[WT_VAR_TABLE] = NULL;
×
2102
  if (tire) {
×
2103
    freeTire(tire);
×
2104
  }
2105
  // save
2106
  strcpy(dbName, db);
×
2107
  taosThreadMutexUnlock(&tiresMutex);
×
2108

2109
  return true;
×
2110
}
2111

2112
// deal create, if have 'create' return true
2113
bool dealCreateCommand(char* sql) {
210✔
2114
  // check keyword
2115
  if (strncasecmp(sql, "create ", 7) != 0) {
210✔
2116
    return false;
201✔
2117
  }
2118

2119
  char  name[1024];
2120
  char* p = sql + 7;
9✔
2121
  if (getWordName(p, name, sizeof(name)) == 0) {
9!
2122
    // no name , return
2123
    return true;
×
2124
  }
2125

2126
  int type = -1;
9✔
2127
  //  dbName is previous use open db name
2128
  if (strcasecmp(name, "database") == 0) {
9!
2129
    type = WT_VAR_DBNAME;
9✔
2130
  } else if (strcasecmp(name, "table") == 0) {
×
2131
    if (strstr(sql, " tags") != NULL && strstr(sql, " using ") == NULL)
×
2132
      type = WT_VAR_STABLE;
×
2133
    else
2134
      type = WT_VAR_TABLE;
×
2135
  } else if (strcasecmp(name, "user") == 0) {
×
2136
    type = WT_VAR_USERNAME;
×
2137
  } else if (strcasecmp(name, "topic") == 0) {
×
2138
    type = WT_VAR_TOPIC;
×
2139
  } else if (strcasecmp(name, "stream") == 0) {
×
2140
    type = WT_VAR_STREAM;
×
2141
  } else {
2142
    // no match , return
2143
    return true;
×
2144
  }
2145

2146
  // move next
2147
  p += strlen(name);
9✔
2148

2149
  // get next word , that is table name
2150
  if (getWordName(p, name, sizeof(name)) == 0) {
9!
2151
    // no name , return
2152
    return true;
×
2153
  }
2154

2155
  // switch new db
2156
  taosThreadMutexLock(&tiresMutex);
9✔
2157
  // STABLE set null
2158
  STire* tire = tires[type];
9✔
2159
  if (tire) {
9!
2160
    insertWord(tire, name);
×
2161
  }
2162
  taosThreadMutexUnlock(&tiresMutex);
9✔
2163

2164
  return true;
9✔
2165
}
2166

2167
// deal create, if have 'drop' return true
2168
bool dealDropCommand(char* sql) {
201✔
2169
  // check keyword
2170
  if (strncasecmp(sql, "drop ", 5) != 0) {
201✔
2171
    return false;
36✔
2172
  }
2173

2174
  char  name[1024];
2175
  char* p = sql + 5;
165✔
2176
  if (getWordName(p, name, sizeof(name)) == 0) {
165!
2177
    // no name , return
2178
    return true;
×
2179
  }
2180

2181
  int type = -1;
165✔
2182
  //  dbName is previous use open db name
2183
  if (strcasecmp(name, "database") == 0) {
165✔
2184
    type = WT_VAR_DBNAME;
141✔
2185
  } else if (strcasecmp(name, "table") == 0) {
24!
2186
    type = WT_VAR_ALLTABLE;
×
2187
  } else if (strcasecmp(name, "dnode") == 0) {
24!
2188
    type = WT_VAR_DNODEID;
×
2189
  } else if (strcasecmp(name, "user") == 0) {
24!
2190
    type = WT_VAR_USERNAME;
×
2191
  } else if (strcasecmp(name, "topic") == 0) {
24!
2192
    type = WT_VAR_TOPIC;
24✔
2193
  } else if (strcasecmp(name, "stream") == 0) {
×
2194
    type = WT_VAR_STREAM;
×
2195
  } else {
2196
    // no match , return
2197
    return true;
×
2198
  }
2199

2200
  // move next
2201
  p += strlen(name);
165✔
2202

2203
  // get next word , that is table name
2204
  if (getWordName(p, name, sizeof(name)) == 0) {
165!
2205
    // no name , return
2206
    return true;
×
2207
  }
2208

2209
  // switch new db
2210
  taosThreadMutexLock(&tiresMutex);
165✔
2211
  // STABLE set null
2212
  if (type == WT_VAR_ALLTABLE) {
165!
2213
    bool del = false;
×
2214
    // del in stable
2215
    STire* tire = tires[WT_VAR_STABLE];
×
2216
    if (tire) del = deleteWord(tire, name);
×
2217
    // del in table
2218
    if (!del) {
×
2219
      tire = tires[WT_VAR_TABLE];
×
2220
      if (tire) del = deleteWord(tire, name);
×
2221
    }
2222
  } else {
2223
    // OTHER TYPE
2224
    STire* tire = tires[type];
165✔
2225
    if (tire) deleteWord(tire, name);
165!
2226
  }
2227
  taosThreadMutexUnlock(&tiresMutex);
165✔
2228

2229
  return true;
165✔
2230
}
2231

2232
// callback autotab module after shell sql execute
2233
void callbackAutoTab(char* sqlstr, TAOS* pSql, bool usedb) {
210✔
2234
  char* sql = sqlstr;
210✔
2235
  // remove prefix blank
2236
  while (*sql == ' ') {
210!
2237
    sql++;
×
2238
  }
2239

2240
  if (dealUseDB(sql)) {
210!
2241
    // change to new db
2242
    if (!varRunOnce) updateTireValue(WT_VAR_STABLE, false);
×
2243
    return;
×
2244
  }
2245

2246
  // create command add name to autotab
2247
  if (dealCreateCommand(sql)) {
210✔
2248
    return;
9✔
2249
  }
2250

2251
  // drop command remove name from autotab
2252
  if (dealDropCommand(sql)) {
201✔
2253
    return;
165✔
2254
  }
2255

2256
  return;
36✔
2257
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc