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

taosdata / TDengine / #4986

15 Mar 2026 08:32AM UTC coverage: 37.305% (-31.3%) from 68.601%
#4986

push

travis-ci

tomchon
test: keep docs and unit test

125478 of 336361 relevant lines covered (37.3%)

1134847.06 hits per line

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

20.26
/tools/shell/src/shellAuto.c
1
/*
2
 * Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
3
 *
4
 * This program is free software: you can use, redistribute, and/or modify
5
 * it under the terms of the GNU Affero General Public License, version 3
6
 * or later ("AGPL"), as published by the Free Software Foundation.
7
 *
8
 * This program is distributed in the hope that it will be useful, but WITHOUT
9
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10
 * FITNESS FOR A PARTICULAR PURPOSE.
11
 *
12
 * You should have received a copy of the GNU Affero General Public License
13
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
14
 */
15

16
#define __USE_XOPEN
17

18
#include "shellAuto.h"
19
#include "shellInt.h"
20
#include "shellTire.h"
21
#include "tthread.h"
22

23
//
24
// ------------- define area  ---------------
25
//
26
#define UNION_ALL " union all "
27

28
// extern function
29
void  shellClearScreen(int32_t ecmd_pos, int32_t cursor_pos);
30
void  shellGetPrevCharSize(const char* str, int32_t pos, int32_t* size, int32_t* width);
31
void  shellShowOnScreen(SShellCmd* cmd);
32
void  shellInsertChar(SShellCmd* cmd, char* c, int size);
33
void  shellInsertStr(SShellCmd* cmd, char* str, int size);
34
bool  appendAfterSelect(TAOS* con, SShellCmd* cmd, char* p, int32_t len);
35
char* tireSearchWord(int type, char* pre);
36
bool  updateTireValue(int type, bool autoFill);
37

38
typedef struct SAutoPtr {
39
  STire* p;
40
  int    ref;
41
} SAutoPtr;
42

43
typedef struct SWord {
44
  int           type;  // word type , see WT_ define
45
  char*         word;
46
  int32_t       len;
47
  struct SWord* next;
48
  bool          free;  // if true need free
49
  bool          end;   // if true is last keyword
50
} SWord;
51

52
typedef struct {
53
  char*   source;
54
  int32_t source_len;  // valid data length in source
55
  int32_t count;
56
  SWord*  head;
57
  // matched information
58
  int32_t matchIndex;  // matched word index in words
59
  int32_t matchLen;    // matched length at matched word
60
} SWords;
61

62
SWords shellCommands[] = {
63
    {"alter database <db_name> <alter_db_options> <anyword> <alter_db_options> <anyword> <alter_db_options> <anyword> "
64
     "<alter_db_options> <anyword> <alter_db_options> <anyword> ;",
65
     0, 0, NULL},
66
    {"alter dnode <dnode_id> \"resetlog\";", 0, 0, NULL},
67
    {"alter dnode <dnode_id> \"debugFlag\" \"141\";", 0, 0, NULL},
68
    {"alter dnode <dnode_id> \"monitor\" \"0\";", 0, 0, NULL},
69
    {"alter dnode <dnode_id> \"monitor\" \"1\";", 0, 0, NULL},
70
    {"alter dnode <dnode_id> \"asynclog\" \"0\";", 0, 0, NULL},
71
    {"alter dnode <dnode_id> \"asynclog\" \"1\";", 0, 0, NULL},
72
    {"alter all dnodes \"resetlog\";", 0, 0, NULL},
73
    {"alter all dnodes \"debugFlag\" \"141\";", 0, 0, NULL},
74
    {"alter all dnodes \"monitor\" \"0\";", 0, 0, NULL},
75
    {"alter all dnodes \"monitor\" \"1\";", 0, 0, NULL},
76
    {"alter table <tb_name> <tb_actions> <anyword> ;", 0, 0, NULL},
77
    {"alter local \"resetlog\";", 0, 0, NULL},
78
    {"alter local \"DebugFlag\" \"143\";", 0, 0, NULL},
79
    {"alter local \"cDebugFlag\" \"143\";", 0, 0, NULL},
80
    {"alter local \"uDebugFlag\" \"143\";", 0, 0, NULL},
81
    {"alter local \"rpcDebugFlag\" \"143\";", 0, 0, NULL},
82
    {"alter local \"tmrDebugFlag\" \"143\";", 0, 0, NULL},
83
    {"alter local \"asynclog\" \"0\";", 0, 0, NULL},
84
    {"alter local \"asynclog\" \"1\";", 0, 0, NULL},
85
    {"alter topic", 0, 0, NULL},
86
#ifdef TD_ENTERPRISE
87
    {"balance vgroup ;", 0, 0, NULL},
88
    {"balance vgroup leader on <vgroup_id>", 0, 0, NULL},
89
    {"alter token <token_name> <token_opt> <anyword> ;", 0, 0, NULL},
90
    {"alter user <user_name> <alter_uopt> <anyword> <alter_uopt> <anyword> <alter_uopt> <anyword> <alter_uopt> <anyword> <alter_uopt> <anyword> <alter_uopt> <anyword>", 0, 0, NULL},
91
#else
92
   {"alter user <user_name> <user_actions> <anyword> ;", 0, 0, NULL},
93
#endif
94

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

560

561
#define WT_TEXT 0xFF
562

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

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

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

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

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

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

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

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

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

848
//
849
//  -------------------  parse words --------------------------
850
//
851

852
#define SHELL_COMMAND_COUNT() (sizeof(shellCommands) / sizeof(SWords))
853

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

862
  return word;
×
863
}
864

865
#define MATCH_WORD(x) atWord(x, x->matchIndex)
866

867
int wordType(const char* p, int32_t len) {
4,422✔
868
  for (int i = 0; i < WT_VAR_CNT; i++) {
124,092✔
869
    if (strncmp(p, varTypes[i], len) == 0) return i;
120,894✔
870
  }
871
  return WT_TEXT;
3,198✔
872
}
873

874
// add word
875
SWord* addWord(const char* p, int32_t len, bool pattern) {
4,476✔
876
  SWord* word = (SWord*)taosMemoryMalloc(sizeof(SWord));
4,476✔
877
  memset(word, 0, sizeof(SWord));
4,476✔
878
  word->word = (char*)p;
4,476✔
879
  word->len = len;
4,476✔
880

881
  // check format
882
  if (pattern && len > 0) {
4,476✔
883
    if (p[len - 1] == ';') {
4,422✔
884
      word->type = wordType(p, len - 1);
894✔
885
      word->end = true;
894✔
886
    } else {
887
      word->type = wordType(p, len);
3,528✔
888
    }
889
  } else {
890
    word->type = WT_TEXT;
54✔
891
  }
892

893
  return word;
4,476✔
894
}
895

896
// parse one command
897
void parseCommand(SWords* command, bool pattern) {
1,104✔
898
  char*   p = command->source;
1,104✔
899
  int32_t start = 0;
1,104✔
900
  int32_t size = command->source_len > 0 ? command->source_len : strlen(p);
1,104✔
901

902
  bool lastBlank = false;
1,104✔
903
  for (int i = 0; i <= size; i++) {
36,486✔
904
    if (p[i] == ' ' || i == size) {
35,382✔
905
      // check continue blank like '    '
906
      if (p[i] == ' ') {
4,488✔
907
        if (lastBlank) {
3,384✔
908
          start++;
12✔
909
          continue;
12✔
910
        }
911
        if (i == 0) {  // first blank
3,372✔
912
          lastBlank = true;
×
913
          start++;
×
914
          continue;
×
915
        }
916
        lastBlank = true;
3,372✔
917
      }
918

919
      // found split or string end , append word
920
      if (command->head == NULL) {
4,476✔
921
        command->head = addWord(p + start, i - start, pattern);
1,104✔
922
        command->count = 1;
1,104✔
923
      } else {
924
        SWord* word = command->head;
3,372✔
925
        while (word->next) {
11,382✔
926
          word = word->next;
8,010✔
927
        }
928
        word->next = addWord(p + start, i - start, pattern);
3,372✔
929
        command->count++;
3,372✔
930
      }
931
      start = i + 1;
4,476✔
932
    } else {
933
      lastBlank = false;
30,894✔
934
    }
935
  }
936
}
1,104✔
937

938
// free SShellCmd
939
void freeCommand(SWords* command) {
1,104✔
940
  SWord* item = command->head;
1,104✔
941
  command->head = NULL;
1,104✔
942
  // loop
943
  while (item) {
5,580✔
944
    SWord* tmp = item;
4,476✔
945
    item = item->next;
4,476✔
946
    // if malloc need free
947
    if (tmp->free && tmp->word) taosMemoryFree(tmp->word);
4,476✔
948
    taosMemoryFree(tmp);
4,476✔
949
  }
950
}
1,104✔
951

952
void GenerateVarType(int type, char** p, int count) {
102✔
953
  STire* tire = createTire(TIRE_LIST);
102✔
954
  for (int i = 0; i < count; i++) {
2,196✔
955
    insertWord(tire, p[i]);
2,094✔
956
  }
957

958
  taosThreadMutexLock(&tiresMutex);
102✔
959
  tires[type] = tire;
102✔
960
  taosThreadMutexUnlock(&tiresMutex);
102✔
961
}
102✔
962

963
//
964
//  -------------------- shell auto ----------------
965
//
966

967
// init shell auto function , shell start call once
968
void shellAutoInit() {
6✔
969
  // command
970
  int32_t count = SHELL_COMMAND_COUNT();
6✔
971
  for (int32_t i = 0; i < count; i++) {
1,110✔
972
    parseCommand(shellCommands + i, true);
1,104✔
973
  }
974

975
  // tires
976
  memset(tires, 0, sizeof(STire*) * WT_VAR_CNT);
6✔
977
  taosThreadMutexInit(&tiresMutex, NULL);
6✔
978

979
  // threads
980
  memset(threads, 0, sizeof(TdThread*) * WT_FROM_DB_CNT);
6✔
981

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

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

1010
// exit shell auto function, shell exit call once
1011
void shellAutoExit() {
6✔
1012
  // free command
1013
  int32_t count = SHELL_COMMAND_COUNT();
6✔
1014
  for (int32_t i = 0; i < count; i++) {
1,110✔
1015
    freeCommand(shellCommands + i);
1,104✔
1016
  }
1017

1018
  // free tires
1019
  taosThreadMutexLock(&tiresMutex);
6✔
1020
  for (int32_t i = 0; i < WT_VAR_CNT; i++) {
198✔
1021
    if (tires[i]) {
192✔
1022
      freeTire(tires[i]);
102✔
1023
      tires[i] = NULL;
102✔
1024
    }
1025
  }
1026
  taosThreadMutexUnlock(&tiresMutex);
6✔
1027
  // destroy
1028
  taosThreadMutexDestroy(&tiresMutex);
6✔
1029

1030
  // free threads
1031
  for (int32_t i = 0; i < WT_FROM_DB_CNT; i++) {
84✔
1032
    if (threads[i]) {
78✔
1033
      taosDestroyThread(threads[i]);
×
1034
      threads[i] = NULL;
×
1035
    }
1036
  }
1037

1038
  // free lastMatch
1039
  if (lastMatch) {
6✔
1040
    freeMatch(lastMatch);
×
1041
    lastMatch = NULL;
×
1042
  }
1043
}
6✔
1044

1045
//
1046
//  -------------------  auto ptr for tires --------------------------
1047
//
1048
bool setNewAutoPtr(int type, STire* pNew) {
×
1049
  if (pNew == NULL) return false;
×
1050

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

1060
  // set new
1061
  tires[type] = pNew;
×
1062
  tires[type]->ref = 1;
×
1063
  taosThreadMutexUnlock(&tiresMutex);
×
1064

1065
  return true;
×
1066
}
1067

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

1074
  taosThreadMutexLock(&tiresMutex);
×
1075
  tires[type]->ref++;
×
1076
  taosThreadMutexUnlock(&tiresMutex);
×
1077

1078
  return tires[type];
×
1079
}
1080

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

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

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

1101
  return;
×
1102
}
1103

1104
//
1105
//  -------------------  var Word --------------------------
1106
//
1107

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

1117
  TAOS_FIELD* fields = taos_fetch_fields(tres);
×
1118
  // create new tires
1119
  char   tireType = type == WT_VAR_TABLE ? TIRE_TREE : TIRE_LIST;
×
1120
  STire* tire = createTire(tireType);
×
1121

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

1134
    name[bytes] = 0;  // set string end
×
1135
    // insert to tire
1136
    insertWord(tire, name);
×
1137

1138
    if (++numOfRows > MAX_CACHED_CNT) {
×
1139
      break;
×
1140
    }
1141

1142
    row = taos_fetch_row(tres);
×
1143
  } while (row != NULL);
×
1144

1145
  // replace old tire
1146
  setNewAutoPtr(type, tire);
×
1147

1148
  return numOfRows;
×
1149
}
1150

1151
void setThreadNull(int type) {
×
1152
  taosThreadMutexLock(&tiresMutex);
×
1153
  if (threads[type]) {
×
1154
    taosMemoryFree(threads[type]);
×
1155
  }
1156
  threads[type] = NULL;
×
1157
  taosThreadMutexUnlock(&tiresMutex);
×
1158
}
×
1159

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

1168
  if (varCon == NULL || type > WT_FROM_DB_MAX) {
×
1169
    return NULL;
×
1170
  }
1171

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

1179
  // write var names from pSql
1180
  int cnt = writeVarNames(type, pSql);
×
1181

1182
  // free sql
1183
  taos_free_result(pSql);
×
1184

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

1191
  setThreadNull(type);
×
1192
  return NULL;
×
1193
}
1194

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

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

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

1224
  return false;
×
1225
}
1226

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

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

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

1252
    // save to lastMatch
1253
    if (match) {
×
1254
      if (lastMatch) freeMatch(lastMatch);
×
1255
      lastMatch = match;
×
1256
    }
1257
  }
1258

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

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

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

1284
      return taosStrdup(item->word);
×
1285
    }
1286

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

1292
      return taosStrdup(item->word);
×
1293
    }
1294

1295
    // move next
1296
    item = item->next;
×
1297
    i++;
×
1298
  }
1299

1300
  return NULL;
×
1301
}
1302

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

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

1316
  if (updateTireValue(type, true)) {
×
1317
    return NULL;
×
1318
  }
1319

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

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

1330
  return str;
×
1331
}
1332

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

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

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

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

1367
  return true;
×
1368
}
1369

1370
//
1371
//  -------------------  match words --------------------------
1372
//
1373

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

1379
  if (wordPattern == NULL || wordInput == NULL) {
×
1380
    return -1;
×
1381
  }
1382

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

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

1426
  return -1;
×
1427
}
1428

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

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

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

1457
  // not match
1458
  return NULL;
×
1459
}
1460

1461
//
1462
//  -------------------  print screen --------------------------
1463
//
1464

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

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

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

1492
  // first tab press
1493
  const char* str = NULL;
×
1494
  int         strLen = 0;
×
1495

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

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

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

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

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

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

1571
  SWord* word = firstMatch->head;
×
1572

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

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

1597
  // create input from firstMatch
1598
  createInputFromFirst(input, firstMatch);
×
1599

1600
  // parse input
1601
  parseCommand(input, false);
×
1602

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

1618
  // print to screen
1619
  printScreen(con, cmd, match);
×
1620
#ifdef WINDOWS
1621
  printf("\r");
1622
  shellShowOnScreen(cmd);
1623
#endif
1624

1625
  // free
1626
  freeCommand(input);
×
1627
  if (input->source) {
×
1628
    taosMemoryFree(input->source);
×
1629
    input->source = NULL;
×
1630
  }
1631
  taosMemoryFree(input);
×
1632

1633
  return true;
×
1634
}
1635

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

1645
  // need insert part string
1646
  char* part = str + strlen(pre);
×
1647

1648
  // show
1649
  int count = strlen(part);
×
1650
  shellInsertStr(cmd, part, count);
×
1651
  cntDel = count;  // next press tab delete current append count
×
1652

1653
  taosMemoryFree(str);
×
1654
  return true;
×
1655
}
1656

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

1666
  // need insert part string
1667
  char* part = str + strlen(pre);
×
1668

1669
  // delete autofill count last append
1670
  if (cntDel > 0) {
×
1671
    deleteCount(cmd, cntDel);
×
1672
    cntDel = 0;
×
1673
  }
1674

1675
  // show
1676
  int count = strlen(part);
×
1677
  shellInsertStr(cmd, part, count);
×
1678
  cntDel = count;  // next press tab delete current append count
×
1679

1680
  taosMemoryFree(str);
×
1681
  return true;
×
1682
}
1683

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

1696
  if (p1 && p2) {
×
1697
    return p1 > p2 ? p1 + 1 : p2 + 1;
×
1698
  } else if (p1) {
×
1699
    return p1 + 1;
×
1700
  } else if (p2) {
×
1701
    return p2 + 1;
×
1702
  } else {
1703
    return p;
×
1704
  }
1705
}
1706

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

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

1738
    // any one word is not blank
1739
    if (allBlank) {
×
1740
      return false;
×
1741
    }
1742

1743
    // like 'select count(*),sum(age) fr' need return true
1744
    if (plast && plast > p3 && p2 > p1 && plast > p2 && p1 > p3) {
×
1745
      return true;
×
1746
    }
1747

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

1754
  char* p4 = strrchr(sql, ' ');
×
1755
  if (p4 == NULL) {
×
1756
    // only one word
1757
    return false;
×
1758
  }
1759

1760
  return true;
×
1761
}
1762

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

1771
  //  select fields input is end
1772
  if (!fieldsInputEnd(sql)) {
×
1773
    return false;
×
1774
  }
1775

1776
  // can insert from keyword
1777
  return true;
×
1778
}
1779

1780
// p is string following select keyword
1781
bool appendAfterSelect(TAOS* con, SShellCmd* cmd, char* sql, int32_t len) {
×
1782
  char* p = taosStrndup(sql, len);
×
1783

1784
  // union all
1785
  char* p1;
1786
  do {
1787
    p1 = strstr(p, UNION_ALL);
×
1788
    if (p1) {
×
1789
      p = p1 + strlen(UNION_ALL);
×
1790
    }
1791
  } while (p1);
×
1792

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

1806
    // fill function
1807
    if (fieldEnd) {
×
1808
      // fields is end , need match keyword
1809
      ret = fillWithType(con, cmd, last, WT_VAR_KEYWORD);
×
1810
    } else {
1811
      ret = fillWithType(con, cmd, last, WT_VAR_FUNC);
×
1812
    }
1813

1814
    taosMemoryFree(p);
×
1815
    return ret;
×
1816
  }
1817

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

1827
  taosMemoryFree(p);
×
1828
  return ret;
×
1829
}
1830

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

1842
    return p1 - p;
×
1843
  }
1844

1845
  // explain as select * from st;
1846
  if (strncasecmp(p, "explain select ", 15) == 0) {
×
1847
    return 15;
×
1848
  }
1849

1850
  char* as_pos_end = strstr(p, " as select ");
×
1851
  if (as_pos_end == NULL) return -1;
×
1852
  as_pos_end += 11;
×
1853

1854
  // create stream <stream_name> as select
1855
  if (strncasecmp(p, "create stream ", 14) == 0) {
×
1856
    return as_pos_end - p;
×
1857
    ;
1858
  }
1859

1860
  // create topic <topic_name> as select
1861
  if (strncasecmp(p, "create topic ", 13) == 0) {
×
1862
    return as_pos_end - p;
×
1863
  }
1864

1865
  return -1;
×
1866
}
1867

1868
bool matchSelectQuery(TAOS* con, SShellCmd* cmd) {
×
1869
  // if continue press Tab , delete bytes by previous autofill
1870
  if (cntDel > 0) {
×
1871
    deleteCount(cmd, cntDel);
×
1872
    cntDel = 0;
×
1873
  }
1874

1875
  // match select ...
1876
  int   len = cmd->commandSize;
×
1877
  char* p = cmd->command;
×
1878

1879
  // remove prefix blank
1880
  while (p[0] == ' ' && len > 0) {
×
1881
    p++;
×
1882
    len--;
×
1883
  }
1884

1885
  // special range
1886
  if (len < 7 || len > 512) {
×
1887
    return false;
×
1888
  }
1889

1890
  // search
1891
  char*   sql_cp = taosStrndup(p, len);
×
1892
  int32_t n = searchAfterSelect(sql_cp, len);
×
1893
  taosMemoryFree(sql_cp);
×
1894
  if (n == -1 || n > len) return false;
×
1895
  p += n;
×
1896
  len -= n;
×
1897

1898
  // append
1899
  return appendAfterSelect(con, cmd, p, len);
×
1900
}
1901

1902
// is fields option area
1903
bool fieldOptionsArea(char* p) {
56✔
1904
  char* p1 = strrchr(p, '(');
56✔
1905
  char* p2 = strrchr(p, ',');
56✔
1906
  if (p1 == NULL && p2 == NULL) {
56✔
1907
    return false;
×
1908
  }
1909

1910
  // find tags
1911
  if (strstr(p, " tags") != NULL) {
56✔
1912
    return false;
16✔
1913
  }
1914

1915
  if (p2 == NULL) {
40✔
1916
    // first field area
1917
    p2 = p1;
4✔
1918
  }
1919

1920
  // find blank count
1921
  int32_t cnt = 0;
40✔
1922
  while (p2) {
190✔
1923
    p2 = strchr(p2, ' ');
150✔
1924
    if (p2) {
150✔
1925
      // get prev char
1926
      char prec = *(p2 - 1);
110✔
1927
      if (prec != ',' && prec != '(') {
110✔
1928
        // blank if before comma, not calc count.  like st(ts timestamp,  age int + BLANK + TAB only two blank
1929
        cnt++;
82✔
1930
      }
1931

1932
      // continue blank is one blank
1933
      while (p2[1] != 0 && p2[1] == ' ') {
136✔
1934
        // move next if blank again
1935
        p2 += 1;
26✔
1936
      }
1937
      p2 += 1;
110✔
1938
    }
1939
  }
1940

1941
  // like  create table st(ts timestamp TAB-KEY or  st(ts timestamp , age int TAB-KEY
1942
  return cnt >= 2;
40✔
1943
}
1944

1945
// if is input create fields or tags area, return true
1946
bool isCreateFieldsArea(char* p) {
56✔
1947
  int32_t n = 0;  // count
56✔
1948
  char*  p1 = p;
56✔
1949
  while (*p1 != 0) {
4,448✔
1950
    switch (*p1) {
4,392✔
1951
      case '(':
162✔
1952
        ++n;
162✔
1953
        break;
162✔
1954
      case ')':
134✔
1955
        --n;
134✔
1956
        break;
134✔
1957
      default:
4,096✔
1958
        break;
4,096✔
1959
    }
1960
    // move next
1961
    ++p1;
4,392✔
1962
  }
1963

1964
  return n > 0;
56✔
1965
}
1966

1967
bool matchCreateTable(TAOS* con, SShellCmd* cmd) {
×
1968
  // if continue press Tab , delete bytes by previous autofill
1969
  if (cntDel > 0) {
×
1970
    deleteCount(cmd, cntDel);
×
1971
    cntDel = 0;
×
1972
  }
1973

1974
  // match select ...
1975
  int   len = cmd->commandSize;
×
1976
  char* p = cmd->command;
×
1977

1978
  // remove prefix blank
1979
  while (p[0] == ' ' && len > 0) {
×
1980
    p++;
×
1981
    len--;
×
1982
  }
1983

1984
  // special range
1985
  if (len < 7 || len > 1024) {
×
1986
    return false;
×
1987
  }
1988

1989
  // select and from
1990
  if (strncasecmp(p, "create table ", 13) != 0) {
×
1991
    // not select query clause
1992
    return false;
×
1993
  }
1994
  p += 13;
×
1995
  len -= 13;
×
1996

1997
  char* ps = taosStrndup(p, len);
×
1998
  bool  ret = false;
×
1999
  char* last = lastWord(ps);
×
2000

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

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

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

2036
  taosMemoryFree(ps);
×
2037
  return ret;
×
2038
}
2039

2040
bool matchOther(TAOS* con, SShellCmd* cmd) {
×
2041
  int   len = cmd->commandSize;
×
2042
  char* p = cmd->command;
×
2043

2044
  // '\\'
2045
  if (p[len - 1] == '\\') {
×
2046
    // append '\G'
2047
    char a[] = "G;";
×
2048
    shellInsertStr(cmd, a, 2);
×
2049
    return true;
×
2050
  }
2051

2052
  // too small
2053
  if (len < 8) return false;
×
2054

2055
  // like 'from ( '
2056
  char* sql = taosStrndup(p, len);
×
2057
  char* last = lastWord(sql);
×
2058

2059
  if (strcmp(last, "from(") == 0) {
×
2060
    fillWithType(con, cmd, "", WT_VAR_KEYSELECT);
×
2061
    taosMemoryFree(sql);
×
2062
    return true;
×
2063
  }
2064
  if (strncmp(last, "(", 1) == 0) {
×
2065
    last += 1;
×
2066
  }
2067

2068
  char* from = strstr(sql, " from");
×
2069
  // find last ' from'
2070
  while (from) {
×
2071
    char* p1 = strstr(from + 5, " from");
×
2072
    if (p1 == NULL) break;
×
2073
    from = p1;
×
2074
  }
2075

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

2097
      // move next
2098
      p2++;
×
2099
    }
2100

2101
    if (found) {
×
2102
      fillWithType(con, cmd, last, WT_VAR_KEYSELECT);
×
2103
      taosMemoryFree(sql);
×
2104
      return true;
×
2105
    }
2106
  }
2107

2108
  // INSERT
2109

2110
  taosMemoryFree(sql);
×
2111

2112
  return false;
×
2113
}
2114

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

2126
  // less one char can match
2127
  if (strlen(last) == 0) {
×
2128
    goto _return;
×
2129
  }
2130
  if (strcmp(last, " ") == 0) {
×
2131
    goto _return;
×
2132
  }
2133

2134
  // match database
2135
  if (elast == NULL) {
×
2136
    // dot need not completed with dbname
2137
    if (fillWithType(con, cmd, last, WT_VAR_DBNAME)) {
×
2138
      ret = true;
×
2139
      goto _return;
×
2140
    }
2141
  }
2142

2143
  if (fillWithType(con, cmd, last, WT_VAR_SYSTABLE)) {
×
2144
    ret = true;
×
2145
    goto _return;
×
2146
  }
2147

2148
  // global keys
2149
  if (fillWithType(con, cmd, last, WT_VAR_GLOBALKEYS)) {
×
2150
    ret = true;
×
2151
    goto _return;
×
2152
  }
2153

2154

2155
_return:
×
2156
  taosMemoryFree(ps);
×
2157
  return ret;
×
2158
}
2159

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

2175
  // save connection to global
2176
  varCmd = cmd;
×
2177
  bool matched = false;
×
2178

2179
  // manual match like create table st( ...
2180
  matched = matchCreateTable(varCon, cmd);
×
2181
  if (matched) return;
×
2182

2183
  // shellCommands match
2184
  if (firstMatchIndex == -1) {
×
2185
    matched = firstMatchCommand(varCon, cmd);
×
2186
  } else {
2187
    matched = nextMatchCommand(varCon, cmd, &shellCommands[firstMatchIndex]);
×
2188
  }
2189
  if (matched) return;
×
2190

2191
  // NOT MATCHED ANYONE
2192
  // match other like '\G' ...
2193
  matched = matchOther(varCon, cmd);
×
2194
  if (matched) return;
×
2195

2196
  // manual match like select * from ...
2197
  matched = matchSelectQuery(varCon, cmd);
×
2198
  if (matched) return;
×
2199

2200
  // match end
2201
  matched = matchEnd(varCon, cmd);
×
2202

2203
  return;
×
2204
}
2205

2206
// press othr key
2207
void pressOtherKey(char c) {
×
2208
#ifdef WINDOWS
2209
  return ;
2210
#endif
2211

2212
  // reset global variant
2213
  firstMatchIndex = -1;
×
2214
  lastMatchIndex = -1;
×
2215
  curMatchIndex = -1;
×
2216
  lastWordBytes = -1;
×
2217

2218
  // var names
2219
  cursorVar = -1;
×
2220
  varMode = false;
×
2221
  waitAutoFill = false;
×
2222
  cntDel = 0;
×
2223

2224
  if (lastMatch) {
×
2225
    freeMatch(lastMatch);
×
2226
    lastMatch = NULL;
×
2227
  }
2228
}
×
2229

2230
// put name into name, return name length
2231
int getWordName(char* p, char* name, int nameLen) {
12✔
2232
  // remove prefix blank
2233
  while (*p == ' ') {
18✔
2234
    p++;
6✔
2235
  }
2236

2237
  // get databases name;
2238
  int i = 0;
12✔
2239
  while (p[i] != 0 && i < nameLen - 1) {
60✔
2240
    name[i] = p[i];
60✔
2241
    i++;
60✔
2242
    if (p[i] == ' ' || p[i] == ';' || p[i] == '(') {
60✔
2243
      // name end
2244
      break;
2245
    }
2246
  }
2247
  name[i] = 0;
12✔
2248

2249
  return i;
12✔
2250
}
2251

2252
// deal use db, if have  'use' return true
2253
bool dealUseDB(char* sql) {
6✔
2254
  // check use keyword
2255
  if (strncasecmp(sql, "use ", 4) != 0) {
6✔
2256
    return false;
6✔
2257
  }
2258

2259
  char  db[256];
2260
  char* p = sql + 4;
×
2261
  if (getWordName(p, db, sizeof(db)) == 0) {
×
2262
    // no name , return
2263
    return true;
×
2264
  }
2265

2266
  //  dbName is previous use open db name
2267
  if (strcasecmp(db, dbName) == 0) {
×
2268
    // same , no need switch
2269
    return true;
×
2270
  }
2271

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

2290
  return true;
×
2291
}
2292

2293
// deal create, if have 'create' return true
2294
bool dealCreateCommand(char* sql) {
6✔
2295
  // check keyword
2296
  if (strncasecmp(sql, "create ", 7) != 0) {
6✔
2297
    return false;
6✔
2298
  }
2299

2300
  char  name[1024];
2301
  char* p = sql + 7;
×
2302
  if (getWordName(p, name, sizeof(name)) == 0) {
×
2303
    // no name , return
2304
    return true;
×
2305
  }
2306

2307
  int type = -1;
×
2308
  //  dbName is previous use open db name
2309
  if (strcasecmp(name, "database") == 0) {
×
2310
    type = WT_VAR_DBNAME;
×
2311
  } else if (strcasecmp(name, "table") == 0) {
×
2312
    if (strstr(sql, " tags") != NULL && strstr(sql, " using ") == NULL)
×
2313
      type = WT_VAR_STABLE;
×
2314
    else
2315
      type = WT_VAR_TABLE;
×
2316
  } else if (strcasecmp(name, "user") == 0) {
×
2317
    type = WT_VAR_USERNAME;
×
2318
  } else if (strcasecmp(name, "topic") == 0) {
×
2319
    type = WT_VAR_TOPIC;
×
2320
  } else if (strcasecmp(name, "stream") == 0) {
×
2321
    type = WT_VAR_STREAM;
×
2322
  } else {
2323
    // no match , return
2324
    return true;
×
2325
  }
2326

2327
  // move next
2328
  p += strlen(name);
×
2329

2330
  // get next word , that is table name
2331
  if (getWordName(p, name, sizeof(name)) == 0) {
×
2332
    // no name , return
2333
    return true;
×
2334
  }
2335

2336
  // switch new db
2337
  taosThreadMutexLock(&tiresMutex);
×
2338
  // STABLE set null
2339
  STire* tire = tires[type];
×
2340
  if (tire) {
×
2341
    insertWord(tire, name);
×
2342
  }
2343
  taosThreadMutexUnlock(&tiresMutex);
×
2344

2345
  return true;
×
2346
}
2347

2348
// deal create, if have 'drop' return true
2349
bool dealDropCommand(char* sql) {
6✔
2350
  // check keyword
2351
  if (strncasecmp(sql, "drop ", 5) != 0) {
6✔
2352
    return false;
×
2353
  }
2354

2355
  char  name[1024];
2356
  char* p = sql + 5;
6✔
2357
  if (getWordName(p, name, sizeof(name)) == 0) {
6✔
2358
    // no name , return
2359
    return true;
×
2360
  }
2361

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

2381
  // move next
2382
  p += strlen(name);
6✔
2383

2384
  // get next word , that is table name
2385
  if (getWordName(p, name, sizeof(name)) == 0) {
6✔
2386
    // no name , return
2387
    return true;
×
2388
  }
2389

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

2410
  return true;
6✔
2411
}
2412

2413
// callback autotab module after shell sql execute
2414
void callbackAutoTab(char* sqlstr, TAOS* pSql, bool usedb) {
6✔
2415
  char* sql = sqlstr;
6✔
2416
  // remove prefix blank
2417
  while (*sql == ' ') {
6✔
2418
    sql++;
×
2419
  }
2420

2421
  if (dealUseDB(sql)) {
6✔
2422
    // change to new db
2423
    if (!varRunOnce) updateTireValue(WT_VAR_STABLE, false);
×
2424
    return;
×
2425
  }
2426

2427
  // create command add name to autotab
2428
  if (dealCreateCommand(sql)) {
6✔
2429
    return;
×
2430
  }
2431

2432
  // drop command remove name from autotab
2433
  if (dealDropCommand(sql)) {
6✔
2434
    return;
6✔
2435
  }
2436

2437
  return;
×
2438
}
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