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

taosdata / TDengine / #4914

06 Jan 2026 01:30AM UTC coverage: 64.876% (-0.008%) from 64.884%
#4914

push

travis-ci

web-flow
merge: from main to 3.0 branch #34167

180 of 319 new or added lines in 14 files covered. (56.43%)

3475 existing lines in 124 files now uncovered.

194993 of 300563 relevant lines covered (64.88%)

116239151.85 hits per line

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

32.99
/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
#ifdef TD_ENTERPRISE
87
    {"balance vgroup ;", 0, 0, NULL},
88
    {"balance vgroup leader on <vgroup_id>", 0, 0, NULL},
89
    {"alter token <token_name> <token_opt> <anyword> ;", 0, 0, NULL},
90
    {"alter user <user_name> <alter_uopt> <anyword> <alter_uopt> <anyword> <alter_uopt> <anyword> <alter_uopt> <anyword> <alter_uopt> <anyword> <alter_uopt> <anyword>", 0, 0, NULL},
91
#else
92
   {"alter user <user_name> <user_actions> <anyword> ;", 0, 0, NULL},
93
#endif
94

95
    // 20
96
    {"create table <anyword> using <stb_name> tags(", 0, 0, NULL},
97
    {"create vtable <anyword> using <stb_name> tags(", 0, 0, NULL},
98
    {"create database <anyword> <db_options> <anyword> <db_options> <anyword> <db_options> <anyword> <db_options> "
99
     "<anyword> <db_options> <anyword> <db_options> <anyword> <db_options> <anyword> <db_options> <anyword> "
100
     "<db_options> <anyword> <db_options> <anyword> ;", 0, 0, NULL},
101
    {"create dnode <anyword>", 0, 0, NULL},
102
    {"create index <anyword> on <stb_name> ()", 0, 0, NULL},
103
    {"create mnode on dnode <dnode_id>;", 0, 0, NULL},
104
    {"create qnode on dnode <dnode_id>;", 0, 0, NULL},
105
    {"create bnode on dnode <dnode_id>;", 0, 0, NULL},
106
    {"create anode <anyword>", 0, 0, NULL},
107
    {"create stream <anyword> into <anyword> as select", 0, 0, NULL},  // 26 append sub sql
108
    {"create topic <anyword> as select", 0, 0, NULL},                  // 27 append sub sql
109
    {"create rsma <anyword> on <all_table> function interval <anyword>", 0, 0, NULL},
110
    {"create tsma <anyword> on <all_table> function", 0, 0, NULL},
111
    {"create recursive tsma <anyword> on <tsma_name> interval(", 0, 0, NULL},
112
    {"create function <anyword> as <anyword> outputtype <data_types> language <udf_language>;", 0, 0, NULL},
113
    {"create or replace <anyword> as <anyword> outputtype <data_types> language <udf_language>;", 0, 0, NULL},
114
    {"create aggregate function  <anyword> as <anyword> outputtype <data_types> bufsize <anyword> language <udf_language>;", 0, 0, NULL},
115
    {"create or replace aggregate function  <anyword> as <anyword> outputtype <data_types> bufsize <anyword> language <udf_language>;", 0, 0, NULL},
116
#ifdef TD_ENTERPRISE    
117
    {"create view <anyword> as select", 0, 0, NULL},
118
    {"compact database <db_name>", 0, 0, NULL},
119
    {"compact vgroups in( <anyword>", 0, 0, NULL},
120
    {"create mount <mount_name> on dnode <dnode_id> from <path>;", 0, 0, NULL},
121
    {"create token <anyword> from user <user_name> <token_opt> <anyword> <token_opt> <anyword> <token_opt> <anyword> <token_opt> <anyword> ;", 0, 0, NULL},
122
    {"create totp_secret for user <user_name>;", 0, 0, NULL},
123
    {"create user <anyword> <create_uopt> <anyword> <create_uopt> <anyword> <create_uopt> <anyword> <create_uopt> <anyword> <create_uopt> <anyword> <create_uopt> <anyword>", 0, 0, NULL},
124
#else
125
    {"create user <anyword> pass <anyword> createdb 1;", 0, 0, NULL},
126
    {"create user <anyword> pass <anyword> createdb 0;", 0, 0, NULL},
127
    {"create user <anyword> pass <anyword> sysinfo 1;", 0, 0, NULL},
128
    {"create user <anyword> pass <anyword> sysinfo 0;", 0, 0, NULL},
129
#endif
130
    {"scan database <db_name>", 0, 0, NULL},
131
    {"desc <all_table>;", 0, 0, NULL},
132
    {"describe <all_table>;", 0, 0, NULL},
133
    {"delete from <all_table> where ", 0, 0, NULL},
134
    {"drop database <db_name>;", 0, 0, NULL},
135
    {"drop index <anyword>;", 0, 0, NULL},
136
    {"drop table <all_table>;", 0, 0, NULL},
137
    {"drop dnode <dnode_id>;", 0, 0, NULL},
138
    {"drop mnode on dnode <dnode_id>;", 0, 0, NULL},
139
    {"drop qnode on dnode <dnode_id>;", 0, 0, NULL},
140
    {"drop bnode on dnode <dnode_id>;", 0, 0, NULL},
141
    {"drop anode <anode_id>;", 0, 0, NULL},
142
    {"drop user <user_name>;", 0, 0, NULL},
143
    // 40
144
    {"drop function <udf_name>;", 0, 0, NULL},
145
    {"drop consumer group <anyword> on ", 0, 0, NULL},
146
    {"drop topic <topic_name>;", 0, 0, NULL},
147
    {"drop stream <stream_name>;", 0, 0, NULL},
148
    {"drop tsma <tsma_name>;", 0, 0, NULL},
149
    {"drop rsma <rsma_name>;", 0, 0, NULL},
150
    {"explain select ", 0, 0, NULL},  // 44 append sub sql
151
    {"flush database <db_name>;", 0, 0, NULL},
152
    {"help;", 0, 0, NULL},
153
    {"grant all on <anyword> to <user_name>;", 0, 0, NULL},
154
    {"grant read on <anyword> to <user_name>;", 0, 0, NULL},
155
    {"grant write on <anyword> to <user_name>;", 0, 0, NULL},
156
    {"kill connection <anyword>;", 0, 0, NULL},
157
    {"kill retention ", 0, 0, NULL},
158
    {"kill query ", 0, 0, NULL},
159
    {"kill transaction ", 0, 0, NULL},
160
#ifdef TD_ENTERPRISE
161
    {"merge vgroup <vgroup_id> <vgroup_id>;", 0, 0, NULL},
162
    {"drop token <token_name>;", 0, 0, NULL},
163
    {"drop totp_secret from user <user_name>;", 0, 0, NULL},
164
    {"drop mount <mount_name>;", 0, 0, NULL},
165
#endif
166
    {"pause stream <stream_name>;", 0, 0, NULL},
167
#ifdef TD_ENTERPRISE
168
    {"redistribute vgroup <vgroup_id> dnode <dnode_id>;", 0, 0, NULL},
169
#endif
170
    {"resume stream <stream_name>;", 0, 0, NULL},
171
    {"reset query cache;", 0, 0, NULL},
172
    {"restore dnode <dnode_id>;", 0, 0, NULL},
173
    {"restore vnode on dnode <dnode_id>;", 0, 0, NULL},
174
    {"restore mnode on dnode <dnode_id>;", 0, 0, NULL},
175
    {"restore qnode on dnode <dnode_id>;", 0, 0, NULL},
176
    {"revoke all on <anyword> from <user_name>;", 0, 0, NULL},
177
    {"revoke read on <anyword> from <user_name>;", 0, 0, NULL},
178
    {"revoke write on <anyword> from <user_name>;", 0, 0, NULL},
179
    {"rollup database <db_name>;", 0, 0, NULL},
180
    {"rollup database <db_name> vgroups in( <anyword>", 0, 0, NULL},
181
    {"select * from <all_table>", 0, 0, NULL},
182
    {"select client_version();", 0, 0, NULL},
183
    // 60
184
    {"select current_user();", 0, 0, NULL},
185
    {"select database();", 0, 0, NULL},
186
    {"select server_version();", 0, 0, NULL},
187
    {"select server_status();", 0, 0, NULL},
188
    {"select now();", 0, 0, NULL},
189
    {"select today();", 0, 0, NULL},
190
    {"select timezone();", 0, 0, NULL},
191
    {"set max_binary_display_width ", 0, 0, NULL},
192
    {"show apps;", 0, 0, NULL},
193
    {"show alive;", 0, 0, NULL},
194
    {"show anodes;", 0, 0, NULL},
195
    {"show anodes full;", 0, 0, NULL},
196
    {"show create database <db_name> \\G;", 0, 0, NULL},
197
    {"show create stable <stb_name> \\G;", 0, 0, NULL},
198
    {"show create table <tb_name> \\G;", 0, 0, NULL},
199
#ifdef TD_ENTERPRISE    
200
    {"show create view <all_table> \\G;", 0, 0, NULL},
201
    {"show compact", 0, 0, NULL},
202
    {"show compacts;", 0, 0, NULL},
203
    {"show tokens;", 0, 0, NULL},
204
#endif
205
    {"show connections;", 0, 0, NULL},
206
    {"show cluster;", 0, 0, NULL},
207
    {"show cluster alive;", 0, 0, NULL},
208
    {"show cluster machines;", 0, 0, NULL},
209
    {"show databases;", 0, 0, NULL},
210
    {"show dnodes;", 0, 0, NULL},
211
    {"show dnode <dnode_id> variables;", 0, 0, NULL},
212
    {"show disk_info;", 0, 0, NULL},
213
    {"show functions;", 0, 0, NULL},
214
    {"show licences;", 0, 0, NULL},
215
    {"show mnodes;", 0, 0, NULL},
216
    {"show queries;", 0, 0, NULL},
217
    // 80
218
    {"show query <anyword> ;", 0, 0, NULL},
219
    {"show qnodes;", 0, 0, NULL},
220
    {"show bnodes;", 0, 0, NULL},
221
    {"show retentions;", 0, 0, NULL},
222
    {"show retention <retention_id>;", 0, 0, NULL},
223
    {"show stables;", 0, 0, NULL},
224
    {"show stables like ", 0, 0, NULL},
225
    {"show streams;", 0, 0, NULL},
226
    {"show scores;", 0, 0, NULL},
227
    {"show snodes;", 0, 0, NULL},
228
    {"show subscriptions;", 0, 0, NULL},
229
    {"show scans;", 0, 0, NULL},
230
    {"show scan <scan_id>;", 0, 0, NULL},
231
    {"show tables;", 0, 0, NULL},
232
    {"show tables like", 0, 0, NULL},
233
    {"show table distributed <all_table>;", 0, 0, NULL},
234
    {"show tags from <tb_name>;", 0, 0, NULL},
235
    {"show table tags from <all_table>;", 0, 0, NULL},
236
    {"show topics;", 0, 0, NULL},
237
    {"show transactions;", 0, 0, NULL},
238
    {"show tsmas;", 0, 0, NULL},
239
    {"show rsmas;", 0, 0, NULL},
240
    {"show roles;", 0, 0, NULL},
241
    {"show role privileges;", 0, 0, NULL},
242
    {"show role column privileges;", 0, 0, NULL},
243
    {"show users;", 0, 0, NULL},
244
    {"show user privileges;", 0, 0, NULL},
245
    {"show user column privileges;", 0, 0, NULL},
246
    {"show variables;", 0, 0, NULL},
247
    {"show local variables;", 0, 0, NULL},
248
    {"show vnodes;", 0, 0, NULL},
249
    {"show vnodes on dnode <dnode_id>;", 0, 0, NULL},
250
    {"show vgroups;", 0, 0, NULL},
251
    {"show vtables;", 0, 0, NULL},
252
    {"show consumers;", 0, 0, NULL},
253
    {"show grants;", 0, 0, NULL},
254
    {"show grants full;", 0, 0, NULL},
255
    {"show grants logs;", 0, 0, NULL},
256
#ifdef TD_ENTERPRISE
257
    {"show views;", 0, 0, NULL},
258
    {"show arbgroups;", 0, 0, NULL},
259
    {"split vgroup <vgroup_id>;", 0, 0, NULL},
260
    {"ssmigrate database <db_name>;", 0, 0, NULL},
261
    {"show mounts;", 0, 0, NULL},
262
    {"show ssmigrates;", 0, 0, NULL},
263
#endif
264
    {"insert into <tb_name> values(", 0, 0, NULL},
265
    {"insert into <tb_name> using <stb_name> tags(", 0, 0, NULL},
266
    {"insert into <tb_name> using <stb_name> <anyword> values(", 0, 0, NULL},
267
    {"insert into <tb_name> file ", 0, 0, NULL},
268
    {"trim database <db_name>;", 0, 0, NULL},
269
    {"use <db_name>;", 0, 0, NULL},
270
    {"update all anodes;", 0, 0, NULL},
271
    {"update anode <anyword>;", 0, 0, NULL},
272
    {"quit", 0, 0, NULL}};
273

274
// where keyword
275
char* keywords[] = {
276
    "where ",       "and ",      "asc ",      "desc ",    "from ",         "fill(",     "limit ",
277
    "interval(",    "order by ", "order by ", "offset ",  "or ",           "group by ", "now()",
278
    "session(",     "sliding ",  "slimit ",   "soffset ", "state_window(", "today() ",  "union all select ",
279
    "partition by ", "match",    "nmatch ",    "between ",  "like ",           "is null ",   "is not null ",
280
    "event_window ",  "count_window(", "anomaly_window("
281
};
282

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

341
char* tb_actions[] = {
342
    "add column ", "modify column ", "drop column ", "rename column ", "add tag ",
343
    "modify tag ", "drop tag ",      "rename tag ",  "set tag ",
344
};
345

346
char* user_actions[] = {"pass ", "enable ", "sysinfo ", "createdb "};
347

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

350
char* db_options[] = {"keep ",
351
                      "replica ",
352
                      "precision ",
353
                      "strict ",
354
                      "buffer ",
355
                      "cachemodel ",
356
                      "cachesize ",
357
                      "comp ",
358
                      "duration ",
359
                      "dnodes ",
360
                      "wal_fsync_period ",
361
                      "maxrows ",
362
                      "minrows ",
363
                      "pages ",
364
                      "pagesize ",
365
                      "retentions ",
366
                      "wal_level ",
367
                      "vgroups ",
368
                      "single_stable ",
369
                      "ss_chunksize ",
370
                      "ss_keeplocal ",
371
                      "ss_compact ",
372
                      "wal_retention_period ",
373
                      "wal_roll_period ",
374
                      "wal_retention_size ",
375
#ifdef TD_ENTERPRISE                      
376
                      "encrypt_algorithm ",
377
                      "compact_interval ",
378
                      "compact_time_range ",
379
                      "compact_time_offset ",
380
#endif
381
                      "keep_time_offset ",
382
                      "wal_segment_size "
383
};
384

385
char* alter_db_options[] = {"cachemodel ", "replica ", "keep ", "stt_trigger ",
386
                            "wal_retention_period ", "wal_retention_size ", "cachesize ", 
387
                                              "ss_keeplocal ", "ss_compact ",
388
                            "wal_fsync_period ", "buffer ", "pages " ,"wal_level "};
389

390
char* data_types[] = {"timestamp",    "int",
391
                      "int unsigned", "varchar(16)",
392
                      "float",        "double",
393
                      "binary(16)",   "nchar(16)",
394
                      "bigint",       "bigint unsigned",
395
                      "smallint",     "smallint unsigned",
396
                      "tinyint",      "tinyint unsigned",
397
                      "geometry(64)", "varbinary(16)",
398
                      "decimal(10,2)", "blob",
399
                      "bool",         "json"};
400

401
char* key_tags[] = {"tags("};
402

403
char* key_select[] = {"select "};
404

405
char* key_systable[] = {
406
    "ins_dnodes",        "ins_mnodes",     "ins_modules",      "ins_qnodes",  "ins_snodes",          "ins_cluster",
407
    "ins_databases",     "ins_functions",  "ins_indexes",      "ins_stables", "ins_tables",          "ins_tags",
408
    "ins_users",         "ins_grants",     "ins_vgroups",      "ins_configs", "ins_dnode_variables", "ins_topics",
409
    "ins_subscriptions", "ins_streams",    "ins_stream_tasks", "ins_vnodes",  "ins_user_privileges", "ins_filesets",
410
    "ins_bnodes",        "ins_disk_usage", "ins_retentions",   "ins_tokens",
411
    "perf_connections", "perf_queries",    "perf_consumers", "perf_trans",       "perf_apps"};
412

413
char* udf_language[] = {"\'Python\'", "\'C\'"};
414

415
char* field_options[] = {
416
    "encode ", "compress ", "level ", 
417
    "\'lz4\' ", "\'zlib\' ", "\'zstd\' ", "\'xz\' ", "\'tsz\' ", "\'disabled\' ", // compress
418
    "\'simple8b\' ", "\'delta-i\' ", "\'delta-d\' ", "\'bit-packing\' ", "\'bss\' ",
419
    "\'high\' ", "\'medium\' ", "\'low\' ",
420
    "comment ",
421
    "primary key "
422
};
423

424
// create user options
425
char * create_uopt[] = {
426
    "pass ",
427
    "account ",
428
    "sysinfo ",
429
    "createdb ",
430
    "changepass ",
431
    "session_per_user ",
432
    "connect_idle_time ",
433
    "connect_time ",
434
    "call_per_session ",
435
    "vnode_per_call ",
436
    "failed_login_attempts ",
437
    "password_life_time ",
438
    "password_reuse_time ",
439
    "password_reuse_max ",
440
    "password_lock_time ",
441
    "password_grace_time ",
442
    "inactive_account_time ",
443
    "allow_token_num ",
444
    "host ",
445
    "not_allow_host ",
446
    "allow_datetime ",
447
    "not_allow_datetime "
448
};
449

450
// alter user options
451
char * alter_uopt[] = {
452
    "pass ",
453
    "account ",
454
    "sysinfo ",
455
    "createdb ",
456
    "changepass ",
457
    "session_per_user ",
458
    "connect_idle_time ",
459
    "connect_time ",
460
    "call_per_session ",
461
    "vnode_per_call ",
462
    "failed_login_attempts ",
463
    "password_life_time ",
464
    "password_reuse_time ",
465
    "password_reuse_max ",
466
    "password_lock_time ",
467
    "password_grace_time ",
468
    "inactive_account_time ",
469
    "allow_token_num ",
470
    "enable ",
471
    "add host ",
472
    "add not_allow_host ",
473
    "drop host ",
474
    "drop not_allow_host ",
475
    "add allow_datetime ",
476
    "add not_allow_datetime ",
477
    "drop allow_datetime ",
478
    "drop not_allow_datetime "
479
};
480

481
// alter user options
482
char * token_opt[] = {
483
    "enable ",
484
    "provider ",
485
    "ttl ",
486
    "extra_info "
487
};
488

489
// global keys can tips on anywhere
490
char* global_keys[] = {
491
    "tbname",         
492
    "now",
493
    "vgroups",
494
    "if exists",
495
    "if not exists",
496
    "distinct",
497
    "like",
498
    "_wstart",      
499
    "_wend",
500
    "_wduration",
501
    "_qstart",          
502
    "_qend",
503
    "_qduration",
504
    "_qtag",
505
    "_isfilled"
506
  };
507

508
//
509
//  ------- global variant define ---------
510
//
511
int32_t firstMatchIndex = -1;  // first match shellCommands index
512
int32_t lastMatchIndex = -1;   // last match shellCommands index
513
int32_t curMatchIndex = -1;    // current match shellCommands index
514
int32_t lastWordBytes = -1;    // printShow last word length
515
bool    waitAutoFill = false;
516

517
//
518
//   ----------- global var array define -----------
519
//
520
#define WT_VAR_DBNAME         0
521
#define WT_VAR_STABLE         1
522
#define WT_VAR_TABLE          2
523
#define WT_VAR_DNODEID        3
524
#define WT_VAR_USERNAME       4
525
#define WT_VAR_TOPIC          5
526
#define WT_VAR_STREAM         6
527
#define WT_VAR_UDFNAME        7
528
#define WT_VAR_VGROUPID       8
529
#define WT_VAR_TSMA           9
530
#define WT_VAR_RSMA           10
531
#define WT_VAR_ANODE          11
532
#define WT_VAR_TOKEN          12
533

534
#define WT_FROM_DB_MAX        12  // max get content from db
535
#define WT_FROM_DB_CNT (WT_FROM_DB_MAX + 1)
536

537
#define WT_VAR_ALLTABLE       WT_FROM_DB_MAX + 1
538
#define WT_VAR_FUNC           WT_FROM_DB_MAX + 2
539
#define WT_VAR_KEYWORD        WT_FROM_DB_MAX + 3
540
#define WT_VAR_TBACTION       WT_FROM_DB_MAX + 4
541
#define WT_VAR_DBOPTION       WT_FROM_DB_MAX + 5
542
#define WT_VAR_ALTER_DBOPTION WT_FROM_DB_MAX + 6
543
#define WT_VAR_DATATYPE       WT_FROM_DB_MAX + 7
544
#define WT_VAR_KEYTAGS        WT_FROM_DB_MAX + 8
545
#define WT_VAR_ANYWORD        WT_FROM_DB_MAX + 9
546
#define WT_VAR_TBOPTION       WT_FROM_DB_MAX + 10
547
#define WT_VAR_USERACTION     WT_FROM_DB_MAX + 11
548
#define WT_VAR_KEYSELECT      WT_FROM_DB_MAX + 12
549
#define WT_VAR_SYSTABLE       WT_FROM_DB_MAX + 13
550
#define WT_VAR_LANGUAGE       WT_FROM_DB_MAX + 14
551
#define WT_VAR_GLOBALKEYS     WT_FROM_DB_MAX + 15
552
#define WT_VAR_FIELD_OPTIONS  WT_FROM_DB_MAX + 16
553
#define WT_VAR_CREATE_USER_OPT WT_FROM_DB_MAX + 17
554
#define WT_VAR_ALTER_USER_OPT  WT_FROM_DB_MAX + 18
555
#define WT_VAR_TOKEN_OPT       WT_FROM_DB_MAX + 19
556
#define WT_VAR_CNT             WT_FROM_DB_MAX + 20
557

558

559
#define WT_TEXT 0xFF
560

561
char dbName[256] = "";  // save use database name;
562
// tire array
563
STire*        tires[WT_VAR_CNT];
564
TdThreadMutex tiresMutex;
565
// save thread handle obtain var name from db server
566
TdThread* threads[WT_FROM_DB_CNT];
567
// obtain var name  with sql from server
568
char varTypes[WT_VAR_CNT][64] = {
569
    // get from db
570
    "<db_name>",    "<stb_name>",  "<tb_name>",  "<dnode_id>",  "<user_name>",    "<topic_name>", "<stream_name>",
571
    "<udf_name>",   "<vgroup_id>", "<tsma_name>", "<rsma_name>", "<anode_id>", "<token_name>",
572
    // get from code
573
    "<all_table>",  "<function>",  "<keyword>",  "<tb_actions>",   "<db_options>", "<alter_db_options>",
574
    "<data_types>", "<key_tags>",  "<anyword>",  "<tb_options>", "<user_actions>", "<key_select>", "<sys_table>", 
575
    "<udf_language>", "<global_keys>", "<field_options>", "<create_uopt>", "<alter_uopt>", "<token_opt>"};
576

577
char varSqls[WT_FROM_DB_CNT][64] = {"show databases;", "show stables;", "show tables;", "show dnodes;",
578
                                    "show users;",     "show topics;",  "show streams;", "show functions;", 
579
                                    "show vgroups;",   "show tsmas;",   "show rsmas;",  "show anodes;",
580
                                    "show tokens;"};
581

582
// var words current cursor, if user press any one key except tab, cursorVar can be reset to -1
583
int  cursorVar = -1;
584
bool varMode = false;  // enter var names list mode
585

586
TAOS*      varCon = NULL;
587
SShellCmd* varCmd = NULL;
588
bool       varRunOnce = false;
589
SMatch*    lastMatch = NULL;  // save last match result
590
int        cntDel = 0;        // delete byte count after next press tab
591

592
// show auto tab introduction
593
void printfIntroduction(EVersionType type) {
210✔
594
  printf("  *********************************  Tab Completion  *************************************\n");
210✔
595
  char secondLine[160] = "\0";
210✔
596
  sprintf(secondLine, "  *   The %s CLI supports tab completion for a variety of items, ", shell.info.cusName);
210✔
597
  printf("%s", secondLine);
210✔
598
  int secondLineLen = strlen(secondLine);
210✔
599
  while (89 - (secondLineLen++) > 0) {
2,940✔
600
    printf(" ");
2,730✔
601
  }
602
  printf("*\n");
210✔
603
  printf("  *   including database names, table names, function names and keywords.                *\n");
210✔
604
  printf("  *   The full list of shortcut keys is as follows:                                      *\n");
210✔
605
  printf("  *    [ TAB ]        ......  complete the current word                                  *\n");
210✔
606
  printf("  *                   ......  if used on a blank line, display all supported commands    *\n");
210✔
607
  printf("  *    [ Ctrl + A ]   ......  move cursor to the st[A]rt of the line                     *\n");
210✔
608
  printf("  *    [ Ctrl + E ]   ......  move cursor to the [E]nd of the line                       *\n");
210✔
609
  printf("  *    [ Ctrl + W ]   ......  move cursor to the middle of the line                      *\n");
210✔
610
  printf("  *    [ Ctrl + L ]   ......  clear the entire screen                                    *\n");
210✔
611
  printf("  *    [ Ctrl + K ]   ......  clear the screen after the cursor                          *\n");
210✔
612
  printf("  *    [ Ctrl + U ]   ......  clear the screen before the cursor                         *\n");
210✔
613
  if (type == TSDB_VERSION_OSS) {
210✔
614
    printf("  * ------------------------------------------------------------------------------------ *\n");
×
615
    printf("  *   You are using TDengine OSS. To experience advanced features, like backup/restore,  *\n");
×
616
    printf("  *   privilege control and more, or receive 7x24 technical support, try TDengine        *\n");
×
UNCOV
617
    printf("  *   Enterprise or TDengine Cloud. Learn more at https://tdengine.com                   *\n");
×
618
  }
619
  printf("  ****************************************************************************************\n\n");
210✔
620
}
210✔
621

622
// show enterprise AD
623
void showAD(bool end) {
×
624
  printf("  You are using TDengine OSS. To experience advanced features, like backup/restore,  \n");
×
625
  printf("  privilege control and more, or receive 7x24 technical support, try TDengine Enterprise \n");
×
626
  printf("  or TDengine Cloud. Learn more at https://tdengine.com   \n");
×
627
  printf("  \n");
×
UNCOV
628
}
×
629

630
void showHelp() {
77✔
631
  printf("\nThe %s CLI supports the following commands:", shell.info.cusName);
77✔
632
  printf(
77✔
633
      "\n\
634
  ----- A ----- \n\
635
    alter database <db_name> <db_options> \n\
636
    alter dnode <dnode_id> 'resetlog';\n\
637
    alter dnode <dnode_id> 'monitor' '0';\n\
638
    alter dnode <dnode_id> 'monitor' \"1\";\n\
639
    alter dnode <dnode_id> \"debugflag\" \"143\";\n\
640
    alter dnode <dnode_id> 'asynclog' '0';\n\
641
    alter dnode <dnode_id> 'asynclog' \"1\";\n\
642
    alter all dnodes \"monitor\" \"0\";\n\
643
    alter all dnodes \"monitor\" \"1\";\n\
644
    alter all dnodes \"resetlog\";\n\
645
    alter all dnodes \"debugFlag\" \n\
646
    alter all dnodes \"asynclog\" \"0\";\n\
647
    alter all dnodes \"asynclog\" \"1\";\n\
648
    alter table <tb_name> <tb_actions> ;\n\
649
    alter local \"resetlog\";\n\
650
    alter local \"DebugFlag\" \"143\";\n\
651
    alter local \"asynclog\" \"0\";\n\
652
    alter local \"asynclog\" \"1\";\n\
653
    alter topic\n\
654
    alter user <user_name> <user_actions> ...\n\
655
  ----- C ----- \n\
656
    create table <tb_name> using <stb_name> tags ...\n\
657
    create vtable <tb_name> using <stb_name> tags ...\n\
658
    create database <db_name> <db_options>  ...\n\
659
    create dnode \"fqdn:port\" ...\n\
660
    create index <index_name> on <stb_name> (tag_column_name);\n\
661
    create mnode on dnode <dnode_id> ;\n\
662
    create qnode on dnode <dnode_id> ;\n\
663
    create bnode on dnode <dnode_id> ;\n\
664
    create anode \"node_url\" ;\n\
665
    create stream <stream_name> into <stb_name> as select ...\n\
666
    create topic <topic_name> as select ...\n\
667
    create function <udf_name> as <file_name> outputtype <data_types> language \'C\' | \'Python\' ;\n\
668
    create aggregate function  <udf_name> as <file_name> outputtype <data_types> bufsize <bufsize_bytes> language \'C\' | \'Python\';\n\
669
    create user <user_name> pass <password> ...\n\
670
  ----- D ----- \n\
671
    describe <all_table>\n\
672
    delete from <all_table> where ...\n\
673
    drop database <db_name>;\n\
674
    drop table <all_table>;\n\
675
    drop dnode <dnode_id>;\n\
676
    drop mnode on dnode <dnode_id> ;\n\
677
    drop qnode on dnode <dnode_id> ;\n\
678
    drop bnode on dnode <dnode_id> ;\n\
679
    drop anode <anode_id> ;\n\
680
    drop user <user_name> ;\n\
681
    drop function <udf_name>;\n\
682
    drop consumer group ... \n\
683
    drop topic <topic_name> ;\n\
684
    drop stream <stream_name> ;\n\
685
    drop index <index_name>;\n\
686
    drop tsma <tsma_name> ;\n\
687
    drop rsma <rsma_name> ;\n\
688
  ----- E ----- \n\
689
    explain select clause ...\n\
690
  ----- F ----- \n\
691
    flush database <db_name>;\n\
692
  ----- H ----- \n\
693
    help;\n\
694
  ----- I ----- \n\
695
    insert into <tb_name> values(...) ;\n\
696
    insert into <tb_name> using <stb_name> tags(...) values(...) ;\n\
697
  ----- G ----- \n\
698
    grant all   on <priv_level> to <user_name> ;\n\
699
    grant read  on <priv_level> to <user_name> ;\n\
700
    grant write on <priv_level> to <user_name> ;\n\
701
  ----- K ----- \n\
702
    kill connection <connection_id>; \n\
703
    kill query <query_id>; \n\
704
    kill retention <retention_id>; \n\
705
    kill transaction <transaction_id>;\n\
706
  ----- P ----- \n\
707
    pause stream <stream_name>;\n\
708
  ----- R ----- \n\
709
    resume stream <stream_name>;\n\
710
    reset query cache;\n\
711
    restore dnode <dnode_id> ;\n\
712
    restore vnode on dnode <dnode_id> ;\n\
713
    restore mnode on dnode <dnode_id> ;\n\
714
    restore qnode on dnode <dnode_id> ;\n\
715
    revoke all   on <priv_level> from <user_name> ;\n\
716
    revoke read  on <priv_level> from <user_name> ;\n\
717
    revoke write on <priv_level> from <user_name> ;\n\
718
  ----- S ----- \n\
719
    select * from <all_table> where ... \n\
720
    select client_version();\n\
721
    select current_user();\n\
722
    select database();\n\
723
    select server_version();\n\
724
    select server_status();\n\
725
    select now();\n\
726
    select today();\n\
727
    select timezone();\n\
728
    set max_binary_display_width ...\n\
729
    show apps;\n\
730
    show alive;\n\
731
    show anodes;\n\
732
    show anodes full;\n\
733
    show create database <db_name>;\n\
734
    show create stable <stb_name>;\n\
735
    show create table <tb_name>;\n\
736
    show connections;\n\
737
    show cluster;\n\
738
    show cluster alive;\n\
739
    show cluster machines;\n\
740
    show databases;\n\
741
    show dnodes;\n\
742
    show dnode <dnode_id> variables;\n\
743
    show disk_info;\n\
744
    show functions;\n\
745
    show licences;\n\
746
    show mnodes;\n\
747
    show queries;\n\
748
    show query <query_id> ;\n\
749
    show qnodes;\n\
750
    show bnodes;\n\
751
    show retentions;\n\
752
    show retention <retention_id>;\n\
753
    show scans;\n\
754
    show scan <scan_id>;\n\
755
    show snodes;\n\
756
    show stables;\n\
757
    show stables like \n\
758
    show streams;\n\
759
    show scores;\n\
760
    show subscriptions;\n\
761
    show tables;\n\
762
    show tables like\n\
763
    show table distributed <all_table>;\n\
764
    show tags from <tb_name>\n\
765
    show tags from <db_name>\n\
766
    show table tags from <all_table>\n\
767
    show topics;\n\
768
    show transactions;\n\
769
    show tsmas;\n\
770
    show rsmas;\n\
771
    show roles;\n\
772
    show role privileges;\n\
773
    show role column privileges;\n\
774
    show users;\n\
775
    show user privileges;\n\
776
    show user column privileges;\n\
777
    show variables;\n\
778
    show local variables;\n\
779
    show vnodes;\n\
780
    show vnodes on dnode <dnode_id>;\n\
781
    show vgroups;\n\
782
    show vtables;\n\
783
    show consumers;\n\
784
    show grants;\n\
785
    show grants full;\n\
786
    show grants logs;\n\
787
  ----- T ----- \n\
788
    trim database <db_name>;\n\
789
  ----- U ----- \n\
790
    update all anodes;\n\
791
    update anode <anode_id>;\n\
792
    use <db_name>;");
793

794
#ifdef TD_ENTERPRISE
795
  printf(
77✔
796
      "\n\n\
797
  ----- special commands on enterpise version ----- \n\
798
    alter token <token_name> [token options];\n\
799
    balance vgroup ;\n\
800
    balance vgroup leader on <vgroup_id> \n\
801
    compact database <db_name>; \n\
802
    compact vgroups in (vgroupId,vgroupId, ...); \n\
803
    create view <view_name> as select ...\n\
804
    create mount <mount_name> on dnode <dnode_id> from <path>;\n\
805
    create token <token_name> from user <user_name> [token options];\n\
806
    create totp_secret for user <user_name>;\n\
807
    drop mount <mount_name>;\n\
808
    drop token <token_name>;\n\
809
    drop totp_secret from user <user_name>;\n\
810
    redistribute vgroup <vgroup_id> dnode <dnode_id> ;\n\
811
    split vgroup <vgroup_id>;\n\
812
    ssmigrate database <db_name>;\n\
813
    show arbgroups;\n\
814
    show compacts;\n\
815
    show compact \n\
816
    show tokens;\n\
817
    show ssmigrates;\n\
818
    show mounts;\n\
819
    show views;\n\
820
    show create view <all_table>;");
821
    
822
#endif
823

824
  printf("\n\n");
77✔
825
  // define in getDuration() function
826
  printf(
77✔
827
      "\
828
  Timestamp expression Format:\n\
829
    b - nanosecond \n\
830
    u - microsecond \n\
831
    a - millisecond \n\
832
    s - second \n\
833
    m - minute \n\
834
    h - hour \n\
835
    d - day \n\
836
    w - week \n\
837
    now - current time \n\
838
  Example : \n\
839
    select * from t1 where ts > now - 2w + 3d and ts <= now - 1w -2h ;\n");
840
  printf(ERROR_CODE_DETAIL);
77✔
841
  printf("\n");
77✔
842
}
77✔
843

844
//
845
//  -------------------  parse words --------------------------
846
//
847

848
#define SHELL_COMMAND_COUNT() (sizeof(shellCommands) / sizeof(SWords))
849

850
// get at
UNCOV
851
SWord* atWord(SWords* command, int32_t index) {
×
852
  SWord* word = command->head;
×
853
  for (int32_t i = 0; i < index; i++) {
×
854
    if (word == NULL) return NULL;
×
855
    word = word->next;
×
856
  }
857

UNCOV
858
  return word;
×
859
}
860

861
#define MATCH_WORD(x) atWord(x, x->matchIndex)
862

863
int wordType(const char* p, int32_t len) {
792,712,110✔
864
  for (int i = 0; i < WT_VAR_CNT; i++) {
2,147,483,647✔
865
    if (strncmp(p, varTypes[i], len) == 0) return i;
2,147,483,647✔
866
  }
867
  return WT_TEXT;
572,272,989✔
868
}
869

870
// add word
871
SWord* addWord(const char* p, int32_t len, bool pattern) {
802,485,273✔
872
  SWord* word = (SWord*)taosMemoryMalloc(sizeof(SWord));
802,485,273✔
873
  memset(word, 0, sizeof(SWord));
802,485,273✔
874
  word->word = (char*)p;
802,485,273✔
875
  word->len = len;
802,485,273✔
876

877
  // check format
878
  if (pattern && len > 0) {
802,485,273✔
879
    if (p[len - 1] == ';') {
792,712,110✔
880
      word->type = wordType(p, len - 1);
159,628,329✔
881
      word->end = true;
159,628,329✔
882
    } else {
883
      word->type = wordType(p, len);
633,083,781✔
884
    }
885
  } else {
886
    word->type = WT_TEXT;
9,773,163✔
887
  }
888

889
  return word;
802,485,273✔
890
}
891

892
// parse one command
893
void parseCommand(SWords* command, bool pattern) {
197,635,074✔
894
  char*   p = command->source;
197,635,074✔
895
  int32_t start = 0;
197,635,074✔
896
  int32_t size = command->source_len > 0 ? command->source_len : strlen(p);
197,635,074✔
897

898
  bool lastBlank = false;
197,635,074✔
899
  for (int i = 0; i <= size; i++) {
2,147,483,647✔
900
    if (p[i] == ' ' || i == size) {
2,147,483,647✔
901
      // check continue blank like '    '
902
      if (p[i] == ' ') {
804,657,087✔
903
        if (lastBlank) {
607,022,013✔
904
          start++;
2,171,814✔
905
          continue;
2,171,814✔
906
        }
907
        if (i == 0) {  // first blank
604,850,199✔
UNCOV
908
          lastBlank = true;
×
909
          start++;
×
910
          continue;
×
911
        }
912
        lastBlank = true;
604,850,199✔
913
      }
914

915
      // found split or string end , append word
916
      if (command->head == NULL) {
802,485,273✔
917
        command->head = addWord(p + start, i - start, pattern);
197,635,074✔
918
        command->count = 1;
197,635,074✔
919
      } else {
920
        SWord* word = command->head;
604,850,199✔
921
        while (word->next) {
2,050,192,416✔
922
          word = word->next;
1,445,342,217✔
923
        }
924
        word->next = addWord(p + start, i - start, pattern);
604,850,199✔
925
        command->count++;
604,850,199✔
926
      }
927
      start = i + 1;
802,485,273✔
928
    } else {
929
      lastBlank = false;
2,147,483,647✔
930
    }
931
  }
932
}
197,635,074✔
933

934
// free SShellCmd
935
void freeCommand(SWords* command) {
197,635,074✔
936
  SWord* item = command->head;
197,635,074✔
937
  command->head = NULL;
197,635,074✔
938
  // loop
939
  while (item) {
1,000,120,347✔
940
    SWord* tmp = item;
802,485,273✔
941
    item = item->next;
802,485,273✔
942
    // if malloc need free
943
    if (tmp->free && tmp->word) taosMemoryFree(tmp->word);
802,485,273✔
944
    taosMemoryFree(tmp);
802,485,273✔
945
  }
946
}
197,635,074✔
947

948
void GenerateVarType(int type, char** p, int count) {
18,460,419✔
949
  STire* tire = createTire(TIRE_LIST);
18,460,419✔
950
  for (int i = 0; i < count; i++) {
397,441,962✔
951
    insertWord(tire, p[i]);
378,981,543✔
952
  }
953

954
  taosThreadMutexLock(&tiresMutex);
18,460,419✔
955
  tires[type] = tire;
18,460,419✔
956
  taosThreadMutexUnlock(&tiresMutex);
18,460,419✔
957
}
18,460,419✔
958

959
//
960
//  -------------------- shell auto ----------------
961
//
962

963
// init shell auto function , shell start call once
964
void shellAutoInit() {
1,085,907✔
965
  // command
966
  int32_t count = SHELL_COMMAND_COUNT();
1,085,907✔
967
  for (int32_t i = 0; i < count; i++) {
198,720,981✔
968
    parseCommand(shellCommands + i, true);
197,635,074✔
969
  }
970

971
  // tires
972
  memset(tires, 0, sizeof(STire*) * WT_VAR_CNT);
1,085,907✔
973
  taosThreadMutexInit(&tiresMutex, NULL);
1,085,907✔
974

975
  // threads
976
  memset(threads, 0, sizeof(TdThread*) * WT_FROM_DB_CNT);
1,085,907✔
977

978
  // generate varType
979
  GenerateVarType(WT_VAR_FUNC, functions, sizeof(functions) / sizeof(char*));
1,085,907✔
980
  GenerateVarType(WT_VAR_KEYWORD, keywords, sizeof(keywords) / sizeof(char*));
1,085,907✔
981
  GenerateVarType(WT_VAR_TBACTION, tb_actions, sizeof(tb_actions) / sizeof(char*));
1,085,907✔
982
  GenerateVarType(WT_VAR_DBOPTION, db_options, sizeof(db_options) / sizeof(char*));
1,085,907✔
983
  GenerateVarType(WT_VAR_ALTER_DBOPTION, alter_db_options, sizeof(alter_db_options) / sizeof(char*));
1,085,907✔
984
  GenerateVarType(WT_VAR_DATATYPE, data_types, sizeof(data_types) / sizeof(char*));
1,085,907✔
985
  GenerateVarType(WT_VAR_KEYTAGS, key_tags, sizeof(key_tags) / sizeof(char*));
1,085,907✔
986
  GenerateVarType(WT_VAR_TBOPTION, tb_options, sizeof(tb_options) / sizeof(char*));
1,085,907✔
987
  GenerateVarType(WT_VAR_USERACTION, user_actions, sizeof(user_actions) / sizeof(char*));
1,085,907✔
988
  GenerateVarType(WT_VAR_KEYSELECT, key_select, sizeof(key_select) / sizeof(char*));
1,085,907✔
989
  GenerateVarType(WT_VAR_SYSTABLE, key_systable, sizeof(key_systable) / sizeof(char*));
1,085,907✔
990
  GenerateVarType(WT_VAR_LANGUAGE, udf_language, sizeof(udf_language) / sizeof(char*));
1,085,907✔
991
  GenerateVarType(WT_VAR_GLOBALKEYS, global_keys, sizeof(global_keys) / sizeof(char*));
1,085,907✔
992
  GenerateVarType(WT_VAR_FIELD_OPTIONS, field_options, sizeof(field_options) / sizeof(char*));
1,085,907✔
993
  GenerateVarType(WT_VAR_CREATE_USER_OPT, create_uopt, sizeof(create_uopt) / sizeof(char*));
1,085,907✔
994
  GenerateVarType(WT_VAR_ALTER_USER_OPT, alter_uopt, sizeof(alter_uopt) / sizeof(char*));
1,085,907✔
995
  GenerateVarType(WT_VAR_TOKEN_OPT, token_opt, sizeof(token_opt) / sizeof(char*));
1,085,907✔
996
}
1,085,907✔
997

998
// set conn
999
void shellSetConn(TAOS* conn, bool runOnce) {
1,084,856✔
1000
  varCon = conn;
1,084,856✔
1001
  varRunOnce = runOnce;
1,084,856✔
1002
  // init database and stable
1003
  if (!runOnce) updateTireValue(WT_VAR_DBNAME, false);
1,084,856✔
1004
}
1,084,856✔
1005

1006
// exit shell auto function, shell exit call once
1007
void shellAutoExit() {
1,085,907✔
1008
  // free command
1009
  int32_t count = SHELL_COMMAND_COUNT();
1,085,907✔
1010
  for (int32_t i = 0; i < count; i++) {
198,720,981✔
1011
    freeCommand(shellCommands + i);
197,635,074✔
1012
  }
1013

1014
  // free tires
1015
  taosThreadMutexLock(&tiresMutex);
1,085,907✔
1016
  for (int32_t i = 0; i < WT_VAR_CNT; i++) {
35,834,931✔
1017
    if (tires[i]) {
34,749,024✔
1018
      freeTire(tires[i]);
18,460,629✔
1019
      tires[i] = NULL;
18,460,629✔
1020
    }
1021
  }
1022
  taosThreadMutexUnlock(&tiresMutex);
1,085,907✔
1023
  // destroy
1024
  taosThreadMutexDestroy(&tiresMutex);
1,085,907✔
1025

1026
  // free threads
1027
  for (int32_t i = 0; i < WT_FROM_DB_CNT; i++) {
15,202,698✔
1028
    if (threads[i]) {
14,116,791✔
UNCOV
1029
      taosDestroyThread(threads[i]);
×
1030
      threads[i] = NULL;
×
1031
    }
1032
  }
1033

1034
  // free lastMatch
1035
  if (lastMatch) {
1,085,907✔
UNCOV
1036
    freeMatch(lastMatch);
×
1037
    lastMatch = NULL;
×
1038
  }
1039
}
1,085,907✔
1040

1041
//
1042
//  -------------------  auto ptr for tires --------------------------
1043
//
1044
bool setNewAutoPtr(int type, STire* pNew) {
210✔
1045
  if (pNew == NULL) return false;
210✔
1046

1047
  taosThreadMutexLock(&tiresMutex);
210✔
1048
  STire* pOld = tires[type];
210✔
1049
  if (pOld != NULL) {
210✔
1050
    // previous have value, release self ref count
UNCOV
1051
    if (--pOld->ref == 0) {
×
1052
      freeTire(pOld);
×
1053
    }
1054
  }
1055

1056
  // set new
1057
  tires[type] = pNew;
210✔
1058
  tires[type]->ref = 1;
210✔
1059
  taosThreadMutexUnlock(&tiresMutex);
210✔
1060

1061
  return true;
210✔
1062
}
1063

1064
// get ptr
UNCOV
1065
STire* getAutoPtr(int type) {
×
1066
  if (tires[type] == NULL) {
×
1067
    return NULL;
×
1068
  }
1069

UNCOV
1070
  taosThreadMutexLock(&tiresMutex);
×
1071
  tires[type]->ref++;
×
1072
  taosThreadMutexUnlock(&tiresMutex);
×
1073

UNCOV
1074
  return tires[type];
×
1075
}
1076

1077
// put back tire to tires[type], if tire not equal tires[type].p, need free tire
UNCOV
1078
void putBackAutoPtr(int type, STire* tire) {
×
1079
  if (tire == NULL) {
×
1080
    return;
×
1081
  }
1082

UNCOV
1083
  taosThreadMutexLock(&tiresMutex);
×
1084
  if (tires[type] != tire) {
×
1085
    // update by out,  can't put back , so free
UNCOV
1086
    if (--tire->ref == 1) {
×
1087
      // support multi thread getAutoPtr
UNCOV
1088
      freeTire(tire);
×
1089
    }
1090

1091
  } else {
UNCOV
1092
    tires[type]->ref--;
×
1093
    ASSERT(tires[type]->ref > 0);
×
1094
  }
UNCOV
1095
  taosThreadMutexUnlock(&tiresMutex);
×
1096

UNCOV
1097
  return;
×
1098
}
1099

1100
//
1101
//  -------------------  var Word --------------------------
1102
//
1103

1104
#define MAX_CACHED_CNT 100000  // max cached rows 10w
1105
// write sql result to var name, return write rows cnt
1106
int writeVarNames(int type, TAOS_RES* tres) {
210✔
1107
  // fetch row
1108
  TAOS_ROW row = taos_fetch_row(tres);
210✔
1109
  if (row == NULL) {
210✔
UNCOV
1110
    return 0;
×
1111
  }
1112

1113
  TAOS_FIELD* fields = taos_fetch_fields(tres);
210✔
1114
  // create new tires
1115
  char   tireType = type == WT_VAR_TABLE ? TIRE_TREE : TIRE_LIST;
210✔
1116
  STire* tire = createTire(tireType);
210✔
1117

1118
  // enum rows
1119
  char name[1024];
210✔
1120
  int  numOfRows = 0;
210✔
1121
  do {
1122
    int32_t* lengths = taos_fetch_lengths(tres);
630✔
1123
    int32_t  bytes = lengths[0];
630✔
1124
    if (fields[0].type == TSDB_DATA_TYPE_INT) {
630✔
UNCOV
1125
      sprintf(name, "%d", *(int16_t*)row[0]);
×
1126
    } else {
1127
      memcpy(name, row[0], bytes);
630✔
1128
    }
1129

1130
    name[bytes] = 0;  // set string end
630✔
1131
    // insert to tire
1132
    insertWord(tire, name);
630✔
1133

1134
    if (++numOfRows > MAX_CACHED_CNT) {
630✔
UNCOV
1135
      break;
×
1136
    }
1137

1138
    row = taos_fetch_row(tres);
630✔
1139
  } while (row != NULL);
630✔
1140

1141
  // replace old tire
1142
  setNewAutoPtr(type, tire);
210✔
1143

1144
  return numOfRows;
210✔
1145
}
1146

1147
void setThreadNull(int type) {
210✔
1148
  taosThreadMutexLock(&tiresMutex);
210✔
1149
  if (threads[type]) {
210✔
1150
    taosMemoryFree(threads[type]);
210✔
1151
  }
1152
  threads[type] = NULL;
210✔
1153
  taosThreadMutexUnlock(&tiresMutex);
210✔
1154
}
210✔
1155

1156
bool firstMatchCommand(TAOS* con, SShellCmd* cmd);
1157
//
1158
//  thread obtain var thread from db server
1159
//
1160
void* varObtainThread(void* param) {
210✔
1161
  int type = *(int*)param;
210✔
1162
  taosMemoryFree(param);
210✔
1163

1164
  if (varCon == NULL || type > WT_FROM_DB_MAX) {
210✔
UNCOV
1165
    return NULL;
×
1166
  }
1167

1168
  TAOS_RES* pSql = taos_query(varCon, varSqls[type]);
210✔
1169
  if (taos_errno(pSql)) {
210✔
UNCOV
1170
    taos_free_result(pSql);
×
1171
    setThreadNull(type);
×
1172
    return NULL;
×
1173
  }
1174

1175
  // write var names from pSql
1176
  int cnt = writeVarNames(type, pSql);
210✔
1177

1178
  // free sql
1179
  taos_free_result(pSql);
210✔
1180

1181
  // check need call auto tab
1182
  if (cnt > 0 && waitAutoFill) {
210✔
1183
    // press tab key by program
UNCOV
1184
    firstMatchCommand(varCon, varCmd);
×
1185
  }
1186

1187
  setThreadNull(type);
210✔
1188
  return NULL;
210✔
1189
}
1190

1191
// return true is need update value by async
1192
bool updateTireValue(int type, bool autoFill) {
210✔
1193
  // TYPE CONTEXT GET FROM DB
1194
  taosThreadMutexLock(&tiresMutex);
210✔
1195

1196
  // check need obtain from server
1197
  if (tires[type] == NULL) {
210✔
1198
    waitAutoFill = autoFill;
210✔
1199
    // need async obtain var names from db sever
1200
    if (threads[type] != NULL) {
210✔
UNCOV
1201
      if (taosThreadRunning(threads[type])) {
×
1202
        // thread running , need not obtain again, return
UNCOV
1203
        taosThreadMutexUnlock(&tiresMutex);
×
1204
        return NULL;
×
1205
      }
1206
      // destroy previous thread handle for new create thread handle
UNCOV
1207
      taosDestroyThread(threads[type]);
×
1208
      threads[type] = NULL;
×
1209
    }
1210

1211
    // create new
1212
    void* param = taosMemoryMalloc(sizeof(int));
210✔
1213
    *((int*)param) = type;
210✔
1214
    threads[type] = taosCreateThread(varObtainThread, param);
210✔
1215
    taosThreadMutexUnlock(&tiresMutex);
210✔
1216
    return true;
210✔
1217
  }
UNCOV
1218
  taosThreadMutexUnlock(&tiresMutex);
×
1219

UNCOV
1220
  return false;
×
1221
}
1222

1223
// only match next one word from all match words, return valuue must free by caller
UNCOV
1224
char* matchNextPrefix(STire* tire, char* pre) {
×
1225
  SMatch* match = NULL;
×
1226
  if (tire == NULL) return NULL;
×
1227

1228
  // re-use last result
UNCOV
1229
  if (lastMatch) {
×
1230
    if (strcmp(pre, lastMatch->pre) == 0) {
×
1231
      // same pre
UNCOV
1232
      match = lastMatch;
×
1233
    }
1234
  }
1235

UNCOV
1236
  if (match == NULL) {
×
1237
    // not same with last result
UNCOV
1238
    if (pre[0] == 0) {
×
1239
      // EMPTY PRE
UNCOV
1240
      match = enumAll(tire);
×
1241
    } else {
1242
      // NOT EMPTY
UNCOV
1243
      match = (SMatch*)taosMemoryMalloc(sizeof(SMatch));
×
1244
      memset(match, 0, sizeof(SMatch));
×
1245
      matchPrefix(tire, pre, match);
×
1246
    }
1247

1248
    // save to lastMatch
UNCOV
1249
    if (match) {
×
1250
      if (lastMatch) freeMatch(lastMatch);
×
1251
      lastMatch = match;
×
1252
    }
1253
  }
1254

1255
  // check valid
UNCOV
1256
  if (match == NULL || match->head == NULL) {
×
1257
    // no one matched
UNCOV
1258
    return NULL;
×
1259
  }
1260

UNCOV
1261
  if (cursorVar == -1) {
×
1262
    // first
UNCOV
1263
    cursorVar = 0;
×
1264
    return taosStrdup(match->head->word);
×
1265
  }
1266

1267
  // according to cursorVar , calculate next one
UNCOV
1268
  int         i = 0;
×
1269
  SMatchNode* item = match->head;
×
1270
  while (item) {
×
1271
    if (i == cursorVar + 1) {
×
1272
      // found next position ok
UNCOV
1273
      if (item->next == NULL) {
×
1274
        // match last item, reset cursorVar to head
UNCOV
1275
        cursorVar = -1;
×
1276
      } else {
UNCOV
1277
        cursorVar = i;
×
1278
      }
1279

UNCOV
1280
      return taosStrdup(item->word);
×
1281
    }
1282

1283
    // check end item
UNCOV
1284
    if (item->next == NULL) {
×
1285
      // if cursorVar > var list count, return last and reset cursorVar
UNCOV
1286
      cursorVar = -1;
×
1287

UNCOV
1288
      return taosStrdup(item->word);
×
1289
    }
1290

1291
    // move next
UNCOV
1292
    item = item->next;
×
1293
    i++;
×
1294
  }
1295

UNCOV
1296
  return NULL;
×
1297
}
1298

1299
// search pre word from tire tree, return value must free by caller
UNCOV
1300
char* tireSearchWord(int type, char* pre) {
×
1301
  if (type == WT_TEXT) {
×
1302
    return NULL;
×
1303
  }
1304

UNCOV
1305
  if (type > WT_FROM_DB_MAX) {
×
1306
    // NOT FROM DB , tires[type] alwary not null
UNCOV
1307
    STire* tire = tires[type];
×
1308
    if (tire == NULL) return NULL;
×
1309
    return matchNextPrefix(tire, pre);
×
1310
  }
1311

UNCOV
1312
  if (updateTireValue(type, true)) {
×
1313
    return NULL;
×
1314
  }
1315

1316
  // can obtain var names from local
UNCOV
1317
  STire* tire = getAutoPtr(type);
×
1318
  if (tire == NULL) {
×
1319
    return NULL;
×
1320
  }
1321

UNCOV
1322
  char* str = matchNextPrefix(tire, pre);
×
1323
  // used finish, put back pointer to autoptr array
UNCOV
1324
  putBackAutoPtr(type, tire);
×
1325

UNCOV
1326
  return str;
×
1327
}
1328

1329
// match var word, word1 is pattern , word2 is input from shell
UNCOV
1330
bool matchVarWord(SWord* word1, SWord* word2) {
×
1331
  // search input word from tire tree
UNCOV
1332
  char pre[512];
×
1333
  memcpy(pre, word2->word, word2->len);
×
1334
  pre[word2->len] = 0;
×
1335

UNCOV
1336
  char* str = NULL;
×
1337
  if (word1->type == WT_VAR_ALLTABLE) {
×
1338
    // ALL_TABLE
UNCOV
1339
    str = tireSearchWord(WT_VAR_STABLE, pre);
×
1340
    if (str == NULL) {
×
1341
      str = tireSearchWord(WT_VAR_TABLE, pre);
×
1342
      if (str == NULL) return false;
×
1343
    }
1344
  } else {
1345
    // OTHER
UNCOV
1346
    str = tireSearchWord(word1->type, pre);
×
1347
    if (str == NULL) {
×
1348
      // not found or word1->type variable list not obtain from server, return not match
UNCOV
1349
      return false;
×
1350
    }
1351
  }
1352

1353
  // free previous malloc
UNCOV
1354
  if (word1->free && word1->word) {
×
1355
    taosMemoryFree(word1->word);
×
1356
  }
1357

1358
  // save
UNCOV
1359
  word1->word = str;
×
1360
  word1->len = strlen(str);
×
1361
  word1->free = true;  // need free
×
1362

UNCOV
1363
  return true;
×
1364
}
1365

1366
//
1367
//  -------------------  match words --------------------------
1368
//
1369

1370
// compare command cmdPattern come from shellCommands , cmdInput come from user input
UNCOV
1371
int32_t compareCommand(SWords* cmdPattern, SWords* cmdInput) {
×
1372
  SWord* wordPattern = cmdPattern->head;
×
1373
  SWord* wordInput = cmdInput->head;
×
1374

UNCOV
1375
  if (wordPattern == NULL || wordInput == NULL) {
×
1376
    return -1;
×
1377
  }
1378

UNCOV
1379
  for (int32_t i = 0; i < cmdPattern->count; i++) {
×
1380
    if (wordPattern->type == WT_TEXT) {
×
1381
      // WT_TEXT match
UNCOV
1382
      if (wordPattern->len == wordInput->len) {
×
1383
        if (strncasecmp(wordPattern->word, wordInput->word, wordPattern->len) != 0) return -1;
×
1384
      } else if (wordPattern->len < wordInput->len) {
×
1385
        return -1;
×
1386
      } else {
1387
        // wordPattern->len > wordInput->len
UNCOV
1388
        if (strncasecmp(wordPattern->word, wordInput->word, wordInput->len) == 0) {
×
1389
          if (i + 1 == cmdInput->count) {
×
1390
            // last word return match
UNCOV
1391
            cmdPattern->matchIndex = i;
×
1392
            cmdPattern->matchLen = wordInput->len;
×
1393
            return i;
×
1394
          } else {
UNCOV
1395
            return -1;
×
1396
          }
1397
        } else {
UNCOV
1398
          return -1;
×
1399
        }
1400
      }
1401
    } else {
1402
      // WT_VAR auto match any one word
UNCOV
1403
      if (wordInput->next == NULL) {  // input words last one
×
1404
        if (matchVarWord(wordPattern, wordInput)) {
×
1405
          cmdPattern->matchIndex = i;
×
1406
          cmdPattern->matchLen = wordInput->len;
×
1407
          varMode = true;
×
1408
          return i;
×
1409
        }
UNCOV
1410
        return -1;
×
1411
      }
1412
    }
1413

1414
    // move next
UNCOV
1415
    wordPattern = wordPattern->next;
×
1416
    wordInput = wordInput->next;
×
1417
    if (wordPattern == NULL || wordInput == NULL) {
×
1418
      return -1;
×
1419
    }
1420
  }
1421

UNCOV
1422
  return -1;
×
1423
}
1424

1425
// match command
UNCOV
1426
SWords* matchCommand(SWords* input, bool continueSearch) {
×
1427
  int32_t count = SHELL_COMMAND_COUNT();
×
1428
  for (int32_t i = 0; i < count; i++) {
×
1429
    SWords* shellCommand = shellCommands + i;
×
1430
    if (continueSearch && lastMatchIndex != -1 && i <= lastMatchIndex) {
×
1431
      // new match must greater than lastMatchIndex
UNCOV
1432
      if (varMode && i == lastMatchIndex) {
×
1433
        // do nothing, var match on lastMatchIndex
1434
      } else {
UNCOV
1435
        continue;
×
1436
      }
1437
    }
1438

1439
    // command is large
UNCOV
1440
    if (input->count > shellCommand->count) {
×
1441
      continue;
×
1442
    }
1443

1444
    // compare
UNCOV
1445
    int32_t index = compareCommand(shellCommand, input);
×
1446
    if (index != -1) {
×
1447
      if (firstMatchIndex == -1) firstMatchIndex = i;
×
1448
      curMatchIndex = i;
×
1449
      return &shellCommands[i];
×
1450
    }
1451
  }
1452

1453
  // not match
UNCOV
1454
  return NULL;
×
1455
}
1456

1457
//
1458
//  -------------------  print screen --------------------------
1459
//
1460

1461
// delete char count
UNCOV
1462
void deleteCount(SShellCmd* cmd, int count) {
×
1463
  int size = 0;
×
1464
  int width = 0;
×
1465
  int prompt_size = 6;
×
1466
  shellClearScreen(cmd->endOffset + prompt_size, cmd->screenOffset + prompt_size);
×
1467

1468
  // loop delete
UNCOV
1469
  while (--count >= 0 && cmd->cursorOffset > 0) {
×
1470
    shellGetPrevCharSize(cmd->command, cmd->cursorOffset, &size, &width);
×
1471
    memmove(cmd->command + cmd->cursorOffset - size, cmd->command + cmd->cursorOffset,
×
1472
            cmd->commandSize - cmd->cursorOffset);
×
1473
    cmd->commandSize -= size;
×
1474
    cmd->cursorOffset -= size;
×
1475
    cmd->screenOffset -= width;
×
1476
    cmd->endOffset -= width;
×
1477
  }
UNCOV
1478
}
×
1479

1480
// show screen
UNCOV
1481
void printScreen(TAOS* con, SShellCmd* cmd, SWords* match) {
×
1482
  // modify SShellCmd
UNCOV
1483
  if (firstMatchIndex == -1 || curMatchIndex == -1) {
×
1484
    // no match
UNCOV
1485
    return;
×
1486
  }
1487

1488
  // first tab press
UNCOV
1489
  const char* str = NULL;
×
1490
  int         strLen = 0;
×
1491

UNCOV
1492
  SWord* word = MATCH_WORD(match);
×
1493
  if (firstMatchIndex == curMatchIndex && lastWordBytes == -1) {
×
1494
    // first press tab
UNCOV
1495
    str = word->word + match->matchLen;
×
1496
    strLen = word->len - match->matchLen;
×
1497
    lastMatchIndex = firstMatchIndex;
×
1498
    lastWordBytes = word->len;
×
1499
  } else {
UNCOV
1500
    if (lastWordBytes == -1) return;
×
1501
    deleteCount(cmd, lastWordBytes);
×
1502
    str = word->word;
×
1503
    strLen = word->len;
×
1504
    // set current to last
UNCOV
1505
    lastMatchIndex = curMatchIndex;
×
1506
    lastWordBytes = word->len;
×
1507
  }
1508

UNCOV
1509
  if (word->end && str[strLen - 1] != ';') {
×
1510
    // append end ';'
UNCOV
1511
    char* p = taosMemoryCalloc(strLen + 8, 1);
×
1512
    if (p) {
×
1513
      tstrncpy(p, str, strLen + 1);
×
1514
      tstrncpy(p + strLen, ";", 1 + 1);
×
1515
      lastWordBytes += 1;
×
1516
      shellInsertStr(cmd, (char*)p, strLen + 1);
×
1517
      taosMemoryFree(p);
×
1518
    } else {
UNCOV
1519
      shellInsertStr(cmd, (char*)str, strLen);
×
1520
    }
1521
  } else {
1522
    // insert new
UNCOV
1523
    shellInsertStr(cmd, (char*)str, strLen);
×
1524
  }
1525
}
1526

1527
// main key press tab , matched return true else false
UNCOV
1528
bool firstMatchCommand(TAOS* con, SShellCmd* cmd) {
×
1529
  if (con == NULL || cmd == NULL) return false;
×
1530
  // parse command
UNCOV
1531
  SWords* input = (SWords*)taosMemoryMalloc(sizeof(SWords));
×
1532
  memset(input, 0, sizeof(SWords));
×
1533
  input->source = cmd->command;
×
1534
  input->source_len = cmd->commandSize;
×
1535
  parseCommand(input, false);
×
1536

1537
  // if have many , default match first, if press tab again , switch to next
UNCOV
1538
  curMatchIndex = -1;
×
1539
  lastMatchIndex = -1;
×
1540
  SWords* match = matchCommand(input, true);
×
1541
  if (match == NULL) {
×
1542
    // not match , nothing to do
UNCOV
1543
    freeCommand(input);
×
1544
    taosMemoryFree(input);
×
1545
    return false;
×
1546
  }
1547

1548
  // print to screen
UNCOV
1549
  printScreen(con, cmd, match);
×
1550
#ifdef WINDOWS
1551
  printf("\r");
1552
  shellShowOnScreen(cmd);
1553
#endif
UNCOV
1554
  freeCommand(input);
×
1555
  taosMemoryFree(input);
×
1556
  return true;
×
1557
}
1558

1559
// create input source
UNCOV
1560
void createInputFromFirst(SWords* input, SWords* firstMatch) {
×
1561
  //
1562
  // if next pressTabKey , input context come from firstMatch, set matched length with source_len
1563
  //
UNCOV
1564
  input->source = (char*)taosMemoryMalloc(1024);
×
1565
  memset((void*)input->source, 0, 1024);
×
1566

UNCOV
1567
  SWord* word = firstMatch->head;
×
1568

1569
  // source_len = full match word->len + half match with firstMatch->matchLen
UNCOV
1570
  for (int i = 0; i < firstMatch->matchIndex && word; i++) {
×
1571
    // combine source from each word
UNCOV
1572
    strncpy(input->source + input->source_len, word->word, word->len);
×
1573
    strcat(input->source, " ");          // append blank space
×
1574
    input->source_len += word->len + 1;  // 1 is blank length
×
1575
    // move next
UNCOV
1576
    word = word->next;
×
1577
  }
1578
  // appand half matched word for last
UNCOV
1579
  if (word) {
×
1580
    strncpy(input->source + input->source_len, word->word, firstMatch->matchLen);
×
1581
    input->source_len += firstMatch->matchLen;
×
1582
  }
UNCOV
1583
}
×
1584

1585
// user press Tabkey again is named next , matched return true else false
UNCOV
1586
bool nextMatchCommand(TAOS* con, SShellCmd* cmd, SWords* firstMatch) {
×
1587
  if (firstMatch == NULL || firstMatch->head == NULL) {
×
1588
    return false;
×
1589
  }
UNCOV
1590
  SWords* input = (SWords*)taosMemoryMalloc(sizeof(SWords));
×
1591
  memset(input, 0, sizeof(SWords));
×
1592

1593
  // create input from firstMatch
UNCOV
1594
  createInputFromFirst(input, firstMatch);
×
1595

1596
  // parse input
UNCOV
1597
  parseCommand(input, false);
×
1598

1599
  // if have many , default match first, if press tab again , switch to next
UNCOV
1600
  SWords* match = matchCommand(input, true);
×
1601
  if (match == NULL) {
×
1602
    // if not match , reset all index
UNCOV
1603
    firstMatchIndex = -1;
×
1604
    curMatchIndex = -1;
×
1605
    match = matchCommand(input, false);
×
1606
    if (match == NULL) {
×
1607
      freeCommand(input);
×
1608
      if (input->source) taosMemoryFree(input->source);
×
1609
      taosMemoryFree(input);
×
1610
      return false;
×
1611
    }
1612
  }
1613

1614
  // print to screen
UNCOV
1615
  printScreen(con, cmd, match);
×
1616
#ifdef WINDOWS
1617
  printf("\r");
1618
  shellShowOnScreen(cmd);
1619
#endif
1620

1621
  // free
UNCOV
1622
  freeCommand(input);
×
1623
  if (input->source) {
×
1624
    taosMemoryFree(input->source);
×
1625
    input->source = NULL;
×
1626
  }
UNCOV
1627
  taosMemoryFree(input);
×
1628

UNCOV
1629
  return true;
×
1630
}
1631

1632
// fill with type
UNCOV
1633
bool fillWithType(TAOS* con, SShellCmd* cmd, char* pre, int type) {
×
1634
  // get type
UNCOV
1635
  STire* tire = tires[type];
×
1636
  char*  str = matchNextPrefix(tire, pre);
×
1637
  if (str == NULL) {
×
1638
    return false;
×
1639
  }
1640

1641
  // need insert part string
UNCOV
1642
  char* part = str + strlen(pre);
×
1643

1644
  // show
UNCOV
1645
  int count = strlen(part);
×
1646
  shellInsertStr(cmd, part, count);
×
1647
  cntDel = count;  // next press tab delete current append count
×
1648

UNCOV
1649
  taosMemoryFree(str);
×
1650
  return true;
×
1651
}
1652

1653
// fill with type
UNCOV
1654
bool fillTableName(TAOS* con, SShellCmd* cmd, char* pre) {
×
1655
  // search stable and table
UNCOV
1656
  char* str = tireSearchWord(WT_VAR_STABLE, pre);
×
1657
  if (str == NULL) {
×
1658
    str = tireSearchWord(WT_VAR_TABLE, pre);
×
1659
    if (str == NULL) return false;
×
1660
  }
1661

1662
  // need insert part string
UNCOV
1663
  char* part = str + strlen(pre);
×
1664

1665
  // delete autofill count last append
UNCOV
1666
  if (cntDel > 0) {
×
1667
    deleteCount(cmd, cntDel);
×
1668
    cntDel = 0;
×
1669
  }
1670

1671
  // show
UNCOV
1672
  int count = strlen(part);
×
1673
  shellInsertStr(cmd, part, count);
×
1674
  cntDel = count;  // next press tab delete current append count
×
1675

UNCOV
1676
  taosMemoryFree(str);
×
1677
  return true;
×
1678
}
1679

1680
//
1681
// find last word from sql select clause
1682
//  example :
1683
//  1 select cou -> press tab  select count(
1684
//  2 select count(*),su -> select count(*), sum(
1685
//  3 select count(*), su -> select count(*), sum(
1686
//
UNCOV
1687
char* lastWord(char* p) {
×
1688
  // get near from end revert find ' ' and ','
UNCOV
1689
  char* p1 = strrchr(p, ' ');
×
1690
  char* p2 = strrchr(p, ',');
×
1691

UNCOV
1692
  if (p1 && p2) {
×
1693
    return p1 > p2 ? p1 + 1 : p2 + 1;
×
1694
  } else if (p1) {
×
1695
    return p1 + 1;
×
1696
  } else if (p2) {
×
1697
    return p2 + 1;
×
1698
  } else {
UNCOV
1699
    return p;
×
1700
  }
1701
}
1702

UNCOV
1703
bool fieldsInputEnd(char* sql) {
×
1704
  // not in '()'
UNCOV
1705
  char* p1 = strrchr(sql, '(');
×
1706
  char* p2 = strrchr(sql, ')');
×
1707
  if (p1 && p2 == NULL) {
×
1708
    // like select count( '  '
UNCOV
1709
    return false;
×
1710
  } else if (p1 && p2 && p1 > p2) {
×
1711
    // like select sum(age), count( ' '
UNCOV
1712
    return false;
×
1713
  }
1714

1715
  // not in ','
UNCOV
1716
  char* p3 = strrchr(sql, ',');
×
1717
  char* p = p3;
×
1718
  // like select ts, age,'    '
UNCOV
1719
  if (p) {
×
1720
    ++p;
×
1721
    bool  allBlank = true;  // after last ','  all char is blank
×
1722
    int   cnt = 0;          // blank count , like '    ' as one blank
×
1723
    char* plast = NULL;     // last blank position
×
1724
    while (*p) {
×
1725
      if (*p == ' ') {
×
1726
        plast = p;
×
1727
        cnt++;
×
1728
      } else {
UNCOV
1729
        allBlank = false;
×
1730
      }
UNCOV
1731
      ++p;
×
1732
    }
1733

1734
    // any one word is not blank
UNCOV
1735
    if (allBlank) {
×
1736
      return false;
×
1737
    }
1738

1739
    // like 'select count(*),sum(age) fr' need return true
UNCOV
1740
    if (plast && plast > p3 && p2 > p1 && plast > p2 && p1 > p3) {
×
1741
      return true;
×
1742
    }
1743

1744
    // if last char not ' ', then not end field, like 'select count(*), su' can fill sum(
UNCOV
1745
    if (sql[strlen(sql) - 1] != ' ' && cnt <= 1) {
×
1746
      return false;
×
1747
    }
1748
  }
1749

UNCOV
1750
  char* p4 = strrchr(sql, ' ');
×
1751
  if (p4 == NULL) {
×
1752
    // only one word
UNCOV
1753
    return false;
×
1754
  }
1755

UNCOV
1756
  return true;
×
1757
}
1758

1759
// need insert from
UNCOV
1760
bool needInsertFrom(char* sql, int len) {
×
1761
  // last is blank
UNCOV
1762
  if (sql[len - 1] != ' ') {
×
1763
    // insert from keyword
UNCOV
1764
    return false;
×
1765
  }
1766

1767
  //  select fields input is end
UNCOV
1768
  if (!fieldsInputEnd(sql)) {
×
1769
    return false;
×
1770
  }
1771

1772
  // can insert from keyword
UNCOV
1773
  return true;
×
1774
}
1775

1776
// p is string following select keyword
UNCOV
1777
bool appendAfterSelect(TAOS* con, SShellCmd* cmd, char* sql, int32_t len) {
×
1778
  char* p = taosStrndup(sql, len);
×
1779

1780
  // union all
1781
  char* p1;
1782
  do {
UNCOV
1783
    p1 = strstr(p, UNION_ALL);
×
1784
    if (p1) {
×
1785
      p = p1 + strlen(UNION_ALL);
×
1786
    }
UNCOV
1787
  } while (p1);
×
1788

UNCOV
1789
  char* from = strstr(p, " from ");
×
1790
  // last word , maybe empty string or some letters of a string
UNCOV
1791
  char* last = lastWord(p);
×
1792
  bool  ret = false;
×
1793
  if (from == NULL) {
×
1794
    bool fieldEnd = fieldsInputEnd(p);
×
1795
    // check fields input end then insert from keyword
UNCOV
1796
    if (fieldEnd && p[len - 1] == ' ') {
×
1797
      shellInsertStr(cmd, "from", 4);
×
1798
      taosMemoryFree(p);
×
1799
      return true;
×
1800
    }
1801

1802
    // fill function
UNCOV
1803
    if (fieldEnd) {
×
1804
      // fields is end , need match keyword
UNCOV
1805
      ret = fillWithType(con, cmd, last, WT_VAR_KEYWORD);
×
1806
    } else {
UNCOV
1807
      ret = fillWithType(con, cmd, last, WT_VAR_FUNC);
×
1808
    }
1809

UNCOV
1810
    taosMemoryFree(p);
×
1811
    return ret;
×
1812
  }
1813

1814
  // have from
UNCOV
1815
  char* blank = strstr(from + 6, " ");
×
1816
  if (blank == NULL) {
×
1817
    // no table name, need fill
UNCOV
1818
    ret = fillTableName(con, cmd, last);
×
1819
  } else {
UNCOV
1820
    ret = fillWithType(con, cmd, last, WT_VAR_KEYWORD);
×
1821
  }
1822

UNCOV
1823
  taosMemoryFree(p);
×
1824
  return ret;
×
1825
}
1826

UNCOV
1827
int32_t searchAfterSelect(char* p, int32_t len) {
×
1828
  // select * from st;
UNCOV
1829
  if (strncasecmp(p, "select ", 7) == 0) {
×
1830
    // check nest query
UNCOV
1831
    char* p1 = p + 7;
×
1832
    while (1) {
×
1833
      char* p2 = strstr(p1, "select ");
×
1834
      if (p2 == NULL) break;
×
1835
      p1 = p2 + 7;
×
1836
    }
1837

UNCOV
1838
    return p1 - p;
×
1839
  }
1840

1841
  // explain as select * from st;
UNCOV
1842
  if (strncasecmp(p, "explain select ", 15) == 0) {
×
1843
    return 15;
×
1844
  }
1845

UNCOV
1846
  char* as_pos_end = strstr(p, " as select ");
×
1847
  if (as_pos_end == NULL) return -1;
×
1848
  as_pos_end += 11;
×
1849

1850
  // create stream <stream_name> as select
UNCOV
1851
  if (strncasecmp(p, "create stream ", 14) == 0) {
×
1852
    return as_pos_end - p;
×
1853
    ;
1854
  }
1855

1856
  // create topic <topic_name> as select
UNCOV
1857
  if (strncasecmp(p, "create topic ", 13) == 0) {
×
1858
    return as_pos_end - p;
×
1859
  }
1860

UNCOV
1861
  return -1;
×
1862
}
1863

UNCOV
1864
bool matchSelectQuery(TAOS* con, SShellCmd* cmd) {
×
1865
  // if continue press Tab , delete bytes by previous autofill
UNCOV
1866
  if (cntDel > 0) {
×
1867
    deleteCount(cmd, cntDel);
×
1868
    cntDel = 0;
×
1869
  }
1870

1871
  // match select ...
UNCOV
1872
  int   len = cmd->commandSize;
×
1873
  char* p = cmd->command;
×
1874

1875
  // remove prefix blank
UNCOV
1876
  while (p[0] == ' ' && len > 0) {
×
1877
    p++;
×
1878
    len--;
×
1879
  }
1880

1881
  // special range
UNCOV
1882
  if (len < 7 || len > 512) {
×
1883
    return false;
×
1884
  }
1885

1886
  // search
UNCOV
1887
  char*   sql_cp = taosStrndup(p, len);
×
1888
  int32_t n = searchAfterSelect(sql_cp, len);
×
1889
  taosMemoryFree(sql_cp);
×
1890
  if (n == -1 || n > len) return false;
×
1891
  p += n;
×
1892
  len -= n;
×
1893

1894
  // append
UNCOV
1895
  return appendAfterSelect(con, cmd, p, len);
×
1896
}
1897

1898
// is fields option area
UNCOV
1899
bool fieldOptionsArea(char* p) {
×
1900
  char* p1 = strrchr(p, '(');
×
1901
  char* p2 = strrchr(p, ',');
×
1902
  if (p1 == NULL && p2 == NULL) {
×
1903
    return false;
×
1904
  }
1905

1906
  // find tags
UNCOV
1907
  if (strstr(p, " tags") != NULL) {
×
1908
    return false;
×
1909
  }
1910

UNCOV
1911
  if (p2 == NULL) {
×
1912
    // first field area
UNCOV
1913
    p2 = p1;
×
1914
  }
1915

1916
  // find blank count
UNCOV
1917
  int32_t cnt = 0;
×
1918
  while (p2) {
×
1919
    p2 = strchr(p2, ' ');
×
1920
    if (p2) {
×
1921
      // get prev char
UNCOV
1922
      char prec = *(p2 - 1);
×
1923
      if (prec != ',' && prec != '(') {
×
1924
        // blank if before comma, not calc count.  like st(ts timestamp,  age int + BLANK + TAB only two blank
UNCOV
1925
        cnt++;
×
1926
      }
1927

1928
      // continue blank is one blank
UNCOV
1929
      while (p2[1] != 0 && p2[1] == ' ') {
×
1930
        // move next if blank again
UNCOV
1931
        p2 += 1;
×
1932
      }
UNCOV
1933
      p2 += 1;
×
1934
    }
1935
  }
1936

1937
  // like  create table st(ts timestamp TAB-KEY or  st(ts timestamp , age int TAB-KEY
UNCOV
1938
  return cnt >= 2;
×
1939
}
1940

1941
// if is input create fields or tags area, return true
UNCOV
1942
bool isCreateFieldsArea(char* p) {
×
1943
  int32_t n = 0;  // count
×
1944
  char*  p1 = p;
×
1945
  while (*p1 != 0) {
×
1946
    switch (*p1) {
×
1947
      case '(':
×
1948
        ++n;
×
1949
        break;
×
1950
      case ')':
×
1951
        --n;
×
1952
        break;
×
1953
      default:
×
1954
        break;
×
1955
    }
1956
    // move next
UNCOV
1957
    ++p1;
×
1958
  }
1959

UNCOV
1960
  return n > 0;
×
1961
}
1962

UNCOV
1963
bool matchCreateTable(TAOS* con, SShellCmd* cmd) {
×
1964
  // if continue press Tab , delete bytes by previous autofill
UNCOV
1965
  if (cntDel > 0) {
×
1966
    deleteCount(cmd, cntDel);
×
1967
    cntDel = 0;
×
1968
  }
1969

1970
  // match select ...
UNCOV
1971
  int   len = cmd->commandSize;
×
1972
  char* p = cmd->command;
×
1973

1974
  // remove prefix blank
UNCOV
1975
  while (p[0] == ' ' && len > 0) {
×
1976
    p++;
×
1977
    len--;
×
1978
  }
1979

1980
  // special range
UNCOV
1981
  if (len < 7 || len > 1024) {
×
1982
    return false;
×
1983
  }
1984

1985
  // select and from
UNCOV
1986
  if (strncasecmp(p, "create table ", 13) != 0) {
×
1987
    // not select query clause
UNCOV
1988
    return false;
×
1989
  }
UNCOV
1990
  p += 13;
×
1991
  len -= 13;
×
1992

UNCOV
1993
  char* ps = taosStrndup(p, len);
×
1994
  bool  ret = false;
×
1995
  char* last = lastWord(ps);
×
1996

1997
  // check in create fields or tags input area
UNCOV
1998
  if (isCreateFieldsArea(ps)) {
×
1999
    if (fieldOptionsArea(ps)) {
×
2000
      // fill field options
UNCOV
2001
      ret = fillWithType(con, cmd, last, WT_VAR_FIELD_OPTIONS);
×
2002
    } else {
2003
      // fill field
UNCOV
2004
      ret = fillWithType(con, cmd, last, WT_VAR_DATATYPE);
×
2005
    }
2006
  }
2007

2008
  // tags
UNCOV
2009
  if (!ret) {
×
2010
    // find only one ')' , can insert tags
UNCOV
2011
    char* p1 = strchr(ps, ')');
×
2012
    if (p1) {
×
2013
      if (strstr(p1 + 1, "tags") == NULL) {
×
2014
        // can insert tags keyword
UNCOV
2015
        ret = fillWithType(con, cmd, last, WT_VAR_KEYTAGS);
×
2016
      }
2017
    }
2018
  }
2019

2020
  // tb options
UNCOV
2021
  if (!ret) {
×
2022
    // find like create table st (...) tags(..)  <here is fill tb option area>
UNCOV
2023
    char* p1 = strchr(ps, ')');  // first ')' end
×
2024
    if (p1) {
×
2025
      if (strchr(p1 + 1, ')')) {  // second ')' end
×
2026
        // here is tb options area, can insert option
UNCOV
2027
        ret = fillWithType(con, cmd, last, WT_VAR_TBOPTION);
×
2028
      }
2029
    }
2030
  }
2031

UNCOV
2032
  taosMemoryFree(ps);
×
2033
  return ret;
×
2034
}
2035

UNCOV
2036
bool matchOther(TAOS* con, SShellCmd* cmd) {
×
2037
  int   len = cmd->commandSize;
×
2038
  char* p = cmd->command;
×
2039

2040
  // '\\'
UNCOV
2041
  if (p[len - 1] == '\\') {
×
2042
    // append '\G'
UNCOV
2043
    char a[] = "G;";
×
2044
    shellInsertStr(cmd, a, 2);
×
2045
    return true;
×
2046
  }
2047

2048
  // too small
UNCOV
2049
  if (len < 8) return false;
×
2050

2051
  // like 'from ( '
UNCOV
2052
  char* sql = taosStrndup(p, len);
×
2053
  char* last = lastWord(sql);
×
2054

UNCOV
2055
  if (strcmp(last, "from(") == 0) {
×
2056
    fillWithType(con, cmd, "", WT_VAR_KEYSELECT);
×
2057
    taosMemoryFree(sql);
×
2058
    return true;
×
2059
  }
UNCOV
2060
  if (strncmp(last, "(", 1) == 0) {
×
2061
    last += 1;
×
2062
  }
2063

UNCOV
2064
  char* from = strstr(sql, " from");
×
2065
  // find last ' from'
UNCOV
2066
  while (from) {
×
2067
    char* p1 = strstr(from + 5, " from");
×
2068
    if (p1 == NULL) break;
×
2069
    from = p1;
×
2070
  }
2071

UNCOV
2072
  if (from) {
×
2073
    // find next is '('
UNCOV
2074
    char* p2 = from + 5;
×
2075
    bool  found = false;   // found 'from ... ( ...'  ... is any count of blank
×
2076
    bool  found1 = false;  // found '('
×
2077
    while (1) {
UNCOV
2078
      if (p2 == last || *p2 == '\0') {
×
2079
        // last word or string end
UNCOV
2080
        if (found1) {
×
2081
          found = true;
×
2082
        }
UNCOV
2083
        break;
×
2084
      } else if (*p2 == '(') {
×
2085
        found1 = true;
×
2086
      } else if (*p2 == ' ') {
×
2087
        // do nothing
2088
      } else {
2089
        // have any other char
UNCOV
2090
        break;
×
2091
      }
2092

2093
      // move next
UNCOV
2094
      p2++;
×
2095
    }
2096

UNCOV
2097
    if (found) {
×
2098
      fillWithType(con, cmd, last, WT_VAR_KEYSELECT);
×
2099
      taosMemoryFree(sql);
×
2100
      return true;
×
2101
    }
2102
  }
2103

2104
  // INSERT
2105

UNCOV
2106
  taosMemoryFree(sql);
×
2107

UNCOV
2108
  return false;
×
2109
}
2110

2111
// last match if nothing matched
UNCOV
2112
bool matchEnd(TAOS* con, SShellCmd* cmd) {
×
2113
  // str dump
UNCOV
2114
  bool  ret = false;
×
2115
  char* ps = taosStrndup(cmd->command, cmd->commandSize);
×
2116
  char* last = lastWord(ps);
×
2117
  char* elast = strrchr(last, '.');  // find end last
×
2118
  if (elast) {
×
2119
    last = elast + 1;
×
2120
  }
2121

2122
  // less one char can match
UNCOV
2123
  if (strlen(last) == 0) {
×
2124
    goto _return;
×
2125
  }
UNCOV
2126
  if (strcmp(last, " ") == 0) {
×
2127
    goto _return;
×
2128
  }
2129

2130
  // match database
UNCOV
2131
  if (elast == NULL) {
×
2132
    // dot need not completed with dbname
UNCOV
2133
    if (fillWithType(con, cmd, last, WT_VAR_DBNAME)) {
×
2134
      ret = true;
×
2135
      goto _return;
×
2136
    }
2137
  }
2138

UNCOV
2139
  if (fillWithType(con, cmd, last, WT_VAR_SYSTABLE)) {
×
2140
    ret = true;
×
2141
    goto _return;
×
2142
  }
2143

2144
  // global keys
UNCOV
2145
  if (fillWithType(con, cmd, last, WT_VAR_GLOBALKEYS)) {
×
2146
    ret = true;
×
2147
    goto _return;
×
2148
  }
2149

2150

UNCOV
2151
_return:
×
2152
  taosMemoryFree(ps);
×
2153
  return ret;
×
2154
}
2155

2156
// main key press tab
UNCOV
2157
void pressTabKey(SShellCmd* cmd) {
×
2158
#ifdef WINDOWS
2159
  return ;
2160
#endif
2161
  // check empty tab key
UNCOV
2162
  if (cmd->commandSize == 0) {
×
2163
    // have multi line tab key
UNCOV
2164
    if (cmd->bufferSize == 0) {
×
2165
      showHelp();
×
2166
    }
UNCOV
2167
    shellShowOnScreen(cmd);
×
2168
    return;
×
2169
  }
2170

2171
  // save connection to global
UNCOV
2172
  varCmd = cmd;
×
2173
  bool matched = false;
×
2174

2175
  // manual match like create table st( ...
UNCOV
2176
  matched = matchCreateTable(varCon, cmd);
×
2177
  if (matched) return;
×
2178

2179
  // shellCommands match
UNCOV
2180
  if (firstMatchIndex == -1) {
×
2181
    matched = firstMatchCommand(varCon, cmd);
×
2182
  } else {
UNCOV
2183
    matched = nextMatchCommand(varCon, cmd, &shellCommands[firstMatchIndex]);
×
2184
  }
UNCOV
2185
  if (matched) return;
×
2186

2187
  // NOT MATCHED ANYONE
2188
  // match other like '\G' ...
UNCOV
2189
  matched = matchOther(varCon, cmd);
×
2190
  if (matched) return;
×
2191

2192
  // manual match like select * from ...
UNCOV
2193
  matched = matchSelectQuery(varCon, cmd);
×
2194
  if (matched) return;
×
2195

2196
  // match end
UNCOV
2197
  matched = matchEnd(varCon, cmd);
×
2198

UNCOV
2199
  return;
×
2200
}
2201

2202
// press othr key
2203
void pressOtherKey(char c) {
4,494✔
2204
#ifdef WINDOWS
2205
  return ;
2206
#endif
2207

2208
  // reset global variant
2209
  firstMatchIndex = -1;
4,494✔
2210
  lastMatchIndex = -1;
4,494✔
2211
  curMatchIndex = -1;
4,494✔
2212
  lastWordBytes = -1;
4,494✔
2213

2214
  // var names
2215
  cursorVar = -1;
4,494✔
2216
  varMode = false;
4,494✔
2217
  waitAutoFill = false;
4,494✔
2218
  cntDel = 0;
4,494✔
2219

2220
  if (lastMatch) {
4,494✔
UNCOV
2221
    freeMatch(lastMatch);
×
2222
    lastMatch = NULL;
×
2223
  }
2224
}
4,494✔
2225

2226
// put name into name, return name length
2227
int getWordName(char* p, char* name, int nameLen) {
18,724✔
2228
  // remove prefix blank
2229
  while (*p == ' ') {
21,535✔
2230
    p++;
2,811✔
2231
  }
2232

2233
  // get databases name;
2234
  int i = 0;
18,724✔
2235
  while (p[i] != 0 && i < nameLen - 1) {
67,540✔
2236
    name[i] = p[i];
67,500✔
2237
    i++;
67,500✔
2238
    if (p[i] == ' ' || p[i] == ';' || p[i] == '(') {
67,500✔
2239
      // name end
2240
      break;
2241
    }
2242
  }
2243
  name[i] = 0;
18,724✔
2244

2245
  return i;
18,724✔
2246
}
2247

2248
// deal use db, if have  'use' return true
2249
bool dealUseDB(char* sql) {
1,240,819✔
2250
  // check use keyword
2251
  if (strncasecmp(sql, "use ", 4) != 0) {
1,240,819✔
2252
    return false;
1,228,513✔
2253
  }
2254

2255
  char  db[256];
12,306✔
2256
  char* p = sql + 4;
12,306✔
2257
  if (getWordName(p, db, sizeof(db)) == 0) {
12,306✔
2258
    // no name , return
UNCOV
2259
    return true;
×
2260
  }
2261

2262
  //  dbName is previous use open db name
2263
  if (strcasecmp(db, dbName) == 0) {
12,306✔
2264
    // same , no need switch
UNCOV
2265
    return true;
×
2266
  }
2267

2268
  // switch new db
2269
  taosThreadMutexLock(&tiresMutex);
12,306✔
2270
  // STABLE set null
2271
  STire* tire = tires[WT_VAR_STABLE];
12,306✔
2272
  tires[WT_VAR_STABLE] = NULL;
12,306✔
2273
  if (tire) {
12,306✔
UNCOV
2274
    freeTire(tire);
×
2275
  }
2276
  // TABLE set null
2277
  tire = tires[WT_VAR_TABLE];
12,306✔
2278
  tires[WT_VAR_TABLE] = NULL;
12,306✔
2279
  if (tire) {
12,306✔
UNCOV
2280
    freeTire(tire);
×
2281
  }
2282
  // save
2283
  strcpy(dbName, db);
12,306✔
2284
  taosThreadMutexUnlock(&tiresMutex);
12,306✔
2285

2286
  return true;
12,306✔
2287
}
2288

2289
// deal create, if have 'create' return true
2290
bool dealCreateCommand(char* sql) {
1,228,513✔
2291
  // check keyword
2292
  if (strncasecmp(sql, "create ", 7) != 0) {
1,228,513✔
2293
    return false;
1,225,397✔
2294
  }
2295

2296
  char  name[1024];
3,101✔
2297
  char* p = sql + 7;
3,116✔
2298
  if (getWordName(p, name, sizeof(name)) == 0) {
3,116✔
2299
    // no name , return
UNCOV
2300
    return true;
×
2301
  }
2302

2303
  int type = -1;
3,116✔
2304
  //  dbName is previous use open db name
2305
  if (strcasecmp(name, "database") == 0) {
3,116✔
2306
    type = WT_VAR_DBNAME;
787✔
2307
  } else if (strcasecmp(name, "table") == 0) {
2,329✔
2308
    if (strstr(sql, " tags") != NULL && strstr(sql, " using ") == NULL)
1,533✔
2309
      type = WT_VAR_STABLE;
153✔
2310
    else
2311
      type = WT_VAR_TABLE;
1,380✔
2312
  } else if (strcasecmp(name, "user") == 0) {
796✔
UNCOV
2313
    type = WT_VAR_USERNAME;
×
2314
  } else if (strcasecmp(name, "topic") == 0) {
796✔
UNCOV
2315
    type = WT_VAR_TOPIC;
×
2316
  } else if (strcasecmp(name, "stream") == 0) {
796✔
UNCOV
2317
    type = WT_VAR_STREAM;
×
2318
  } else {
2319
    // no match , return
2320
    return true;
796✔
2321
  }
2322

2323
  // move next
2324
  p += strlen(name);
2,320✔
2325

2326
  // get next word , that is table name
2327
  if (getWordName(p, name, sizeof(name)) == 0) {
2,320✔
2328
    // no name , return
UNCOV
2329
    return true;
×
2330
  }
2331

2332
  // switch new db
2333
  taosThreadMutexLock(&tiresMutex);
2,320✔
2334
  // STABLE set null
2335
  STire* tire = tires[type];
2,320✔
2336
  if (tire) {
2,320✔
2337
    insertWord(tire, name);
210✔
2338
  }
2339
  taosThreadMutexUnlock(&tiresMutex);
2,320✔
2340

2341
  return true;
2,320✔
2342
}
2343

2344
// deal create, if have 'drop' return true
2345
bool dealDropCommand(char* sql) {
1,225,397✔
2346
  // check keyword
2347
  if (strncasecmp(sql, "drop ", 5) != 0) {
1,225,397✔
2348
    return false;
1,224,906✔
2349
  }
2350

2351
  char  name[1024];
194✔
2352
  char* p = sql + 5;
491✔
2353
  if (getWordName(p, name, sizeof(name)) == 0) {
491✔
2354
    // no name , return
UNCOV
2355
    return true;
×
2356
  }
2357

2358
  int type = -1;
491✔
2359
  //  dbName is previous use open db name
2360
  if (strcasecmp(name, "database") == 0) {
491✔
2361
    type = WT_VAR_DBNAME;
455✔
2362
  } else if (strcasecmp(name, "table") == 0) {
36✔
UNCOV
2363
    type = WT_VAR_ALLTABLE;
×
2364
  } else if (strcasecmp(name, "dnode") == 0) {
36✔
UNCOV
2365
    type = WT_VAR_DNODEID;
×
2366
  } else if (strcasecmp(name, "user") == 0) {
36✔
UNCOV
2367
    type = WT_VAR_USERNAME;
×
2368
  } else if (strcasecmp(name, "topic") == 0) {
36✔
2369
    type = WT_VAR_TOPIC;
36✔
UNCOV
2370
  } else if (strcasecmp(name, "stream") == 0) {
×
2371
    type = WT_VAR_STREAM;
×
2372
  } else {
2373
    // no match , return
UNCOV
2374
    return true;
×
2375
  }
2376

2377
  // move next
2378
  p += strlen(name);
491✔
2379

2380
  // get next word , that is table name
2381
  if (getWordName(p, name, sizeof(name)) == 0) {
491✔
2382
    // no name , return
UNCOV
2383
    return true;
×
2384
  }
2385

2386
  // switch new db
2387
  taosThreadMutexLock(&tiresMutex);
491✔
2388
  // STABLE set null
2389
  if (type == WT_VAR_ALLTABLE) {
491✔
UNCOV
2390
    bool del = false;
×
2391
    // del in stable
UNCOV
2392
    STire* tire = tires[WT_VAR_STABLE];
×
2393
    if (tire) del = deleteWord(tire, name);
×
2394
    // del in table
UNCOV
2395
    if (!del) {
×
2396
      tire = tires[WT_VAR_TABLE];
×
2397
      if (tire) del = deleteWord(tire, name);
×
2398
    }
2399
  } else {
2400
    // OTHER TYPE
2401
    STire* tire = tires[type];
491✔
2402
    if (tire) deleteWord(tire, name);
491✔
2403
  }
2404
  taosThreadMutexUnlock(&tiresMutex);
491✔
2405

2406
  return true;
491✔
2407
}
2408

2409
// callback autotab module after shell sql execute
2410
void callbackAutoTab(char* sqlstr, TAOS* pSql, bool usedb) {
1,240,819✔
2411
  char* sql = sqlstr;
1,240,819✔
2412
  // remove prefix blank
2413
  while (*sql == ' ') {
1,240,819✔
UNCOV
2414
    sql++;
×
2415
  }
2416

2417
  if (dealUseDB(sql)) {
1,240,819✔
2418
    // change to new db
2419
    if (!varRunOnce) updateTireValue(WT_VAR_STABLE, false);
12,306✔
2420
    return;
12,306✔
2421
  }
2422

2423
  // create command add name to autotab
2424
  if (dealCreateCommand(sql)) {
1,228,513✔
2425
    return;
3,116✔
2426
  }
2427

2428
  // drop command remove name from autotab
2429
  if (dealDropCommand(sql)) {
1,225,397✔
2430
    return;
491✔
2431
  }
2432

2433
  return;
1,224,906✔
2434
}
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