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

taosdata / TDengine / #5034

24 Apr 2026 11:25AM UTC coverage: 73.058%. Remained the same
#5034

push

travis-ci

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

merge: from main to 3.0 branch[manual-only]

1336 of 1975 new or added lines in 48 files covered. (67.65%)

14149 existing lines in 164 files now uncovered.

275896 of 377640 relevant lines covered (73.06%)

132944440.29 hits per line

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

35.96
/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
#endif
204
    {"show connections;", 0, 0, NULL},
205
    {"show cluster;", 0, 0, NULL},
206
    {"show cluster alive;", 0, 0, NULL},
207
    {"show cluster machines;", 0, 0, NULL},
208
    {"show databases;", 0, 0, NULL},
209
    {"show dnodes;", 0, 0, NULL},
210
    {"show dnode <dnode_id> variables;", 0, 0, NULL},
211
    {"show disk_info;", 0, 0, NULL},
212
    {"show functions;", 0, 0, NULL},
213
    {"show licences;", 0, 0, NULL},
214
    {"show mnodes;", 0, 0, NULL},
215
    {"show queries;", 0, 0, NULL},
216
    // 80
217
    {"show query <anyword> ;", 0, 0, NULL},
218
    {"show qnodes;", 0, 0, NULL},
219
    {"show bnodes;", 0, 0, NULL},
220
    {"show retentions;", 0, 0, NULL},
221
    {"show retention <retention_id>;", 0, 0, NULL},
222
    {"show security_policies;", 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 indexes from <stb_name>;", 0, 0, NULL},
239
    {"show tsmas;", 0, 0, NULL},
240
    {"show rsmas;", 0, 0, NULL},
241
    {"show roles;", 0, 0, NULL},
242
    {"show role privileges;", 0, 0, NULL},
243
    {"show role column privileges;", 0, 0, NULL},
244
    {"show users;", 0, 0, NULL},
245
    {"show users full;", 0, 0, NULL},
246
    {"show user privileges;", 0, 0, NULL},
247
    {"show user column privileges;", 0, 0, NULL},
248
    {"show variables;", 0, 0, NULL},
249
    {"show local variables;", 0, 0, NULL},
250
    {"show vnodes;", 0, 0, NULL},
251
    {"show vnodes on dnode <dnode_id>;", 0, 0, NULL},
252
    {"show vgroups;", 0, 0, NULL},
253
    {"show vtables;", 0, 0, NULL},
254
    {"show consumers;", 0, 0, NULL},
255
    {"show grants;", 0, 0, NULL},
256
    {"show grants full;", 0, 0, NULL},
257
    {"show grants logs;", 0, 0, NULL},
258
#ifdef TD_ENTERPRISE
259
    {"show views;", 0, 0, NULL},
260
    {"show arbgroups;", 0, 0, NULL},
261
    {"split vgroup <vgroup_id>;", 0, 0, NULL},
262
    {"ssmigrate database <db_name>;", 0, 0, NULL},
263
    {"show mounts;", 0, 0, NULL},
264
    {"show ssmigrates;", 0, 0, NULL},
265
    {"show tokens;", 0, 0, NULL},
266
#endif
267
    {"insert into <tb_name> values(", 0, 0, NULL},
268
    {"insert into <tb_name> using <stb_name> tags(", 0, 0, NULL},
269
    {"insert into <tb_name> using <stb_name> <anyword> values(", 0, 0, NULL},
270
    {"insert into <tb_name> file ", 0, 0, NULL},
271
    {"trim database <db_name>;", 0, 0, NULL},
272
    {"use <db_name>;", 0, 0, NULL},
273
    {"update all anodes;", 0, 0, NULL},
274
    {"update anode <anyword>;", 0, 0, NULL},
275
    {"quit", 0, 0, NULL}};
276

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

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

344
char* tb_actions[] = {
345
    "add column ", "modify column ", "drop column ", "rename column ", "add tag ",
346
    "modify tag ", "drop tag ",      "rename tag ",  "set tag ",
347
};
348

349
char* user_actions[] = {"pass ", "enable ", "sysinfo ", "createdb "};
350

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

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

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

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

404
char* key_tags[] = {"tags("};
405

406
char* key_select[] = {"select "};
407

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

416
char* udf_language[] = {"\'Python\'", "\'C\'"};
417

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

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

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

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

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

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

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

537
#define WT_FROM_DB_MAX        12  // max get content from db
538
#define WT_FROM_DB_CNT (WT_FROM_DB_MAX + 1)
539

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

561

562
#define WT_TEXT 0xFF
563

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

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

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

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

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

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

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

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

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

850
//
851
//  -------------------  parse words --------------------------
852
//
853

854
#define SHELL_COMMAND_COUNT() (sizeof(shellCommands) / sizeof(SWords))
855

856
// get at
UNCOV
857
SWord* atWord(SWords* command, int32_t index) {
×
UNCOV
858
  SWord* word = command->head;
×
859
  for (int32_t i = 0; i < index; i++) {
×
860
    if (word == NULL) return NULL;
×
861
    word = word->next;
×
862
  }
863

UNCOV
864
  return word;
×
865
}
866

867
#define MATCH_WORD(x) atWord(x, x->matchIndex)
868

869
int wordType(const char* p, int32_t len) {
819,911,632✔
870
  for (int i = 0; i < WT_VAR_CNT; i++) {
2,147,483,647✔
871
    if (strncmp(p, varTypes[i], len) == 0) return i;
2,147,483,647✔
872
  }
873
  return WT_TEXT;
593,576,080✔
874
}
875

876
// add word
877
SWord* addWord(const char* p, int32_t len, bool pattern) {
829,897,024✔
878
  SWord* word = (SWord*)taosMemoryMalloc(sizeof(SWord));
829,897,024✔
879
  memset(word, 0, sizeof(SWord));
829,897,024✔
880
  word->word = (char*)p;
829,897,024✔
881
  word->len = len;
829,897,024✔
882

883
  // check format
884
  if (pattern && len > 0) {
829,897,024✔
885
    if (p[len - 1] == ';') {
819,911,632✔
886
      word->type = wordType(p, len - 1);
166,423,200✔
887
      word->end = true;
166,423,200✔
888
    } else {
889
      word->type = wordType(p, len);
653,488,432✔
890
    }
891
  } else {
892
    word->type = WT_TEXT;
9,985,392✔
893
  }
894

895
  return word;
829,897,024✔
896
}
897

898
// parse one command
899
void parseCommand(SWords* command, bool pattern) {
205,255,280✔
900
  char*   p = command->source;
205,255,280✔
901
  int32_t start = 0;
205,255,280✔
902
  int32_t size = command->source_len > 0 ? command->source_len : strlen(p);
205,255,280✔
903

904
  bool lastBlank = false;
205,255,280✔
905
  for (int i = 0; i <= size; i++) {
2,147,483,647✔
906
    if (p[i] == ' ' || i == size) {
2,147,483,647✔
907
      // check continue blank like '    '
908
      if (p[i] == ' ') {
832,116,000✔
909
        if (lastBlank) {
626,860,720✔
910
          start++;
2,218,976✔
911
          continue;
2,218,976✔
912
        }
913
        if (i == 0) {  // first blank
624,641,744✔
UNCOV
914
          lastBlank = true;
×
UNCOV
915
          start++;
×
916
          continue;
×
917
        }
918
        lastBlank = true;
624,641,744✔
919
      }
920

921
      // found split or string end , append word
922
      if (command->head == NULL) {
829,897,024✔
923
        command->head = addWord(p + start, i - start, pattern);
205,255,280✔
924
        command->count = 1;
205,255,280✔
925
      } else {
926
        SWord* word = command->head;
624,641,744✔
927
        while (word->next) {
2,105,808,224✔
928
          word = word->next;
1,481,166,480✔
929
        }
930
        word->next = addWord(p + start, i - start, pattern);
624,641,744✔
931
        command->count++;
624,641,744✔
932
      }
933
      start = i + 1;
829,897,024✔
934
    } else {
935
      lastBlank = false;
2,147,483,647✔
936
    }
937
  }
938
}
205,255,280✔
939

940
// free SShellCmd
941
void freeCommand(SWords* command) {
205,255,280✔
942
  SWord* item = command->head;
205,255,280✔
943
  command->head = NULL;
205,255,280✔
944
  // loop
945
  while (item) {
1,035,152,304✔
946
    SWord* tmp = item;
829,897,024✔
947
    item = item->next;
829,897,024✔
948
    // if malloc need free
949
    if (tmp->free && tmp->word) taosMemoryFree(tmp->word);
829,897,024✔
950
    taosMemoryFree(tmp);
829,897,024✔
951
  }
952
}
205,255,280✔
953

954
void GenerateVarType(int type, char** p, int count) {
18,861,296✔
955
  STire* tire = createTire(TIRE_LIST);
18,861,296✔
956
  for (int i = 0; i < count; i++) {
406,072,608✔
957
    insertWord(tire, p[i]);
387,211,312✔
958
  }
959

960
  taosThreadMutexLock(&tiresMutex);
18,861,296✔
961
  tires[type] = tire;
18,861,296✔
962
  taosThreadMutexUnlock(&tiresMutex);
18,861,296✔
963
}
18,861,296✔
964

965
//
966
//  -------------------- shell auto ----------------
967
//
968

969
// init shell auto function , shell start call once
970
void shellAutoInit() {
1,109,488✔
971
  // command
972
  int32_t count = SHELL_COMMAND_COUNT();
1,109,488✔
973
  for (int32_t i = 0; i < count; i++) {
206,364,768✔
974
    parseCommand(shellCommands + i, true);
205,255,280✔
975
  }
976

977
  // tires
978
  memset(tires, 0, sizeof(STire*) * WT_VAR_CNT);
1,109,488✔
979
  taosThreadMutexInit(&tiresMutex, NULL);
1,109,488✔
980

981
  // threads
982
  memset(threads, 0, sizeof(TdThread*) * WT_FROM_DB_CNT);
1,109,488✔
983

984
  // generate varType
985
  GenerateVarType(WT_VAR_FUNC, functions, sizeof(functions) / sizeof(char*));
1,109,488✔
986
  GenerateVarType(WT_VAR_KEYWORD, keywords, sizeof(keywords) / sizeof(char*));
1,109,488✔
987
  GenerateVarType(WT_VAR_TBACTION, tb_actions, sizeof(tb_actions) / sizeof(char*));
1,109,488✔
988
  GenerateVarType(WT_VAR_DBOPTION, db_options, sizeof(db_options) / sizeof(char*));
1,109,488✔
989
  GenerateVarType(WT_VAR_ALTER_DBOPTION, alter_db_options, sizeof(alter_db_options) / sizeof(char*));
1,109,488✔
990
  GenerateVarType(WT_VAR_DATATYPE, data_types, sizeof(data_types) / sizeof(char*));
1,109,488✔
991
  GenerateVarType(WT_VAR_KEYTAGS, key_tags, sizeof(key_tags) / sizeof(char*));
1,109,488✔
992
  GenerateVarType(WT_VAR_TBOPTION, tb_options, sizeof(tb_options) / sizeof(char*));
1,109,488✔
993
  GenerateVarType(WT_VAR_USERACTION, user_actions, sizeof(user_actions) / sizeof(char*));
1,109,488✔
994
  GenerateVarType(WT_VAR_KEYSELECT, key_select, sizeof(key_select) / sizeof(char*));
1,109,488✔
995
  GenerateVarType(WT_VAR_SYSTABLE, key_systable, sizeof(key_systable) / sizeof(char*));
1,109,488✔
996
  GenerateVarType(WT_VAR_LANGUAGE, udf_language, sizeof(udf_language) / sizeof(char*));
1,109,488✔
997
  GenerateVarType(WT_VAR_GLOBALKEYS, global_keys, sizeof(global_keys) / sizeof(char*));
1,109,488✔
998
  GenerateVarType(WT_VAR_FIELD_OPTIONS, field_options, sizeof(field_options) / sizeof(char*));
1,109,488✔
999
  GenerateVarType(WT_VAR_CREATE_USER_OPT, create_uopt, sizeof(create_uopt) / sizeof(char*));
1,109,488✔
1000
  GenerateVarType(WT_VAR_ALTER_USER_OPT, alter_uopt, sizeof(alter_uopt) / sizeof(char*));
1,109,488✔
1001
  GenerateVarType(WT_VAR_TOKEN_OPT, token_opt, sizeof(token_opt) / sizeof(char*));
1,109,488✔
1002
}
1,109,488✔
1003

1004
// set conn
1005
void shellSetConn(TAOS* conn, bool runOnce) {
1,104,546✔
1006
  varCon = conn;
1,104,546✔
1007
  varRunOnce = runOnce;
1,104,546✔
1008
  // init database and stable
1009
  if (!runOnce) updateTireValue(WT_VAR_DBNAME, false);
1,104,546✔
1010
}
1,104,546✔
1011

1012
// exit shell auto function, shell exit call once
1013
void shellAutoExit() {
1,109,488✔
1014
  // free command
1015
  int32_t count = SHELL_COMMAND_COUNT();
1,109,488✔
1016
  for (int32_t i = 0; i < count; i++) {
206,364,768✔
1017
    freeCommand(shellCommands + i);
205,255,280✔
1018
  }
1019

1020
  // free tires
1021
  taosThreadMutexLock(&tiresMutex);
1,109,488✔
1022
  for (int32_t i = 0; i < WT_VAR_CNT; i++) {
36,613,104✔
1023
    if (tires[i]) {
35,503,616✔
1024
      freeTire(tires[i]);
18,862,092✔
1025
      tires[i] = NULL;
18,862,092✔
1026
    }
1027
  }
1028
  taosThreadMutexUnlock(&tiresMutex);
1,109,488✔
1029
  // destroy
1030
  taosThreadMutexDestroy(&tiresMutex);
1,109,488✔
1031

1032
  // free threads
1033
  for (int32_t i = 0; i < WT_FROM_DB_CNT; i++) {
15,532,832✔
1034
    if (threads[i]) {
14,423,344✔
UNCOV
1035
      taosDestroyThread(threads[i]);
×
UNCOV
1036
      threads[i] = NULL;
×
1037
    }
1038
  }
1039

1040
  // free lastMatch
1041
  if (lastMatch) {
1,109,488✔
UNCOV
1042
    freeMatch(lastMatch);
×
UNCOV
1043
    lastMatch = NULL;
×
1044
  }
1045
}
1,109,488✔
1046

1047
//
1048
//  -------------------  auto ptr for tires --------------------------
1049
//
1050
bool setNewAutoPtr(int type, STire* pNew) {
796✔
1051
  if (pNew == NULL) return false;
796✔
1052

1053
  taosThreadMutexLock(&tiresMutex);
796✔
1054
  STire* pOld = tires[type];
796✔
1055
  if (pOld != NULL) {
796✔
1056
    // previous have value, release self ref count
UNCOV
1057
    if (--pOld->ref == 0) {
×
UNCOV
1058
      freeTire(pOld);
×
1059
    }
1060
  }
1061

1062
  // set new
1063
  tires[type] = pNew;
796✔
1064
  tires[type]->ref = 1;
796✔
1065
  taosThreadMutexUnlock(&tiresMutex);
796✔
1066

1067
  return true;
796✔
1068
}
1069

1070
// get ptr
UNCOV
1071
STire* getAutoPtr(int type) {
×
UNCOV
1072
  if (tires[type] == NULL) {
×
1073
    return NULL;
×
1074
  }
1075

UNCOV
1076
  taosThreadMutexLock(&tiresMutex);
×
UNCOV
1077
  tires[type]->ref++;
×
1078
  taosThreadMutexUnlock(&tiresMutex);
×
1079

1080
  return tires[type];
×
1081
}
1082

1083
// put back tire to tires[type], if tire not equal tires[type].p, need free tire
UNCOV
1084
void putBackAutoPtr(int type, STire* tire) {
×
UNCOV
1085
  if (tire == NULL) {
×
1086
    return;
×
1087
  }
1088

UNCOV
1089
  taosThreadMutexLock(&tiresMutex);
×
UNCOV
1090
  if (tires[type] != tire) {
×
1091
    // update by out,  can't put back , so free
1092
    if (--tire->ref == 1) {
×
1093
      // support multi thread getAutoPtr
1094
      freeTire(tire);
×
1095
    }
1096

1097
  } else {
UNCOV
1098
    tires[type]->ref--;
×
UNCOV
1099
    ASSERT(tires[type]->ref > 0);
×
1100
  }
1101
  taosThreadMutexUnlock(&tiresMutex);
×
1102

1103
  return;
×
1104
}
1105

1106
//
1107
//  -------------------  var Word --------------------------
1108
//
1109

1110
#define MAX_CACHED_CNT 100000  // max cached rows 10w
1111
// write sql result to var name, return write rows cnt
1112
int writeVarNames(int type, TAOS_RES* tres) {
796✔
1113
  // fetch row
1114
  TAOS_ROW row = taos_fetch_row(tres);
796✔
1115
  if (row == NULL) {
796✔
UNCOV
1116
    return 0;
×
1117
  }
1118

1119
  TAOS_FIELD* fields = taos_fetch_fields(tres);
796✔
1120
  // create new tires
1121
  char   tireType = type == WT_VAR_TABLE ? TIRE_TREE : TIRE_LIST;
796✔
1122
  STire* tire = createTire(tireType);
796✔
1123

1124
  // enum rows
1125
  char name[1024];
796✔
1126
  int  numOfRows = 0;
796✔
1127
  do {
1128
    int32_t* lengths = taos_fetch_lengths(tres);
2,388✔
1129
    int32_t  bytes = lengths[0];
2,388✔
1130
    if (fields[0].type == TSDB_DATA_TYPE_INT) {
2,388✔
UNCOV
1131
      sprintf(name, "%d", *(int16_t*)row[0]);
×
1132
    } else {
1133
      memcpy(name, row[0], bytes);
2,388✔
1134
    }
1135

1136
    name[bytes] = 0;  // set string end
2,388✔
1137
    // insert to tire
1138
    insertWord(tire, name);
2,388✔
1139

1140
    if (++numOfRows > MAX_CACHED_CNT) {
2,388✔
UNCOV
1141
      break;
×
1142
    }
1143

1144
    row = taos_fetch_row(tres);
2,388✔
1145
  } while (row != NULL);
2,388✔
1146

1147
  // replace old tire
1148
  setNewAutoPtr(type, tire);
796✔
1149

1150
  return numOfRows;
796✔
1151
}
1152

1153
void setThreadNull(int type) {
796✔
1154
  taosThreadMutexLock(&tiresMutex);
796✔
1155
  if (threads[type]) {
796✔
1156
    taosMemoryFree(threads[type]);
796✔
1157
  }
1158
  threads[type] = NULL;
796✔
1159
  taosThreadMutexUnlock(&tiresMutex);
796✔
1160
}
796✔
1161

1162
bool firstMatchCommand(TAOS* con, SShellCmd* cmd);
1163
//
1164
//  thread obtain var thread from db server
1165
//
1166
void* varObtainThread(void* param) {
796✔
1167
  int type = *(int*)param;
796✔
1168
  taosMemoryFree(param);
796✔
1169

1170
  if (varCon == NULL || type > WT_FROM_DB_MAX) {
796✔
UNCOV
1171
    return NULL;
×
1172
  }
1173

1174
  TAOS_RES* pSql = taos_query(varCon, varSqls[type]);
796✔
1175
  if (taos_errno(pSql)) {
796✔
UNCOV
1176
    taos_free_result(pSql);
×
UNCOV
1177
    setThreadNull(type);
×
1178
    return NULL;
×
1179
  }
1180

1181
  // write var names from pSql
1182
  int cnt = writeVarNames(type, pSql);
796✔
1183

1184
  // free sql
1185
  taos_free_result(pSql);
796✔
1186

1187
  // check need call auto tab
1188
  if (cnt > 0 && waitAutoFill) {
796✔
1189
    // press tab key by program
UNCOV
1190
    firstMatchCommand(varCon, varCmd);
×
1191
  }
1192

1193
  setThreadNull(type);
796✔
1194
  return NULL;
796✔
1195
}
1196

1197
// return true is need update value by async
1198
bool updateTireValue(int type, bool autoFill) {
796✔
1199
  // TYPE CONTEXT GET FROM DB
1200
  taosThreadMutexLock(&tiresMutex);
796✔
1201

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

1217
    // create new
1218
    void* param = taosMemoryMalloc(sizeof(int));
796✔
1219
    *((int*)param) = type;
796✔
1220
    threads[type] = taosCreateThread(varObtainThread, param);
796✔
1221
    taosThreadMutexUnlock(&tiresMutex);
796✔
1222
    return true;
796✔
1223
  }
UNCOV
1224
  taosThreadMutexUnlock(&tiresMutex);
×
1225

1226
  return false;
×
1227
}
1228

1229
// only match next one word from all match words, return valuue must free by caller
UNCOV
1230
char* matchNextPrefix(STire* tire, char* pre) {
×
UNCOV
1231
  SMatch* match = NULL;
×
1232
  if (tire == NULL) return NULL;
×
1233

1234
  // re-use last result
UNCOV
1235
  if (lastMatch) {
×
UNCOV
1236
    if (strcmp(pre, lastMatch->pre) == 0) {
×
1237
      // same pre
1238
      match = lastMatch;
×
1239
    }
1240
  }
1241

UNCOV
1242
  if (match == NULL) {
×
1243
    // not same with last result
1244
    if (pre[0] == 0) {
×
1245
      // EMPTY PRE
1246
      match = enumAll(tire);
×
1247
    } else {
1248
      // NOT EMPTY
UNCOV
1249
      match = (SMatch*)taosMemoryMalloc(sizeof(SMatch));
×
UNCOV
1250
      memset(match, 0, sizeof(SMatch));
×
1251
      matchPrefix(tire, pre, match);
×
1252
    }
1253

1254
    // save to lastMatch
UNCOV
1255
    if (match) {
×
UNCOV
1256
      if (lastMatch) freeMatch(lastMatch);
×
1257
      lastMatch = match;
×
1258
    }
1259
  }
1260

1261
  // check valid
UNCOV
1262
  if (match == NULL || match->head == NULL) {
×
1263
    // no one matched
1264
    return NULL;
×
1265
  }
1266

UNCOV
1267
  if (cursorVar == -1) {
×
1268
    // first
1269
    cursorVar = 0;
×
UNCOV
1270
    return taosStrdup(match->head->word);
×
1271
  }
1272

1273
  // according to cursorVar , calculate next one
UNCOV
1274
  int         i = 0;
×
UNCOV
1275
  SMatchNode* item = match->head;
×
1276
  while (item) {
×
1277
    if (i == cursorVar + 1) {
×
1278
      // found next position ok
1279
      if (item->next == NULL) {
×
1280
        // match last item, reset cursorVar to head
1281
        cursorVar = -1;
×
1282
      } else {
1283
        cursorVar = i;
×
1284
      }
1285

UNCOV
1286
      return taosStrdup(item->word);
×
1287
    }
1288

1289
    // check end item
UNCOV
1290
    if (item->next == NULL) {
×
1291
      // if cursorVar > var list count, return last and reset cursorVar
1292
      cursorVar = -1;
×
1293

1294
      return taosStrdup(item->word);
×
1295
    }
1296

1297
    // move next
UNCOV
1298
    item = item->next;
×
UNCOV
1299
    i++;
×
1300
  }
1301

UNCOV
1302
  return NULL;
×
1303
}
1304

1305
// search pre word from tire tree, return value must free by caller
UNCOV
1306
char* tireSearchWord(int type, char* pre) {
×
UNCOV
1307
  if (type == WT_TEXT) {
×
1308
    return NULL;
×
1309
  }
1310

UNCOV
1311
  if (type > WT_FROM_DB_MAX) {
×
1312
    // NOT FROM DB , tires[type] alwary not null
1313
    STire* tire = tires[type];
×
UNCOV
1314
    if (tire == NULL) return NULL;
×
1315
    return matchNextPrefix(tire, pre);
×
1316
  }
1317

UNCOV
1318
  if (updateTireValue(type, true)) {
×
UNCOV
1319
    return NULL;
×
1320
  }
1321

1322
  // can obtain var names from local
UNCOV
1323
  STire* tire = getAutoPtr(type);
×
UNCOV
1324
  if (tire == NULL) {
×
1325
    return NULL;
×
1326
  }
1327

UNCOV
1328
  char* str = matchNextPrefix(tire, pre);
×
1329
  // used finish, put back pointer to autoptr array
1330
  putBackAutoPtr(type, tire);
×
1331

1332
  return str;
×
1333
}
1334

1335
// match var word, word1 is pattern , word2 is input from shell
UNCOV
1336
bool matchVarWord(SWord* word1, SWord* word2) {
×
1337
  // search input word from tire tree
1338
  char pre[512];
×
UNCOV
1339
  memcpy(pre, word2->word, word2->len);
×
1340
  pre[word2->len] = 0;
×
1341

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

1359
  // free previous malloc
UNCOV
1360
  if (word1->free && word1->word) {
×
UNCOV
1361
    taosMemoryFree(word1->word);
×
1362
  }
1363

1364
  // save
UNCOV
1365
  word1->word = str;
×
UNCOV
1366
  word1->len = strlen(str);
×
1367
  word1->free = true;  // need free
×
1368

1369
  return true;
×
1370
}
1371

1372
//
1373
//  -------------------  match words --------------------------
1374
//
1375

1376
// compare command cmdPattern come from shellCommands , cmdInput come from user input
UNCOV
1377
int32_t compareCommand(SWords* cmdPattern, SWords* cmdInput) {
×
UNCOV
1378
  SWord* wordPattern = cmdPattern->head;
×
1379
  SWord* wordInput = cmdInput->head;
×
1380

1381
  if (wordPattern == NULL || wordInput == NULL) {
×
UNCOV
1382
    return -1;
×
1383
  }
1384

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

1420
    // move next
UNCOV
1421
    wordPattern = wordPattern->next;
×
UNCOV
1422
    wordInput = wordInput->next;
×
1423
    if (wordPattern == NULL || wordInput == NULL) {
×
1424
      return -1;
×
1425
    }
1426
  }
1427

UNCOV
1428
  return -1;
×
1429
}
1430

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

1445
    // command is large
UNCOV
1446
    if (input->count > shellCommand->count) {
×
UNCOV
1447
      continue;
×
1448
    }
1449

1450
    // compare
UNCOV
1451
    int32_t index = compareCommand(shellCommand, input);
×
UNCOV
1452
    if (index != -1) {
×
1453
      if (firstMatchIndex == -1) firstMatchIndex = i;
×
1454
      curMatchIndex = i;
×
1455
      return &shellCommands[i];
×
1456
    }
1457
  }
1458

1459
  // not match
UNCOV
1460
  return NULL;
×
1461
}
1462

1463
//
1464
//  -------------------  print screen --------------------------
1465
//
1466

1467
// delete char count
UNCOV
1468
void deleteCount(SShellCmd* cmd, int count) {
×
UNCOV
1469
  int size = 0;
×
1470
  int width = 0;
×
1471
  int prompt_size = 6;
×
1472
  shellClearScreen(cmd->endOffset + prompt_size, cmd->screenOffset + prompt_size);
×
1473

1474
  // loop delete
UNCOV
1475
  while (--count >= 0 && cmd->cursorOffset > 0) {
×
UNCOV
1476
    shellGetPrevCharSize(cmd->command, cmd->cursorOffset, &size, &width);
×
1477
    memmove(cmd->command + cmd->cursorOffset - size, cmd->command + cmd->cursorOffset,
×
1478
            cmd->commandSize - cmd->cursorOffset);
×
1479
    cmd->commandSize -= size;
×
1480
    cmd->cursorOffset -= size;
×
1481
    cmd->screenOffset -= width;
×
1482
    cmd->endOffset -= width;
×
1483
  }
1484
}
×
1485

1486
// show screen
UNCOV
1487
void printScreen(TAOS* con, SShellCmd* cmd, SWords* match) {
×
1488
  // modify SShellCmd
1489
  if (firstMatchIndex == -1 || curMatchIndex == -1) {
×
1490
    // no match
1491
    return;
×
1492
  }
1493

1494
  // first tab press
UNCOV
1495
  const char* str = NULL;
×
UNCOV
1496
  int         strLen = 0;
×
1497

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

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

1533
// main key press tab , matched return true else false
UNCOV
1534
bool firstMatchCommand(TAOS* con, SShellCmd* cmd) {
×
UNCOV
1535
  if (con == NULL || cmd == NULL) return false;
×
1536
  // parse command
1537
  SWords* input = (SWords*)taosMemoryMalloc(sizeof(SWords));
×
UNCOV
1538
  memset(input, 0, sizeof(SWords));
×
1539
  input->source = cmd->command;
×
1540
  input->source_len = cmd->commandSize;
×
1541
  parseCommand(input, false);
×
1542

1543
  // if have many , default match first, if press tab again , switch to next
UNCOV
1544
  curMatchIndex = -1;
×
UNCOV
1545
  lastMatchIndex = -1;
×
1546
  SWords* match = matchCommand(input, true);
×
1547
  if (match == NULL) {
×
1548
    // not match , nothing to do
1549
    freeCommand(input);
×
UNCOV
1550
    taosMemoryFree(input);
×
1551
    return false;
×
1552
  }
1553

1554
  // print to screen
UNCOV
1555
  printScreen(con, cmd, match);
×
1556
#ifdef WINDOWS
1557
  printf("\r");
1558
  shellShowOnScreen(cmd);
1559
#endif
UNCOV
1560
  freeCommand(input);
×
UNCOV
1561
  taosMemoryFree(input);
×
1562
  return true;
×
1563
}
1564

1565
// create input source
UNCOV
1566
void createInputFromFirst(SWords* input, SWords* firstMatch) {
×
UNCOV
1567
  if (input == NULL || firstMatch == NULL) return;
×
1568

1569
  input->source = NULL;
×
UNCOV
1570
  input->source_len = 0;
×
1571

1572
  SWord* word = firstMatch->head;
×
UNCOV
1573
  int32_t i = 0;
×
1574

1575
  /* 1) calculate required buffer size */
UNCOV
1576
  size_t needed = 0;
×
UNCOV
1577
  while (word && i < firstMatch->matchIndex) {
×
1578
    needed += (size_t)word->len; /* length of the word itself */
×
1579
    needed += 1;                 /* following space */
×
1580
    word = word->next;
×
1581
    i++;
×
1582
  }
1583

1584
  /* add matchLen for the last (partially matched) word (but not exceeding the word's len) */
UNCOV
1585
  if (word) {
×
UNCOV
1586
    int32_t copylen = firstMatch->matchLen;
×
1587
    if (copylen > word->len) copylen = word->len;
×
1588
    needed += (size_t)copylen;
×
1589
  }
1590

1591
  /* include null terminator */
UNCOV
1592
  needed += 1;
×
1593

1594
  /* 2) allocate buffer of exact size */
UNCOV
1595
  char* buf = (char*)taosMemoryMalloc((int)needed);
×
UNCOV
1596
  if (buf == NULL) {
×
1597
    /* on failure keep input->source NULL and return */
1598
    return;
×
1599
  }
1600

1601
  /* 3) construct string using memcpy to avoid repeated traversal and strcat boundary issues */
UNCOV
1602
  char* p = buf;
×
UNCOV
1603
  word = firstMatch->head;
×
1604
  i = 0;
×
1605
  while (word && i < firstMatch->matchIndex) {
×
1606
    if (word->len > 0) {
×
1607
      memcpy(p, word->word, word->len);
×
1608
      p += word->len;
×
1609
    }
1610
    /* add a space (only when not appending the final partial word) */
UNCOV
1611
    *p++ = ' ';
×
UNCOV
1612
    word = word->next;
×
1613
    i++;
×
1614
  }
1615

UNCOV
1616
  if (word) {
×
UNCOV
1617
    int32_t copylen = firstMatch->matchLen;
×
1618
    if (copylen > word->len) copylen = word->len;
×
1619
    if (copylen > 0) {
×
1620
      memcpy(p, word->word, copylen);
×
1621
      p += copylen;
×
1622
    }
1623
  }
1624

1625
  /* null-terminate and set length */
UNCOV
1626
  *p = '\0';
×
UNCOV
1627
  input->source = buf;
×
1628
  input->source_len = (int32_t)(p - buf);
×
1629
}
1630

1631
// user press Tabkey again is named next , matched return true else false
UNCOV
1632
bool nextMatchCommand(TAOS* con, SShellCmd* cmd, SWords* firstMatch) {
×
UNCOV
1633
  if (firstMatch == NULL || firstMatch->head == NULL) {
×
1634
    return false;
×
1635
  }
1636
  SWords* input = (SWords*)taosMemoryMalloc(sizeof(SWords));
×
UNCOV
1637
  memset(input, 0, sizeof(SWords));
×
1638

1639
  // create input from firstMatch
UNCOV
1640
  createInputFromFirst(input, firstMatch);
×
1641

1642
  // parse input
UNCOV
1643
  parseCommand(input, false);
×
1644

1645
  // if have many , default match first, if press tab again , switch to next
UNCOV
1646
  SWords* match = matchCommand(input, true);
×
UNCOV
1647
  if (match == NULL) {
×
1648
    // if not match , reset all index
1649
    firstMatchIndex = -1;
×
UNCOV
1650
    curMatchIndex = -1;
×
1651
    match = matchCommand(input, false);
×
1652
    if (match == NULL) {
×
1653
      freeCommand(input);
×
1654
      if (input->source) taosMemoryFree(input->source);
×
1655
      taosMemoryFree(input);
×
1656
      return false;
×
1657
    }
1658
  }
1659

1660
  // print to screen
UNCOV
1661
  printScreen(con, cmd, match);
×
1662
#ifdef WINDOWS
1663
  printf("\r");
1664
  shellShowOnScreen(cmd);
1665
#endif
1666

1667
  // free
UNCOV
1668
  freeCommand(input);
×
UNCOV
1669
  if (input->source) {
×
1670
    taosMemoryFree(input->source);
×
1671
    input->source = NULL;
×
1672
  }
1673
  taosMemoryFree(input);
×
1674

1675
  return true;
×
1676
}
1677

1678
// fill with type
UNCOV
1679
bool fillWithType(TAOS* con, SShellCmd* cmd, char* pre, int type) {
×
1680
  // get type
1681
  STire* tire = tires[type];
×
UNCOV
1682
  char*  str = matchNextPrefix(tire, pre);
×
1683
  if (str == NULL) {
×
1684
    return false;
×
1685
  }
1686

1687
  // need insert part string
UNCOV
1688
  char* part = str + strlen(pre);
×
1689

1690
  // show
UNCOV
1691
  int count = strlen(part);
×
UNCOV
1692
  shellInsertStr(cmd, part, count);
×
1693
  cntDel = count;  // next press tab delete current append count
×
1694

1695
  taosMemoryFree(str);
×
UNCOV
1696
  return true;
×
1697
}
1698

1699
// fill with type
UNCOV
1700
bool fillTableName(TAOS* con, SShellCmd* cmd, char* pre) {
×
1701
  // search stable and table
1702
  char* str = tireSearchWord(WT_VAR_STABLE, pre);
×
UNCOV
1703
  if (str == NULL) {
×
1704
    str = tireSearchWord(WT_VAR_TABLE, pre);
×
1705
    if (str == NULL) return false;
×
1706
  }
1707

1708
  // need insert part string
UNCOV
1709
  char* part = str + strlen(pre);
×
1710

1711
  // delete autofill count last append
UNCOV
1712
  if (cntDel > 0) {
×
UNCOV
1713
    deleteCount(cmd, cntDel);
×
1714
    cntDel = 0;
×
1715
  }
1716

1717
  // show
UNCOV
1718
  int count = strlen(part);
×
UNCOV
1719
  shellInsertStr(cmd, part, count);
×
1720
  cntDel = count;  // next press tab delete current append count
×
1721

1722
  taosMemoryFree(str);
×
UNCOV
1723
  return true;
×
1724
}
1725

1726
//
1727
// find last word from sql select clause
1728
//  example :
1729
//  1 select cou -> press tab  select count(
1730
//  2 select count(*),su -> select count(*), sum(
1731
//  3 select count(*), su -> select count(*), sum(
1732
//
UNCOV
1733
char* lastWord(char* p) {
×
1734
  // get near from end revert find ' ' and ','
1735
  char* p1 = strrchr(p, ' ');
×
UNCOV
1736
  char* p2 = strrchr(p, ',');
×
1737

1738
  if (p1 && p2) {
×
UNCOV
1739
    return p1 > p2 ? p1 + 1 : p2 + 1;
×
1740
  } else if (p1) {
×
1741
    return p1 + 1;
×
1742
  } else if (p2) {
×
1743
    return p2 + 1;
×
1744
  } else {
1745
    return p;
×
1746
  }
1747
}
1748

UNCOV
1749
bool fieldsInputEnd(char* sql) {
×
1750
  // not in '()'
1751
  char* p1 = strrchr(sql, '(');
×
UNCOV
1752
  char* p2 = strrchr(sql, ')');
×
1753
  if (p1 && p2 == NULL) {
×
1754
    // like select count( '  '
1755
    return false;
×
UNCOV
1756
  } else if (p1 && p2 && p1 > p2) {
×
1757
    // like select sum(age), count( ' '
1758
    return false;
×
1759
  }
1760

1761
  // not in ','
UNCOV
1762
  char* p3 = strrchr(sql, ',');
×
UNCOV
1763
  char* p = p3;
×
1764
  // like select ts, age,'    '
1765
  if (p) {
×
UNCOV
1766
    ++p;
×
1767
    bool  allBlank = true;  // after last ','  all char is blank
×
1768
    int   cnt = 0;          // blank count , like '    ' as one blank
×
1769
    char* plast = NULL;     // last blank position
×
1770
    while (*p) {
×
1771
      if (*p == ' ') {
×
1772
        plast = p;
×
1773
        cnt++;
×
1774
      } else {
1775
        allBlank = false;
×
1776
      }
1777
      ++p;
×
1778
    }
1779

1780
    // any one word is not blank
UNCOV
1781
    if (allBlank) {
×
UNCOV
1782
      return false;
×
1783
    }
1784

1785
    // like 'select count(*),sum(age) fr' need return true
UNCOV
1786
    if (plast && plast > p3 && p2 > p1 && plast > p2 && p1 > p3) {
×
UNCOV
1787
      return true;
×
1788
    }
1789

1790
    // if last char not ' ', then not end field, like 'select count(*), su' can fill sum(
UNCOV
1791
    if (sql[strlen(sql) - 1] != ' ' && cnt <= 1) {
×
UNCOV
1792
      return false;
×
1793
    }
1794
  }
1795

UNCOV
1796
  char* p4 = strrchr(sql, ' ');
×
UNCOV
1797
  if (p4 == NULL) {
×
1798
    // only one word
1799
    return false;
×
1800
  }
1801

UNCOV
1802
  return true;
×
1803
}
1804

1805
// need insert from
UNCOV
1806
bool needInsertFrom(char* sql, int len) {
×
1807
  // last is blank
1808
  if (sql[len - 1] != ' ') {
×
1809
    // insert from keyword
1810
    return false;
×
1811
  }
1812

1813
  //  select fields input is end
UNCOV
1814
  if (!fieldsInputEnd(sql)) {
×
UNCOV
1815
    return false;
×
1816
  }
1817

1818
  // can insert from keyword
UNCOV
1819
  return true;
×
1820
}
1821

1822
// p is string following select keyword
UNCOV
1823
bool appendAfterSelect(TAOS* con, SShellCmd* cmd, char* sql, int32_t len) {
×
UNCOV
1824
  char* p = taosStrndup(sql, len);
×
1825

1826
  // union all
1827
  char* p1;
1828
  do {
UNCOV
1829
    p1 = strstr(p, UNION_ALL);
×
UNCOV
1830
    if (p1) {
×
1831
      p = p1 + strlen(UNION_ALL);
×
1832
    }
1833
  } while (p1);
×
1834

1835
  char* from = strstr(p, " from ");
×
1836
  // last word , maybe empty string or some letters of a string
1837
  char* last = lastWord(p);
×
UNCOV
1838
  bool  ret = false;
×
1839
  if (from == NULL) {
×
1840
    bool fieldEnd = fieldsInputEnd(p);
×
1841
    // check fields input end then insert from keyword
1842
    if (fieldEnd && p[len - 1] == ' ') {
×
UNCOV
1843
      shellInsertStr(cmd, "from", 4);
×
1844
      taosMemoryFree(p);
×
1845
      return true;
×
1846
    }
1847

1848
    // fill function
UNCOV
1849
    if (fieldEnd) {
×
1850
      // fields is end , need match keyword
1851
      ret = fillWithType(con, cmd, last, WT_VAR_KEYWORD);
×
1852
    } else {
1853
      ret = fillWithType(con, cmd, last, WT_VAR_FUNC);
×
1854
    }
1855

UNCOV
1856
    taosMemoryFree(p);
×
UNCOV
1857
    return ret;
×
1858
  }
1859

1860
  // have from
UNCOV
1861
  char* blank = strstr(from + 6, " ");
×
UNCOV
1862
  if (blank == NULL) {
×
1863
    // no table name, need fill
1864
    ret = fillTableName(con, cmd, last);
×
1865
  } else {
1866
    ret = fillWithType(con, cmd, last, WT_VAR_KEYWORD);
×
1867
  }
1868

UNCOV
1869
  taosMemoryFree(p);
×
UNCOV
1870
  return ret;
×
1871
}
1872

UNCOV
1873
int32_t searchAfterSelect(char* p, int32_t len) {
×
1874
  // select * from st;
1875
  if (strncasecmp(p, "select ", 7) == 0) {
×
1876
    // check nest query
1877
    char* p1 = p + 7;
×
UNCOV
1878
    while (1) {
×
1879
      char* p2 = strstr(p1, "select ");
×
1880
      if (p2 == NULL) break;
×
1881
      p1 = p2 + 7;
×
1882
    }
1883

UNCOV
1884
    return p1 - p;
×
1885
  }
1886

1887
  // explain as select * from st;
UNCOV
1888
  if (strncasecmp(p, "explain select ", 15) == 0) {
×
UNCOV
1889
    return 15;
×
1890
  }
1891

UNCOV
1892
  char* as_pos_end = strstr(p, " as select ");
×
UNCOV
1893
  if (as_pos_end == NULL) return -1;
×
1894
  as_pos_end += 11;
×
1895

1896
  // create stream <stream_name> as select
UNCOV
1897
  if (strncasecmp(p, "create stream ", 14) == 0) {
×
UNCOV
1898
    return as_pos_end - p;
×
1899
    ;
1900
  }
1901

1902
  // create topic <topic_name> as select
UNCOV
1903
  if (strncasecmp(p, "create topic ", 13) == 0) {
×
UNCOV
1904
    return as_pos_end - p;
×
1905
  }
1906

UNCOV
1907
  return -1;
×
1908
}
1909

UNCOV
1910
bool matchSelectQuery(TAOS* con, SShellCmd* cmd) {
×
1911
  // if continue press Tab , delete bytes by previous autofill
1912
  if (cntDel > 0) {
×
UNCOV
1913
    deleteCount(cmd, cntDel);
×
1914
    cntDel = 0;
×
1915
  }
1916

1917
  // match select ...
UNCOV
1918
  int   len = cmd->commandSize;
×
UNCOV
1919
  char* p = cmd->command;
×
1920

1921
  // remove prefix blank
UNCOV
1922
  while (p[0] == ' ' && len > 0) {
×
UNCOV
1923
    p++;
×
1924
    len--;
×
1925
  }
1926

1927
  // special range
UNCOV
1928
  if (len < 7 || len > 512) {
×
UNCOV
1929
    return false;
×
1930
  }
1931

1932
  // search
UNCOV
1933
  char*   sql_cp = taosStrndup(p, len);
×
UNCOV
1934
  int32_t n = searchAfterSelect(sql_cp, len);
×
1935
  taosMemoryFree(sql_cp);
×
1936
  if (n == -1 || n > len) return false;
×
1937
  p += n;
×
1938
  len -= n;
×
1939

1940
  // append
UNCOV
1941
  return appendAfterSelect(con, cmd, p, len);
×
1942
}
1943

1944
// is fields option area
1945
bool fieldOptionsArea(char* p) {
5,488✔
1946
  char* p1 = strrchr(p, '(');
5,488✔
1947
  char* p2 = strrchr(p, ',');
5,488✔
1948
  if (p1 == NULL && p2 == NULL) {
5,488✔
UNCOV
1949
    return false;
×
1950
  }
1951

1952
  // find tags
1953
  if (strstr(p, " tags") != NULL) {
5,488✔
1954
    return false;
1,568✔
1955
  }
1956

1957
  if (p2 == NULL) {
3,920✔
1958
    // first field area
1959
    p2 = p1;
392✔
1960
  }
1961

1962
  // find blank count
1963
  int32_t cnt = 0;
3,920✔
1964
  while (p2) {
18,620✔
1965
    p2 = strchr(p2, ' ');
14,700✔
1966
    if (p2) {
14,700✔
1967
      // get prev char
1968
      char prec = *(p2 - 1);
10,780✔
1969
      if (prec != ',' && prec != '(') {
10,780✔
1970
        // blank if before comma, not calc count.  like st(ts timestamp,  age int + BLANK + TAB only two blank
1971
        cnt++;
8,036✔
1972
      }
1973

1974
      // continue blank is one blank
1975
      while (p2[1] != 0 && p2[1] == ' ') {
13,328✔
1976
        // move next if blank again
1977
        p2 += 1;
2,548✔
1978
      }
1979
      p2 += 1;
10,780✔
1980
    }
1981
  }
1982

1983
  // like  create table st(ts timestamp TAB-KEY or  st(ts timestamp , age int TAB-KEY
1984
  return cnt >= 2;
3,920✔
1985
}
1986

1987
// if is input create fields or tags area, return true
1988
bool isCreateFieldsArea(char* p) {
5,488✔
1989
  int32_t n = 0;  // count
5,488✔
1990
  char*  p1 = p;
5,488✔
1991
  while (*p1 != 0) {
435,904✔
1992
    switch (*p1) {
430,416✔
1993
      case '(':
15,876✔
1994
        ++n;
15,876✔
1995
        break;
15,876✔
1996
      case ')':
13,132✔
1997
        --n;
13,132✔
1998
        break;
13,132✔
1999
      default:
401,408✔
2000
        break;
401,408✔
2001
    }
2002
    // move next
2003
    ++p1;
430,416✔
2004
  }
2005

2006
  return n > 0;
5,488✔
2007
}
2008

UNCOV
2009
bool matchCreateTable(TAOS* con, SShellCmd* cmd) {
×
2010
  // if continue press Tab , delete bytes by previous autofill
2011
  if (cntDel > 0) {
×
UNCOV
2012
    deleteCount(cmd, cntDel);
×
2013
    cntDel = 0;
×
2014
  }
2015

2016
  // match select ...
UNCOV
2017
  int   len = cmd->commandSize;
×
UNCOV
2018
  char* p = cmd->command;
×
2019

2020
  // remove prefix blank
UNCOV
2021
  while (p[0] == ' ' && len > 0) {
×
UNCOV
2022
    p++;
×
2023
    len--;
×
2024
  }
2025

2026
  // special range
UNCOV
2027
  if (len < 7 || len > 1024) {
×
UNCOV
2028
    return false;
×
2029
  }
2030

2031
  // select and from
UNCOV
2032
  if (strncasecmp(p, "create table ", 13) != 0) {
×
2033
    // not select query clause
2034
    return false;
×
2035
  }
2036
  p += 13;
×
UNCOV
2037
  len -= 13;
×
2038

2039
  char* ps = taosStrndup(p, len);
×
UNCOV
2040
  bool  ret = false;
×
2041
  char* last = lastWord(ps);
×
2042

2043
  // check in create fields or tags input area
UNCOV
2044
  if (isCreateFieldsArea(ps)) {
×
UNCOV
2045
    if (fieldOptionsArea(ps)) {
×
2046
      // fill field options
2047
      ret = fillWithType(con, cmd, last, WT_VAR_FIELD_OPTIONS);
×
2048
    } else {
2049
      // fill field
UNCOV
2050
      ret = fillWithType(con, cmd, last, WT_VAR_DATATYPE);
×
2051
    }
2052
  }
2053

2054
  // tags
UNCOV
2055
  if (!ret) {
×
2056
    // find only one ')' , can insert tags
2057
    char* p1 = strchr(ps, ')');
×
UNCOV
2058
    if (p1) {
×
2059
      if (strstr(p1 + 1, "tags") == NULL) {
×
2060
        // can insert tags keyword
2061
        ret = fillWithType(con, cmd, last, WT_VAR_KEYTAGS);
×
2062
      }
2063
    }
2064
  }
2065

2066
  // tb options
UNCOV
2067
  if (!ret) {
×
2068
    // find like create table st (...) tags(..)  <here is fill tb option area>
2069
    char* p1 = strchr(ps, ')');  // first ')' end
×
UNCOV
2070
    if (p1) {
×
2071
      if (strchr(p1 + 1, ')')) {  // second ')' end
×
2072
        // here is tb options area, can insert option
2073
        ret = fillWithType(con, cmd, last, WT_VAR_TBOPTION);
×
2074
      }
2075
    }
2076
  }
2077

UNCOV
2078
  taosMemoryFree(ps);
×
UNCOV
2079
  return ret;
×
2080
}
2081

UNCOV
2082
bool matchOther(TAOS* con, SShellCmd* cmd) {
×
UNCOV
2083
  int   len = cmd->commandSize;
×
2084
  char* p = cmd->command;
×
2085

2086
  // '\\'
UNCOV
2087
  if (p[len - 1] == '\\') {
×
2088
    // append '\G'
2089
    char a[] = "G;";
×
UNCOV
2090
    shellInsertStr(cmd, a, 2);
×
2091
    return true;
×
2092
  }
2093

2094
  // too small
UNCOV
2095
  if (len < 8) return false;
×
2096

2097
  // like 'from ( '
UNCOV
2098
  char* sql = taosStrndup(p, len);
×
UNCOV
2099
  char* last = lastWord(sql);
×
2100

2101
  if (strcmp(last, "from(") == 0) {
×
UNCOV
2102
    fillWithType(con, cmd, "", WT_VAR_KEYSELECT);
×
2103
    taosMemoryFree(sql);
×
2104
    return true;
×
2105
  }
2106
  if (strncmp(last, "(", 1) == 0) {
×
UNCOV
2107
    last += 1;
×
2108
  }
2109

UNCOV
2110
  char* from = strstr(sql, " from");
×
2111
  // find last ' from'
2112
  while (from) {
×
UNCOV
2113
    char* p1 = strstr(from + 5, " from");
×
2114
    if (p1 == NULL) break;
×
2115
    from = p1;
×
2116
  }
2117

UNCOV
2118
  if (from) {
×
2119
    // find next is '('
2120
    char* p2 = from + 5;
×
UNCOV
2121
    bool  found = false;   // found 'from ... ( ...'  ... is any count of blank
×
2122
    bool  found1 = false;  // found '('
×
2123
    while (1) {
2124
      if (p2 == last || *p2 == '\0') {
×
2125
        // last word or string end
2126
        if (found1) {
×
UNCOV
2127
          found = true;
×
2128
        }
2129
        break;
×
UNCOV
2130
      } else if (*p2 == '(') {
×
2131
        found1 = true;
×
2132
      } else if (*p2 == ' ') {
×
2133
        // do nothing
2134
      } else {
2135
        // have any other char
UNCOV
2136
        break;
×
2137
      }
2138

2139
      // move next
UNCOV
2140
      p2++;
×
2141
    }
2142

UNCOV
2143
    if (found) {
×
UNCOV
2144
      fillWithType(con, cmd, last, WT_VAR_KEYSELECT);
×
2145
      taosMemoryFree(sql);
×
2146
      return true;
×
2147
    }
2148
  }
2149

2150
  // INSERT
2151

UNCOV
2152
  taosMemoryFree(sql);
×
2153

2154
  return false;
×
2155
}
2156

2157
// last match if nothing matched
UNCOV
2158
bool matchEnd(TAOS* con, SShellCmd* cmd) {
×
2159
  // str dump
2160
  bool  ret = false;
×
UNCOV
2161
  char* ps = taosStrndup(cmd->command, cmd->commandSize);
×
2162
  char* last = lastWord(ps);
×
2163
  char* elast = strrchr(last, '.');  // find end last
×
2164
  if (elast) {
×
2165
    last = elast + 1;
×
2166
  }
2167

2168
  // less one char can match
UNCOV
2169
  if (strlen(last) == 0) {
×
UNCOV
2170
    goto _return;
×
2171
  }
2172
  if (strcmp(last, " ") == 0) {
×
UNCOV
2173
    goto _return;
×
2174
  }
2175

2176
  // match database
UNCOV
2177
  if (elast == NULL) {
×
2178
    // dot need not completed with dbname
2179
    if (fillWithType(con, cmd, last, WT_VAR_DBNAME)) {
×
UNCOV
2180
      ret = true;
×
2181
      goto _return;
×
2182
    }
2183
  }
2184

UNCOV
2185
  if (fillWithType(con, cmd, last, WT_VAR_SYSTABLE)) {
×
UNCOV
2186
    ret = true;
×
2187
    goto _return;
×
2188
  }
2189

2190
  // global keys
UNCOV
2191
  if (fillWithType(con, cmd, last, WT_VAR_GLOBALKEYS)) {
×
UNCOV
2192
    ret = true;
×
2193
    goto _return;
×
2194
  }
2195

2196

UNCOV
2197
_return:
×
UNCOV
2198
  taosMemoryFree(ps);
×
2199
  return ret;
×
2200
}
2201

2202
// main key press tab
UNCOV
2203
void pressTabKey(SShellCmd* cmd) {
×
2204
#ifdef WINDOWS
2205
  return ;
2206
#endif
2207
  // check empty tab key
UNCOV
2208
  if (cmd->commandSize == 0) {
×
2209
    // have multi line tab key
2210
    if (cmd->bufferSize == 0) {
×
UNCOV
2211
      showHelp();
×
2212
    }
2213
    shellShowOnScreen(cmd);
×
UNCOV
2214
    return;
×
2215
  }
2216

2217
  // save connection to global
UNCOV
2218
  varCmd = cmd;
×
UNCOV
2219
  bool matched = false;
×
2220

2221
  // manual match like create table st( ...
UNCOV
2222
  matched = matchCreateTable(varCon, cmd);
×
UNCOV
2223
  if (matched) return;
×
2224

2225
  // shellCommands match
UNCOV
2226
  if (firstMatchIndex == -1) {
×
UNCOV
2227
    matched = firstMatchCommand(varCon, cmd);
×
2228
  } else {
2229
    matched = nextMatchCommand(varCon, cmd, &shellCommands[firstMatchIndex]);
×
2230
  }
2231
  if (matched) return;
×
2232

2233
  // NOT MATCHED ANYONE
2234
  // match other like '\G' ...
UNCOV
2235
  matched = matchOther(varCon, cmd);
×
UNCOV
2236
  if (matched) return;
×
2237

2238
  // manual match like select * from ...
UNCOV
2239
  matched = matchSelectQuery(varCon, cmd);
×
UNCOV
2240
  if (matched) return;
×
2241

2242
  // match end
UNCOV
2243
  matched = matchEnd(varCon, cmd);
×
2244

2245
  return;
×
2246
}
2247

2248
// press othr key
2249
void pressOtherKey(char c) {
26,773✔
2250
#ifdef WINDOWS
2251
  return ;
2252
#endif
2253

2254
  // reset global variant
2255
  firstMatchIndex = -1;
26,773✔
2256
  lastMatchIndex = -1;
26,773✔
2257
  curMatchIndex = -1;
26,773✔
2258
  lastWordBytes = -1;
26,773✔
2259

2260
  // var names
2261
  cursorVar = -1;
26,773✔
2262
  varMode = false;
26,773✔
2263
  waitAutoFill = false;
26,773✔
2264
  cntDel = 0;
26,773✔
2265

2266
  if (lastMatch) {
26,773✔
UNCOV
2267
    freeMatch(lastMatch);
×
UNCOV
2268
    lastMatch = NULL;
×
2269
  }
2270
}
26,773✔
2271

2272
// put name into name, return name length
2273
int getWordName(char* p, char* name, int nameLen) {
38,783✔
2274
  // remove prefix blank
2275
  while (*p == ' ') {
44,101✔
2276
    p++;
5,318✔
2277
  }
2278

2279
  // get databases name;
2280
  int i = 0;
38,783✔
2281
  while (p[i] != 0 && i < nameLen - 1) {
214,933✔
2282
    name[i] = p[i];
214,838✔
2283
    i++;
214,838✔
2284
    if (p[i] == ' ' || p[i] == ';' || p[i] == '(') {
214,838✔
2285
      // name end
2286
      break;
2287
    }
2288
  }
2289
  name[i] = 0;
38,783✔
2290

2291
  return i;
38,783✔
2292
}
2293

2294
// deal use db, if have  'use' return true
2295
bool dealUseDB(char* sql) {
1,478,622✔
2296
  // check use keyword
2297
  if (strncasecmp(sql, "use ", 4) != 0) {
1,478,622✔
2298
    return false;
1,451,488✔
2299
  }
2300

2301
  char  db[256];
25,812✔
2302
  char* p = sql + 4;
27,134✔
2303
  if (getWordName(p, db, sizeof(db)) == 0) {
27,134✔
2304
    // no name , return
UNCOV
2305
    return true;
×
2306
  }
2307

2308
  //  dbName is previous use open db name
2309
  if (strcasecmp(db, dbName) == 0) {
27,134✔
2310
    // same , no need switch
UNCOV
2311
    return true;
×
2312
  }
2313

2314
  // switch new db
2315
  taosThreadMutexLock(&tiresMutex);
27,134✔
2316
  // STABLE set null
2317
  STire* tire = tires[WT_VAR_STABLE];
27,134✔
2318
  tires[WT_VAR_STABLE] = NULL;
27,134✔
2319
  if (tire) {
27,134✔
UNCOV
2320
    freeTire(tire);
×
2321
  }
2322
  // TABLE set null
2323
  tire = tires[WT_VAR_TABLE];
27,134✔
2324
  tires[WT_VAR_TABLE] = NULL;
27,134✔
2325
  if (tire) {
27,134✔
UNCOV
2326
    freeTire(tire);
×
2327
  }
2328
  // save
2329
  strcpy(dbName, db);
27,134✔
2330
  taosThreadMutexUnlock(&tiresMutex);
27,134✔
2331

2332
  return true;
27,134✔
2333
}
2334

2335
// deal create, if have 'create' return true
2336
bool dealCreateCommand(char* sql) {
1,451,488✔
2337
  // check keyword
2338
  if (strncasecmp(sql, "create ", 7) != 0) {
1,451,488✔
2339
    return false;
1,446,092✔
2340
  }
2341

2342
  char  name[1024];
5,276✔
2343
  char* p = sql + 7;
5,396✔
2344
  if (getWordName(p, name, sizeof(name)) == 0) {
5,396✔
2345
    // no name , return
UNCOV
2346
    return true;
×
2347
  }
2348

2349
  int type = -1;
5,396✔
2350
  //  dbName is previous use open db name
2351
  if (strcasecmp(name, "database") == 0) {
5,396✔
2352
    type = WT_VAR_DBNAME;
1,128✔
2353
  } else if (strcasecmp(name, "table") == 0) {
4,268✔
2354
    if (strstr(sql, " tags") != NULL && strstr(sql, " using ") == NULL)
2,005✔
2355
      type = WT_VAR_STABLE;
248✔
2356
    else
2357
      type = WT_VAR_TABLE;
1,757✔
2358
  } else if (strcasecmp(name, "user") == 0) {
2,263✔
UNCOV
2359
    type = WT_VAR_USERNAME;
×
2360
  } else if (strcasecmp(name, "topic") == 0) {
2,263✔
2361
    type = WT_VAR_TOPIC;
×
2362
  } else if (strcasecmp(name, "stream") == 0) {
2,263✔
2363
    type = WT_VAR_STREAM;
1,250✔
2364
  } else {
2365
    // no match , return
2366
    return true;
1,013✔
2367
  }
2368

2369
  // move next
2370
  p += strlen(name);
4,383✔
2371

2372
  // get next word , that is table name
2373
  if (getWordName(p, name, sizeof(name)) == 0) {
4,383✔
2374
    // no name , return
UNCOV
2375
    return true;
×
2376
  }
2377

2378
  // switch new db
2379
  taosThreadMutexLock(&tiresMutex);
4,383✔
2380
  // STABLE set null
2381
  STire* tire = tires[type];
4,383✔
2382
  if (tire) {
4,383✔
2383
    insertWord(tire, name);
352✔
2384
  }
2385
  taosThreadMutexUnlock(&tiresMutex);
4,383✔
2386

2387
  return true;
4,383✔
2388
}
2389

2390
// deal create, if have 'drop' return true
2391
bool dealDropCommand(char* sql) {
1,446,092✔
2392
  // check keyword
2393
  if (strncasecmp(sql, "drop ", 5) != 0) {
1,446,092✔
2394
    return false;
1,445,157✔
2395
  }
2396

2397
  char  name[1024];
315✔
2398
  char* p = sql + 5;
935✔
2399
  if (getWordName(p, name, sizeof(name)) == 0) {
935✔
2400
    // no name , return
UNCOV
2401
    return true;
×
2402
  }
2403

2404
  int type = -1;
935✔
2405
  //  dbName is previous use open db name
2406
  if (strcasecmp(name, "database") == 0) {
935✔
2407
    type = WT_VAR_DBNAME;
854✔
2408
  } else if (strcasecmp(name, "table") == 0) {
81✔
UNCOV
2409
    type = WT_VAR_ALLTABLE;
×
2410
  } else if (strcasecmp(name, "dnode") == 0) {
81✔
2411
    type = WT_VAR_DNODEID;
×
2412
  } else if (strcasecmp(name, "user") == 0) {
81✔
2413
    type = WT_VAR_USERNAME;
×
2414
  } else if (strcasecmp(name, "topic") == 0) {
81✔
2415
    type = WT_VAR_TOPIC;
81✔
UNCOV
2416
  } else if (strcasecmp(name, "stream") == 0) {
×
UNCOV
2417
    type = WT_VAR_STREAM;
×
2418
  } else {
2419
    // no match , return
UNCOV
2420
    return true;
×
2421
  }
2422

2423
  // move next
2424
  p += strlen(name);
935✔
2425

2426
  // get next word , that is table name
2427
  if (getWordName(p, name, sizeof(name)) == 0) {
935✔
2428
    // no name , return
UNCOV
2429
    return true;
×
2430
  }
2431

2432
  // switch new db
2433
  taosThreadMutexLock(&tiresMutex);
935✔
2434
  // STABLE set null
2435
  if (type == WT_VAR_ALLTABLE) {
935✔
UNCOV
2436
    bool del = false;
×
2437
    // del in stable
2438
    STire* tire = tires[WT_VAR_STABLE];
×
UNCOV
2439
    if (tire) del = deleteWord(tire, name);
×
2440
    // del in table
2441
    if (!del) {
×
UNCOV
2442
      tire = tires[WT_VAR_TABLE];
×
2443
      if (tire) del = deleteWord(tire, name);
×
2444
    }
2445
  } else {
2446
    // OTHER TYPE
2447
    STire* tire = tires[type];
935✔
2448
    if (tire) deleteWord(tire, name);
935✔
2449
  }
2450
  taosThreadMutexUnlock(&tiresMutex);
935✔
2451

2452
  return true;
935✔
2453
}
2454

2455
// callback autotab module after shell sql execute
2456
void callbackAutoTab(char* sqlstr, TAOS* pSql, bool usedb) {
1,478,622✔
2457
  char* sql = sqlstr;
1,478,622✔
2458
  // remove prefix blank
2459
  while (*sql == ' ') {
1,478,622✔
UNCOV
2460
    sql++;
×
2461
  }
2462

2463
  if (dealUseDB(sql)) {
1,478,622✔
2464
    // change to new db
2465
    if (!varRunOnce) updateTireValue(WT_VAR_STABLE, false);
27,134✔
2466
    return;
27,134✔
2467
  }
2468

2469
  // create command add name to autotab
2470
  if (dealCreateCommand(sql)) {
1,451,488✔
2471
    return;
5,396✔
2472
  }
2473

2474
  // drop command remove name from autotab
2475
  if (dealDropCommand(sql)) {
1,446,092✔
2476
    return;
935✔
2477
  }
2478

2479
  return;
1,445,157✔
2480
}
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