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

taosdata / TDengine / #4905

29 Dec 2025 02:08PM UTC coverage: 65.423% (-0.3%) from 65.734%
#4905

push

travis-ci

web-flow
enh: sign connect request (#34067)

23 of 29 new or added lines in 4 files covered. (79.31%)

11614 existing lines in 186 files now uncovered.

193476 of 295730 relevant lines covered (65.42%)

115752566.53 hits per line

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

423
// create user options
424
char * create_uopt[] = {
425
    "pass ",
426
    "totpseed ",
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
    "totpseed ",
454
    "account ",
455
    "sysinfo ",
456
    "createdb ",
457
    "changepass ",
458
    "session_per_user ",
459
    "connect_idle_time ",
460
    "connect_time ",
461
    "call_per_session ",
462
    "vnode_per_call ",
463
    "failed_login_attempts ",
464
    "password_life_time ",
465
    "password_reuse_time ",
466
    "password_reuse_max ",
467
    "password_lock_time ",
468
    "password_grace_time ",
469
    "inactive_account_time ",
470
    "allow_token_num ",
471
    "enable ",
472
    "add host ",
473
    "add not_allow_host ",
474
    "drop host ",
475
    "drop not_allow_host ",
476
    "add allow_datetime ",
477
    "add not_allow_datetime ",
478
    "drop allow_datetime ",
479
    "drop not_allow_datetime "
480
};
481

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

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

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

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

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

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

559

560
#define WT_TEXT 0xFF
561

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

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

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

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

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

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

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

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

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

843
//
844
//  -------------------  parse words --------------------------
845
//
846

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

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

UNCOV
857
  return word;
×
858
}
859

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

862
int wordType(const char* p, int32_t len) {
556,220,880✔
863
  for (int i = 0; i < WT_VAR_CNT; i++) {
2,147,483,647✔
864
    if (strncmp(p, varTypes[i], len) == 0) return i;
2,147,483,647✔
865
  }
866
  return WT_TEXT;
400,942,551✔
867
}
868

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

876
  // check format
877
  if (pattern && len > 0) {
563,173,641✔
878
    if (p[len - 1] == ';') {
556,220,880✔
879
      word->type = wordType(p, len - 1);
112,016,705✔
880
      word->end = true;
112,016,705✔
881
    } else {
882
      word->type = wordType(p, len);
444,204,175✔
883
    }
884
  } else {
885
    word->type = WT_TEXT;
6,952,761✔
886
  }
887

888
  return word;
563,173,641✔
889
}
890

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

897
  bool lastBlank = false;
139,055,220✔
898
  for (int i = 0; i <= size; i++) {
2,147,483,647✔
899
    if (p[i] == ' ' || i == size) {
2,147,483,647✔
900
      // check continue blank like '    '
901
      if (p[i] == ' ') {
564,718,699✔
902
        if (lastBlank) {
425,663,479✔
903
          start++;
1,545,058✔
904
          continue;
1,545,058✔
905
        }
906
        if (i == 0) {  // first blank
424,118,421✔
UNCOV
907
          lastBlank = true;
×
UNCOV
908
          start++;
×
UNCOV
909
          continue;
×
910
        }
911
        lastBlank = true;
424,118,421✔
912
      }
913

914
      // found split or string end , append word
915
      if (command->head == NULL) {
563,173,641✔
916
        command->head = addWord(p + start, i - start, pattern);
139,055,220✔
917
        command->count = 1;
139,055,220✔
918
      } else {
919
        SWord* word = command->head;
424,118,421✔
920
        while (word->next) {
1,443,084,172✔
921
          word = word->next;
1,018,965,751✔
922
        }
923
        word->next = addWord(p + start, i - start, pattern);
424,118,421✔
924
        command->count++;
424,118,421✔
925
      }
926
      start = i + 1;
563,173,641✔
927
    } else {
928
      lastBlank = false;
2,147,483,647✔
929
    }
930
  }
931
}
139,055,220✔
932

933
// free SShellCmd
934
void freeCommand(SWords* command) {
139,055,220✔
935
  SWord* item = command->head;
139,055,220✔
936
  command->head = NULL;
139,055,220✔
937
  // loop
938
  while (item) {
702,228,861✔
939
    SWord* tmp = item;
563,173,641✔
940
    item = item->next;
563,173,641✔
941
    // if malloc need free
942
    if (tmp->free && tmp->word) taosMemoryFree(tmp->word);
563,173,641✔
943
    taosMemoryFree(tmp);
563,173,641✔
944
  }
945
}
139,055,220✔
946

947
void GenerateVarType(int type, char** p, int count) {
13,132,993✔
948
  STire* tire = createTire(TIRE_LIST);
13,132,993✔
949
  for (int i = 0; i < count; i++) {
285,063,201✔
950
    insertWord(tire, p[i]);
271,930,208✔
951
  }
952

953
  taosThreadMutexLock(&tiresMutex);
13,132,993✔
954
  tires[type] = tire;
13,132,993✔
955
  taosThreadMutexUnlock(&tiresMutex);
13,132,993✔
956
}
13,132,993✔
957

958
//
959
//  -------------------- shell auto ----------------
960
//
961

962
// init shell auto function , shell start call once
963
void shellAutoInit() {
772,529✔
964
  // command
965
  int32_t count = SHELL_COMMAND_COUNT();
772,529✔
966
  for (int32_t i = 0; i < count; i++) {
139,827,749✔
967
    parseCommand(shellCommands + i, true);
139,055,220✔
968
  }
969

970
  // tires
971
  memset(tires, 0, sizeof(STire*) * WT_VAR_CNT);
772,529✔
972
  taosThreadMutexInit(&tiresMutex, NULL);
772,529✔
973

974
  // threads
975
  memset(threads, 0, sizeof(TdThread*) * WT_FROM_DB_CNT);
772,529✔
976

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

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

1005
// exit shell auto function, shell exit call once
1006
void shellAutoExit() {
772,529✔
1007
  // free command
1008
  int32_t count = SHELL_COMMAND_COUNT();
772,529✔
1009
  for (int32_t i = 0; i < count; i++) {
139,827,749✔
1010
    freeCommand(shellCommands + i);
139,055,220✔
1011
  }
1012

1013
  // free tires
1014
  taosThreadMutexLock(&tiresMutex);
772,529✔
1015
  for (int32_t i = 0; i < WT_VAR_CNT; i++) {
25,493,457✔
1016
    if (tires[i]) {
24,720,928✔
1017
      freeTire(tires[i]);
13,133,308✔
1018
      tires[i] = NULL;
13,133,308✔
1019
    }
1020
  }
1021
  taosThreadMutexUnlock(&tiresMutex);
772,529✔
1022
  // destroy
1023
  taosThreadMutexDestroy(&tiresMutex);
772,529✔
1024

1025
  // free threads
1026
  for (int32_t i = 0; i < WT_FROM_DB_CNT; i++) {
10,815,406✔
1027
    if (threads[i]) {
10,042,877✔
UNCOV
1028
      taosDestroyThread(threads[i]);
×
UNCOV
1029
      threads[i] = NULL;
×
1030
    }
1031
  }
1032

1033
  // free lastMatch
1034
  if (lastMatch) {
772,529✔
UNCOV
1035
    freeMatch(lastMatch);
×
UNCOV
1036
    lastMatch = NULL;
×
1037
  }
1038
}
772,529✔
1039

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

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

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

1060
  return true;
315✔
1061
}
1062

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

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

1073
  return tires[type];
×
1074
}
1075

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

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

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

UNCOV
1096
  return;
×
1097
}
1098

1099
//
1100
//  -------------------  var Word --------------------------
1101
//
1102

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

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

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

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

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

1137
    row = taos_fetch_row(tres);
945✔
1138
  } while (row != NULL);
945✔
1139

1140
  // replace old tire
1141
  setNewAutoPtr(type, tire);
315✔
1142

1143
  return numOfRows;
315✔
1144
}
1145

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

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

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

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

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

1177
  // free sql
1178
  taos_free_result(pSql);
315✔
1179

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

1186
  setThreadNull(type);
315✔
1187
  return NULL;
315✔
1188
}
1189

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

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

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

1219
  return false;
×
1220
}
1221

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

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

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

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

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

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

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

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

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

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

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

UNCOV
1295
  return NULL;
×
1296
}
1297

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

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

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

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

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

1325
  return str;
×
1326
}
1327

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

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

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

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

1362
  return true;
×
1363
}
1364

1365
//
1366
//  -------------------  match words --------------------------
1367
//
1368

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

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

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

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

1421
  return -1;
×
1422
}
1423

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

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

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

1452
  // not match
1453
  return NULL;
×
1454
}
1455

1456
//
1457
//  -------------------  print screen --------------------------
1458
//
1459

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

UNCOV
1628
  return true;
×
1629
}
1630

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

UNCOV
1755
  return true;
×
1756
}
1757

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

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

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

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

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

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

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

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

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

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

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

1837
    return p1 - p;
×
1838
  }
1839

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

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

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

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

UNCOV
1860
  return -1;
×
1861
}
1862

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

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

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

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

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

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

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

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

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

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

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

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

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

UNCOV
1959
  return n > 0;
×
1960
}
1961

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

2103
  // INSERT
2104

2105
  taosMemoryFree(sql);
×
2106

2107
  return false;
×
2108
}
2109

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

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

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

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

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

2149

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

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

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

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

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

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

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

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

UNCOV
2198
  return;
×
2199
}
2200

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

2207
  // reset global variant
2208
  firstMatchIndex = -1;
6,742✔
2209
  lastMatchIndex = -1;
6,742✔
2210
  curMatchIndex = -1;
6,742✔
2211
  lastWordBytes = -1;
6,742✔
2212

2213
  // var names
2214
  cursorVar = -1;
6,742✔
2215
  varMode = false;
6,742✔
2216
  waitAutoFill = false;
6,742✔
2217
  cntDel = 0;
6,742✔
2218

2219
  if (lastMatch) {
6,742✔
UNCOV
2220
    freeMatch(lastMatch);
×
UNCOV
2221
    lastMatch = NULL;
×
2222
  }
2223
}
6,742✔
2224

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

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

2244
  return i;
18,796✔
2245
}
2246

2247
// deal use db, if have  'use' return true
2248
bool dealUseDB(char* sql) {
1,268,642✔
2249
  // check use keyword
2250
  if (strncasecmp(sql, "use ", 4) != 0) {
1,268,642✔
2251
    return false;
1,256,186✔
2252
  }
2253

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

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

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

2285
  return true;
12,456✔
2286
}
2287

2288
// deal create, if have 'create' return true
2289
bool dealCreateCommand(char* sql) {
1,256,186✔
2290
  // check keyword
2291
  if (strncasecmp(sql, "create ", 7) != 0) {
1,256,186✔
2292
    return false;
1,253,057✔
2293
  }
2294

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

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

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

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

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

2340
  return true;
2,229✔
2341
}
2342

2343
// deal create, if have 'drop' return true
2344
bool dealDropCommand(char* sql) {
1,253,057✔
2345
  // check keyword
2346
  if (strncasecmp(sql, "drop ", 5) != 0) {
1,253,057✔
2347
    return false;
1,252,566✔
2348
  }
2349

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

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

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

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

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

2405
  return true;
491✔
2406
}
2407

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

2416
  if (dealUseDB(sql)) {
1,268,642✔
2417
    // change to new db
2418
    if (!varRunOnce) updateTireValue(WT_VAR_STABLE, false);
12,456✔
2419
    return;
12,456✔
2420
  }
2421

2422
  // create command add name to autotab
2423
  if (dealCreateCommand(sql)) {
1,256,186✔
2424
    return;
3,129✔
2425
  }
2426

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

2432
  return;
1,252,566✔
2433
}
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