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

taosdata / TDengine / #4898

26 Dec 2025 09:58AM UTC coverage: 65.061% (-0.7%) from 65.717%
#4898

push

travis-ci

web-flow
feat: support encryption of configuration files, data files and metadata files (#33801)

350 of 1333 new or added lines in 31 files covered. (26.26%)

2796 existing lines in 159 files now uncovered.

184024 of 282850 relevant lines covered (65.06%)

113940470.33 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 users;", 0, 0, NULL},
239
    {"show variables;", 0, 0, NULL},
240
    {"show local variables;", 0, 0, NULL},
241
    {"show vnodes;", 0, 0, NULL},
242
    {"show vnodes on dnode <dnode_id>;", 0, 0, NULL},
243
    {"show vgroups;", 0, 0, NULL},
244
    {"show vtables;", 0, 0, NULL},
245
    {"show consumers;", 0, 0, NULL},
246
    {"show grants;", 0, 0, NULL},
247
    {"show grants full;", 0, 0, NULL},
248
    {"show grants logs;", 0, 0, NULL},
249
#ifdef TD_ENTERPRISE
250
    {"show views;", 0, 0, NULL},
251
    {"show arbgroups;", 0, 0, NULL},
252
    {"split vgroup <vgroup_id>;", 0, 0, NULL},
253
    {"ssmigrate database <db_name>;", 0, 0, NULL},
254
    {"show mounts;", 0, 0, NULL},
255
    {"show ssmigrates;", 0, 0, NULL},
256
#endif
257
    {"insert into <tb_name> values(", 0, 0, NULL},
258
    {"insert into <tb_name> using <stb_name> tags(", 0, 0, NULL},
259
    {"insert into <tb_name> using <stb_name> <anyword> values(", 0, 0, NULL},
260
    {"insert into <tb_name> file ", 0, 0, NULL},
261
    {"trim database <db_name>;", 0, 0, NULL},
262
    {"use <db_name>;", 0, 0, NULL},
263
    {"update all anodes;", 0, 0, NULL},
264
    {"update anode <anyword>;", 0, 0, NULL},
265
    {"quit", 0, 0, NULL}};
266

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

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

335
char* tb_actions[] = {
336
    "add column ", "modify column ", "drop column ", "rename column ", "add tag ",
337
    "modify tag ", "drop tag ",      "rename tag ",  "set tag ",
338
};
339

340
char* user_actions[] = {"pass ", "enable ", "sysinfo ", "createdb "};
341

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

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

379
char* alter_db_options[] = {"cachemodel ", "replica ", "keep ", "stt_trigger ",
380
                            "wal_retention_period ", "wal_retention_size ", "cachesize ", 
381
                                              "ss_keeplocal ", "ss_compact ",
382
                            "wal_fsync_period ", "buffer ", "pages " ,"wal_level "};
383

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

395
char* key_tags[] = {"tags("};
396

397
char* key_select[] = {"select "};
398

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

407
char* udf_language[] = {"\'Python\'", "\'C\'"};
408

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

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

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

477
// alter user options
478
char * token_opt[] = {
479
    "enable ",
480
    "provider ",
481
    "ttl ",
482
    "extra_info "
483
};
484

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

504
//
505
//  ------- global variant define ---------
506
//
507
int32_t firstMatchIndex = -1;  // first match shellCommands index
508
int32_t lastMatchIndex = -1;   // last match shellCommands index
509
int32_t curMatchIndex = -1;    // current match shellCommands index
510
int32_t lastWordBytes = -1;    // printShow last word length
511
bool    waitAutoFill = false;
512

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

530
#define WT_FROM_DB_MAX        12  // max get content from db
531
#define WT_FROM_DB_CNT (WT_FROM_DB_MAX + 1)
532

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

554

555
#define WT_TEXT 0xFF
556

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

573
char varSqls[WT_FROM_DB_CNT][64] = {"show databases;", "show stables;", "show tables;", "show dnodes;",
574
                                    "show users;",     "show topics;",  "show streams;", "show functions;", 
575
                                    "show vgroups;",   "show tsmas;",   "show rsmas;",  "show anodes;",
576
                                    "show tokens;"};
577

578
// var words current cursor, if user press any one key except tab, cursorVar can be reset to -1
579
int  cursorVar = -1;
580
bool varMode = false;  // enter var names list mode
581

582
TAOS*      varCon = NULL;
583
SShellCmd* varCmd = NULL;
584
bool       varRunOnce = false;
585
SMatch*    lastMatch = NULL;  // save last match result
586
int        cntDel = 0;        // delete byte count after next press tab
587

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

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

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

785
#ifdef TD_ENTERPRISE
786
  printf(
26✔
787
      "\n\n\
788
  ----- special commands on enterpise version ----- \n\
789
    alter token <token_name> [token options];\n\
790
    balance vgroup ;\n\
791
    balance vgroup leader on <vgroup_id> \n\
792
    compact database <db_name>; \n\
793
    compact vgroups in (vgroupId,vgroupId, ...); \n\
794
    create view <view_name> as select ...\n\
795
    create mount <mount_name> on dnode <dnode_id> from <path>;\n\
796
    create token <token_name> from user <user_name> [token options];\n\
797
    drop mount <mount_name>;\n\
798
    drop token <token_name>;\n\
799
    redistribute vgroup <vgroup_id> dnode <dnode_id> ;\n\
800
    split vgroup <vgroup_id>;\n\
801
    ssmigrate database <db_name>;\n\
802
    show arbgroups;\n\
803
    show compacts;\n\
804
    show compact \n\
805
    show tokens;\n\
806
    show ssmigrates;\n\
807
    show mounts;\n\
808
    show views;\n\
809
    show create view <all_table>;");
810
    
811
#endif
812

813
  printf("\n\n");
26✔
814
  // define in getDuration() function
815
  printf(
26✔
816
      "\
817
  Timestamp expression Format:\n\
818
    b - nanosecond \n\
819
    u - microsecond \n\
820
    a - millisecond \n\
821
    s - second \n\
822
    m - minute \n\
823
    h - hour \n\
824
    d - day \n\
825
    w - week \n\
826
    now - current time \n\
827
  Example : \n\
828
    select * from t1 where ts > now - 2w + 3d and ts <= now - 1w -2h ;\n");
829
  printf(ERROR_CODE_DETAIL);
26✔
830
  printf("\n");
26✔
831
}
26✔
832

833
//
834
//  -------------------  parse words --------------------------
835
//
836

837
#define SHELL_COMMAND_COUNT() (sizeof(shellCommands) / sizeof(SWords))
838

839
// get at
UNCOV
840
SWord* atWord(SWords* command, int32_t index) {
×
UNCOV
841
  SWord* word = command->head;
×
UNCOV
842
  for (int32_t i = 0; i < index; i++) {
×
UNCOV
843
    if (word == NULL) return NULL;
×
UNCOV
844
    word = word->next;
×
845
  }
846

UNCOV
847
  return word;
×
848
}
849

850
#define MATCH_WORD(x) atWord(x, x->matchIndex)
851

852
int wordType(const char* p, int32_t len) {
527,258,688✔
853
  for (int i = 0; i < WT_VAR_CNT; i++) {
2,147,483,647✔
854
    if (strncmp(p, varTypes[i], len) == 0) return i;
2,147,483,647✔
855
  }
856
  return WT_TEXT;
376,720,341✔
857
}
858

859
// add word
860
SWord* addWord(const char* p, int32_t len, bool pattern) {
533,999,211✔
861
  SWord* word = (SWord*)taosMemoryMalloc(sizeof(SWord));
533,999,211✔
862
  memset(word, 0, sizeof(SWord));
533,999,211✔
863
  word->word = (char*)p;
533,999,211✔
864
  word->len = len;
533,999,211✔
865

866
  // check format
867
  if (pattern && len > 0) {
533,999,211✔
868
    if (p[len - 1] == ';') {
527,258,688✔
869
      word->type = wordType(p, len - 1);
104,852,580✔
870
      word->end = true;
104,852,580✔
871
    } else {
872
      word->type = wordType(p, len);
422,406,108✔
873
    }
874
  } else {
875
    word->type = WT_TEXT;
6,740,523✔
876
  }
877

878
  return word;
533,999,211✔
879
}
880

881
// parse one command
882
void parseCommand(SWords* command, bool pattern) {
131,065,725✔
883
  char*   p = command->source;
131,065,725✔
884
  int32_t start = 0;
131,065,725✔
885
  int32_t size = command->source_len > 0 ? command->source_len : strlen(p);
131,065,725✔
886

887
  bool lastBlank = false;
131,065,725✔
888
  for (int i = 0; i <= size; i++) {
2,147,483,647✔
889
    if (p[i] == ' ' || i == size) {
2,147,483,647✔
890
      // check continue blank like '    '
891
      if (p[i] == ' ') {
535,497,105✔
892
        if (lastBlank) {
404,431,380✔
893
          start++;
1,497,894✔
894
          continue;
1,497,894✔
895
        }
896
        if (i == 0) {  // first blank
402,933,486✔
UNCOV
897
          lastBlank = true;
×
UNCOV
898
          start++;
×
UNCOV
899
          continue;
×
900
        }
901
        lastBlank = true;
402,933,486✔
902
      }
903

904
      // found split or string end , append word
905
      if (command->head == NULL) {
533,999,211✔
906
        command->head = addWord(p + start, i - start, pattern);
131,065,725✔
907
        command->count = 1;
131,065,725✔
908
      } else {
909
        SWord* word = command->head;
402,933,486✔
910
        while (word->next) {
1,384,803,003✔
911
          word = word->next;
981,869,517✔
912
        }
913
        word->next = addWord(p + start, i - start, pattern);
402,933,486✔
914
        command->count++;
402,933,486✔
915
      }
916
      start = i + 1;
533,999,211✔
917
    } else {
918
      lastBlank = false;
2,147,483,647✔
919
    }
920
  }
921
}
131,065,725✔
922

923
// free SShellCmd
924
void freeCommand(SWords* command) {
131,065,725✔
925
  SWord* item = command->head;
131,065,725✔
926
  command->head = NULL;
131,065,725✔
927
  // loop
928
  while (item) {
665,064,936✔
929
    SWord* tmp = item;
533,999,211✔
930
    item = item->next;
533,999,211✔
931
    // if malloc need free
932
    if (tmp->free && tmp->word) taosMemoryFree(tmp->word);
533,999,211✔
933
    taosMemoryFree(tmp);
533,999,211✔
934
  }
935
}
131,065,725✔
936

937
void GenerateVarType(int type, char** p, int count) {
12,732,099✔
938
  STire* tire = createTire(TIRE_LIST);
12,732,099✔
939
  for (int i = 0; i < count; i++) {
276,361,443✔
940
    insertWord(tire, p[i]);
263,629,344✔
941
  }
942

943
  taosThreadMutexLock(&tiresMutex);
12,732,099✔
944
  tires[type] = tire;
12,732,099✔
945
  taosThreadMutexUnlock(&tiresMutex);
12,732,099✔
946
}
12,732,099✔
947

948
//
949
//  -------------------- shell auto ----------------
950
//
951

952
// init shell auto function , shell start call once
953
void shellAutoInit() {
748,947✔
954
  // command
955
  int32_t count = SHELL_COMMAND_COUNT();
748,947✔
956
  for (int32_t i = 0; i < count; i++) {
131,814,672✔
957
    parseCommand(shellCommands + i, true);
131,065,725✔
958
  }
959

960
  // tires
961
  memset(tires, 0, sizeof(STire*) * WT_VAR_CNT);
748,947✔
962
  taosThreadMutexInit(&tiresMutex, NULL);
748,947✔
963

964
  // threads
965
  memset(threads, 0, sizeof(TdThread*) * WT_FROM_DB_CNT);
748,947✔
966

967
  // generate varType
968
  GenerateVarType(WT_VAR_FUNC, functions, sizeof(functions) / sizeof(char*));
748,947✔
969
  GenerateVarType(WT_VAR_KEYWORD, keywords, sizeof(keywords) / sizeof(char*));
748,947✔
970
  GenerateVarType(WT_VAR_TBACTION, tb_actions, sizeof(tb_actions) / sizeof(char*));
748,947✔
971
  GenerateVarType(WT_VAR_DBOPTION, db_options, sizeof(db_options) / sizeof(char*));
748,947✔
972
  GenerateVarType(WT_VAR_ALTER_DBOPTION, alter_db_options, sizeof(alter_db_options) / sizeof(char*));
748,947✔
973
  GenerateVarType(WT_VAR_DATATYPE, data_types, sizeof(data_types) / sizeof(char*));
748,947✔
974
  GenerateVarType(WT_VAR_KEYTAGS, key_tags, sizeof(key_tags) / sizeof(char*));
748,947✔
975
  GenerateVarType(WT_VAR_TBOPTION, tb_options, sizeof(tb_options) / sizeof(char*));
748,947✔
976
  GenerateVarType(WT_VAR_USERACTION, user_actions, sizeof(user_actions) / sizeof(char*));
748,947✔
977
  GenerateVarType(WT_VAR_KEYSELECT, key_select, sizeof(key_select) / sizeof(char*));
748,947✔
978
  GenerateVarType(WT_VAR_SYSTABLE, key_systable, sizeof(key_systable) / sizeof(char*));
748,947✔
979
  GenerateVarType(WT_VAR_LANGUAGE, udf_language, sizeof(udf_language) / sizeof(char*));
748,947✔
980
  GenerateVarType(WT_VAR_GLOBALKEYS, global_keys, sizeof(global_keys) / sizeof(char*));
748,947✔
981
  GenerateVarType(WT_VAR_FIELD_OPTIONS, field_options, sizeof(field_options) / sizeof(char*));
748,947✔
982
  GenerateVarType(WT_VAR_CREATE_USER_OPT, create_uopt, sizeof(create_uopt) / sizeof(char*));
748,947✔
983
  GenerateVarType(WT_VAR_ALTER_USER_OPT, alter_uopt, sizeof(alter_uopt) / sizeof(char*));
748,947✔
984
  GenerateVarType(WT_VAR_TOKEN_OPT, token_opt, sizeof(token_opt) / sizeof(char*));
748,947✔
985
}
748,947✔
986

987
// set conn
988
void shellSetConn(TAOS* conn, bool runOnce) {
748,190✔
989
  varCon = conn;
748,190✔
990
  varRunOnce = runOnce;
748,190✔
991
  // init database and stable
992
  if (!runOnce) updateTireValue(WT_VAR_DBNAME, false);
748,190✔
993
}
748,190✔
994

995
// exit shell auto function, shell exit call once
996
void shellAutoExit() {
748,947✔
997
  // free command
998
  int32_t count = SHELL_COMMAND_COUNT();
748,947✔
999
  for (int32_t i = 0; i < count; i++) {
131,814,672✔
1000
    freeCommand(shellCommands + i);
131,065,725✔
1001
  }
1002

1003
  // free tires
1004
  taosThreadMutexLock(&tiresMutex);
748,947✔
1005
  for (int32_t i = 0; i < WT_VAR_CNT; i++) {
24,715,251✔
1006
    if (tires[i]) {
23,966,304✔
1007
      freeTire(tires[i]);
12,732,313✔
1008
      tires[i] = NULL;
12,732,313✔
1009
    }
1010
  }
1011
  taosThreadMutexUnlock(&tiresMutex);
748,947✔
1012
  // destroy
1013
  taosThreadMutexDestroy(&tiresMutex);
748,947✔
1014

1015
  // free threads
1016
  for (int32_t i = 0; i < WT_FROM_DB_CNT; i++) {
10,485,258✔
1017
    if (threads[i]) {
9,736,311✔
UNCOV
1018
      taosDestroyThread(threads[i]);
×
UNCOV
1019
      threads[i] = NULL;
×
1020
    }
1021
  }
1022

1023
  // free lastMatch
1024
  if (lastMatch) {
748,947✔
UNCOV
1025
    freeMatch(lastMatch);
×
UNCOV
1026
    lastMatch = NULL;
×
1027
  }
1028
}
748,947✔
1029

1030
//
1031
//  -------------------  auto ptr for tires --------------------------
1032
//
1033
bool setNewAutoPtr(int type, STire* pNew) {
214✔
1034
  if (pNew == NULL) return false;
214✔
1035

1036
  taosThreadMutexLock(&tiresMutex);
214✔
1037
  STire* pOld = tires[type];
214✔
1038
  if (pOld != NULL) {
214✔
1039
    // previous have value, release self ref count
1040
    if (--pOld->ref == 0) {
×
1041
      freeTire(pOld);
×
1042
    }
1043
  }
1044

1045
  // set new
1046
  tires[type] = pNew;
214✔
1047
  tires[type]->ref = 1;
214✔
1048
  taosThreadMutexUnlock(&tiresMutex);
214✔
1049

1050
  return true;
214✔
1051
}
1052

1053
// get ptr
UNCOV
1054
STire* getAutoPtr(int type) {
×
1055
  if (tires[type] == NULL) {
×
UNCOV
1056
    return NULL;
×
1057
  }
1058

UNCOV
1059
  taosThreadMutexLock(&tiresMutex);
×
UNCOV
1060
  tires[type]->ref++;
×
1061
  taosThreadMutexUnlock(&tiresMutex);
×
1062

UNCOV
1063
  return tires[type];
×
1064
}
1065

1066
// put back tire to tires[type], if tire not equal tires[type].p, need free tire
UNCOV
1067
void putBackAutoPtr(int type, STire* tire) {
×
UNCOV
1068
  if (tire == NULL) {
×
UNCOV
1069
    return;
×
1070
  }
1071

UNCOV
1072
  taosThreadMutexLock(&tiresMutex);
×
UNCOV
1073
  if (tires[type] != tire) {
×
1074
    // update by out,  can't put back , so free
UNCOV
1075
    if (--tire->ref == 1) {
×
1076
      // support multi thread getAutoPtr
UNCOV
1077
      freeTire(tire);
×
1078
    }
1079

1080
  } else {
UNCOV
1081
    tires[type]->ref--;
×
UNCOV
1082
    ASSERT(tires[type]->ref > 0);
×
1083
  }
UNCOV
1084
  taosThreadMutexUnlock(&tiresMutex);
×
1085

UNCOV
1086
  return;
×
1087
}
1088

1089
//
1090
//  -------------------  var Word --------------------------
1091
//
1092

1093
#define MAX_CACHED_CNT 100000  // max cached rows 10w
1094
// write sql result to var name, return write rows cnt
1095
int writeVarNames(int type, TAOS_RES* tres) {
214✔
1096
  // fetch row
1097
  TAOS_ROW row = taos_fetch_row(tres);
214✔
1098
  if (row == NULL) {
214✔
UNCOV
1099
    return 0;
×
1100
  }
1101

1102
  TAOS_FIELD* fields = taos_fetch_fields(tres);
214✔
1103
  // create new tires
1104
  char   tireType = type == WT_VAR_TABLE ? TIRE_TREE : TIRE_LIST;
214✔
1105
  STire* tire = createTire(tireType);
214✔
1106

1107
  // enum rows
1108
  char name[1024];
214✔
1109
  int  numOfRows = 0;
214✔
1110
  do {
1111
    int32_t* lengths = taos_fetch_lengths(tres);
556✔
1112
    int32_t  bytes = lengths[0];
556✔
1113
    if (fields[0].type == TSDB_DATA_TYPE_INT) {
556✔
UNCOV
1114
      sprintf(name, "%d", *(int16_t*)row[0]);
×
1115
    } else {
1116
      memcpy(name, row[0], bytes);
556✔
1117
    }
1118

1119
    name[bytes] = 0;  // set string end
556✔
1120
    // insert to tire
1121
    insertWord(tire, name);
556✔
1122

1123
    if (++numOfRows > MAX_CACHED_CNT) {
556✔
UNCOV
1124
      break;
×
1125
    }
1126

1127
    row = taos_fetch_row(tres);
556✔
1128
  } while (row != NULL);
556✔
1129

1130
  // replace old tire
1131
  setNewAutoPtr(type, tire);
214✔
1132

1133
  return numOfRows;
214✔
1134
}
1135

1136
void setThreadNull(int type) {
214✔
1137
  taosThreadMutexLock(&tiresMutex);
214✔
1138
  if (threads[type]) {
214✔
1139
    taosMemoryFree(threads[type]);
214✔
1140
  }
1141
  threads[type] = NULL;
214✔
1142
  taosThreadMutexUnlock(&tiresMutex);
214✔
1143
}
214✔
1144

1145
bool firstMatchCommand(TAOS* con, SShellCmd* cmd);
1146
//
1147
//  thread obtain var thread from db server
1148
//
1149
void* varObtainThread(void* param) {
214✔
1150
  int type = *(int*)param;
214✔
1151
  taosMemoryFree(param);
214✔
1152

1153
  if (varCon == NULL || type > WT_FROM_DB_MAX) {
214✔
UNCOV
1154
    return NULL;
×
1155
  }
1156

1157
  TAOS_RES* pSql = taos_query(varCon, varSqls[type]);
214✔
1158
  if (taos_errno(pSql)) {
214✔
UNCOV
1159
    taos_free_result(pSql);
×
UNCOV
1160
    setThreadNull(type);
×
UNCOV
1161
    return NULL;
×
1162
  }
1163

1164
  // write var names from pSql
1165
  int cnt = writeVarNames(type, pSql);
214✔
1166

1167
  // free sql
1168
  taos_free_result(pSql);
214✔
1169

1170
  // check need call auto tab
1171
  if (cnt > 0 && waitAutoFill) {
214✔
1172
    // press tab key by program
1173
    firstMatchCommand(varCon, varCmd);
×
1174
  }
1175

1176
  setThreadNull(type);
214✔
1177
  return NULL;
214✔
1178
}
1179

1180
// return true is need update value by async
1181
bool updateTireValue(int type, bool autoFill) {
214✔
1182
  // TYPE CONTEXT GET FROM DB
1183
  taosThreadMutexLock(&tiresMutex);
214✔
1184

1185
  // check need obtain from server
1186
  if (tires[type] == NULL) {
214✔
1187
    waitAutoFill = autoFill;
214✔
1188
    // need async obtain var names from db sever
1189
    if (threads[type] != NULL) {
214✔
UNCOV
1190
      if (taosThreadRunning(threads[type])) {
×
1191
        // thread running , need not obtain again, return
UNCOV
1192
        taosThreadMutexUnlock(&tiresMutex);
×
1193
        return NULL;
×
1194
      }
1195
      // destroy previous thread handle for new create thread handle
UNCOV
1196
      taosDestroyThread(threads[type]);
×
UNCOV
1197
      threads[type] = NULL;
×
1198
    }
1199

1200
    // create new
1201
    void* param = taosMemoryMalloc(sizeof(int));
214✔
1202
    *((int*)param) = type;
214✔
1203
    threads[type] = taosCreateThread(varObtainThread, param);
214✔
1204
    taosThreadMutexUnlock(&tiresMutex);
214✔
1205
    return true;
214✔
1206
  }
1207
  taosThreadMutexUnlock(&tiresMutex);
×
1208

1209
  return false;
×
1210
}
1211

1212
// only match next one word from all match words, return valuue must free by caller
1213
char* matchNextPrefix(STire* tire, char* pre) {
×
1214
  SMatch* match = NULL;
×
UNCOV
1215
  if (tire == NULL) return NULL;
×
1216

1217
  // re-use last result
1218
  if (lastMatch) {
×
1219
    if (strcmp(pre, lastMatch->pre) == 0) {
×
1220
      // same pre
UNCOV
1221
      match = lastMatch;
×
1222
    }
1223
  }
1224

1225
  if (match == NULL) {
×
1226
    // not same with last result
1227
    if (pre[0] == 0) {
×
1228
      // EMPTY PRE
UNCOV
1229
      match = enumAll(tire);
×
1230
    } else {
1231
      // NOT EMPTY
1232
      match = (SMatch*)taosMemoryMalloc(sizeof(SMatch));
×
1233
      memset(match, 0, sizeof(SMatch));
×
UNCOV
1234
      matchPrefix(tire, pre, match);
×
1235
    }
1236

1237
    // save to lastMatch
1238
    if (match) {
×
1239
      if (lastMatch) freeMatch(lastMatch);
×
1240
      lastMatch = match;
×
1241
    }
1242
  }
1243

1244
  // check valid
UNCOV
1245
  if (match == NULL || match->head == NULL) {
×
1246
    // no one matched
UNCOV
1247
    return NULL;
×
1248
  }
1249

UNCOV
1250
  if (cursorVar == -1) {
×
1251
    // first
UNCOV
1252
    cursorVar = 0;
×
1253
    return taosStrdup(match->head->word);
×
1254
  }
1255

1256
  // according to cursorVar , calculate next one
1257
  int         i = 0;
×
UNCOV
1258
  SMatchNode* item = match->head;
×
UNCOV
1259
  while (item) {
×
UNCOV
1260
    if (i == cursorVar + 1) {
×
1261
      // found next position ok
1262
      if (item->next == NULL) {
×
1263
        // match last item, reset cursorVar to head
UNCOV
1264
        cursorVar = -1;
×
1265
      } else {
UNCOV
1266
        cursorVar = i;
×
1267
      }
1268

1269
      return taosStrdup(item->word);
×
1270
    }
1271

1272
    // check end item
UNCOV
1273
    if (item->next == NULL) {
×
1274
      // if cursorVar > var list count, return last and reset cursorVar
UNCOV
1275
      cursorVar = -1;
×
1276

1277
      return taosStrdup(item->word);
×
1278
    }
1279

1280
    // move next
1281
    item = item->next;
×
1282
    i++;
×
1283
  }
1284

UNCOV
1285
  return NULL;
×
1286
}
1287

1288
// search pre word from tire tree, return value must free by caller
UNCOV
1289
char* tireSearchWord(int type, char* pre) {
×
UNCOV
1290
  if (type == WT_TEXT) {
×
1291
    return NULL;
×
1292
  }
1293

UNCOV
1294
  if (type > WT_FROM_DB_MAX) {
×
1295
    // NOT FROM DB , tires[type] alwary not null
UNCOV
1296
    STire* tire = tires[type];
×
UNCOV
1297
    if (tire == NULL) return NULL;
×
UNCOV
1298
    return matchNextPrefix(tire, pre);
×
1299
  }
1300

1301
  if (updateTireValue(type, true)) {
×
1302
    return NULL;
×
1303
  }
1304

1305
  // can obtain var names from local
1306
  STire* tire = getAutoPtr(type);
×
UNCOV
1307
  if (tire == NULL) {
×
1308
    return NULL;
×
1309
  }
1310

1311
  char* str = matchNextPrefix(tire, pre);
×
1312
  // used finish, put back pointer to autoptr array
UNCOV
1313
  putBackAutoPtr(type, tire);
×
1314

1315
  return str;
×
1316
}
1317

1318
// match var word, word1 is pattern , word2 is input from shell
UNCOV
1319
bool matchVarWord(SWord* word1, SWord* word2) {
×
1320
  // search input word from tire tree
UNCOV
1321
  char pre[512];
×
UNCOV
1322
  memcpy(pre, word2->word, word2->len);
×
1323
  pre[word2->len] = 0;
×
1324

UNCOV
1325
  char* str = NULL;
×
UNCOV
1326
  if (word1->type == WT_VAR_ALLTABLE) {
×
1327
    // ALL_TABLE
1328
    str = tireSearchWord(WT_VAR_STABLE, pre);
×
1329
    if (str == NULL) {
×
1330
      str = tireSearchWord(WT_VAR_TABLE, pre);
×
UNCOV
1331
      if (str == NULL) return false;
×
1332
    }
1333
  } else {
1334
    // OTHER
UNCOV
1335
    str = tireSearchWord(word1->type, pre);
×
UNCOV
1336
    if (str == NULL) {
×
1337
      // not found or word1->type variable list not obtain from server, return not match
UNCOV
1338
      return false;
×
1339
    }
1340
  }
1341

1342
  // free previous malloc
UNCOV
1343
  if (word1->free && word1->word) {
×
1344
    taosMemoryFree(word1->word);
×
1345
  }
1346

1347
  // save
1348
  word1->word = str;
×
1349
  word1->len = strlen(str);
×
UNCOV
1350
  word1->free = true;  // need free
×
1351

1352
  return true;
×
1353
}
1354

1355
//
1356
//  -------------------  match words --------------------------
1357
//
1358

1359
// compare command cmdPattern come from shellCommands , cmdInput come from user input
1360
int32_t compareCommand(SWords* cmdPattern, SWords* cmdInput) {
×
1361
  SWord* wordPattern = cmdPattern->head;
×
1362
  SWord* wordInput = cmdInput->head;
×
1363

1364
  if (wordPattern == NULL || wordInput == NULL) {
×
UNCOV
1365
    return -1;
×
1366
  }
1367

UNCOV
1368
  for (int32_t i = 0; i < cmdPattern->count; i++) {
×
UNCOV
1369
    if (wordPattern->type == WT_TEXT) {
×
1370
      // WT_TEXT match
UNCOV
1371
      if (wordPattern->len == wordInput->len) {
×
1372
        if (strncasecmp(wordPattern->word, wordInput->word, wordPattern->len) != 0) return -1;
×
1373
      } else if (wordPattern->len < wordInput->len) {
×
1374
        return -1;
×
1375
      } else {
1376
        // wordPattern->len > wordInput->len
1377
        if (strncasecmp(wordPattern->word, wordInput->word, wordInput->len) == 0) {
×
UNCOV
1378
          if (i + 1 == cmdInput->count) {
×
1379
            // last word return match
UNCOV
1380
            cmdPattern->matchIndex = i;
×
UNCOV
1381
            cmdPattern->matchLen = wordInput->len;
×
UNCOV
1382
            return i;
×
1383
          } else {
1384
            return -1;
×
1385
          }
1386
        } else {
1387
          return -1;
×
1388
        }
1389
      }
1390
    } else {
1391
      // WT_VAR auto match any one word
UNCOV
1392
      if (wordInput->next == NULL) {  // input words last one
×
UNCOV
1393
        if (matchVarWord(wordPattern, wordInput)) {
×
UNCOV
1394
          cmdPattern->matchIndex = i;
×
1395
          cmdPattern->matchLen = wordInput->len;
×
1396
          varMode = true;
×
1397
          return i;
×
1398
        }
1399
        return -1;
×
1400
      }
1401
    }
1402

1403
    // move next
1404
    wordPattern = wordPattern->next;
×
UNCOV
1405
    wordInput = wordInput->next;
×
UNCOV
1406
    if (wordPattern == NULL || wordInput == NULL) {
×
UNCOV
1407
      return -1;
×
1408
    }
1409
  }
1410

UNCOV
1411
  return -1;
×
1412
}
1413

1414
// match command
1415
SWords* matchCommand(SWords* input, bool continueSearch) {
×
1416
  int32_t count = SHELL_COMMAND_COUNT();
×
1417
  for (int32_t i = 0; i < count; i++) {
×
1418
    SWords* shellCommand = shellCommands + i;
×
UNCOV
1419
    if (continueSearch && lastMatchIndex != -1 && i <= lastMatchIndex) {
×
1420
      // new match must greater than lastMatchIndex
UNCOV
1421
      if (varMode && i == lastMatchIndex) {
×
1422
        // do nothing, var match on lastMatchIndex
1423
      } else {
UNCOV
1424
        continue;
×
1425
      }
1426
    }
1427

1428
    // command is large
UNCOV
1429
    if (input->count > shellCommand->count) {
×
UNCOV
1430
      continue;
×
1431
    }
1432

1433
    // compare
1434
    int32_t index = compareCommand(shellCommand, input);
×
1435
    if (index != -1) {
×
UNCOV
1436
      if (firstMatchIndex == -1) firstMatchIndex = i;
×
UNCOV
1437
      curMatchIndex = i;
×
1438
      return &shellCommands[i];
×
1439
    }
1440
  }
1441

1442
  // not match
1443
  return NULL;
×
1444
}
1445

1446
//
1447
//  -------------------  print screen --------------------------
1448
//
1449

1450
// delete char count
UNCOV
1451
void deleteCount(SShellCmd* cmd, int count) {
×
1452
  int size = 0;
×
UNCOV
1453
  int width = 0;
×
1454
  int prompt_size = 6;
×
UNCOV
1455
  shellClearScreen(cmd->endOffset + prompt_size, cmd->screenOffset + prompt_size);
×
1456

1457
  // loop delete
1458
  while (--count >= 0 && cmd->cursorOffset > 0) {
×
1459
    shellGetPrevCharSize(cmd->command, cmd->cursorOffset, &size, &width);
×
UNCOV
1460
    memmove(cmd->command + cmd->cursorOffset - size, cmd->command + cmd->cursorOffset,
×
1461
            cmd->commandSize - cmd->cursorOffset);
×
1462
    cmd->commandSize -= size;
×
UNCOV
1463
    cmd->cursorOffset -= size;
×
1464
    cmd->screenOffset -= width;
×
1465
    cmd->endOffset -= width;
×
1466
  }
1467
}
×
1468

1469
// show screen
1470
void printScreen(TAOS* con, SShellCmd* cmd, SWords* match) {
×
1471
  // modify SShellCmd
1472
  if (firstMatchIndex == -1 || curMatchIndex == -1) {
×
1473
    // no match
1474
    return;
×
1475
  }
1476

1477
  // first tab press
1478
  const char* str = NULL;
×
UNCOV
1479
  int         strLen = 0;
×
1480

1481
  SWord* word = MATCH_WORD(match);
×
1482
  if (firstMatchIndex == curMatchIndex && lastWordBytes == -1) {
×
1483
    // first press tab
1484
    str = word->word + match->matchLen;
×
1485
    strLen = word->len - match->matchLen;
×
1486
    lastMatchIndex = firstMatchIndex;
×
UNCOV
1487
    lastWordBytes = word->len;
×
1488
  } else {
UNCOV
1489
    if (lastWordBytes == -1) return;
×
UNCOV
1490
    deleteCount(cmd, lastWordBytes);
×
UNCOV
1491
    str = word->word;
×
1492
    strLen = word->len;
×
1493
    // set current to last
UNCOV
1494
    lastMatchIndex = curMatchIndex;
×
UNCOV
1495
    lastWordBytes = word->len;
×
1496
  }
1497

1498
  if (word->end && str[strLen - 1] != ';') {
×
1499
    // append end ';'
1500
    char* p = taosMemoryCalloc(strLen + 8, 1);
×
1501
    if (p) {
×
1502
      tstrncpy(p, str, strLen + 1);
×
1503
      tstrncpy(p + strLen, ";", 1 + 1);
×
1504
      lastWordBytes += 1;
×
UNCOV
1505
      shellInsertStr(cmd, (char*)p, strLen + 1);
×
UNCOV
1506
      taosMemoryFree(p);
×
1507
    } else {
1508
      shellInsertStr(cmd, (char*)str, strLen);
×
1509
    }
1510
  } else {
1511
    // insert new
1512
    shellInsertStr(cmd, (char*)str, strLen);
×
1513
  }
1514
}
1515

1516
// main key press tab , matched return true else false
UNCOV
1517
bool firstMatchCommand(TAOS* con, SShellCmd* cmd) {
×
1518
  if (con == NULL || cmd == NULL) return false;
×
1519
  // parse command
UNCOV
1520
  SWords* input = (SWords*)taosMemoryMalloc(sizeof(SWords));
×
UNCOV
1521
  memset(input, 0, sizeof(SWords));
×
UNCOV
1522
  input->source = cmd->command;
×
1523
  input->source_len = cmd->commandSize;
×
1524
  parseCommand(input, false);
×
1525

1526
  // if have many , default match first, if press tab again , switch to next
UNCOV
1527
  curMatchIndex = -1;
×
UNCOV
1528
  lastMatchIndex = -1;
×
1529
  SWords* match = matchCommand(input, true);
×
UNCOV
1530
  if (match == NULL) {
×
1531
    // not match , nothing to do
UNCOV
1532
    freeCommand(input);
×
1533
    taosMemoryFree(input);
×
1534
    return false;
×
1535
  }
1536

1537
  // print to screen
UNCOV
1538
  printScreen(con, cmd, match);
×
1539
#ifdef WINDOWS
1540
  printf("\r");
1541
  shellShowOnScreen(cmd);
1542
#endif
1543
  freeCommand(input);
×
UNCOV
1544
  taosMemoryFree(input);
×
1545
  return true;
×
1546
}
1547

1548
// create input source
1549
void createInputFromFirst(SWords* input, SWords* firstMatch) {
×
1550
  //
1551
  // if next pressTabKey , input context come from firstMatch, set matched length with source_len
1552
  //
UNCOV
1553
  input->source = (char*)taosMemoryMalloc(1024);
×
UNCOV
1554
  memset((void*)input->source, 0, 1024);
×
1555

1556
  SWord* word = firstMatch->head;
×
1557

1558
  // source_len = full match word->len + half match with firstMatch->matchLen
1559
  for (int i = 0; i < firstMatch->matchIndex && word; i++) {
×
1560
    // combine source from each word
UNCOV
1561
    strncpy(input->source + input->source_len, word->word, word->len);
×
UNCOV
1562
    strcat(input->source, " ");          // append blank space
×
1563
    input->source_len += word->len + 1;  // 1 is blank length
×
1564
    // move next
UNCOV
1565
    word = word->next;
×
1566
  }
1567
  // appand half matched word for last
UNCOV
1568
  if (word) {
×
1569
    strncpy(input->source + input->source_len, word->word, firstMatch->matchLen);
×
1570
    input->source_len += firstMatch->matchLen;
×
1571
  }
1572
}
×
1573

1574
// user press Tabkey again is named next , matched return true else false
1575
bool nextMatchCommand(TAOS* con, SShellCmd* cmd, SWords* firstMatch) {
×
1576
  if (firstMatch == NULL || firstMatch->head == NULL) {
×
1577
    return false;
×
1578
  }
1579
  SWords* input = (SWords*)taosMemoryMalloc(sizeof(SWords));
×
UNCOV
1580
  memset(input, 0, sizeof(SWords));
×
1581

1582
  // create input from firstMatch
UNCOV
1583
  createInputFromFirst(input, firstMatch);
×
1584

1585
  // parse input
UNCOV
1586
  parseCommand(input, false);
×
1587

1588
  // if have many , default match first, if press tab again , switch to next
UNCOV
1589
  SWords* match = matchCommand(input, true);
×
UNCOV
1590
  if (match == NULL) {
×
1591
    // if not match , reset all index
1592
    firstMatchIndex = -1;
×
1593
    curMatchIndex = -1;
×
1594
    match = matchCommand(input, false);
×
UNCOV
1595
    if (match == NULL) {
×
1596
      freeCommand(input);
×
UNCOV
1597
      if (input->source) taosMemoryFree(input->source);
×
1598
      taosMemoryFree(input);
×
UNCOV
1599
      return false;
×
1600
    }
1601
  }
1602

1603
  // print to screen
1604
  printScreen(con, cmd, match);
×
1605
#ifdef WINDOWS
1606
  printf("\r");
1607
  shellShowOnScreen(cmd);
1608
#endif
1609

1610
  // free
1611
  freeCommand(input);
×
UNCOV
1612
  if (input->source) {
×
UNCOV
1613
    taosMemoryFree(input->source);
×
1614
    input->source = NULL;
×
1615
  }
1616
  taosMemoryFree(input);
×
1617

1618
  return true;
×
1619
}
1620

1621
// fill with type
UNCOV
1622
bool fillWithType(TAOS* con, SShellCmd* cmd, char* pre, int type) {
×
1623
  // get type
UNCOV
1624
  STire* tire = tires[type];
×
1625
  char*  str = matchNextPrefix(tire, pre);
×
1626
  if (str == NULL) {
×
1627
    return false;
×
1628
  }
1629

1630
  // need insert part string
UNCOV
1631
  char* part = str + strlen(pre);
×
1632

1633
  // show
UNCOV
1634
  int count = strlen(part);
×
1635
  shellInsertStr(cmd, part, count);
×
1636
  cntDel = count;  // next press tab delete current append count
×
1637

UNCOV
1638
  taosMemoryFree(str);
×
UNCOV
1639
  return true;
×
1640
}
1641

1642
// fill with type
1643
bool fillTableName(TAOS* con, SShellCmd* cmd, char* pre) {
×
1644
  // search stable and table
1645
  char* str = tireSearchWord(WT_VAR_STABLE, pre);
×
1646
  if (str == NULL) {
×
UNCOV
1647
    str = tireSearchWord(WT_VAR_TABLE, pre);
×
UNCOV
1648
    if (str == NULL) return false;
×
1649
  }
1650

1651
  // need insert part string
UNCOV
1652
  char* part = str + strlen(pre);
×
1653

1654
  // delete autofill count last append
UNCOV
1655
  if (cntDel > 0) {
×
1656
    deleteCount(cmd, cntDel);
×
UNCOV
1657
    cntDel = 0;
×
1658
  }
1659

1660
  // show
1661
  int count = strlen(part);
×
1662
  shellInsertStr(cmd, part, count);
×
1663
  cntDel = count;  // next press tab delete current append count
×
1664

1665
  taosMemoryFree(str);
×
1666
  return true;
×
1667
}
1668

1669
//
1670
// find last word from sql select clause
1671
//  example :
1672
//  1 select cou -> press tab  select count(
1673
//  2 select count(*),su -> select count(*), sum(
1674
//  3 select count(*), su -> select count(*), sum(
1675
//
1676
char* lastWord(char* p) {
×
1677
  // get near from end revert find ' ' and ','
1678
  char* p1 = strrchr(p, ' ');
×
1679
  char* p2 = strrchr(p, ',');
×
1680

1681
  if (p1 && p2) {
×
UNCOV
1682
    return p1 > p2 ? p1 + 1 : p2 + 1;
×
UNCOV
1683
  } else if (p1) {
×
UNCOV
1684
    return p1 + 1;
×
1685
  } else if (p2) {
×
1686
    return p2 + 1;
×
1687
  } else {
1688
    return p;
×
1689
  }
1690
}
1691

1692
bool fieldsInputEnd(char* sql) {
×
1693
  // not in '()'
1694
  char* p1 = strrchr(sql, '(');
×
1695
  char* p2 = strrchr(sql, ')');
×
1696
  if (p1 && p2 == NULL) {
×
1697
    // like select count( '  '
1698
    return false;
×
UNCOV
1699
  } else if (p1 && p2 && p1 > p2) {
×
1700
    // like select sum(age), count( ' '
UNCOV
1701
    return false;
×
1702
  }
1703

1704
  // not in ','
1705
  char* p3 = strrchr(sql, ',');
×
UNCOV
1706
  char* p = p3;
×
1707
  // like select ts, age,'    '
UNCOV
1708
  if (p) {
×
1709
    ++p;
×
1710
    bool  allBlank = true;  // after last ','  all char is blank
×
UNCOV
1711
    int   cnt = 0;          // blank count , like '    ' as one blank
×
UNCOV
1712
    char* plast = NULL;     // last blank position
×
UNCOV
1713
    while (*p) {
×
1714
      if (*p == ' ') {
×
1715
        plast = p;
×
UNCOV
1716
        cnt++;
×
1717
      } else {
UNCOV
1718
        allBlank = false;
×
1719
      }
1720
      ++p;
×
1721
    }
1722

1723
    // any one word is not blank
UNCOV
1724
    if (allBlank) {
×
1725
      return false;
×
1726
    }
1727

1728
    // like 'select count(*),sum(age) fr' need return true
1729
    if (plast && plast > p3 && p2 > p1 && plast > p2 && p1 > p3) {
×
UNCOV
1730
      return true;
×
1731
    }
1732

1733
    // if last char not ' ', then not end field, like 'select count(*), su' can fill sum(
UNCOV
1734
    if (sql[strlen(sql) - 1] != ' ' && cnt <= 1) {
×
UNCOV
1735
      return false;
×
1736
    }
1737
  }
1738

UNCOV
1739
  char* p4 = strrchr(sql, ' ');
×
UNCOV
1740
  if (p4 == NULL) {
×
1741
    // only one word
1742
    return false;
×
1743
  }
1744

UNCOV
1745
  return true;
×
1746
}
1747

1748
// need insert from
UNCOV
1749
bool needInsertFrom(char* sql, int len) {
×
1750
  // last is blank
UNCOV
1751
  if (sql[len - 1] != ' ') {
×
1752
    // insert from keyword
1753
    return false;
×
1754
  }
1755

1756
  //  select fields input is end
UNCOV
1757
  if (!fieldsInputEnd(sql)) {
×
1758
    return false;
×
1759
  }
1760

1761
  // can insert from keyword
1762
  return true;
×
1763
}
1764

1765
// p is string following select keyword
1766
bool appendAfterSelect(TAOS* con, SShellCmd* cmd, char* sql, int32_t len) {
×
1767
  char* p = taosStrndup(sql, len);
×
1768

1769
  // union all
1770
  char* p1;
1771
  do {
1772
    p1 = strstr(p, UNION_ALL);
×
UNCOV
1773
    if (p1) {
×
1774
      p = p1 + strlen(UNION_ALL);
×
1775
    }
1776
  } while (p1);
×
1777

UNCOV
1778
  char* from = strstr(p, " from ");
×
1779
  // last word , maybe empty string or some letters of a string
1780
  char* last = lastWord(p);
×
UNCOV
1781
  bool  ret = false;
×
UNCOV
1782
  if (from == NULL) {
×
UNCOV
1783
    bool fieldEnd = fieldsInputEnd(p);
×
1784
    // check fields input end then insert from keyword
1785
    if (fieldEnd && p[len - 1] == ' ') {
×
UNCOV
1786
      shellInsertStr(cmd, "from", 4);
×
1787
      taosMemoryFree(p);
×
UNCOV
1788
      return true;
×
1789
    }
1790

1791
    // fill function
1792
    if (fieldEnd) {
×
1793
      // fields is end , need match keyword
UNCOV
1794
      ret = fillWithType(con, cmd, last, WT_VAR_KEYWORD);
×
1795
    } else {
1796
      ret = fillWithType(con, cmd, last, WT_VAR_FUNC);
×
1797
    }
1798

UNCOV
1799
    taosMemoryFree(p);
×
1800
    return ret;
×
1801
  }
1802

1803
  // have from
1804
  char* blank = strstr(from + 6, " ");
×
UNCOV
1805
  if (blank == NULL) {
×
1806
    // no table name, need fill
1807
    ret = fillTableName(con, cmd, last);
×
1808
  } else {
UNCOV
1809
    ret = fillWithType(con, cmd, last, WT_VAR_KEYWORD);
×
1810
  }
1811

1812
  taosMemoryFree(p);
×
UNCOV
1813
  return ret;
×
1814
}
1815

1816
int32_t searchAfterSelect(char* p, int32_t len) {
×
1817
  // select * from st;
UNCOV
1818
  if (strncasecmp(p, "select ", 7) == 0) {
×
1819
    // check nest query
1820
    char* p1 = p + 7;
×
1821
    while (1) {
×
UNCOV
1822
      char* p2 = strstr(p1, "select ");
×
UNCOV
1823
      if (p2 == NULL) break;
×
UNCOV
1824
      p1 = p2 + 7;
×
1825
    }
1826

1827
    return p1 - p;
×
1828
  }
1829

1830
  // explain as select * from st;
UNCOV
1831
  if (strncasecmp(p, "explain select ", 15) == 0) {
×
UNCOV
1832
    return 15;
×
1833
  }
1834

1835
  char* as_pos_end = strstr(p, " as select ");
×
1836
  if (as_pos_end == NULL) return -1;
×
1837
  as_pos_end += 11;
×
1838

1839
  // create stream <stream_name> as select
UNCOV
1840
  if (strncasecmp(p, "create stream ", 14) == 0) {
×
1841
    return as_pos_end - p;
×
1842
    ;
1843
  }
1844

1845
  // create topic <topic_name> as select
1846
  if (strncasecmp(p, "create topic ", 13) == 0) {
×
1847
    return as_pos_end - p;
×
1848
  }
1849

UNCOV
1850
  return -1;
×
1851
}
1852

UNCOV
1853
bool matchSelectQuery(TAOS* con, SShellCmd* cmd) {
×
1854
  // if continue press Tab , delete bytes by previous autofill
UNCOV
1855
  if (cntDel > 0) {
×
1856
    deleteCount(cmd, cntDel);
×
1857
    cntDel = 0;
×
1858
  }
1859

1860
  // match select ...
1861
  int   len = cmd->commandSize;
×
UNCOV
1862
  char* p = cmd->command;
×
1863

1864
  // remove prefix blank
UNCOV
1865
  while (p[0] == ' ' && len > 0) {
×
UNCOV
1866
    p++;
×
UNCOV
1867
    len--;
×
1868
  }
1869

1870
  // special range
1871
  if (len < 7 || len > 512) {
×
1872
    return false;
×
1873
  }
1874

1875
  // search
1876
  char*   sql_cp = taosStrndup(p, len);
×
1877
  int32_t n = searchAfterSelect(sql_cp, len);
×
UNCOV
1878
  taosMemoryFree(sql_cp);
×
UNCOV
1879
  if (n == -1 || n > len) return false;
×
1880
  p += n;
×
UNCOV
1881
  len -= n;
×
1882

1883
  // append
UNCOV
1884
  return appendAfterSelect(con, cmd, p, len);
×
1885
}
1886

1887
// is fields option area
1888
bool fieldOptionsArea(char* p) {
×
1889
  char* p1 = strrchr(p, '(');
×
UNCOV
1890
  char* p2 = strrchr(p, ',');
×
1891
  if (p1 == NULL && p2 == NULL) {
×
1892
    return false;
×
1893
  }
1894

1895
  // find tags
UNCOV
1896
  if (strstr(p, " tags") != NULL) {
×
UNCOV
1897
    return false;
×
1898
  }
1899

1900
  if (p2 == NULL) {
×
1901
    // first field area
1902
    p2 = p1;
×
1903
  }
1904

1905
  // find blank count
UNCOV
1906
  int32_t cnt = 0;
×
1907
  while (p2) {
×
UNCOV
1908
    p2 = strchr(p2, ' ');
×
UNCOV
1909
    if (p2) {
×
1910
      // get prev char
1911
      char prec = *(p2 - 1);
×
1912
      if (prec != ',' && prec != '(') {
×
1913
        // blank if before comma, not calc count.  like st(ts timestamp,  age int + BLANK + TAB only two blank
1914
        cnt++;
×
1915
      }
1916

1917
      // continue blank is one blank
1918
      while (p2[1] != 0 && p2[1] == ' ') {
×
1919
        // move next if blank again
1920
        p2 += 1;
×
1921
      }
1922
      p2 += 1;
×
1923
    }
1924
  }
1925

1926
  // like  create table st(ts timestamp TAB-KEY or  st(ts timestamp , age int TAB-KEY
UNCOV
1927
  return cnt >= 2;
×
1928
}
1929

1930
// if is input create fields or tags area, return true
UNCOV
1931
bool isCreateFieldsArea(char* p) {
×
1932
  int32_t n = 0;  // count
×
UNCOV
1933
  char*  p1 = p;
×
1934
  while (*p1 != 0) {
×
1935
    switch (*p1) {
×
1936
      case '(':
×
UNCOV
1937
        ++n;
×
UNCOV
1938
        break;
×
UNCOV
1939
      case ')':
×
1940
        --n;
×
1941
        break;
×
UNCOV
1942
      default:
×
UNCOV
1943
        break;
×
1944
    }
1945
    // move next
1946
    ++p1;
×
1947
  }
1948

UNCOV
1949
  return n > 0;
×
1950
}
1951

UNCOV
1952
bool matchCreateTable(TAOS* con, SShellCmd* cmd) {
×
1953
  // if continue press Tab , delete bytes by previous autofill
UNCOV
1954
  if (cntDel > 0) {
×
1955
    deleteCount(cmd, cntDel);
×
UNCOV
1956
    cntDel = 0;
×
1957
  }
1958

1959
  // match select ...
1960
  int   len = cmd->commandSize;
×
UNCOV
1961
  char* p = cmd->command;
×
1962

1963
  // remove prefix blank
1964
  while (p[0] == ' ' && len > 0) {
×
UNCOV
1965
    p++;
×
UNCOV
1966
    len--;
×
1967
  }
1968

1969
  // special range
1970
  if (len < 7 || len > 1024) {
×
UNCOV
1971
    return false;
×
1972
  }
1973

1974
  // select and from
UNCOV
1975
  if (strncasecmp(p, "create table ", 13) != 0) {
×
1976
    // not select query clause
UNCOV
1977
    return false;
×
1978
  }
UNCOV
1979
  p += 13;
×
1980
  len -= 13;
×
1981

1982
  char* ps = taosStrndup(p, len);
×
UNCOV
1983
  bool  ret = false;
×
1984
  char* last = lastWord(ps);
×
1985

1986
  // check in create fields or tags input area
UNCOV
1987
  if (isCreateFieldsArea(ps)) {
×
UNCOV
1988
    if (fieldOptionsArea(ps)) {
×
1989
      // fill field options
1990
      ret = fillWithType(con, cmd, last, WT_VAR_FIELD_OPTIONS);
×
1991
    } else {
1992
      // fill field
1993
      ret = fillWithType(con, cmd, last, WT_VAR_DATATYPE);
×
1994
    }
1995
  }
1996

1997
  // tags
UNCOV
1998
  if (!ret) {
×
1999
    // find only one ')' , can insert tags
UNCOV
2000
    char* p1 = strchr(ps, ')');
×
2001
    if (p1) {
×
2002
      if (strstr(p1 + 1, "tags") == NULL) {
×
2003
        // can insert tags keyword
UNCOV
2004
        ret = fillWithType(con, cmd, last, WT_VAR_KEYTAGS);
×
2005
      }
2006
    }
2007
  }
2008

2009
  // tb options
2010
  if (!ret) {
×
2011
    // find like create table st (...) tags(..)  <here is fill tb option area>
2012
    char* p1 = strchr(ps, ')');  // first ')' end
×
2013
    if (p1) {
×
2014
      if (strchr(p1 + 1, ')')) {  // second ')' end
×
2015
        // here is tb options area, can insert option
UNCOV
2016
        ret = fillWithType(con, cmd, last, WT_VAR_TBOPTION);
×
2017
      }
2018
    }
2019
  }
2020

2021
  taosMemoryFree(ps);
×
2022
  return ret;
×
2023
}
2024

2025
bool matchOther(TAOS* con, SShellCmd* cmd) {
×
2026
  int   len = cmd->commandSize;
×
2027
  char* p = cmd->command;
×
2028

2029
  // '\\'
2030
  if (p[len - 1] == '\\') {
×
2031
    // append '\G'
UNCOV
2032
    char a[] = "G;";
×
2033
    shellInsertStr(cmd, a, 2);
×
UNCOV
2034
    return true;
×
2035
  }
2036

2037
  // too small
2038
  if (len < 8) return false;
×
2039

2040
  // like 'from ( '
2041
  char* sql = taosStrndup(p, len);
×
UNCOV
2042
  char* last = lastWord(sql);
×
2043

2044
  if (strcmp(last, "from(") == 0) {
×
2045
    fillWithType(con, cmd, "", WT_VAR_KEYSELECT);
×
UNCOV
2046
    taosMemoryFree(sql);
×
2047
    return true;
×
2048
  }
2049
  if (strncmp(last, "(", 1) == 0) {
×
2050
    last += 1;
×
2051
  }
2052

2053
  char* from = strstr(sql, " from");
×
2054
  // find last ' from'
2055
  while (from) {
×
UNCOV
2056
    char* p1 = strstr(from + 5, " from");
×
UNCOV
2057
    if (p1 == NULL) break;
×
UNCOV
2058
    from = p1;
×
2059
  }
2060

UNCOV
2061
  if (from) {
×
2062
    // find next is '('
2063
    char* p2 = from + 5;
×
UNCOV
2064
    bool  found = false;   // found 'from ... ( ...'  ... is any count of blank
×
UNCOV
2065
    bool  found1 = false;  // found '('
×
2066
    while (1) {
2067
      if (p2 == last || *p2 == '\0') {
×
2068
        // last word or string end
2069
        if (found1) {
×
UNCOV
2070
          found = true;
×
2071
        }
UNCOV
2072
        break;
×
UNCOV
2073
      } else if (*p2 == '(') {
×
UNCOV
2074
        found1 = true;
×
2075
      } else if (*p2 == ' ') {
×
2076
        // do nothing
2077
      } else {
2078
        // have any other char
UNCOV
2079
        break;
×
2080
      }
2081

2082
      // move next
2083
      p2++;
×
2084
    }
2085

2086
    if (found) {
×
2087
      fillWithType(con, cmd, last, WT_VAR_KEYSELECT);
×
2088
      taosMemoryFree(sql);
×
UNCOV
2089
      return true;
×
2090
    }
2091
  }
2092

2093
  // INSERT
2094

2095
  taosMemoryFree(sql);
×
2096

UNCOV
2097
  return false;
×
2098
}
2099

2100
// last match if nothing matched
UNCOV
2101
bool matchEnd(TAOS* con, SShellCmd* cmd) {
×
2102
  // str dump
2103
  bool  ret = false;
×
2104
  char* ps = taosStrndup(cmd->command, cmd->commandSize);
×
UNCOV
2105
  char* last = lastWord(ps);
×
UNCOV
2106
  char* elast = strrchr(last, '.');  // find end last
×
UNCOV
2107
  if (elast) {
×
2108
    last = elast + 1;
×
2109
  }
2110

2111
  // less one char can match
UNCOV
2112
  if (strlen(last) == 0) {
×
UNCOV
2113
    goto _return;
×
2114
  }
2115
  if (strcmp(last, " ") == 0) {
×
2116
    goto _return;
×
2117
  }
2118

2119
  // match database
2120
  if (elast == NULL) {
×
2121
    // dot need not completed with dbname
2122
    if (fillWithType(con, cmd, last, WT_VAR_DBNAME)) {
×
UNCOV
2123
      ret = true;
×
UNCOV
2124
      goto _return;
×
2125
    }
2126
  }
2127

UNCOV
2128
  if (fillWithType(con, cmd, last, WT_VAR_SYSTABLE)) {
×
UNCOV
2129
    ret = true;
×
UNCOV
2130
    goto _return;
×
2131
  }
2132

2133
  // global keys
2134
  if (fillWithType(con, cmd, last, WT_VAR_GLOBALKEYS)) {
×
UNCOV
2135
    ret = true;
×
2136
    goto _return;
×
2137
  }
2138

2139

UNCOV
2140
_return:
×
2141
  taosMemoryFree(ps);
×
2142
  return ret;
×
2143
}
2144

2145
// main key press tab
2146
void pressTabKey(SShellCmd* cmd) {
×
2147
#ifdef WINDOWS
2148
  return ;
2149
#endif
2150
  // check empty tab key
UNCOV
2151
  if (cmd->commandSize == 0) {
×
2152
    // have multi line tab key
UNCOV
2153
    if (cmd->bufferSize == 0) {
×
2154
      showHelp();
×
2155
    }
UNCOV
2156
    shellShowOnScreen(cmd);
×
UNCOV
2157
    return;
×
2158
  }
2159

2160
  // save connection to global
UNCOV
2161
  varCmd = cmd;
×
2162
  bool matched = false;
×
2163

2164
  // manual match like create table st( ...
UNCOV
2165
  matched = matchCreateTable(varCon, cmd);
×
2166
  if (matched) return;
×
2167

2168
  // shellCommands match
UNCOV
2169
  if (firstMatchIndex == -1) {
×
UNCOV
2170
    matched = firstMatchCommand(varCon, cmd);
×
2171
  } else {
UNCOV
2172
    matched = nextMatchCommand(varCon, cmd, &shellCommands[firstMatchIndex]);
×
2173
  }
UNCOV
2174
  if (matched) return;
×
2175

2176
  // NOT MATCHED ANYONE
2177
  // match other like '\G' ...
UNCOV
2178
  matched = matchOther(varCon, cmd);
×
UNCOV
2179
  if (matched) return;
×
2180

2181
  // manual match like select * from ...
UNCOV
2182
  matched = matchSelectQuery(varCon, cmd);
×
UNCOV
2183
  if (matched) return;
×
2184

2185
  // match end
UNCOV
2186
  matched = matchEnd(varCon, cmd);
×
2187

UNCOV
2188
  return;
×
2189
}
2190

2191
// press othr key
2192
void pressOtherKey(char c) {
4,580✔
2193
#ifdef WINDOWS
2194
  return ;
2195
#endif
2196

2197
  // reset global variant
2198
  firstMatchIndex = -1;
4,580✔
2199
  lastMatchIndex = -1;
4,580✔
2200
  curMatchIndex = -1;
4,580✔
2201
  lastWordBytes = -1;
4,580✔
2202

2203
  // var names
2204
  cursorVar = -1;
4,580✔
2205
  varMode = false;
4,580✔
2206
  waitAutoFill = false;
4,580✔
2207
  cntDel = 0;
4,580✔
2208

2209
  if (lastMatch) {
4,580✔
UNCOV
2210
    freeMatch(lastMatch);
×
UNCOV
2211
    lastMatch = NULL;
×
2212
  }
2213
}
4,580✔
2214

2215
// put name into name, return name length
2216
int getWordName(char* p, char* name, int nameLen) {
17,927✔
2217
  // remove prefix blank
2218
  while (*p == ' ') {
20,324✔
2219
    p++;
2,397✔
2220
  }
2221

2222
  // get databases name;
2223
  int i = 0;
17,927✔
2224
  while (p[i] != 0 && i < nameLen - 1) {
62,838✔
2225
    name[i] = p[i];
62,791✔
2226
    i++;
62,791✔
2227
    if (p[i] == ' ' || p[i] == ';' || p[i] == '(') {
62,791✔
2228
      // name end
2229
      break;
2230
    }
2231
  }
2232
  name[i] = 0;
17,927✔
2233

2234
  return i;
17,927✔
2235
}
2236

2237
// deal use db, if have  'use' return true
2238
bool dealUseDB(char* sql) {
1,249,283✔
2239
  // check use keyword
2240
  if (strncasecmp(sql, "use ", 4) != 0) {
1,249,283✔
2241
    return false;
1,236,939✔
2242
  }
2243

2244
  char  db[256];
12,276✔
2245
  char* p = sql + 4;
12,344✔
2246
  if (getWordName(p, db, sizeof(db)) == 0) {
12,344✔
2247
    // no name , return
UNCOV
2248
    return true;
×
2249
  }
2250

2251
  //  dbName is previous use open db name
2252
  if (strcasecmp(db, dbName) == 0) {
12,344✔
2253
    // same , no need switch
UNCOV
2254
    return true;
×
2255
  }
2256

2257
  // switch new db
2258
  taosThreadMutexLock(&tiresMutex);
12,344✔
2259
  // STABLE set null
2260
  STire* tire = tires[WT_VAR_STABLE];
12,344✔
2261
  tires[WT_VAR_STABLE] = NULL;
12,344✔
2262
  if (tire) {
12,344✔
UNCOV
2263
    freeTire(tire);
×
2264
  }
2265
  // TABLE set null
2266
  tire = tires[WT_VAR_TABLE];
12,344✔
2267
  tires[WT_VAR_TABLE] = NULL;
12,344✔
2268
  if (tire) {
12,344✔
2269
    freeTire(tire);
×
2270
  }
2271
  // save
2272
  strcpy(dbName, db);
12,344✔
2273
  taosThreadMutexUnlock(&tiresMutex);
12,344✔
2274

2275
  return true;
12,344✔
2276
}
2277

2278
// deal create, if have 'create' return true
2279
bool dealCreateCommand(char* sql) {
1,236,939✔
2280
  // check keyword
2281
  if (strncasecmp(sql, "create ", 7) != 0) {
1,236,939✔
2282
    return false;
1,234,126✔
2283
  }
2284

2285
  char  name[1024];
2,639✔
2286
  char* p = sql + 7;
2,813✔
2287
  if (getWordName(p, name, sizeof(name)) == 0) {
2,813✔
2288
    // no name , return
UNCOV
2289
    return true;
×
2290
  }
2291

2292
  int type = -1;
2,813✔
2293
  //  dbName is previous use open db name
2294
  if (strcasecmp(name, "database") == 0) {
2,813✔
2295
    type = WT_VAR_DBNAME;
691✔
2296
  } else if (strcasecmp(name, "table") == 0) {
2,122✔
2297
    if (strstr(sql, " tags") != NULL && strstr(sql, " using ") == NULL)
1,333✔
2298
      type = WT_VAR_STABLE;
53✔
2299
    else
2300
      type = WT_VAR_TABLE;
1,280✔
2301
  } else if (strcasecmp(name, "user") == 0) {
789✔
UNCOV
2302
    type = WT_VAR_USERNAME;
×
2303
  } else if (strcasecmp(name, "topic") == 0) {
789✔
UNCOV
2304
    type = WT_VAR_TOPIC;
×
2305
  } else if (strcasecmp(name, "stream") == 0) {
789✔
UNCOV
2306
    type = WT_VAR_STREAM;
×
2307
  } else {
2308
    // no match , return
2309
    return true;
789✔
2310
  }
2311

2312
  // move next
2313
  p += strlen(name);
2,024✔
2314

2315
  // get next word , that is table name
2316
  if (getWordName(p, name, sizeof(name)) == 0) {
2,024✔
2317
    // no name , return
UNCOV
2318
    return true;
×
2319
  }
2320

2321
  // switch new db
2322
  taosThreadMutexLock(&tiresMutex);
2,024✔
2323
  // STABLE set null
2324
  STire* tire = tires[type];
2,024✔
2325
  if (tire) {
2,024✔
2326
    insertWord(tire, name);
214✔
2327
  }
2328
  taosThreadMutexUnlock(&tiresMutex);
2,024✔
2329

2330
  return true;
2,024✔
2331
}
2332

2333
// deal create, if have 'drop' return true
2334
bool dealDropCommand(char* sql) {
1,234,126✔
2335
  // check keyword
2336
  if (strncasecmp(sql, "drop ", 5) != 0) {
1,234,126✔
2337
    return false;
1,233,753✔
2338
  }
2339

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

2347
  int type = -1;
373✔
2348
  //  dbName is previous use open db name
2349
  if (strcasecmp(name, "database") == 0) {
373✔
2350
    type = WT_VAR_DBNAME;
335✔
2351
  } else if (strcasecmp(name, "table") == 0) {
38✔
2352
    type = WT_VAR_ALLTABLE;
×
2353
  } else if (strcasecmp(name, "dnode") == 0) {
38✔
UNCOV
2354
    type = WT_VAR_DNODEID;
×
2355
  } else if (strcasecmp(name, "user") == 0) {
38✔
UNCOV
2356
    type = WT_VAR_USERNAME;
×
2357
  } else if (strcasecmp(name, "topic") == 0) {
38✔
2358
    type = WT_VAR_TOPIC;
38✔
2359
  } else if (strcasecmp(name, "stream") == 0) {
×
UNCOV
2360
    type = WT_VAR_STREAM;
×
2361
  } else {
2362
    // no match , return
UNCOV
2363
    return true;
×
2364
  }
2365

2366
  // move next
2367
  p += strlen(name);
373✔
2368

2369
  // get next word , that is table name
2370
  if (getWordName(p, name, sizeof(name)) == 0) {
373✔
2371
    // no name , return
UNCOV
2372
    return true;
×
2373
  }
2374

2375
  // switch new db
2376
  taosThreadMutexLock(&tiresMutex);
373✔
2377
  // STABLE set null
2378
  if (type == WT_VAR_ALLTABLE) {
373✔
UNCOV
2379
    bool del = false;
×
2380
    // del in stable
UNCOV
2381
    STire* tire = tires[WT_VAR_STABLE];
×
UNCOV
2382
    if (tire) del = deleteWord(tire, name);
×
2383
    // del in table
UNCOV
2384
    if (!del) {
×
UNCOV
2385
      tire = tires[WT_VAR_TABLE];
×
UNCOV
2386
      if (tire) del = deleteWord(tire, name);
×
2387
    }
2388
  } else {
2389
    // OTHER TYPE
2390
    STire* tire = tires[type];
373✔
2391
    if (tire) deleteWord(tire, name);
373✔
2392
  }
2393
  taosThreadMutexUnlock(&tiresMutex);
373✔
2394

2395
  return true;
373✔
2396
}
2397

2398
// callback autotab module after shell sql execute
2399
void callbackAutoTab(char* sqlstr, TAOS* pSql, bool usedb) {
1,249,283✔
2400
  char* sql = sqlstr;
1,249,283✔
2401
  // remove prefix blank
2402
  while (*sql == ' ') {
1,249,283✔
UNCOV
2403
    sql++;
×
2404
  }
2405

2406
  if (dealUseDB(sql)) {
1,249,283✔
2407
    // change to new db
2408
    if (!varRunOnce) updateTireValue(WT_VAR_STABLE, false);
12,344✔
2409
    return;
12,344✔
2410
  }
2411

2412
  // create command add name to autotab
2413
  if (dealCreateCommand(sql)) {
1,236,939✔
2414
    return;
2,813✔
2415
  }
2416

2417
  // drop command remove name from autotab
2418
  if (dealDropCommand(sql)) {
1,234,126✔
2419
    return;
373✔
2420
  }
2421

2422
  return;
1,233,753✔
2423
}
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