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

taosdata / TDengine / #5071

17 May 2026 01:15AM UTC coverage: 63.054% (-10.3%) from 73.326%
#5071

push

travis-ci

web-flow
feat (TDgpt): Dynamic Model Synchronization Enhancements (#35344)

* refactor: do some internal refactor.

* fix: fix multiprocess sync issue.

* feat: add dynamic anomaly detection and forecasting services

* fix: log error message for undeploying model in exception handling

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* fix: handle undeploy when model exists only on disk

Agent-Logs-Url: https://github.com/taosdata/TDengine/sessions/286aafa0-c3ce-4c27-b803-2707571e9dc1

Co-authored-by: hjxilinx <8252296+hjxilinx@users.noreply.github.com>

* fix: guard dynamic registry concurrent access

Agent-Logs-Url: https://github.com/taosdata/TDengine/sessions/5e4db858-6458-40f4-ac28-d1b1b7f97c18

Co-authored-by: hjxilinx <8252296+hjxilinx@users.noreply.github.com>

* fix: tighten service list locking scope

Agent-Logs-Url: https://github.com/taosdata/TDengine/sessions/5e4db858-6458-40f4-ac28-d1b1b7f97c18

Co-authored-by: hjxilinx <8252296+hjxilinx@users.noreply.github.com>

* fix: restore prophet support and update tests per review feedback

Agent-Logs-Url: https://github.com/taosdata/TDengine/sessions/92298ae1-7da6-4d07-b20e-101c7cd0b26b

Co-authored-by: hjxilinx <8252296+hjxilinx@users.noreply.github.com>

* fix: improve test name and move copy inside lock scope

Agent-Logs-Url: https://github.com/taosdata/TDengine/sessions/92298ae1-7da6-4d07-b20e-101c7cd0b26b

Co-authored-by: hjxilinx <8252296+hjxilinx@users.noreply.github.com>

* Potential fix for pull request finding

Co-au... (continued)

238317 of 377957 relevant lines covered (63.05%)

130539817.12 hits per line

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

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

16
#define __USE_XOPEN
17

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

561

562
#define WT_TEXT 0xFF
563

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

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

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

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

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

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

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

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

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

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

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

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

864
  return word;
×
865
}
866

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

869
int wordType(const char* p, int32_t len) {
782,550,748✔
870
  for (int i = 0; i < WT_VAR_CNT; i++) {
2,147,483,647✔
871
    if (strncmp(p, varTypes[i], len) == 0) return i;
2,147,483,647✔
872
  }
873
  return WT_TEXT;
566,528,620✔
874
}
875

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

883
  // check format
884
  if (pattern && len > 0) {
792,081,136✔
885
    if (p[len - 1] == ';') {
782,550,748✔
886
      word->type = wordType(p, len - 1);
158,839,800✔
887
      word->end = true;
158,839,800✔
888
    } else {
889
      word->type = wordType(p, len);
623,710,948✔
890
    }
891
  } else {
892
    word->type = WT_TEXT;
9,530,388✔
893
  }
894

895
  return word;
792,081,136✔
896
}
897

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

904
  bool lastBlank = false;
195,902,420✔
905
  for (int i = 0; i <= size; i++) {
2,147,483,647✔
906
    if (p[i] == ' ' || i == size) {
2,147,483,647✔
907
      // check continue blank like '    '
908
      if (p[i] == ' ') {
794,199,000✔
909
        if (lastBlank) {
598,296,580✔
910
          start++;
2,117,864✔
911
          continue;
2,117,864✔
912
        }
913
        if (i == 0) {  // first blank
596,178,716✔
914
          lastBlank = true;
×
915
          start++;
×
916
          continue;
×
917
        }
918
        lastBlank = true;
596,178,716✔
919
      }
920

921
      // found split or string end , append word
922
      if (command->head == NULL) {
792,081,136✔
923
        command->head = addWord(p + start, i - start, pattern);
195,902,420✔
924
        command->count = 1;
195,902,420✔
925
      } else {
926
        SWord* word = command->head;
596,178,716✔
927
        while (word->next) {
2,009,852,936✔
928
          word = word->next;
1,413,674,220✔
929
        }
930
        word->next = addWord(p + start, i - start, pattern);
596,178,716✔
931
        command->count++;
596,178,716✔
932
      }
933
      start = i + 1;
792,081,136✔
934
    } else {
935
      lastBlank = false;
2,147,483,647✔
936
    }
937
  }
938
}
195,902,420✔
939

940
// free SShellCmd
941
void freeCommand(SWords* command) {
195,902,420✔
942
  SWord* item = command->head;
195,902,420✔
943
  command->head = NULL;
195,902,420✔
944
  // loop
945
  while (item) {
987,983,556✔
946
    SWord* tmp = item;
792,081,136✔
947
    item = item->next;
792,081,136✔
948
    // if malloc need free
949
    if (tmp->free && tmp->word) taosMemoryFree(tmp->word);
792,081,136✔
950
    taosMemoryFree(tmp);
792,081,136✔
951
  }
952
}
195,902,420✔
953

954
void GenerateVarType(int type, char** p, int count) {
18,001,844✔
955
  STire* tire = createTire(TIRE_LIST);
18,001,844✔
956
  for (int i = 0; i < count; i++) {
387,569,112✔
957
    insertWord(tire, p[i]);
369,567,268✔
958
  }
959

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

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

969
// init shell auto function , shell start call once
970
void shellAutoInit() {
1,058,932✔
971
  // command
972
  int32_t count = SHELL_COMMAND_COUNT();
1,058,932✔
973
  for (int32_t i = 0; i < count; i++) {
196,961,352✔
974
    parseCommand(shellCommands + i, true);
195,902,420✔
975
  }
976

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

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

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

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

1012
// exit shell auto function, shell exit call once
1013
void shellAutoExit() {
1,058,932✔
1014
  // free command
1015
  int32_t count = SHELL_COMMAND_COUNT();
1,058,932✔
1016
  for (int32_t i = 0; i < count; i++) {
196,961,352✔
1017
    freeCommand(shellCommands + i);
195,902,420✔
1018
  }
1019

1020
  // free tires
1021
  taosThreadMutexLock(&tiresMutex);
1,058,932✔
1022
  for (int32_t i = 0; i < WT_VAR_CNT; i++) {
34,944,756✔
1023
    if (tires[i]) {
33,885,824✔
1024
      freeTire(tires[i]);
18,001,844✔
1025
      tires[i] = NULL;
18,001,844✔
1026
    }
1027
  }
1028
  taosThreadMutexUnlock(&tiresMutex);
1,058,932✔
1029
  // destroy
1030
  taosThreadMutexDestroy(&tiresMutex);
1,058,932✔
1031

1032
  // free threads
1033
  for (int32_t i = 0; i < WT_FROM_DB_CNT; i++) {
14,825,048✔
1034
    if (threads[i]) {
13,766,116✔
1035
      taosDestroyThread(threads[i]);
×
1036
      threads[i] = NULL;
×
1037
    }
1038
  }
1039

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

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

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

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

1067
  return true;
×
1068
}
1069

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

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

1080
  return tires[type];
×
1081
}
1082

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

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

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

1103
  return;
×
1104
}
1105

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

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

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

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

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

1140
    if (++numOfRows > MAX_CACHED_CNT) {
×
1141
      break;
×
1142
    }
1143

1144
    row = taos_fetch_row(tres);
×
1145
  } while (row != NULL);
×
1146

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

1150
  return numOfRows;
×
1151
}
1152

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

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

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

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

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

1184
  // free sql
1185
  taos_free_result(pSql);
×
1186

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

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

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

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

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

1226
  return false;
×
1227
}
1228

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

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

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

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

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

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

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

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

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

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

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

1302
  return NULL;
×
1303
}
1304

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

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

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

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

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

1332
  return str;
×
1333
}
1334

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

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

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

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

1369
  return true;
×
1370
}
1371

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

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

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

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

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

1428
  return -1;
×
1429
}
1430

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

1675
  return true;
×
1676
}
1677

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

1802
  return true;
×
1803
}
1804

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

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

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

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

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

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

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

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

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

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

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

1884
    return p1 - p;
×
1885
  }
1886

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

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

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

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

1907
  return -1;
×
1908
}
1909

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

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

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

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

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

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

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

1952
  // find tags
1953
  if (strstr(p, " tags") != NULL) {
2,828✔
1954
    return false;
808✔
1955
  }
1956

1957
  if (p2 == NULL) {
2,020✔
1958
    // first field area
1959
    p2 = p1;
202✔
1960
  }
1961

1962
  // find blank count
1963
  int32_t cnt = 0;
2,020✔
1964
  while (p2) {
9,595✔
1965
    p2 = strchr(p2, ' ');
7,575✔
1966
    if (p2) {
7,575✔
1967
      // get prev char
1968
      char prec = *(p2 - 1);
5,555✔
1969
      if (prec != ',' && prec != '(') {
5,555✔
1970
        // blank if before comma, not calc count.  like st(ts timestamp,  age int + BLANK + TAB only two blank
1971
        cnt++;
4,141✔
1972
      }
1973

1974
      // continue blank is one blank
1975
      while (p2[1] != 0 && p2[1] == ' ') {
6,868✔
1976
        // move next if blank again
1977
        p2 += 1;
1,313✔
1978
      }
1979
      p2 += 1;
5,555✔
1980
    }
1981
  }
1982

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

1987
// if is input create fields or tags area, return true
1988
bool isCreateFieldsArea(char* p) {
2,828✔
1989
  int32_t n = 0;  // count
2,828✔
1990
  char*  p1 = p;
2,828✔
1991
  while (*p1 != 0) {
224,624✔
1992
    switch (*p1) {
221,796✔
1993
      case '(':
8,181✔
1994
        ++n;
8,181✔
1995
        break;
8,181✔
1996
      case ')':
6,767✔
1997
        --n;
6,767✔
1998
        break;
6,767✔
1999
      default:
206,848✔
2000
        break;
206,848✔
2001
    }
2002
    // move next
2003
    ++p1;
221,796✔
2004
  }
2005

2006
  return n > 0;
2,828✔
2007
}
2008

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

2150
  // INSERT
2151

2152
  taosMemoryFree(sql);
×
2153

2154
  return false;
×
2155
}
2156

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

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

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

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

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

2196

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

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

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

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

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

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

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

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

2245
  return;
×
2246
}
2247

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

2254
  // reset global variant
2255
  firstMatchIndex = -1;
×
2256
  lastMatchIndex = -1;
×
2257
  curMatchIndex = -1;
×
2258
  lastWordBytes = -1;
×
2259

2260
  // var names
2261
  cursorVar = -1;
×
2262
  varMode = false;
×
2263
  waitAutoFill = false;
×
2264
  cntDel = 0;
×
2265

2266
  if (lastMatch) {
×
2267
    freeMatch(lastMatch);
×
2268
    lastMatch = NULL;
×
2269
  }
2270
}
×
2271

2272
// put name into name, return name length
2273
int getWordName(char* p, char* name, int nameLen) {
34,524✔
2274
  // remove prefix blank
2275
  while (*p == ' ') {
37,816✔
2276
    p++;
3,292✔
2277
  }
2278

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

2291
  return i;
34,524✔
2292
}
2293

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

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

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

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

2332
  return true;
27,439✔
2333
}
2334

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

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

2349
  int type = -1;
3,793✔
2350
  //  dbName is previous use open db name
2351
  if (strcasecmp(name, "database") == 0) {
3,793✔
2352
    type = WT_VAR_DBNAME;
501✔
2353
  } else if (strcasecmp(name, "table") == 0) {
3,292✔
2354
    if (strstr(sql, " tags") != NULL && strstr(sql, " using ") == NULL)
1,503✔
2355
      type = WT_VAR_STABLE;
×
2356
    else
2357
      type = WT_VAR_TABLE;
1,503✔
2358
  } else if (strcasecmp(name, "user") == 0) {
1,789✔
2359
    type = WT_VAR_USERNAME;
×
2360
  } else if (strcasecmp(name, "topic") == 0) {
1,789✔
2361
    type = WT_VAR_TOPIC;
×
2362
  } else if (strcasecmp(name, "stream") == 0) {
1,789✔
2363
    type = WT_VAR_STREAM;
1,288✔
2364
  } else {
2365
    // no match , return
2366
    return true;
501✔
2367
  }
2368

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

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

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

2387
  return true;
3,292✔
2388
}
2389

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

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

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

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

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

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

2452
  return true;
×
2453
}
2454

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

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

2469
  // create command add name to autotab
2470
  if (dealCreateCommand(sql)) {
1,521,286✔
2471
    return;
3,793✔
2472
  }
2473

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

2479
  return;
1,517,493✔
2480
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc