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

taosdata / TDengine / #4870

26 Nov 2025 05:46AM UTC coverage: 64.545% (+0.006%) from 64.539%
#4870

push

travis-ci

guanshengliang
Merge branch '3.0' into cover/3.0

768 of 945 new or added lines in 33 files covered. (81.27%)

2982 existing lines in 119 files now uncovered.

158219 of 245129 relevant lines covered (64.55%)

112474797.36 hits per line

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

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

196
#endif
197
    {"show connections;", 0, 0, NULL},
198
    {"show cluster;", 0, 0, NULL},
199
    {"show cluster alive;", 0, 0, NULL},
200
    {"show cluster machines;", 0, 0, NULL},
201
    {"show databases;", 0, 0, NULL},
202
    {"show dnodes;", 0, 0, NULL},
203
    {"show dnode <dnode_id> variables;", 0, 0, NULL},
204
    {"show disk_info;", 0, 0, NULL},
205
    {"show functions;", 0, 0, NULL},
206
    {"show licences;", 0, 0, NULL},
207
    {"show mnodes;", 0, 0, NULL},
208
    {"show queries;", 0, 0, NULL},
209
    // 80
210
    {"show query <anyword> ;", 0, 0, NULL},
211
    {"show qnodes;", 0, 0, NULL},
212
    {"show bnodes;", 0, 0, NULL},
213
    {"show retentions;", 0, 0, NULL},
214
    {"show retention <retention_id>;", 0, 0, NULL},
215
    {"show scans;", 0, 0, NULL},
216
    {"show scan <scan_id>;", 0, 0, NULL},
217
    {"show stables;", 0, 0, NULL},
218
    {"show stables like ", 0, 0, NULL},
219
    {"show streams;", 0, 0, NULL},
220
    {"show scores;", 0, 0, NULL},
221
    {"show snodes;", 0, 0, NULL},
222
    {"show subscriptions;", 0, 0, NULL},
223
    {"show tables;", 0, 0, NULL},
224
    {"show tables like", 0, 0, NULL},
225
    {"show table distributed <all_table>;", 0, 0, NULL},
226
    {"show tags from <tb_name>;", 0, 0, NULL},
227
    {"show table tags from <all_table>;", 0, 0, NULL},
228
    {"show topics;", 0, 0, NULL},
229
    {"show transactions;", 0, 0, NULL},
230
    {"show tsmas;", 0, 0, NULL},
231
    {"show rsmas;", 0, 0, NULL},
232
    {"show users;", 0, 0, NULL},
233
    {"show variables;", 0, 0, NULL},
234
    {"show local variables;", 0, 0, NULL},
235
    {"show vnodes;", 0, 0, NULL},
236
    {"show vnodes on dnode <dnode_id>;", 0, 0, NULL},
237
    {"show vgroups;", 0, 0, NULL},
238
    {"show consumers;", 0, 0, NULL},
239
    {"show grants;", 0, 0, NULL},
240
    {"show grants full;", 0, 0, NULL},
241
    {"show grants logs;", 0, 0, NULL},
242
#ifdef TD_ENTERPRISE
243
    {"show views;", 0, 0, NULL},
244
    {"show arbgroups;", 0, 0, NULL},
245
    {"split vgroup <vgroup_id>;", 0, 0, NULL},
246
    {"ssmigrate database <db_name>;", 0, 0, NULL},
247
    {"show mounts;", 0, 0, NULL},
248
#endif
249
    {"insert into <tb_name> values(", 0, 0, NULL},
250
    {"insert into <tb_name> using <stb_name> tags(", 0, 0, NULL},
251
    {"insert into <tb_name> using <stb_name> <anyword> values(", 0, 0, NULL},
252
    {"insert into <tb_name> file ", 0, 0, NULL},
253
    {"trim database <db_name>;", 0, 0, NULL},
254
    {"use <db_name>;", 0, 0, NULL},
255
    {"update all anodes;", 0, 0, NULL},
256
    {"update anode <anyword>;", 0, 0, NULL},
257
    {"quit", 0, 0, NULL}};
258

259
// where keyword
260
char* keywords[] = {
261
    "where ",       "and ",      "asc ",      "desc ",    "from ",         "fill(",     "limit ",
262
    "interval(",    "order by ", "order by ", "offset ",  "or ",           "group by ", "now()",
263
    "session(",     "sliding ",  "slimit ",   "soffset ", "state_window(", "today() ",  "union all select ",
264
    "partition by ", "match",    "nmatch ",    "between ",  "like ",           "is null ",   "is not null ",
265
    "event_window ",  "count_window(", "anomaly_window("
266
};
267

268
char* functions[] = {
269
    "count(",         "sum(",
270
    "avg(",           "last(",
271
    "last_row(",      "top(",
272
    "interp(",        "max(",
273
    "min(",           "now()",
274
    "today()",        "percentile(",
275
    "tail(",          "pow(",
276
    "abs(",           "atan(",
277
    "acos(",          "asin(",
278
    "apercentile(",   "bottom(",
279
    "cast(",          "ceil(",
280
    "char_length(",   "cos(",
281
    "concat(",        "concat_ws(",
282
    "csum(",          "diff(",
283
    "derivative(",    "elapsed(",
284
    "first(",         "floor(",
285
    "hyperloglog(",   "histogram(",
286
    "irate(",         "leastsquares(",
287
    "length(",        "log(",
288
    "lower(",         "ltrim(",
289
    "mavg(",          "mode(",
290
    "tan(",           "round(",
291
    "rtrim(",         "sample(",
292
    "sin(",           "spread(",
293
    "substr(",        "statecount(",
294
    "stateduration(", "stddev(",
295
    "sqrt(",          "timediff(",
296
    "timezone(",      "timetruncate(",
297
    "twa(",           "to_unixtimestamp(",
298
    "unique(",        "upper(",
299
    "pi(",            "round(",
300
    "truncate(",      "exp(",
301
    "ln(",            "mod(",
302
    "rand(",          "sign(",
303
    "degrees(",       "radians(",
304
    "greatest(",      "least(",
305
    "char_length(",   "char(",
306
    "ascii(",         "position(",
307
    "trim(",           "replace(",
308
    "repeat(",         "substring(",
309
    "substring_index(","timediff(",
310
    "week(",           "weekday(",
311
    "weekofyear(",     "dayofweek(",
312
    "stddev_pop(",     "var_pop(",
313
    "forecast(",       "imputation(",
314
    "std(",            "variance(",
315
    "stddev_samp(",    "var_samp(",
316
    "group_concat(",   "if(",
317
    "ifnull(",         "nvl(",
318
    "nvl2(",           "isnull(",
319
    "isnotnull(",      "coalesce(",
320
    "date(",           "corr(",
321
    "cols(",           "find_in_set(",
322
    "like_in_set(",    "regexp_in_set(",
323
    "case ",           "when "
324
};
325

326
char* tb_actions[] = {
327
    "add column ", "modify column ", "drop column ", "rename column ", "add tag ",
328
    "modify tag ", "drop tag ",      "rename tag ",  "set tag ",
329
};
330

331
char* user_actions[] = {"pass ", "enable ", "sysinfo ", "createdb "};
332

333
char* tb_options[] = {"comment ", "watermark ", "max_delay ", "ttl ", "rollup(", "sma(", "virtual 1"};
334

335
char* db_options[] = {"keep ",
336
                      "replica ",
337
                      "precision ",
338
                      "strict ",
339
                      "buffer ",
340
                      "cachemodel ",
341
                      "cachesize ",
342
                      "comp ",
343
                      "duration ",
344
                      "dnodes ",
345
                      "wal_fsync_period ",
346
                      "maxrows ",
347
                      "minrows ",
348
                      "pages ",
349
                      "pagesize ",
350
                      "retentions ",
351
                      "wal_level ",
352
                      "vgroups ",
353
                      "single_stable ",
354
                      "ss_chunksize ",
355
                      "ss_keeplocal ",
356
                      "ss_compact ",
357
                      "wal_retention_period ",
358
                      "wal_roll_period ",
359
                      "wal_retention_size ",
360
#ifdef TD_ENTERPRISE                      
361
                      "encrypt_algorithm ",
362
                      "compact_interval ",
363
                      "compact_time_range ",
364
                      "compact_time_offset ",
365
#endif
366
                      "keep_time_offset ",
367
                      "wal_segment_size "
368
};
369

370
char* alter_db_options[] = {"cachemodel ", "replica ", "keep ", "stt_trigger ",
371
                            "wal_retention_period ", "wal_retention_size ", "cachesize ", 
372
                                              "ss_keeplocal ", "ss_compact ",
373
                            "wal_fsync_period ", "buffer ", "pages " ,"wal_level "};
374

375
char* data_types[] = {"timestamp",    "int",
376
                      "int unsigned", "varchar(16)",
377
                      "float",        "double",
378
                      "binary(16)",   "nchar(16)",
379
                      "bigint",       "bigint unsigned",
380
                      "smallint",     "smallint unsigned",
381
                      "tinyint",      "tinyint unsigned",
382
                      "geometry(64)", "varbinary(16)",
383
                      "decimal(10,2)", "blob",
384
                      "bool",         "json"};
385

386
char* key_tags[] = {"tags("};
387

388
char* key_select[] = {"select "};
389

390
char* key_systable[] = {
391
    "ins_dnodes",        "ins_mnodes",     "ins_modules",      "ins_qnodes",  "ins_snodes",          "ins_cluster",
392
    "ins_databases",     "ins_functions",  "ins_indexes",      "ins_stables", "ins_tables",          "ins_tags",
393
    "ins_users",         "ins_grants",     "ins_vgroups",      "ins_configs", "ins_dnode_variables", "ins_topics",
394
    "ins_subscriptions", "ins_streams",    "ins_stream_tasks", "ins_vnodes",  "ins_user_privileges", "ins_filesets",
395
    "ins_bnodes",        "ins_disk_usage", "ins_retentions",
396
    "perf_connections", "perf_queries",    "perf_consumers", "perf_trans",       "perf_apps"};
397

398
char* udf_language[] = {"\'Python\'", "\'C\'"};
399

400
char* field_options[] = {
401
    "encode ", "compress ", "level ", 
402
    "\'lz4\' ", "\'zlib\' ", "\'zstd\' ", "\'xz\' ", "\'tsz\' ", "\'disabled\' ", // compress
403
    "\'simple8b\' ", "\'delta-i\' ", "\'delta-d\' ", "\'bit-packing\' ", "\'bss\' ",
404
    "\'high\' ", "\'medium\' ", "\'low\' ",
405
    "comment ",
406
    "primary key "
407
};
408

409
// global keys can tips on anywhere
410
char* global_keys[] = {
411
    "tbname",         
412
    "now",
413
    "vgroups",
414
    "_wstart",      
415
    "_wend",
416
    "_wduration",
417
    "_qstart",          
418
    "_qend",
419
    "_qduration",
420
    "_qtag",
421
    "_isfilled"
422
  };
423

424
//
425
//  ------- global variant define ---------
426
//
427
int32_t firstMatchIndex = -1;  // first match shellCommands index
428
int32_t lastMatchIndex = -1;   // last match shellCommands index
429
int32_t curMatchIndex = -1;    // current match shellCommands index
430
int32_t lastWordBytes = -1;    // printShow last word length
431
bool    waitAutoFill = false;
432

433
//
434
//   ----------- global var array define -----------
435
//
436
#define WT_VAR_DBNAME         0
437
#define WT_VAR_STABLE         1
438
#define WT_VAR_TABLE          2
439
#define WT_VAR_DNODEID        3
440
#define WT_VAR_USERNAME       4
441
#define WT_VAR_TOPIC          5
442
#define WT_VAR_STREAM         6
443
#define WT_VAR_UDFNAME        7
444
#define WT_VAR_VGROUPID       8
445
#define WT_VAR_TSMA           9
446
#define WT_VAR_RSMA           10
447
#define WT_VAR_ANODE          11
448

449
#define WT_FROM_DB_MAX        11  // max get content from db
450
#define WT_FROM_DB_CNT (WT_FROM_DB_MAX + 1)
451

452
#define WT_VAR_ALLTABLE       12
453
#define WT_VAR_FUNC           13
454
#define WT_VAR_KEYWORD        14
455
#define WT_VAR_TBACTION       15
456
#define WT_VAR_DBOPTION       16
457
#define WT_VAR_ALTER_DBOPTION 17
458
#define WT_VAR_DATATYPE       18
459
#define WT_VAR_KEYTAGS        19
460
#define WT_VAR_ANYWORD        20
461
#define WT_VAR_TBOPTION       21
462
#define WT_VAR_USERACTION     22
463
#define WT_VAR_KEYSELECT      23
464
#define WT_VAR_SYSTABLE       24
465
#define WT_VAR_LANGUAGE       25
466
#define WT_VAR_GLOBALKEYS     26
467
#define WT_VAR_FIELD_OPTIONS  27
468

469
#define WT_VAR_CNT 28
470

471

472
#define WT_TEXT 0xFF
473

474
char dbName[256] = "";  // save use database name;
475
// tire array
476
STire*        tires[WT_VAR_CNT];
477
TdThreadMutex tiresMutex;
478
// save thread handle obtain var name from db server
479
TdThread* threads[WT_FROM_DB_CNT];
480
// obtain var name  with sql from server
481
char varTypes[WT_VAR_CNT][64] = {
482
    // get from db
483
    "<db_name>",    "<stb_name>",  "<tb_name>",  "<dnode_id>",  "<user_name>",    "<topic_name>", "<stream_name>",
484
    "<udf_name>",   "<vgroup_id>", "<tsma_name>", "<rsma_name>", "<anode_id>", 
485
    // get from code
486
    "<all_table>",  "<function>",  "<keyword>",  "<tb_actions>",   "<db_options>", "<alter_db_options>",
487
    "<data_types>", "<key_tags>",  "<anyword>",  "<tb_options>", "<user_actions>", "<key_select>", "<sys_table>", 
488
    "<udf_language>", "<global_keys>", "<field_options>"};
489

490
char varSqls[WT_FROM_DB_CNT][64] = {"show databases;", "show stables;", "show tables;", "show dnodes;",
491
                                    "show users;",     "show topics;",  "show streams;", "show functions;", 
492
                                    "show vgroups;",   "show tsmas;",   "show rsmas;",  "show anodes;"};
493

494
// var words current cursor, if user press any one key except tab, cursorVar can be reset to -1
495
int  cursorVar = -1;
496
bool varMode = false;  // enter var names list mode
497

498
TAOS*      varCon = NULL;
499
SShellCmd* varCmd = NULL;
500
bool       varRunOnce = false;
501
SMatch*    lastMatch = NULL;  // save last match result
502
int        cntDel = 0;        // delete byte count after next press tab
503

504
// show auto tab introduction
505
void printfIntroduction(EVersionType type) {
630✔
506
  printf("  *********************************  Tab Completion  *************************************\n");
630✔
507
  char secondLine[160] = "\0";
630✔
508
  sprintf(secondLine, "  *   The %s CLI supports tab completion for a variety of items, ", shell.info.cusName);
630✔
509
  printf("%s", secondLine);
630✔
510
  int secondLineLen = strlen(secondLine);
630✔
511
  while (89 - (secondLineLen++) > 0) {
8,820✔
512
    printf(" ");
8,190✔
513
  }
514
  printf("*\n");
630✔
515
  printf("  *   including database names, table names, function names and keywords.                *\n");
630✔
516
  printf("  *   The full list of shortcut keys is as follows:                                      *\n");
630✔
517
  printf("  *    [ TAB ]        ......  complete the current word                                  *\n");
630✔
518
  printf("  *                   ......  if used on a blank line, display all supported commands    *\n");
630✔
519
  printf("  *    [ Ctrl + A ]   ......  move cursor to the st[A]rt of the line                     *\n");
630✔
520
  printf("  *    [ Ctrl + E ]   ......  move cursor to the [E]nd of the line                       *\n");
630✔
521
  printf("  *    [ Ctrl + W ]   ......  move cursor to the middle of the line                      *\n");
630✔
522
  printf("  *    [ Ctrl + L ]   ......  clear the entire screen                                    *\n");
630✔
523
  printf("  *    [ Ctrl + K ]   ......  clear the screen after the cursor                          *\n");
630✔
524
  printf("  *    [ Ctrl + U ]   ......  clear the screen before the cursor                         *\n");
630✔
525
  if (type == TSDB_VERSION_OSS) {
630✔
UNCOV
526
    printf("  * ------------------------------------------------------------------------------------ *\n");
×
UNCOV
527
    printf("  *   You are using TDengine OSS. To experience advanced features, like backup/restore,  *\n");
×
UNCOV
528
    printf("  *   privilege control and more, or receive 7x24 technical support, try TDengine        *\n");
×
UNCOV
529
    printf("  *   Enterprise or TDengine Cloud. Learn more at https://tdengine.com                   *\n");
×
530
  }
531
  printf("  ****************************************************************************************\n\n");
630✔
532
}
630✔
533

534
// show enterprise AD
UNCOV
535
void showAD(bool end) {
×
UNCOV
536
  printf("  You are using TDengine OSS. To experience advanced features, like backup/restore,  \n");
×
UNCOV
537
  printf("  privilege control and more, or receive 7x24 technical support, try TDengine Enterprise \n");
×
UNCOV
538
  printf("  or TDengine Cloud. Learn more at https://tdengine.com   \n");
×
UNCOV
539
  printf("  \n");
×
UNCOV
540
}
×
541

542
void showHelp() {
517✔
543
  printf("\nThe %s CLI supports the following commands:", shell.info.cusName);
517✔
544
  printf(
517✔
545
      "\n\
546
  ----- A ----- \n\
547
    alter database <db_name> <db_options> \n\
548
    alter dnode <dnode_id> 'resetlog';\n\
549
    alter dnode <dnode_id> 'monitor' '0';\n\
550
    alter dnode <dnode_id> 'monitor' \"1\";\n\
551
    alter dnode <dnode_id> \"debugflag\" \"143\";\n\
552
    alter dnode <dnode_id> 'asynclog' '0';\n\
553
    alter dnode <dnode_id> 'asynclog' \"1\";\n\
554
    alter all dnodes \"monitor\" \"0\";\n\
555
    alter all dnodes \"monitor\" \"1\";\n\
556
    alter all dnodes \"resetlog\";\n\
557
    alter all dnodes \"debugFlag\" \n\
558
    alter all dnodes \"asynclog\" \"0\";\n\
559
    alter all dnodes \"asynclog\" \"1\";\n\
560
    alter table <tb_name> <tb_actions> ;\n\
561
    alter local \"resetlog\";\n\
562
    alter local \"DebugFlag\" \"143\";\n\
563
    alter local \"asynclog\" \"0\";\n\
564
    alter local \"asynclog\" \"1\";\n\
565
    alter topic\n\
566
    alter user <user_name> <user_actions> ...\n\
567
  ----- C ----- \n\
568
    create table <tb_name> using <stb_name> tags ...\n\
569
    create vtable <tb_name> using <stb_name> tags ...\n\
570
    create database <db_name> <db_options>  ...\n\
571
    create dnode \"fqdn:port\" ...\n\
572
    create index <index_name> on <stb_name> (tag_column_name);\n\
573
    create mnode on dnode <dnode_id> ;\n\
574
    create qnode on dnode <dnode_id> ;\n\
575
    create bnode on dnode <dnode_id> ;\n\
576
    create anode \"node_url\" ;\n\
577
    create stream <stream_name> into <stb_name> as select ...\n\
578
    create topic <topic_name> as select ...\n\
579
    create function <udf_name> as <file_name> outputtype <data_types> language \'C\' | \'Python\' ;\n\
580
    create aggregate function  <udf_name> as <file_name> outputtype <data_types> bufsize <bufsize_bytes> language \'C\' | \'Python\';\n\
581
    create user <user_name> pass <password> ...\n\
582
  ----- D ----- \n\
583
    describe <all_table>\n\
584
    delete from <all_table> where ...\n\
585
    drop database <db_name>;\n\
586
    drop table <all_table>;\n\
587
    drop dnode <dnode_id>;\n\
588
    drop mnode on dnode <dnode_id> ;\n\
589
    drop qnode on dnode <dnode_id> ;\n\
590
    drop bnode on dnode <dnode_id> ;\n\
591
    drop anode <anode_id> ;\n\
592
    drop user <user_name> ;\n\
593
    drop function <udf_name>;\n\
594
    drop consumer group ... \n\
595
    drop topic <topic_name> ;\n\
596
    drop stream <stream_name> ;\n\
597
    drop index <index_name>;\n\
598
    drop tsma <tsma_name> ;\n\
599
    drop rsma <rsma_name> ;\n\
600
  ----- E ----- \n\
601
    explain select clause ...\n\
602
  ----- F ----- \n\
603
    flush database <db_name>;\n\
604
  ----- H ----- \n\
605
    help;\n\
606
  ----- I ----- \n\
607
    insert into <tb_name> values(...) ;\n\
608
    insert into <tb_name> using <stb_name> tags(...) values(...) ;\n\
609
  ----- G ----- \n\
610
    grant all   on <priv_level> to <user_name> ;\n\
611
    grant read  on <priv_level> to <user_name> ;\n\
612
    grant write on <priv_level> to <user_name> ;\n\
613
  ----- K ----- \n\
614
    kill connection <connection_id>; \n\
615
    kill query <query_id>; \n\
616
    kill retention <retention_id>; \n\
617
    kill transaction <transaction_id>;\n\
618
  ----- P ----- \n\
619
    pause stream <stream_name>;\n\
620
  ----- R ----- \n\
621
    resume stream <stream_name>;\n\
622
    reset query cache;\n\
623
    restore dnode <dnode_id> ;\n\
624
    restore vnode on dnode <dnode_id> ;\n\
625
    restore mnode on dnode <dnode_id> ;\n\
626
    restore qnode on dnode <dnode_id> ;\n\
627
    revoke all   on <priv_level> from <user_name> ;\n\
628
    revoke read  on <priv_level> from <user_name> ;\n\
629
    revoke write on <priv_level> from <user_name> ;\n\
630
  ----- S ----- \n\
631
    select * from <all_table> where ... \n\
632
    select client_version();\n\
633
    select current_user();\n\
634
    select database();\n\
635
    select server_version();\n\
636
    select server_status();\n\
637
    select now();\n\
638
    select today();\n\
639
    select timezone();\n\
640
    set max_binary_display_width ...\n\
641
    show apps;\n\
642
    show alive;\n\
643
    show anodes;\n\
644
    show anodes full;\n\
645
    show create database <db_name>;\n\
646
    show create stable <stb_name>;\n\
647
    show create table <tb_name>;\n\
648
    show connections;\n\
649
    show cluster;\n\
650
    show cluster alive;\n\
651
    show cluster machines;\n\
652
    show databases;\n\
653
    show dnodes;\n\
654
    show dnode <dnode_id> variables;\n\
655
    show disk_info;\n\
656
    show functions;\n\
657
    show licences;\n\
658
    show mnodes;\n\
659
    show queries;\n\
660
    show query <query_id> ;\n\
661
    show qnodes;\n\
662
    show bnodes;\n\
663
    show retentions;\n\
664
    show retention <retention_id>;\n\
665
    show scans;\n\
666
    show scan <scan_id>;\n\
667
    show snodes;\n\
668
    show stables;\n\
669
    show stables like \n\
670
    show streams;\n\
671
    show scores;\n\
672
    show subscriptions;\n\
673
    show tables;\n\
674
    show tables like\n\
675
    show table distributed <all_table>;\n\
676
    show tags from <tb_name>\n\
677
    show tags from <db_name>\n\
678
    show table tags from <all_table>\n\
679
    show topics;\n\
680
    show transactions;\n\
681
    show tsmas;\n\
682
    show rsmas;\n\
683
    show users;\n\
684
    show variables;\n\
685
    show local variables;\n\
686
    show vnodes;\n\
687
    show vnodes on dnode <dnode_id>;\n\
688
    show vgroups;\n\
689
    show consumers;\n\
690
    show grants;\n\
691
    show grants full;\n\
692
    show grants logs;\n\
693
  ----- T ----- \n\
694
    trim database <db_name>;\n\
695
  ----- U ----- \n\
696
    update all anodes;\n\
697
    update anode <anode_id>;\n\
698
    use <db_name>;");
699

700
#ifdef TD_ENTERPRISE
701
  printf(
517✔
702
      "\n\n\
703
  ----- special commands on enterpise version ----- \n\
704
    balance vgroup ;\n\
705
    balance vgroup leader on <vgroup_id> \n\
706
    compact database <db_name>; \n\
707
    compact vgroups in (vgroupId,vgroupId, ...); \n\
708
    create view <view_name> as select ...\n\
709
    create mount <mount_name> on dnode <dnode_id> from <path>;\n\
710
    drop mount <mount_name>;\n\
711
    redistribute vgroup <vgroup_id> dnode <dnode_id> ;\n\
712
    split vgroup <vgroup_id>;\n\
713
    ssmigrate database <db_name>;\n\
714
    show compacts;\n\
715
    show compact \n\
716
    show ssmigrates;\n\
717
    show arbgroups;\n\
718
    show mounts;\n\
719
    show views;\n\
720
    show create view <all_table>;");
721
#endif
722

723
  printf("\n\n");
517✔
724
  // define in getDuration() function
725
  printf(
517✔
726
      "\
727
  Timestamp expression Format:\n\
728
    b - nanosecond \n\
729
    u - microsecond \n\
730
    a - millisecond \n\
731
    s - second \n\
732
    m - minute \n\
733
    h - hour \n\
734
    d - day \n\
735
    w - week \n\
736
    now - current time \n\
737
  Example : \n\
738
    select * from t1 where ts > now - 2w + 3d and ts <= now - 1w -2h ;\n");
739
  printf(ERROR_CODE_DETAIL);
517✔
740
  printf("\n");
517✔
741
}
517✔
742

743
//
744
//  -------------------  parse words --------------------------
745
//
746

747
#define SHELL_COMMAND_COUNT() (sizeof(shellCommands) / sizeof(SWords))
748

749
// get at
UNCOV
750
SWord* atWord(SWords* command, int32_t index) {
×
UNCOV
751
  SWord* word = command->head;
×
UNCOV
752
  for (int32_t i = 0; i < index; i++) {
×
UNCOV
753
    if (word == NULL) return NULL;
×
UNCOV
754
    word = word->next;
×
755
  }
756

UNCOV
757
  return word;
×
758
}
759

760
#define MATCH_WORD(x) atWord(x, x->matchIndex)
761

762
int wordType(const char* p, int32_t len) {
800,651,040✔
763
  for (int i = 0; i < WT_VAR_CNT; i++) {
2,147,483,647✔
764
    if (strncmp(p, varTypes[i], len) == 0) return i;
2,147,483,647✔
765
  }
766
  return WT_TEXT;
599,310,852✔
767
}
768

769
// add word
770
SWord* addWord(const char* p, int32_t len, bool pattern) {
811,247,892✔
771
  SWord* word = (SWord*)taosMemoryMalloc(sizeof(SWord));
811,247,892✔
772
  memset(word, 0, sizeof(SWord));
811,247,892✔
773
  word->word = (char*)p;
811,247,892✔
774
  word->len = len;
811,247,892✔
775

776
  // check format
777
  if (pattern && len > 0) {
811,247,892✔
778
    if (p[len - 1] == ';') {
800,651,040✔
779
      word->type = wordType(p, len - 1);
164,839,920✔
780
      word->end = true;
164,839,920✔
781
    } else {
782
      word->type = wordType(p, len);
635,811,120✔
783
    }
784
  } else {
785
    word->type = WT_TEXT;
10,596,852✔
786
  }
787

788
  return word;
811,247,892✔
789
}
790

791
// parse one command
792
void parseCommand(SWords* command, bool pattern) {
203,695,044✔
793
  char*   p = command->source;
203,695,044✔
794
  int32_t start = 0;
203,695,044✔
795
  int32_t size = command->source_len > 0 ? command->source_len : strlen(p);
203,695,044✔
796

797
  bool lastBlank = false;
203,695,044✔
798
  for (int i = 0; i <= size; i++) {
2,147,483,647✔
799
    if (p[i] == ' ' || i == size) {
2,147,483,647✔
800
      // check continue blank like '    '
801
      if (p[i] == ' ') {
813,602,748✔
802
        if (lastBlank) {
609,907,704✔
803
          start++;
2,354,856✔
804
          continue;
2,354,856✔
805
        }
806
        if (i == 0) {  // first blank
607,552,848✔
UNCOV
807
          lastBlank = true;
×
UNCOV
808
          start++;
×
UNCOV
809
          continue;
×
810
        }
811
        lastBlank = true;
607,552,848✔
812
      }
813

814
      // found split or string end , append word
815
      if (command->head == NULL) {
811,247,892✔
816
        command->head = addWord(p + start, i - start, pattern);
203,695,044✔
817
        command->count = 1;
203,695,044✔
818
      } else {
819
        SWord* word = command->head;
607,552,848✔
820
        while (word->next) {
1,899,191,364✔
821
          word = word->next;
1,291,638,516✔
822
        }
823
        word->next = addWord(p + start, i - start, pattern);
607,552,848✔
824
        command->count++;
607,552,848✔
825
      }
826
      start = i + 1;
811,247,892✔
827
    } else {
828
      lastBlank = false;
2,147,483,647✔
829
    }
830
  }
831
}
203,695,044✔
832

833
// free SShellCmd
834
void freeCommand(SWords* command) {
203,695,044✔
835
  SWord* item = command->head;
203,695,044✔
836
  command->head = NULL;
203,695,044✔
837
  // loop
838
  while (item) {
1,014,942,936✔
839
    SWord* tmp = item;
811,247,892✔
840
    item = item->next;
811,247,892✔
841
    // if malloc need free
842
    if (tmp->free && tmp->word) taosMemoryFree(tmp->word);
811,247,892✔
843
    taosMemoryFree(tmp);
811,247,892✔
844
  }
845
}
203,695,044✔
846

847
void GenerateVarType(int type, char** p, int count) {
16,483,992✔
848
  STire* tire = createTire(TIRE_LIST);
16,483,992✔
849
  for (int i = 0; i < count; i++) {
359,115,540✔
850
    insertWord(tire, p[i]);
342,631,548✔
851
  }
852

853
  taosThreadMutexLock(&tiresMutex);
16,483,992✔
854
  tires[type] = tire;
16,483,992✔
855
  taosThreadMutexUnlock(&tiresMutex);
16,483,992✔
856
}
16,483,992✔
857

858
//
859
//  -------------------- shell auto ----------------
860
//
861

862
// init shell auto function , shell start call once
863
void shellAutoInit() {
1,177,428✔
864
  // command
865
  int32_t count = SHELL_COMMAND_COUNT();
1,177,428✔
866
  for (int32_t i = 0; i < count; i++) {
204,872,472✔
867
    parseCommand(shellCommands + i, true);
203,695,044✔
868
  }
869

870
  // tires
871
  memset(tires, 0, sizeof(STire*) * WT_VAR_CNT);
1,177,428✔
872
  taosThreadMutexInit(&tiresMutex, NULL);
1,177,428✔
873

874
  // threads
875
  memset(threads, 0, sizeof(TdThread*) * WT_FROM_DB_CNT);
1,177,428✔
876

877
  // generate varType
878
  GenerateVarType(WT_VAR_FUNC, functions, sizeof(functions) / sizeof(char*));
1,177,428✔
879
  GenerateVarType(WT_VAR_KEYWORD, keywords, sizeof(keywords) / sizeof(char*));
1,177,428✔
880
  GenerateVarType(WT_VAR_TBACTION, tb_actions, sizeof(tb_actions) / sizeof(char*));
1,177,428✔
881
  GenerateVarType(WT_VAR_DBOPTION, db_options, sizeof(db_options) / sizeof(char*));
1,177,428✔
882
  GenerateVarType(WT_VAR_ALTER_DBOPTION, alter_db_options, sizeof(alter_db_options) / sizeof(char*));
1,177,428✔
883
  GenerateVarType(WT_VAR_DATATYPE, data_types, sizeof(data_types) / sizeof(char*));
1,177,428✔
884
  GenerateVarType(WT_VAR_KEYTAGS, key_tags, sizeof(key_tags) / sizeof(char*));
1,177,428✔
885
  GenerateVarType(WT_VAR_TBOPTION, tb_options, sizeof(tb_options) / sizeof(char*));
1,177,428✔
886
  GenerateVarType(WT_VAR_USERACTION, user_actions, sizeof(user_actions) / sizeof(char*));
1,177,428✔
887
  GenerateVarType(WT_VAR_KEYSELECT, key_select, sizeof(key_select) / sizeof(char*));
1,177,428✔
888
  GenerateVarType(WT_VAR_SYSTABLE, key_systable, sizeof(key_systable) / sizeof(char*));
1,177,428✔
889
  GenerateVarType(WT_VAR_LANGUAGE, udf_language, sizeof(udf_language) / sizeof(char*));
1,177,428✔
890
  GenerateVarType(WT_VAR_GLOBALKEYS, global_keys, sizeof(global_keys) / sizeof(char*));
1,177,428✔
891
  GenerateVarType(WT_VAR_FIELD_OPTIONS, field_options, sizeof(field_options) / sizeof(char*));
1,177,428✔
892
}
1,177,428✔
893

894
// set conn
895
void shellSetConn(TAOS* conn, bool runOnce) {
1,165,640✔
896
  varCon = conn;
1,165,640✔
897
  varRunOnce = runOnce;
1,165,640✔
898
  // init database and stable
899
  if (!runOnce) updateTireValue(WT_VAR_DBNAME, false);
1,165,640✔
900
}
1,165,640✔
901

902
// exit shell auto function, shell exit call once
903
void shellAutoExit() {
1,177,428✔
904
  // free command
905
  int32_t count = SHELL_COMMAND_COUNT();
1,177,428✔
906
  for (int32_t i = 0; i < count; i++) {
204,872,472✔
907
    freeCommand(shellCommands + i);
203,695,044✔
908
  }
909

910
  // free tires
911
  taosThreadMutexLock(&tiresMutex);
1,177,428✔
912
  for (int32_t i = 0; i < WT_VAR_CNT; i++) {
34,145,412✔
913
    if (tires[i]) {
32,967,984✔
914
      freeTire(tires[i]);
16,484,622✔
915
      tires[i] = NULL;
16,484,622✔
916
    }
917
  }
918
  taosThreadMutexUnlock(&tiresMutex);
1,177,428✔
919
  // destroy
920
  taosThreadMutexDestroy(&tiresMutex);
1,177,428✔
921

922
  // free threads
923
  for (int32_t i = 0; i < WT_FROM_DB_CNT; i++) {
15,306,564✔
924
    if (threads[i]) {
14,129,136✔
UNCOV
925
      taosDestroyThread(threads[i]);
×
UNCOV
926
      threads[i] = NULL;
×
927
    }
928
  }
929

930
  // free lastMatch
931
  if (lastMatch) {
1,177,428✔
UNCOV
932
    freeMatch(lastMatch);
×
UNCOV
933
    lastMatch = NULL;
×
934
  }
935
}
1,177,428✔
936

937
//
938
//  -------------------  auto ptr for tires --------------------------
939
//
940
bool setNewAutoPtr(int type, STire* pNew) {
630✔
941
  if (pNew == NULL) return false;
630✔
942

943
  taosThreadMutexLock(&tiresMutex);
630✔
944
  STire* pOld = tires[type];
630✔
945
  if (pOld != NULL) {
630✔
946
    // previous have value, release self ref count
UNCOV
947
    if (--pOld->ref == 0) {
×
UNCOV
948
      freeTire(pOld);
×
949
    }
950
  }
951

952
  // set new
953
  tires[type] = pNew;
630✔
954
  tires[type]->ref = 1;
630✔
955
  taosThreadMutexUnlock(&tiresMutex);
630✔
956

957
  return true;
630✔
958
}
959

960
// get ptr
UNCOV
961
STire* getAutoPtr(int type) {
×
UNCOV
962
  if (tires[type] == NULL) {
×
UNCOV
963
    return NULL;
×
964
  }
965

UNCOV
966
  taosThreadMutexLock(&tiresMutex);
×
UNCOV
967
  tires[type]->ref++;
×
UNCOV
968
  taosThreadMutexUnlock(&tiresMutex);
×
969

UNCOV
970
  return tires[type];
×
971
}
972

973
// put back tire to tires[type], if tire not equal tires[type].p, need free tire
UNCOV
974
void putBackAutoPtr(int type, STire* tire) {
×
UNCOV
975
  if (tire == NULL) {
×
UNCOV
976
    return;
×
977
  }
978

979
  taosThreadMutexLock(&tiresMutex);
×
980
  if (tires[type] != tire) {
×
981
    // update by out,  can't put back , so free
UNCOV
982
    if (--tire->ref == 1) {
×
983
      // support multi thread getAutoPtr
UNCOV
984
      freeTire(tire);
×
985
    }
986

987
  } else {
UNCOV
988
    tires[type]->ref--;
×
UNCOV
989
    ASSERT(tires[type]->ref > 0);
×
990
  }
UNCOV
991
  taosThreadMutexUnlock(&tiresMutex);
×
992

UNCOV
993
  return;
×
994
}
995

996
//
997
//  -------------------  var Word --------------------------
998
//
999

1000
#define MAX_CACHED_CNT 100000  // max cached rows 10w
1001
// write sql result to var name, return write rows cnt
1002
int writeVarNames(int type, TAOS_RES* tres) {
630✔
1003
  // fetch row
1004
  TAOS_ROW row = taos_fetch_row(tres);
630✔
1005
  if (row == NULL) {
630✔
UNCOV
1006
    return 0;
×
1007
  }
1008

1009
  TAOS_FIELD* fields = taos_fetch_fields(tres);
630✔
1010
  // create new tires
1011
  char   tireType = type == WT_VAR_TABLE ? TIRE_TREE : TIRE_LIST;
630✔
1012
  STire* tire = createTire(tireType);
630✔
1013

1014
  // enum rows
1015
  char name[1024];
630✔
1016
  int  numOfRows = 0;
630✔
1017
  do {
1018
    int32_t* lengths = taos_fetch_lengths(tres);
1,638✔
1019
    int32_t  bytes = lengths[0];
1,638✔
1020
    if (fields[0].type == TSDB_DATA_TYPE_INT) {
1,638✔
1021
      sprintf(name, "%d", *(int16_t*)row[0]);
×
1022
    } else {
1023
      memcpy(name, row[0], bytes);
1,638✔
1024
    }
1025

1026
    name[bytes] = 0;  // set string end
1,638✔
1027
    // insert to tire
1028
    insertWord(tire, name);
1,638✔
1029

1030
    if (++numOfRows > MAX_CACHED_CNT) {
1,638✔
1031
      break;
×
1032
    }
1033

1034
    row = taos_fetch_row(tres);
1,638✔
1035
  } while (row != NULL);
1,638✔
1036

1037
  // replace old tire
1038
  setNewAutoPtr(type, tire);
630✔
1039

1040
  return numOfRows;
630✔
1041
}
1042

1043
void setThreadNull(int type) {
630✔
1044
  taosThreadMutexLock(&tiresMutex);
630✔
1045
  if (threads[type]) {
630✔
1046
    taosMemoryFree(threads[type]);
630✔
1047
  }
1048
  threads[type] = NULL;
630✔
1049
  taosThreadMutexUnlock(&tiresMutex);
630✔
1050
}
630✔
1051

1052
bool firstMatchCommand(TAOS* con, SShellCmd* cmd);
1053
//
1054
//  thread obtain var thread from db server
1055
//
1056
void* varObtainThread(void* param) {
630✔
1057
  int type = *(int*)param;
630✔
1058
  taosMemoryFree(param);
630✔
1059

1060
  if (varCon == NULL || type > WT_FROM_DB_MAX) {
630✔
UNCOV
1061
    return NULL;
×
1062
  }
1063

1064
  TAOS_RES* pSql = taos_query(varCon, varSqls[type]);
630✔
1065
  if (taos_errno(pSql)) {
630✔
UNCOV
1066
    taos_free_result(pSql);
×
UNCOV
1067
    setThreadNull(type);
×
1068
    return NULL;
×
1069
  }
1070

1071
  // write var names from pSql
1072
  int cnt = writeVarNames(type, pSql);
630✔
1073

1074
  // free sql
1075
  taos_free_result(pSql);
630✔
1076

1077
  // check need call auto tab
1078
  if (cnt > 0 && waitAutoFill) {
630✔
1079
    // press tab key by program
UNCOV
1080
    firstMatchCommand(varCon, varCmd);
×
1081
  }
1082

1083
  setThreadNull(type);
630✔
1084
  return NULL;
630✔
1085
}
1086

1087
// return true is need update value by async
1088
bool updateTireValue(int type, bool autoFill) {
630✔
1089
  // TYPE CONTEXT GET FROM DB
1090
  taosThreadMutexLock(&tiresMutex);
630✔
1091

1092
  // check need obtain from server
1093
  if (tires[type] == NULL) {
630✔
1094
    waitAutoFill = autoFill;
630✔
1095
    // need async obtain var names from db sever
1096
    if (threads[type] != NULL) {
630✔
UNCOV
1097
      if (taosThreadRunning(threads[type])) {
×
1098
        // thread running , need not obtain again, return
UNCOV
1099
        taosThreadMutexUnlock(&tiresMutex);
×
UNCOV
1100
        return NULL;
×
1101
      }
1102
      // destroy previous thread handle for new create thread handle
UNCOV
1103
      taosDestroyThread(threads[type]);
×
UNCOV
1104
      threads[type] = NULL;
×
1105
    }
1106

1107
    // create new
1108
    void* param = taosMemoryMalloc(sizeof(int));
630✔
1109
    *((int*)param) = type;
630✔
1110
    threads[type] = taosCreateThread(varObtainThread, param);
630✔
1111
    taosThreadMutexUnlock(&tiresMutex);
630✔
1112
    return true;
630✔
1113
  }
1114
  taosThreadMutexUnlock(&tiresMutex);
×
1115

UNCOV
1116
  return false;
×
1117
}
1118

1119
// only match next one word from all match words, return valuue must free by caller
UNCOV
1120
char* matchNextPrefix(STire* tire, char* pre) {
×
UNCOV
1121
  SMatch* match = NULL;
×
UNCOV
1122
  if (tire == NULL) return NULL;
×
1123

1124
  // re-use last result
UNCOV
1125
  if (lastMatch) {
×
UNCOV
1126
    if (strcmp(pre, lastMatch->pre) == 0) {
×
1127
      // same pre
UNCOV
1128
      match = lastMatch;
×
1129
    }
1130
  }
1131

UNCOV
1132
  if (match == NULL) {
×
1133
    // not same with last result
UNCOV
1134
    if (pre[0] == 0) {
×
1135
      // EMPTY PRE
UNCOV
1136
      match = enumAll(tire);
×
1137
    } else {
1138
      // NOT EMPTY
UNCOV
1139
      match = (SMatch*)taosMemoryMalloc(sizeof(SMatch));
×
UNCOV
1140
      memset(match, 0, sizeof(SMatch));
×
UNCOV
1141
      matchPrefix(tire, pre, match);
×
1142
    }
1143

1144
    // save to lastMatch
UNCOV
1145
    if (match) {
×
1146
      if (lastMatch) freeMatch(lastMatch);
×
1147
      lastMatch = match;
×
1148
    }
1149
  }
1150

1151
  // check valid
UNCOV
1152
  if (match == NULL || match->head == NULL) {
×
1153
    // no one matched
UNCOV
1154
    return NULL;
×
1155
  }
1156

UNCOV
1157
  if (cursorVar == -1) {
×
1158
    // first
UNCOV
1159
    cursorVar = 0;
×
UNCOV
1160
    return taosStrdup(match->head->word);
×
1161
  }
1162

1163
  // according to cursorVar , calculate next one
UNCOV
1164
  int         i = 0;
×
UNCOV
1165
  SMatchNode* item = match->head;
×
UNCOV
1166
  while (item) {
×
1167
    if (i == cursorVar + 1) {
×
1168
      // found next position ok
1169
      if (item->next == NULL) {
×
1170
        // match last item, reset cursorVar to head
UNCOV
1171
        cursorVar = -1;
×
1172
      } else {
1173
        cursorVar = i;
×
1174
      }
1175

UNCOV
1176
      return taosStrdup(item->word);
×
1177
    }
1178

1179
    // check end item
UNCOV
1180
    if (item->next == NULL) {
×
1181
      // if cursorVar > var list count, return last and reset cursorVar
UNCOV
1182
      cursorVar = -1;
×
1183

UNCOV
1184
      return taosStrdup(item->word);
×
1185
    }
1186

1187
    // move next
1188
    item = item->next;
×
UNCOV
1189
    i++;
×
1190
  }
1191

1192
  return NULL;
×
1193
}
1194

1195
// search pre word from tire tree, return value must free by caller
UNCOV
1196
char* tireSearchWord(int type, char* pre) {
×
UNCOV
1197
  if (type == WT_TEXT) {
×
UNCOV
1198
    return NULL;
×
1199
  }
1200

1201
  if (type > WT_FROM_DB_MAX) {
×
1202
    // NOT FROM DB , tires[type] alwary not null
UNCOV
1203
    STire* tire = tires[type];
×
1204
    if (tire == NULL) return NULL;
×
UNCOV
1205
    return matchNextPrefix(tire, pre);
×
1206
  }
1207

UNCOV
1208
  if (updateTireValue(type, true)) {
×
UNCOV
1209
    return NULL;
×
1210
  }
1211

1212
  // can obtain var names from local
1213
  STire* tire = getAutoPtr(type);
×
1214
  if (tire == NULL) {
×
UNCOV
1215
    return NULL;
×
1216
  }
1217

1218
  char* str = matchNextPrefix(tire, pre);
×
1219
  // used finish, put back pointer to autoptr array
1220
  putBackAutoPtr(type, tire);
×
1221

UNCOV
1222
  return str;
×
1223
}
1224

1225
// match var word, word1 is pattern , word2 is input from shell
UNCOV
1226
bool matchVarWord(SWord* word1, SWord* word2) {
×
1227
  // search input word from tire tree
UNCOV
1228
  char pre[512];
×
1229
  memcpy(pre, word2->word, word2->len);
×
UNCOV
1230
  pre[word2->len] = 0;
×
1231

UNCOV
1232
  char* str = NULL;
×
UNCOV
1233
  if (word1->type == WT_VAR_ALLTABLE) {
×
1234
    // ALL_TABLE
1235
    str = tireSearchWord(WT_VAR_STABLE, pre);
×
1236
    if (str == NULL) {
×
UNCOV
1237
      str = tireSearchWord(WT_VAR_TABLE, pre);
×
UNCOV
1238
      if (str == NULL) return false;
×
1239
    }
1240
  } else {
1241
    // OTHER
UNCOV
1242
    str = tireSearchWord(word1->type, pre);
×
1243
    if (str == NULL) {
×
1244
      // not found or word1->type variable list not obtain from server, return not match
1245
      return false;
×
1246
    }
1247
  }
1248

1249
  // free previous malloc
1250
  if (word1->free && word1->word) {
×
1251
    taosMemoryFree(word1->word);
×
1252
  }
1253

1254
  // save
1255
  word1->word = str;
×
1256
  word1->len = strlen(str);
×
UNCOV
1257
  word1->free = true;  // need free
×
1258

UNCOV
1259
  return true;
×
1260
}
1261

1262
//
1263
//  -------------------  match words --------------------------
1264
//
1265

1266
// compare command cmdPattern come from shellCommands , cmdInput come from user input
1267
int32_t compareCommand(SWords* cmdPattern, SWords* cmdInput) {
×
UNCOV
1268
  SWord* wordPattern = cmdPattern->head;
×
1269
  SWord* wordInput = cmdInput->head;
×
1270

UNCOV
1271
  if (wordPattern == NULL || wordInput == NULL) {
×
UNCOV
1272
    return -1;
×
1273
  }
1274

1275
  for (int32_t i = 0; i < cmdPattern->count; i++) {
×
1276
    if (wordPattern->type == WT_TEXT) {
×
1277
      // WT_TEXT match
UNCOV
1278
      if (wordPattern->len == wordInput->len) {
×
1279
        if (strncasecmp(wordPattern->word, wordInput->word, wordPattern->len) != 0) return -1;
×
1280
      } else if (wordPattern->len < wordInput->len) {
×
UNCOV
1281
        return -1;
×
1282
      } else {
1283
        // wordPattern->len > wordInput->len
1284
        if (strncasecmp(wordPattern->word, wordInput->word, wordInput->len) == 0) {
×
1285
          if (i + 1 == cmdInput->count) {
×
1286
            // last word return match
UNCOV
1287
            cmdPattern->matchIndex = i;
×
UNCOV
1288
            cmdPattern->matchLen = wordInput->len;
×
1289
            return i;
×
1290
          } else {
UNCOV
1291
            return -1;
×
1292
          }
1293
        } else {
UNCOV
1294
          return -1;
×
1295
        }
1296
      }
1297
    } else {
1298
      // WT_VAR auto match any one word
UNCOV
1299
      if (wordInput->next == NULL) {  // input words last one
×
UNCOV
1300
        if (matchVarWord(wordPattern, wordInput)) {
×
UNCOV
1301
          cmdPattern->matchIndex = i;
×
1302
          cmdPattern->matchLen = wordInput->len;
×
1303
          varMode = true;
×
1304
          return i;
×
1305
        }
1306
        return -1;
×
1307
      }
1308
    }
1309

1310
    // move next
UNCOV
1311
    wordPattern = wordPattern->next;
×
UNCOV
1312
    wordInput = wordInput->next;
×
UNCOV
1313
    if (wordPattern == NULL || wordInput == NULL) {
×
1314
      return -1;
×
1315
    }
1316
  }
1317

1318
  return -1;
×
1319
}
1320

1321
// match command
1322
SWords* matchCommand(SWords* input, bool continueSearch) {
×
1323
  int32_t count = SHELL_COMMAND_COUNT();
×
UNCOV
1324
  for (int32_t i = 0; i < count; i++) {
×
1325
    SWords* shellCommand = shellCommands + i;
×
1326
    if (continueSearch && lastMatchIndex != -1 && i <= lastMatchIndex) {
×
1327
      // new match must greater than lastMatchIndex
1328
      if (varMode && i == lastMatchIndex) {
×
1329
        // do nothing, var match on lastMatchIndex
1330
      } else {
1331
        continue;
×
1332
      }
1333
    }
1334

1335
    // command is large
1336
    if (input->count > shellCommand->count) {
×
UNCOV
1337
      continue;
×
1338
    }
1339

1340
    // compare
1341
    int32_t index = compareCommand(shellCommand, input);
×
UNCOV
1342
    if (index != -1) {
×
UNCOV
1343
      if (firstMatchIndex == -1) firstMatchIndex = i;
×
UNCOV
1344
      curMatchIndex = i;
×
UNCOV
1345
      return &shellCommands[i];
×
1346
    }
1347
  }
1348

1349
  // not match
1350
  return NULL;
×
1351
}
1352

1353
//
1354
//  -------------------  print screen --------------------------
1355
//
1356

1357
// delete char count
1358
void deleteCount(SShellCmd* cmd, int count) {
×
1359
  int size = 0;
×
1360
  int width = 0;
×
1361
  int prompt_size = 6;
×
UNCOV
1362
  shellClearScreen(cmd->endOffset + prompt_size, cmd->screenOffset + prompt_size);
×
1363

1364
  // loop delete
1365
  while (--count >= 0 && cmd->cursorOffset > 0) {
×
UNCOV
1366
    shellGetPrevCharSize(cmd->command, cmd->cursorOffset, &size, &width);
×
UNCOV
1367
    memmove(cmd->command + cmd->cursorOffset - size, cmd->command + cmd->cursorOffset,
×
UNCOV
1368
            cmd->commandSize - cmd->cursorOffset);
×
1369
    cmd->commandSize -= size;
×
1370
    cmd->cursorOffset -= size;
×
1371
    cmd->screenOffset -= width;
×
1372
    cmd->endOffset -= width;
×
1373
  }
UNCOV
1374
}
×
1375

1376
// show screen
UNCOV
1377
void printScreen(TAOS* con, SShellCmd* cmd, SWords* match) {
×
1378
  // modify SShellCmd
UNCOV
1379
  if (firstMatchIndex == -1 || curMatchIndex == -1) {
×
1380
    // no match
UNCOV
1381
    return;
×
1382
  }
1383

1384
  // first tab press
UNCOV
1385
  const char* str = NULL;
×
UNCOV
1386
  int         strLen = 0;
×
1387

1388
  SWord* word = MATCH_WORD(match);
×
1389
  if (firstMatchIndex == curMatchIndex && lastWordBytes == -1) {
×
1390
    // first press tab
1391
    str = word->word + match->matchLen;
×
1392
    strLen = word->len - match->matchLen;
×
UNCOV
1393
    lastMatchIndex = firstMatchIndex;
×
UNCOV
1394
    lastWordBytes = word->len;
×
1395
  } else {
UNCOV
1396
    if (lastWordBytes == -1) return;
×
1397
    deleteCount(cmd, lastWordBytes);
×
UNCOV
1398
    str = word->word;
×
UNCOV
1399
    strLen = word->len;
×
1400
    // set current to last
UNCOV
1401
    lastMatchIndex = curMatchIndex;
×
UNCOV
1402
    lastWordBytes = word->len;
×
1403
  }
1404

1405
  if (word->end && str[strLen - 1] != ';') {
×
1406
    // append end ';'
1407
    char* p = taosMemoryCalloc(strLen + 8, 1);
×
1408
    if (p) {
×
1409
      tstrncpy(p, str, strLen + 1);
×
UNCOV
1410
      tstrncpy(p + strLen, ";", 1 + 1);
×
UNCOV
1411
      lastWordBytes += 1;
×
1412
      shellInsertStr(cmd, (char*)p, strLen + 1);
×
1413
      taosMemoryFree(p);
×
1414
    } else {
1415
      shellInsertStr(cmd, (char*)str, strLen);
×
1416
    }
1417
  } else {
1418
    // insert new
1419
    shellInsertStr(cmd, (char*)str, strLen);
×
1420
  }
1421
}
1422

1423
// main key press tab , matched return true else false
1424
bool firstMatchCommand(TAOS* con, SShellCmd* cmd) {
×
UNCOV
1425
  if (con == NULL || cmd == NULL) return false;
×
1426
  // parse command
UNCOV
1427
  SWords* input = (SWords*)taosMemoryMalloc(sizeof(SWords));
×
1428
  memset(input, 0, sizeof(SWords));
×
UNCOV
1429
  input->source = cmd->command;
×
UNCOV
1430
  input->source_len = cmd->commandSize;
×
UNCOV
1431
  parseCommand(input, false);
×
1432

1433
  // if have many , default match first, if press tab again , switch to next
UNCOV
1434
  curMatchIndex = -1;
×
1435
  lastMatchIndex = -1;
×
1436
  SWords* match = matchCommand(input, true);
×
UNCOV
1437
  if (match == NULL) {
×
1438
    // not match , nothing to do
1439
    freeCommand(input);
×
1440
    taosMemoryFree(input);
×
1441
    return false;
×
1442
  }
1443

1444
  // print to screen
1445
  printScreen(con, cmd, match);
×
1446
#ifdef WINDOWS
1447
  printf("\r");
1448
  shellShowOnScreen(cmd);
1449
#endif
UNCOV
1450
  freeCommand(input);
×
UNCOV
1451
  taosMemoryFree(input);
×
1452
  return true;
×
1453
}
1454

1455
// create input source
1456
void createInputFromFirst(SWords* input, SWords* firstMatch) {
×
1457
  //
1458
  // if next pressTabKey , input context come from firstMatch, set matched length with source_len
1459
  //
1460
  input->source = (char*)taosMemoryMalloc(1024);
×
UNCOV
1461
  memset((void*)input->source, 0, 1024);
×
1462

UNCOV
1463
  SWord* word = firstMatch->head;
×
1464

1465
  // source_len = full match word->len + half match with firstMatch->matchLen
1466
  for (int i = 0; i < firstMatch->matchIndex && word; i++) {
×
1467
    // combine source from each word
UNCOV
1468
    strncpy(input->source + input->source_len, word->word, word->len);
×
UNCOV
1469
    strcat(input->source, " ");          // append blank space
×
UNCOV
1470
    input->source_len += word->len + 1;  // 1 is blank length
×
1471
    // move next
1472
    word = word->next;
×
1473
  }
1474
  // appand half matched word for last
1475
  if (word) {
×
1476
    strncpy(input->source + input->source_len, word->word, firstMatch->matchLen);
×
1477
    input->source_len += firstMatch->matchLen;
×
1478
  }
UNCOV
1479
}
×
1480

1481
// user press Tabkey again is named next , matched return true else false
1482
bool nextMatchCommand(TAOS* con, SShellCmd* cmd, SWords* firstMatch) {
×
1483
  if (firstMatch == NULL || firstMatch->head == NULL) {
×
1484
    return false;
×
1485
  }
1486
  SWords* input = (SWords*)taosMemoryMalloc(sizeof(SWords));
×
1487
  memset(input, 0, sizeof(SWords));
×
1488

1489
  // create input from firstMatch
UNCOV
1490
  createInputFromFirst(input, firstMatch);
×
1491

1492
  // parse input
UNCOV
1493
  parseCommand(input, false);
×
1494

1495
  // if have many , default match first, if press tab again , switch to next
UNCOV
1496
  SWords* match = matchCommand(input, true);
×
1497
  if (match == NULL) {
×
1498
    // if not match , reset all index
1499
    firstMatchIndex = -1;
×
UNCOV
1500
    curMatchIndex = -1;
×
UNCOV
1501
    match = matchCommand(input, false);
×
UNCOV
1502
    if (match == NULL) {
×
1503
      freeCommand(input);
×
UNCOV
1504
      if (input->source) taosMemoryFree(input->source);
×
UNCOV
1505
      taosMemoryFree(input);
×
UNCOV
1506
      return false;
×
1507
    }
1508
  }
1509

1510
  // print to screen
UNCOV
1511
  printScreen(con, cmd, match);
×
1512
#ifdef WINDOWS
1513
  printf("\r");
1514
  shellShowOnScreen(cmd);
1515
#endif
1516

1517
  // free
UNCOV
1518
  freeCommand(input);
×
1519
  if (input->source) {
×
UNCOV
1520
    taosMemoryFree(input->source);
×
UNCOV
1521
    input->source = NULL;
×
1522
  }
1523
  taosMemoryFree(input);
×
1524

UNCOV
1525
  return true;
×
1526
}
1527

1528
// fill with type
1529
bool fillWithType(TAOS* con, SShellCmd* cmd, char* pre, int type) {
×
1530
  // get type
1531
  STire* tire = tires[type];
×
UNCOV
1532
  char*  str = matchNextPrefix(tire, pre);
×
1533
  if (str == NULL) {
×
1534
    return false;
×
1535
  }
1536

1537
  // need insert part string
UNCOV
1538
  char* part = str + strlen(pre);
×
1539

1540
  // show
UNCOV
1541
  int count = strlen(part);
×
UNCOV
1542
  shellInsertStr(cmd, part, count);
×
1543
  cntDel = count;  // next press tab delete current append count
×
1544

UNCOV
1545
  taosMemoryFree(str);
×
1546
  return true;
×
1547
}
1548

1549
// fill with type
1550
bool fillTableName(TAOS* con, SShellCmd* cmd, char* pre) {
×
1551
  // search stable and table
1552
  char* str = tireSearchWord(WT_VAR_STABLE, pre);
×
1553
  if (str == NULL) {
×
UNCOV
1554
    str = tireSearchWord(WT_VAR_TABLE, pre);
×
UNCOV
1555
    if (str == NULL) return false;
×
1556
  }
1557

1558
  // need insert part string
UNCOV
1559
  char* part = str + strlen(pre);
×
1560

1561
  // delete autofill count last append
UNCOV
1562
  if (cntDel > 0) {
×
UNCOV
1563
    deleteCount(cmd, cntDel);
×
UNCOV
1564
    cntDel = 0;
×
1565
  }
1566

1567
  // show
1568
  int count = strlen(part);
×
UNCOV
1569
  shellInsertStr(cmd, part, count);
×
1570
  cntDel = count;  // next press tab delete current append count
×
1571

1572
  taosMemoryFree(str);
×
UNCOV
1573
  return true;
×
1574
}
1575

1576
//
1577
// find last word from sql select clause
1578
//  example :
1579
//  1 select cou -> press tab  select count(
1580
//  2 select count(*),su -> select count(*), sum(
1581
//  3 select count(*), su -> select count(*), sum(
1582
//
UNCOV
1583
char* lastWord(char* p) {
×
1584
  // get near from end revert find ' ' and ','
1585
  char* p1 = strrchr(p, ' ');
×
UNCOV
1586
  char* p2 = strrchr(p, ',');
×
1587

1588
  if (p1 && p2) {
×
1589
    return p1 > p2 ? p1 + 1 : p2 + 1;
×
1590
  } else if (p1) {
×
UNCOV
1591
    return p1 + 1;
×
1592
  } else if (p2) {
×
1593
    return p2 + 1;
×
1594
  } else {
UNCOV
1595
    return p;
×
1596
  }
1597
}
1598

1599
bool fieldsInputEnd(char* sql) {
×
1600
  // not in '()'
1601
  char* p1 = strrchr(sql, '(');
×
1602
  char* p2 = strrchr(sql, ')');
×
UNCOV
1603
  if (p1 && p2 == NULL) {
×
1604
    // like select count( '  '
UNCOV
1605
    return false;
×
1606
  } else if (p1 && p2 && p1 > p2) {
×
1607
    // like select sum(age), count( ' '
UNCOV
1608
    return false;
×
1609
  }
1610

1611
  // not in ','
UNCOV
1612
  char* p3 = strrchr(sql, ',');
×
UNCOV
1613
  char* p = p3;
×
1614
  // like select ts, age,'    '
1615
  if (p) {
×
1616
    ++p;
×
1617
    bool  allBlank = true;  // after last ','  all char is blank
×
UNCOV
1618
    int   cnt = 0;          // blank count , like '    ' as one blank
×
1619
    char* plast = NULL;     // last blank position
×
1620
    while (*p) {
×
UNCOV
1621
      if (*p == ' ') {
×
UNCOV
1622
        plast = p;
×
UNCOV
1623
        cnt++;
×
1624
      } else {
UNCOV
1625
        allBlank = false;
×
1626
      }
UNCOV
1627
      ++p;
×
1628
    }
1629

1630
    // any one word is not blank
UNCOV
1631
    if (allBlank) {
×
1632
      return false;
×
1633
    }
1634

1635
    // like 'select count(*),sum(age) fr' need return true
1636
    if (plast && plast > p3 && p2 > p1 && plast > p2 && p1 > p3) {
×
1637
      return true;
×
1638
    }
1639

1640
    // if last char not ' ', then not end field, like 'select count(*), su' can fill sum(
UNCOV
1641
    if (sql[strlen(sql) - 1] != ' ' && cnt <= 1) {
×
1642
      return false;
×
1643
    }
1644
  }
1645

1646
  char* p4 = strrchr(sql, ' ');
×
UNCOV
1647
  if (p4 == NULL) {
×
1648
    // only one word
1649
    return false;
×
1650
  }
1651

1652
  return true;
×
1653
}
1654

1655
// need insert from
UNCOV
1656
bool needInsertFrom(char* sql, int len) {
×
1657
  // last is blank
UNCOV
1658
  if (sql[len - 1] != ' ') {
×
1659
    // insert from keyword
1660
    return false;
×
1661
  }
1662

1663
  //  select fields input is end
1664
  if (!fieldsInputEnd(sql)) {
×
1665
    return false;
×
1666
  }
1667

1668
  // can insert from keyword
1669
  return true;
×
1670
}
1671

1672
// p is string following select keyword
UNCOV
1673
bool appendAfterSelect(TAOS* con, SShellCmd* cmd, char* sql, int32_t len) {
×
1674
  char* p = taosStrndup(sql, len);
×
1675

1676
  // union all
1677
  char* p1;
1678
  do {
1679
    p1 = strstr(p, UNION_ALL);
×
UNCOV
1680
    if (p1) {
×
UNCOV
1681
      p = p1 + strlen(UNION_ALL);
×
1682
    }
1683
  } while (p1);
×
1684

UNCOV
1685
  char* from = strstr(p, " from ");
×
1686
  // last word , maybe empty string or some letters of a string
UNCOV
1687
  char* last = lastWord(p);
×
1688
  bool  ret = false;
×
1689
  if (from == NULL) {
×
UNCOV
1690
    bool fieldEnd = fieldsInputEnd(p);
×
1691
    // check fields input end then insert from keyword
UNCOV
1692
    if (fieldEnd && p[len - 1] == ' ') {
×
1693
      shellInsertStr(cmd, "from", 4);
×
1694
      taosMemoryFree(p);
×
UNCOV
1695
      return true;
×
1696
    }
1697

1698
    // fill function
1699
    if (fieldEnd) {
×
1700
      // fields is end , need match keyword
UNCOV
1701
      ret = fillWithType(con, cmd, last, WT_VAR_KEYWORD);
×
1702
    } else {
1703
      ret = fillWithType(con, cmd, last, WT_VAR_FUNC);
×
1704
    }
1705

UNCOV
1706
    taosMemoryFree(p);
×
1707
    return ret;
×
1708
  }
1709

1710
  // have from
1711
  char* blank = strstr(from + 6, " ");
×
1712
  if (blank == NULL) {
×
1713
    // no table name, need fill
UNCOV
1714
    ret = fillTableName(con, cmd, last);
×
1715
  } else {
1716
    ret = fillWithType(con, cmd, last, WT_VAR_KEYWORD);
×
1717
  }
1718

UNCOV
1719
  taosMemoryFree(p);
×
1720
  return ret;
×
1721
}
1722

UNCOV
1723
int32_t searchAfterSelect(char* p, int32_t len) {
×
1724
  // select * from st;
UNCOV
1725
  if (strncasecmp(p, "select ", 7) == 0) {
×
1726
    // check nest query
1727
    char* p1 = p + 7;
×
1728
    while (1) {
×
UNCOV
1729
      char* p2 = strstr(p1, "select ");
×
1730
      if (p2 == NULL) break;
×
UNCOV
1731
      p1 = p2 + 7;
×
1732
    }
1733

1734
    return p1 - p;
×
1735
  }
1736

1737
  // explain as select * from st;
UNCOV
1738
  if (strncasecmp(p, "explain select ", 15) == 0) {
×
1739
    return 15;
×
1740
  }
1741

1742
  char* as_pos_end = strstr(p, " as select ");
×
UNCOV
1743
  if (as_pos_end == NULL) return -1;
×
UNCOV
1744
  as_pos_end += 11;
×
1745

1746
  // create stream <stream_name> as select
UNCOV
1747
  if (strncasecmp(p, "create stream ", 14) == 0) {
×
1748
    return as_pos_end - p;
×
1749
    ;
1750
  }
1751

1752
  // create topic <topic_name> as select
1753
  if (strncasecmp(p, "create topic ", 13) == 0) {
×
1754
    return as_pos_end - p;
×
1755
  }
1756

UNCOV
1757
  return -1;
×
1758
}
1759

UNCOV
1760
bool matchSelectQuery(TAOS* con, SShellCmd* cmd) {
×
1761
  // if continue press Tab , delete bytes by previous autofill
UNCOV
1762
  if (cntDel > 0) {
×
1763
    deleteCount(cmd, cntDel);
×
UNCOV
1764
    cntDel = 0;
×
1765
  }
1766

1767
  // match select ...
UNCOV
1768
  int   len = cmd->commandSize;
×
UNCOV
1769
  char* p = cmd->command;
×
1770

1771
  // remove prefix blank
1772
  while (p[0] == ' ' && len > 0) {
×
UNCOV
1773
    p++;
×
1774
    len--;
×
1775
  }
1776

1777
  // special range
1778
  if (len < 7 || len > 512) {
×
UNCOV
1779
    return false;
×
1780
  }
1781

1782
  // search
UNCOV
1783
  char*   sql_cp = taosStrndup(p, len);
×
UNCOV
1784
  int32_t n = searchAfterSelect(sql_cp, len);
×
1785
  taosMemoryFree(sql_cp);
×
1786
  if (n == -1 || n > len) return false;
×
UNCOV
1787
  p += n;
×
UNCOV
1788
  len -= n;
×
1789

1790
  // append
1791
  return appendAfterSelect(con, cmd, p, len);
×
1792
}
1793

1794
// is fields option area
1795
bool fieldOptionsArea(char* p) {
×
UNCOV
1796
  char* p1 = strrchr(p, '(');
×
UNCOV
1797
  char* p2 = strrchr(p, ',');
×
UNCOV
1798
  if (p1 == NULL && p2 == NULL) {
×
UNCOV
1799
    return false;
×
1800
  }
1801

1802
  // find tags
UNCOV
1803
  if (strstr(p, " tags") != NULL) {
×
1804
    return false;
×
1805
  }
1806

1807
  if (p2 == NULL) {
×
1808
    // first field area
1809
    p2 = p1;
×
1810
  }
1811

1812
  // find blank count
UNCOV
1813
  int32_t cnt = 0;
×
UNCOV
1814
  while (p2) {
×
1815
    p2 = strchr(p2, ' ');
×
1816
    if (p2) {
×
1817
      // get prev char
UNCOV
1818
      char prec = *(p2 - 1);
×
1819
      if (prec != ',' && prec != '(') {
×
1820
        // blank if before comma, not calc count.  like st(ts timestamp,  age int + BLANK + TAB only two blank
1821
        cnt++;
×
1822
      }
1823

1824
      // continue blank is one blank
1825
      while (p2[1] != 0 && p2[1] == ' ') {
×
1826
        // move next if blank again
UNCOV
1827
        p2 += 1;
×
1828
      }
UNCOV
1829
      p2 += 1;
×
1830
    }
1831
  }
1832

1833
  // like  create table st(ts timestamp TAB-KEY or  st(ts timestamp , age int TAB-KEY
1834
  return cnt >= 2;
×
1835
}
1836

1837
// if is input create fields or tags area, return true
1838
bool isCreateFieldsArea(char* p) {
×
UNCOV
1839
  int32_t n = 0;  // count
×
UNCOV
1840
  char*  p1 = p;
×
UNCOV
1841
  while (*p1 != 0) {
×
1842
    switch (*p1) {
×
1843
      case '(':
×
1844
        ++n;
×
1845
        break;
×
1846
      case ')':
×
UNCOV
1847
        --n;
×
UNCOV
1848
        break;
×
UNCOV
1849
      default:
×
1850
        break;
×
1851
    }
1852
    // move next
UNCOV
1853
    ++p1;
×
1854
  }
1855

1856
  return n > 0;
×
1857
}
1858

UNCOV
1859
bool matchCreateTable(TAOS* con, SShellCmd* cmd) {
×
1860
  // if continue press Tab , delete bytes by previous autofill
1861
  if (cntDel > 0) {
×
1862
    deleteCount(cmd, cntDel);
×
1863
    cntDel = 0;
×
1864
  }
1865

1866
  // match select ...
UNCOV
1867
  int   len = cmd->commandSize;
×
1868
  char* p = cmd->command;
×
1869

1870
  // remove prefix blank
UNCOV
1871
  while (p[0] == ' ' && len > 0) {
×
1872
    p++;
×
UNCOV
1873
    len--;
×
1874
  }
1875

1876
  // special range
UNCOV
1877
  if (len < 7 || len > 1024) {
×
UNCOV
1878
    return false;
×
1879
  }
1880

1881
  // select and from
UNCOV
1882
  if (strncasecmp(p, "create table ", 13) != 0) {
×
1883
    // not select query clause
UNCOV
1884
    return false;
×
1885
  }
1886
  p += 13;
×
1887
  len -= 13;
×
1888

1889
  char* ps = taosStrndup(p, len);
×
1890
  bool  ret = false;
×
1891
  char* last = lastWord(ps);
×
1892

1893
  // check in create fields or tags input area
1894
  if (isCreateFieldsArea(ps)) {
×
1895
    if (fieldOptionsArea(ps)) {
×
1896
      // fill field options
1897
      ret = fillWithType(con, cmd, last, WT_VAR_FIELD_OPTIONS);
×
1898
    } else {
1899
      // fill field
1900
      ret = fillWithType(con, cmd, last, WT_VAR_DATATYPE);
×
1901
    }
1902
  }
1903

1904
  // tags
UNCOV
1905
  if (!ret) {
×
1906
    // find only one ')' , can insert tags
UNCOV
1907
    char* p1 = strchr(ps, ')');
×
1908
    if (p1) {
×
1909
      if (strstr(p1 + 1, "tags") == NULL) {
×
1910
        // can insert tags keyword
UNCOV
1911
        ret = fillWithType(con, cmd, last, WT_VAR_KEYTAGS);
×
1912
      }
1913
    }
1914
  }
1915

1916
  // tb options
UNCOV
1917
  if (!ret) {
×
1918
    // find like create table st (...) tags(..)  <here is fill tb option area>
1919
    char* p1 = strchr(ps, ')');  // first ')' end
×
1920
    if (p1) {
×
UNCOV
1921
      if (strchr(p1 + 1, ')')) {  // second ')' end
×
1922
        // here is tb options area, can insert option
UNCOV
1923
        ret = fillWithType(con, cmd, last, WT_VAR_TBOPTION);
×
1924
      }
1925
    }
1926
  }
1927

UNCOV
1928
  taosMemoryFree(ps);
×
1929
  return ret;
×
1930
}
1931

UNCOV
1932
bool matchOther(TAOS* con, SShellCmd* cmd) {
×
1933
  int   len = cmd->commandSize;
×
1934
  char* p = cmd->command;
×
1935

1936
  // '\\'
1937
  if (p[len - 1] == '\\') {
×
1938
    // append '\G'
UNCOV
1939
    char a[] = "G;";
×
UNCOV
1940
    shellInsertStr(cmd, a, 2);
×
1941
    return true;
×
1942
  }
1943

1944
  // too small
UNCOV
1945
  if (len < 8) return false;
×
1946

1947
  // like 'from ( '
UNCOV
1948
  char* sql = taosStrndup(p, len);
×
UNCOV
1949
  char* last = lastWord(sql);
×
1950

UNCOV
1951
  if (strcmp(last, "from(") == 0) {
×
1952
    fillWithType(con, cmd, "", WT_VAR_KEYSELECT);
×
UNCOV
1953
    taosMemoryFree(sql);
×
1954
    return true;
×
1955
  }
1956
  if (strncmp(last, "(", 1) == 0) {
×
UNCOV
1957
    last += 1;
×
1958
  }
1959

UNCOV
1960
  char* from = strstr(sql, " from");
×
1961
  // find last ' from'
UNCOV
1962
  while (from) {
×
UNCOV
1963
    char* p1 = strstr(from + 5, " from");
×
1964
    if (p1 == NULL) break;
×
UNCOV
1965
    from = p1;
×
1966
  }
1967

1968
  if (from) {
×
1969
    // find next is '('
1970
    char* p2 = from + 5;
×
UNCOV
1971
    bool  found = false;   // found 'from ... ( ...'  ... is any count of blank
×
UNCOV
1972
    bool  found1 = false;  // found '('
×
1973
    while (1) {
UNCOV
1974
      if (p2 == last || *p2 == '\0') {
×
1975
        // last word or string end
1976
        if (found1) {
×
UNCOV
1977
          found = true;
×
1978
        }
1979
        break;
×
1980
      } else if (*p2 == '(') {
×
1981
        found1 = true;
×
UNCOV
1982
      } else if (*p2 == ' ') {
×
1983
        // do nothing
1984
      } else {
1985
        // have any other char
1986
        break;
×
1987
      }
1988

1989
      // move next
UNCOV
1990
      p2++;
×
1991
    }
1992

UNCOV
1993
    if (found) {
×
UNCOV
1994
      fillWithType(con, cmd, last, WT_VAR_KEYSELECT);
×
1995
      taosMemoryFree(sql);
×
1996
      return true;
×
1997
    }
1998
  }
1999

2000
  // INSERT
2001

UNCOV
2002
  taosMemoryFree(sql);
×
2003

2004
  return false;
×
2005
}
2006

2007
// last match if nothing matched
UNCOV
2008
bool matchEnd(TAOS* con, SShellCmd* cmd) {
×
2009
  // str dump
2010
  bool  ret = false;
×
2011
  char* ps = taosStrndup(cmd->command, cmd->commandSize);
×
2012
  char* last = lastWord(ps);
×
UNCOV
2013
  char* elast = strrchr(last, '.');  // find end last
×
UNCOV
2014
  if (elast) {
×
2015
    last = elast + 1;
×
2016
  }
2017

2018
  // less one char can match
2019
  if (strlen(last) == 0) {
×
UNCOV
2020
    goto _return;
×
2021
  }
UNCOV
2022
  if (strcmp(last, " ") == 0) {
×
2023
    goto _return;
×
2024
  }
2025

2026
  // match database
2027
  if (elast == NULL) {
×
2028
    // dot need not completed with dbname
2029
    if (fillWithType(con, cmd, last, WT_VAR_DBNAME)) {
×
UNCOV
2030
      ret = true;
×
UNCOV
2031
      goto _return;
×
2032
    }
2033
  }
2034

UNCOV
2035
  if (fillWithType(con, cmd, last, WT_VAR_SYSTABLE)) {
×
UNCOV
2036
    ret = true;
×
2037
    goto _return;
×
2038
  }
2039

2040
  // global keys
2041
  if (fillWithType(con, cmd, last, WT_VAR_GLOBALKEYS)) {
×
2042
    ret = true;
×
2043
    goto _return;
×
2044
  }
2045

2046

UNCOV
2047
_return:
×
UNCOV
2048
  taosMemoryFree(ps);
×
2049
  return ret;
×
2050
}
2051

2052
// main key press tab
UNCOV
2053
void pressTabKey(SShellCmd* cmd) {
×
2054
#ifdef WINDOWS
2055
  return ;
2056
#endif
2057
  // check empty tab key
2058
  if (cmd->commandSize == 0) {
×
2059
    // have multi line tab key
2060
    if (cmd->bufferSize == 0) {
×
2061
      showHelp();
×
2062
    }
UNCOV
2063
    shellShowOnScreen(cmd);
×
UNCOV
2064
    return;
×
2065
  }
2066

2067
  // save connection to global
UNCOV
2068
  varCmd = cmd;
×
2069
  bool matched = false;
×
2070

2071
  // manual match like create table st( ...
UNCOV
2072
  matched = matchCreateTable(varCon, cmd);
×
UNCOV
2073
  if (matched) return;
×
2074

2075
  // shellCommands match
2076
  if (firstMatchIndex == -1) {
×
2077
    matched = firstMatchCommand(varCon, cmd);
×
2078
  } else {
UNCOV
2079
    matched = nextMatchCommand(varCon, cmd, &shellCommands[firstMatchIndex]);
×
2080
  }
UNCOV
2081
  if (matched) return;
×
2082

2083
  // NOT MATCHED ANYONE
2084
  // match other like '\G' ...
UNCOV
2085
  matched = matchOther(varCon, cmd);
×
UNCOV
2086
  if (matched) return;
×
2087

2088
  // manual match like select * from ...
2089
  matched = matchSelectQuery(varCon, cmd);
×
2090
  if (matched) return;
×
2091

2092
  // match end
UNCOV
2093
  matched = matchEnd(varCon, cmd);
×
2094

2095
  return;
×
2096
}
2097

2098
// press othr key
2099
void pressOtherKey(char c) {
13,483✔
2100
#ifdef WINDOWS
2101
  return ;
2102
#endif
2103

2104
  // reset global variant
2105
  firstMatchIndex = -1;
13,483✔
2106
  lastMatchIndex = -1;
13,483✔
2107
  curMatchIndex = -1;
13,483✔
2108
  lastWordBytes = -1;
13,483✔
2109

2110
  // var names
2111
  cursorVar = -1;
13,483✔
2112
  varMode = false;
13,483✔
2113
  waitAutoFill = false;
13,483✔
2114
  cntDel = 0;
13,483✔
2115

2116
  if (lastMatch) {
13,483✔
UNCOV
2117
    freeMatch(lastMatch);
×
UNCOV
2118
    lastMatch = NULL;
×
2119
  }
2120
}
13,483✔
2121

2122
// put name into name, return name length
2123
int getWordName(char* p, char* name, int nameLen) {
29,681✔
2124
  // remove prefix blank
2125
  while (*p == ' ') {
38,450✔
2126
    p++;
8,769✔
2127
  }
2128

2129
  // get databases name;
2130
  int i = 0;
29,681✔
2131
  while (p[i] != 0 && i < nameLen - 1) {
131,635✔
2132
    name[i] = p[i];
131,635✔
2133
    i++;
131,635✔
2134
    if (p[i] == ' ' || p[i] == ';' || p[i] == '(') {
131,635✔
2135
      // name end
2136
      break;
2137
    }
2138
  }
2139
  name[i] = 0;
29,681✔
2140

2141
  return i;
29,681✔
2142
}
2143

2144
// deal use db, if have  'use' return true
2145
bool dealUseDB(char* sql) {
1,281,250✔
2146
  // check use keyword
2147
  if (strncasecmp(sql, "use ", 4) != 0) {
1,281,250✔
2148
    return false;
1,270,841✔
2149
  }
2150

2151
  char  db[256];
10,409✔
2152
  char* p = sql + 4;
10,409✔
2153
  if (getWordName(p, db, sizeof(db)) == 0) {
10,409✔
2154
    // no name , return
UNCOV
2155
    return true;
×
2156
  }
2157

2158
  //  dbName is previous use open db name
2159
  if (strcasecmp(db, dbName) == 0) {
10,409✔
2160
    // same , no need switch
UNCOV
2161
    return true;
×
2162
  }
2163

2164
  // switch new db
2165
  taosThreadMutexLock(&tiresMutex);
10,409✔
2166
  // STABLE set null
2167
  STire* tire = tires[WT_VAR_STABLE];
10,409✔
2168
  tires[WT_VAR_STABLE] = NULL;
10,409✔
2169
  if (tire) {
10,409✔
UNCOV
2170
    freeTire(tire);
×
2171
  }
2172
  // TABLE set null
2173
  tire = tires[WT_VAR_TABLE];
10,409✔
2174
  tires[WT_VAR_TABLE] = NULL;
10,409✔
2175
  if (tire) {
10,409✔
UNCOV
2176
    freeTire(tire);
×
2177
  }
2178
  // save
2179
  strcpy(dbName, db);
10,409✔
2180
  taosThreadMutexUnlock(&tiresMutex);
10,409✔
2181

2182
  return true;
10,409✔
2183
}
2184

2185
// deal create, if have 'create' return true
2186
bool dealCreateCommand(char* sql) {
1,270,841✔
2187
  // check keyword
2188
  if (strncasecmp(sql, "create ", 7) != 0) {
1,270,841✔
2189
    return false;
1,262,908✔
2190
  }
2191

2192
  char  name[1024];
7,492✔
2193
  char* p = sql + 7;
7,933✔
2194
  if (getWordName(p, name, sizeof(name)) == 0) {
7,933✔
2195
    // no name , return
UNCOV
2196
    return true;
×
2197
  }
2198

2199
  int type = -1;
7,933✔
2200
  //  dbName is previous use open db name
2201
  if (strcasecmp(name, "database") == 0) {
7,933✔
2202
    type = WT_VAR_DBNAME;
2,611✔
2203
  } else if (strcasecmp(name, "table") == 0) {
5,322✔
2204
    if (strstr(sql, " tags") != NULL && strstr(sql, " using ") == NULL)
3,588✔
2205
      type = WT_VAR_STABLE;
1,032✔
2206
    else
2207
      type = WT_VAR_TABLE;
2,556✔
2208
  } else if (strcasecmp(name, "user") == 0) {
1,734✔
UNCOV
2209
    type = WT_VAR_USERNAME;
×
2210
  } else if (strcasecmp(name, "topic") == 0) {
1,734✔
UNCOV
2211
    type = WT_VAR_TOPIC;
×
2212
  } else if (strcasecmp(name, "stream") == 0) {
1,734✔
UNCOV
2213
    type = WT_VAR_STREAM;
×
2214
  } else {
2215
    // no match , return
2216
    return true;
1,734✔
2217
  }
2218

2219
  // move next
2220
  p += strlen(name);
6,199✔
2221

2222
  // get next word , that is table name
2223
  if (getWordName(p, name, sizeof(name)) == 0) {
6,199✔
2224
    // no name , return
UNCOV
2225
    return true;
×
2226
  }
2227

2228
  // switch new db
2229
  taosThreadMutexLock(&tiresMutex);
6,199✔
2230
  // STABLE set null
2231
  STire* tire = tires[type];
6,199✔
2232
  if (tire) {
6,199✔
2233
    insertWord(tire, name);
630✔
2234
  }
2235
  taosThreadMutexUnlock(&tiresMutex);
6,199✔
2236

2237
  return true;
6,199✔
2238
}
2239

2240
// deal create, if have 'drop' return true
2241
bool dealDropCommand(char* sql) {
1,262,908✔
2242
  // check keyword
2243
  if (strncasecmp(sql, "drop ", 5) != 0) {
1,262,908✔
2244
    return false;
1,260,338✔
2245
  }
2246

2247
  char  name[1024];
1,292✔
2248
  char* p = sql + 5;
2,570✔
2249
  if (getWordName(p, name, sizeof(name)) == 0) {
2,570✔
2250
    // no name , return
UNCOV
2251
    return true;
×
2252
  }
2253

2254
  int type = -1;
2,570✔
2255
  //  dbName is previous use open db name
2256
  if (strcasecmp(name, "database") == 0) {
2,570✔
2257
    type = WT_VAR_DBNAME;
2,570✔
2258
  } else if (strcasecmp(name, "table") == 0) {
×
UNCOV
2259
    type = WT_VAR_ALLTABLE;
×
2260
  } else if (strcasecmp(name, "dnode") == 0) {
×
UNCOV
2261
    type = WT_VAR_DNODEID;
×
UNCOV
2262
  } else if (strcasecmp(name, "user") == 0) {
×
UNCOV
2263
    type = WT_VAR_USERNAME;
×
UNCOV
2264
  } else if (strcasecmp(name, "topic") == 0) {
×
UNCOV
2265
    type = WT_VAR_TOPIC;
×
UNCOV
2266
  } else if (strcasecmp(name, "stream") == 0) {
×
UNCOV
2267
    type = WT_VAR_STREAM;
×
2268
  } else {
2269
    // no match , return
UNCOV
2270
    return true;
×
2271
  }
2272

2273
  // move next
2274
  p += strlen(name);
2,570✔
2275

2276
  // get next word , that is table name
2277
  if (getWordName(p, name, sizeof(name)) == 0) {
2,570✔
2278
    // no name , return
UNCOV
2279
    return true;
×
2280
  }
2281

2282
  // switch new db
2283
  taosThreadMutexLock(&tiresMutex);
2,570✔
2284
  // STABLE set null
2285
  if (type == WT_VAR_ALLTABLE) {
2,570✔
UNCOV
2286
    bool del = false;
×
2287
    // del in stable
UNCOV
2288
    STire* tire = tires[WT_VAR_STABLE];
×
UNCOV
2289
    if (tire) del = deleteWord(tire, name);
×
2290
    // del in table
UNCOV
2291
    if (!del) {
×
UNCOV
2292
      tire = tires[WT_VAR_TABLE];
×
UNCOV
2293
      if (tire) del = deleteWord(tire, name);
×
2294
    }
2295
  } else {
2296
    // OTHER TYPE
2297
    STire* tire = tires[type];
2,570✔
2298
    if (tire) deleteWord(tire, name);
2,570✔
2299
  }
2300
  taosThreadMutexUnlock(&tiresMutex);
2,570✔
2301

2302
  return true;
2,570✔
2303
}
2304

2305
// callback autotab module after shell sql execute
2306
void callbackAutoTab(char* sqlstr, TAOS* pSql, bool usedb) {
1,281,250✔
2307
  char* sql = sqlstr;
1,281,250✔
2308
  // remove prefix blank
2309
  while (*sql == ' ') {
1,282,072✔
2310
    sql++;
822✔
2311
  }
2312

2313
  if (dealUseDB(sql)) {
1,281,250✔
2314
    // change to new db
2315
    if (!varRunOnce) updateTireValue(WT_VAR_STABLE, false);
10,409✔
2316
    return;
10,409✔
2317
  }
2318

2319
  // create command add name to autotab
2320
  if (dealCreateCommand(sql)) {
1,270,841✔
2321
    return;
7,933✔
2322
  }
2323

2324
  // drop command remove name from autotab
2325
  if (dealDropCommand(sql)) {
1,262,908✔
2326
    return;
2,570✔
2327
  }
2328

2329
  return;
1,260,338✔
2330
}
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