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

taosdata / TDengine / #3660

15 Mar 2025 09:06AM UTC coverage: 62.039% (-1.3%) from 63.314%
#3660

push

travis-ci

web-flow
feat(stream): support stream processing for virtual tables (#30144)

* enh: add client processing

* enh: add mnode vtables processing

* enh: add mnode vtable processing

* enh: add normal child vtable support

* fix: compile issues

* fix: compile issues

* fix: create stream issues

* fix: multi stream scan issue

* fix: remove debug info

* fix: agg task and task level issues

* fix: correct task output type

* fix: split vtablescan from agg

* fix: memory leak issues

* fix: add limitations

* Update 09-error-code.md

* Update 09-error-code.md

* fix: remove usless case

* feat(stream): extract original table data in source scan task

Implemented functionality in the source task to extract data
corresponding to the virtual table from the original table using WAL.
The extracted data is then sent to the downstream merge task for further
processing.

* feat(stream): multi-way merge using loser tree in virtual merge task

Implemented multi-way merge in the merge task using a loser tree to
combine data from multiple original table into a single virtual table.
The merged virtual table data is then pushed downstream for further
processing.  Introduced memory limit handling during the merge process
with configurable behavior when the memory limit is reached.

* fix(test): remove useless cases

---------

Co-authored-by: dapan1121 <wpan@taosdata.com>
Co-authored-by: Pan Wei <72057773+dapan1121@users.noreply.github.com>

154078 of 317582 branches covered (48.52%)

Branch coverage included in aggregate %.

313 of 2391 new or added lines in 34 files covered. (13.09%)

26134 existing lines in 205 files now uncovered.

240261 of 318051 relevant lines covered (75.54%)

16655189.27 hits per line

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

88.92
/source/os/src/osString.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 ALLOW_FORBID_FUNC
17
#define _DEFAULT_SOURCE
18
#include "os.h"
19

20
#ifndef DISALLOW_NCHAR_WITHOUT_ICONV
21
#include "iconv.h"
22
#endif
23

24
extern int wcwidth(wchar_t c);
25
extern int wcswidth(const wchar_t *s, size_t n);
26

27
char *tstrdup(const char *str) {
306,403,179✔
28
  if (str == NULL) {
306,403,179✔
29
    terrno = TSDB_CODE_INVALID_PARA;
1✔
30
    return NULL;
1✔
31
  }
32
#ifdef WINDOWS
33
  return _strdup(str);
34
#else
35
  char *p = strdup(str);
306,403,178✔
36
  if (NULL == p) {
306,403,178!
37
    terrno = TSDB_CODE_OUT_OF_MEMORY;
×
38
  }
39
  return p;
306,403,178✔
40

41
#endif
42
}
43

44
#ifdef WINDOWS
45

46
// No errors are expected to occur
47
char *strsep(char **stringp, const char *delim) {
48
  if (stringp == NULL) {
49
    terrno = TSDB_CODE_INVALID_PARA;
50
    return NULL;
51
  }
52
  char       *s;
53
  const char *spanp;
54
  int32_t     c, sc;
55
  char       *tok;
56
  if ((s = *stringp) == NULL) return (NULL);
57
  if (delim == NULL) {
58
    terrno = TSDB_CODE_INVALID_PARA;
59
    return NULL;
60
  }
61
  for (tok = s;;) {
62
    c = *s++;
63
    spanp = delim;
64
    do {
65
      if ((sc = *spanp++) == c) {
66
        if (c == 0)
67
          s = NULL;
68
        else
69
          s[-1] = 0;
70
        *stringp = s;
71
        return (tok);
72
      }
73
    } while (sc != 0);
74
  }
75
  /* NOTREACHED */
76
}
77
/* Duplicate a string, up to at most size characters */
78
char *taosStrndupi(const char *s, int64_t size) {
79
  if (s == NULL) return NULL;
80
  size_t l;
81
  char  *s2;
82
  l = strlen(s);
83
  if (l > size) l = size;
84
  s2 = malloc(l + 1);
85
  if (s2) {
86
    tstrncpy(s2, s, l + 1);
87
    s2[l] = '\0';
88
  } else {
89
    terrno = TSDB_CODE_OUT_OF_MEMORY;
90
  }
91
  return s2;
92
}
93
/* Copy no more than N characters of SRC to DEST, returning the address of
94
   the terminating '\0' in DEST, if any, or else DEST + N.  */
95
char *stpncpy(char *dest, const char *src, int n) {
96
  if (dest == NULL || src == NULL) {
97
    terrno = TSDB_CODE_INVALID_PARA;
98
    return NULL;
99
  }
100
  size_t size = strnlen(src, n);
101
  memcpy(dest, src, size);
102
  dest += size;
103
  if (size == n) return dest;
104
  return memset(dest, '\0', n - size);
105
}
106
#elif defined(TD_ASTRA)
107
/* Copy no more than N characters of SRC to DEST, returning the address of
108
   the terminating '\0' in DEST, if any, or else DEST + N.  */
109
char *stpncpy(char *dest, const char *src, int n) {
110
  if (dest == NULL || src == NULL) { 
111
    terrno = TSDB_CODE_INVALID_PARA;
112
    return NULL;
113
  }
114
  if (n == 0) {
115
    return dest;
116
  }
117
  char *orig_dest = dest;
118
  const char *end = (const char *)memchr(src, '\0', n);
119
  size_t      len = (end != NULL) ? (size_t)(end - src) : n;
120
  memcpy(dest, src, len);
121
  if (len < n) {
122
    memset(dest + len, '\0', n - len);
123
  }
124
  return orig_dest + len;
125
}
126
char *taosStrndupi(const char *s, int64_t size) {
127
  if (s == NULL) {
128
    terrno = TSDB_CODE_INVALID_PARA;
129
    return NULL;
130
  }
131

132
  const char *end = (const char *)memchr(s, '\0', size);
133
  size_t      actual_len = (end != NULL) ? (size_t)(end - s) : (size_t)size;
134

135
  char *p = (char *)malloc(actual_len + 1);
136
  if (p == NULL) {
137
    terrno = TSDB_CODE_OUT_OF_MEMORY;
138
    return NULL;
139
  }
140

141
  memcpy(p, s, actual_len);
142
  p[actual_len] = '\0';
143

144
  return p;
145
}
146
#else
147
char *taosStrndupi(const char *s, int64_t size) {
400,123,325✔
148
  if (s == NULL) {
400,123,325✔
149
    return NULL;
1✔
150
  }
151
  char *p = strndup(s, size);
400,123,324✔
152
  if (NULL == p) {
400,123,324!
153
    terrno = TSDB_CODE_OUT_OF_MEMORY;
×
154
  }
155
  return p;
400,123,324✔
156
}
157
#endif
158

159
char *tstrndup(const char *str, int64_t size) {
1✔
160
#if defined(WINDOWS) || defined(TD_ASTRA)
161
  return taosStrndupi(str, size);
162
#else
163
  char *p = strndup(str, size);
1✔
164
  if (str != NULL && NULL == p) {
1!
165
    terrno = TSDB_CODE_OUT_OF_MEMORY;
×
166
  }
167
  return p;
1✔
168

169
#endif
170
}
171

172
int32_t taosStr2int64(const char *str, int64_t *val) {
223,974,486✔
173
  if (str == NULL || val == NULL) {
223,974,486!
174
    return TSDB_CODE_INVALID_PARA;
×
175
  }
176
  SET_ERRNO(0);
224,012,236✔
177
  char   *endptr = NULL;
224,012,236✔
178
  int64_t ret = strtoll(str, &endptr, 10);
224,012,236✔
179
  if (ERRNO != 0) {
224,099,565!
180
    return TAOS_SYSTEM_ERROR(ERRNO);
×
181
  } else {
182
    if (endptr == str) {
224,099,565✔
183
      return TSDB_CODE_INVALID_PARA;
70✔
184
    }
185
    *val = ret;
224,099,495✔
186
    return 0;
224,099,495✔
187
  }
188
}
189

190
int32_t taosStr2int32(const char *str, int32_t *val) {
221,986,473✔
191
  OS_PARAM_CHECK(str);
221,986,473✔
192
  OS_PARAM_CHECK(val);
221,986,472✔
193
  int64_t tmp = 0;
221,986,471✔
194
  int32_t code = taosStr2int64(str, &tmp);
221,986,471✔
195
  if (code) {
222,028,210✔
196
    return code;
15✔
197
  } else if (tmp > INT32_MAX || tmp < INT32_MIN) {
222,028,195!
198
    return TAOS_SYSTEM_ERROR(ERANGE);
×
199
  } else {
200
    *val = (int32_t)tmp;
222,076,130✔
201
    return 0;
222,076,130✔
202
  }
203
}
204
int32_t taosStr2int16(const char *str, int16_t *val) {
27✔
205
  OS_PARAM_CHECK(str);
27✔
206
  OS_PARAM_CHECK(val);
26✔
207
  int64_t tmp = 0;
25✔
208
  int32_t code = taosStr2int64(str, &tmp);
25✔
209
  if (code) {
25✔
210
    return code;
15✔
211
  } else if (tmp > INT16_MAX || tmp < INT16_MIN) {
10✔
212
    return TAOS_SYSTEM_ERROR(ERANGE);
2✔
213
  } else {
214
    *val = (int16_t)tmp;
8✔
215
    return 0;
8✔
216
  }
217
}
218

219
int32_t taosStr2int8(const char *str, int8_t *val) {
33✔
220
  OS_PARAM_CHECK(str);
33✔
221
  OS_PARAM_CHECK(val);
32✔
222
  int64_t tmp = 0;
31✔
223
  int32_t code = taosStr2int64(str, &tmp);
31✔
224
  if (code) {
31✔
225
    return code;
21✔
226
  } else if (tmp > INT8_MAX || tmp < INT8_MIN) {
10✔
227
    return TAOS_SYSTEM_ERROR(ERANGE);
2✔
228
  } else {
229
    *val = (int8_t)tmp;
8✔
230
    return 0;
8✔
231
  }
232
}
233

234
int32_t taosStr2Uint64(const char *str, uint64_t *val) {
41✔
235
  if (str == NULL || val == NULL) {
41✔
236
    return TSDB_CODE_INVALID_PARA;
2✔
237
  }
238
  char *endptr = NULL;
39✔
239
  SET_ERRNO(0);
39✔
240
  uint64_t ret = strtoull(str, &endptr, 10);
39✔
241

242
  if (ERRNO != 0) {
39!
243
    return TAOS_SYSTEM_ERROR(ERRNO);
×
244
  } else {
245
    if (endptr == str) {
39✔
246
      return TSDB_CODE_INVALID_PARA;
12✔
247
    }
248
    *val = ret;
27✔
249
    return 0;
27✔
250
  }
251
}
252

253
int32_t taosStr2Uint32(const char *str, uint32_t *val) {
12✔
254
  OS_PARAM_CHECK(str);
12✔
255
  OS_PARAM_CHECK(val);
11✔
256
  uint64_t tmp = 0;
10✔
257
  int32_t  code = taosStr2Uint64(str, &tmp);
10✔
258
  if (code) {
10✔
259
    return code;
3✔
260
  } else if (tmp > UINT32_MAX) {
7✔
261
    return TAOS_SYSTEM_ERROR(ERANGE);
1✔
262
  } else {
263
    *val = (int32_t)tmp;
6✔
264
    return 0;
6✔
265
  }
266
}
267

268
int32_t taosStr2Uint16(const char *str, uint16_t *val) {
12✔
269
  OS_PARAM_CHECK(str);
12✔
270
  OS_PARAM_CHECK(val);
11✔
271
  uint64_t tmp = 0;
10✔
272
  int32_t  code = taosStr2Uint64(str, &tmp);
10✔
273
  if (code) {
10✔
274
    return code;
3✔
275
  } else if (tmp > UINT16_MAX) {
7✔
276
    return TAOS_SYSTEM_ERROR(ERANGE);
1✔
277
  } else {
278
    *val = (int16_t)tmp;
6✔
279
    return 0;
6✔
280
  }
281
}
282

283
int32_t taosStr2Uint8(const char *str, uint8_t *val) {
12✔
284
  OS_PARAM_CHECK(str);
12✔
285
  OS_PARAM_CHECK(val);
11✔
286
  uint64_t tmp = 0;
10✔
287
  int32_t  code = taosStr2Uint64(str, &tmp);
10✔
288
  if (code) {
10✔
289
    return code;
3✔
290
  } else if (tmp > UINT8_MAX) {
7✔
291
    return TAOS_SYSTEM_ERROR(ERANGE);
1✔
292
  } else {
293
    *val = (int8_t)tmp;
6✔
294
    return 0;
6✔
295
  }
296
}
297

298
int32_t taosUcs4Compare(TdUcs4 *f1_ucs4, TdUcs4 *f2_ucs4, int32_t bytes) {
116,666,913✔
299
  if ((f1_ucs4 == NULL || f2_ucs4 == NULL)) {
116,666,913!
300
    return TSDB_CODE_INVALID_PARA;
×
301
  }
302
  for (int32_t i = 0; i < bytes; i += sizeof(TdUcs4)) {
696,629,377✔
303
    int32_t f1 = *(int32_t *)((char *)f1_ucs4 + i);
639,853,952✔
304
    int32_t f2 = *(int32_t *)((char *)f2_ucs4 + i);
639,853,952✔
305

306
    if ((f1 == 0 && f2 != 0) || (f1 != 0 && f2 == 0)) {
639,853,952✔
307
      return f1 - f2;
2✔
308
    } else if (f1 == 0 && f2 == 0) {
639,853,950!
309
      return 0;
1✔
310
    }
311

312
    if (f1 != f2) {
639,853,949✔
313
      return f1 - f2;
59,988,759✔
314
    }
315
  }
316

317
  return 0;
56,775,425✔
318

319
  //#if 0
320
  //  int32_t ucs4_max_len = bytes + 4;
321
  //  char *f1_mbs = taosMemoryCalloc(bytes, 1);
322
  //  char *f2_mbs = taosMemoryCalloc(bytes, 1);
323
  //  if (taosUcs4ToMbs(f1_ucs4, ucs4_max_len, f1_mbs) < 0) {
324
  //    return -1;
325
  //  }
326
  //  if (taosUcs4ToMbs(f2_ucs4, ucs4_max_len, f2_mbs) < 0) {
327
  //    return -1;
328
  //  }
329
  //  int32_t ret = strcmp(f1_mbs, f2_mbs);
330
  //  taosMemoryFree(f1_mbs);
331
  //  taosMemoryFree(f2_mbs);
332
  //  return ret;
333
  //#endif
334
}
335

336
#if 0
337
int32_t tasoUcs4Copy(TdUcs4 *target_ucs4, TdUcs4 *source_ucs4, int32_t len_ucs4) {
338
  if (target_ucs4 == NULL || source_ucs4 == NULL || len_ucs4 <= 0) {
339
    return TSDB_CODE_INVALID_PARA;
340
  }
341
#ifndef TD_ASTRA
342
  if (taosMemorySize(target_ucs4) < len_ucs4 * sizeof(TdUcs4)) {
343
    terrno = TSDB_CODE_INVALID_PARA;
344
    return terrno;
345
  }
346

347
  (void)memcpy(target_ucs4, source_ucs4, len_ucs4 * sizeof(TdUcs4));
348

349
  return TSDB_CODE_SUCCESS;
350
#else
351
  return TSDB_CODE_APP_ERROR;
352
#endif
353
}
354
#endif 
355

356
iconv_t taosAcquireConv(int32_t *idx, ConvType type, void* charsetCxt) {
310,456,637✔
357
#ifndef DISALLOW_NCHAR_WITHOUT_ICONV
358
  if(idx == NULL) {
310,456,637✔
359
    terrno = TSDB_CODE_INVALID_PARA;
1✔
360
    return (iconv_t)NULL;
1✔
361
  }
362
  if (charsetCxt == NULL){
310,456,636!
363
    charsetCxt = tsCharsetCxt;
310,490,432✔
364
  }
365
  SConvInfo *info = (SConvInfo *)charsetCxt;
310,456,636✔
366
  if (info == NULL) {
310,456,636✔
367
    *idx = -1;
84✔
368
    if (type == M2C) {
84✔
369
      iconv_t c = iconv_open(DEFAULT_UNICODE_ENCODEC, "UTF-8");
44✔
370
      if ((iconv_t)-1 == c) {
44!
371
        terrno = TAOS_SYSTEM_ERROR(ERRNO);
×
372
      }
373
      return c;
44✔
374
    } else {
375
      iconv_t c = iconv_open("UTF-8", DEFAULT_UNICODE_ENCODEC);
40✔
376
      if ((iconv_t)-1 == c) {
40!
377
        terrno = TAOS_SYSTEM_ERROR(ERRNO);
×
378
      }
379
      return c;
40✔
380
    }
381
  }
382

383
  while (true) {
×
384
    int32_t used = atomic_add_fetch_32(&info->convUsed[type], 1);
310,456,552✔
385
    if (used > info->gConvMaxNum[type]) {
310,922,628!
386
      (void)atomic_sub_fetch_32(&info->convUsed[type], 1);
×
387
      (void)sched_yield();
×
388
      continue;
×
389
    }
390

391
    break;
310,936,513✔
392
  }
393

394
  int32_t startId = taosGetSelfPthreadId() % info->gConvMaxNum[type];
310,936,513✔
UNCOV
395
  while (true) {
×
396
    if (info->gConv[type][startId].inUse) {
310,855,051✔
397
      startId = (startId + 1) % info->gConvMaxNum[type];
48,871✔
398
      continue;
48,871✔
399
    }
400

401
    int8_t old = atomic_val_compare_exchange_8(&info->gConv[type][startId].inUse, 0, 1);
310,806,180✔
402
    if (0 == old) {
310,823,512!
403
      break;
310,876,754✔
404
    }
405
  }
406

407
  *idx = startId;
310,876,754✔
408
  if ((iconv_t)0 == info->gConv[type][startId].conv) {
310,876,754!
409
    return (iconv_t)-1;
×
410
  } else {
411
    return info->gConv[type][startId].conv;
310,876,754✔
412
  }
413
#else
414
  terrno = TSDB_CODE_APP_ERROR;
415
  return (iconv_t)-1;
416
#endif
417
}
418

419
void taosReleaseConv(int32_t idx, iconv_t conv, ConvType type, void *charsetCxt) {
310,575,577✔
420
#ifndef DISALLOW_NCHAR_WITHOUT_ICONV
421
  if (idx < 0) {
310,575,577✔
422
    (void)iconv_close(conv);
84✔
423
    return;
84✔
424
  }
425

426
  if (charsetCxt == NULL) {
310,575,493!
427
    charsetCxt = tsCharsetCxt;
310,608,445✔
428
  }
429
  SConvInfo *info = (SConvInfo *)charsetCxt;
310,575,493✔
430

431
  atomic_store_8(&info->gConv[type][idx].inUse, 0);
310,575,493✔
432
  (void)atomic_sub_fetch_32(&info->convUsed[type], 1);
310,855,151✔
433
#endif
434
}
435

436
bool taosMbsToUcs4(const char *mbs, size_t mbsLength, TdUcs4 *ucs4, int32_t ucs4_max_len, int32_t *len, void* charsetCxt) {
89,292,281✔
437
  if (ucs4_max_len == 0) {
89,292,281✔
438
    return true;
700,459✔
439
  }
440
  if (ucs4_max_len < 0 || mbs == NULL || ucs4 == NULL) {
88,591,822!
441
    terrno = TSDB_CODE_INVALID_PARA;
×
442
    return false;
×
443
  }
444
#ifdef DISALLOW_NCHAR_WITHOUT_ICONV
445
  printf("Nchar cannot be read and written without iconv, please install iconv library and recompile.\n");
446
  terrno = TSDB_CODE_APP_ERROR;
447
  return false;
448
#else
449
  (void)memset(ucs4, 0, ucs4_max_len);
88,669,888✔
450

451
  int32_t idx = -1;
88,669,888✔
452
  iconv_t conv = taosAcquireConv(&idx, M2C, charsetCxt);
88,669,888✔
453
  if ((iconv_t)-1 == conv) {
88,822,323!
454
    return false;
×
455
  }
456

457
  size_t ucs4_input_len = mbsLength;
88,822,323✔
458
  size_t outLeft = ucs4_max_len;
88,822,323✔
459
  if (iconv(conv, (char **)&mbs, &ucs4_input_len, (char **)&ucs4, &outLeft) == -1) {
88,822,323✔
460
    terrno = TAOS_SYSTEM_ERROR(ERRNO);
201✔
461
    taosReleaseConv(idx, conv, M2C, charsetCxt);
201✔
462
    return false;
12,166✔
463
  }
464

465
  taosReleaseConv(idx, conv, M2C, charsetCxt);
88,746,003✔
466
  if (len != NULL) {
88,884,281!
467
    *len = (int32_t)(ucs4_max_len - outLeft);
88,888,288✔
468
    if (*len < 0) {
88,888,288!
469
      // can not happen
470
      terrno = TSDB_CODE_APP_ERROR;
×
471
      return false;
×
472
    }
473
  }
474

475
  return true;
88,884,281✔
476
#endif
477
}
478

479
// if success, return the number of bytes written to mbs ( >= 0)
480
// otherwise return error code ( < 0)
481
int32_t taosUcs4ToMbs(TdUcs4 *ucs4, int32_t ucs4_max_len, char *mbs, void* charsetCxt) {
220,619,391✔
482
  if (ucs4_max_len == 0) {
220,619,391✔
483
    return 0;
217✔
484
  }
485
  if (ucs4_max_len < 0 || ucs4 == NULL || mbs == NULL) {
220,619,174!
486
    terrno = TSDB_CODE_INVALID_PARA;
×
487
    return terrno;
3✔
488
  }
489
#ifdef DISALLOW_NCHAR_WITHOUT_ICONV
490
  printf("Nchar cannot be read and written without iconv, please install iconv library and recompile.\n");
491
  terrno = TSDB_CODE_APP_ERROR;
492
  return terrno;
493
#else
494

495
  int32_t idx = -1;
220,633,452✔
496
  int32_t code = 0;
220,633,452✔
497
  iconv_t conv = taosAcquireConv(&idx, C2M, charsetCxt);
220,633,452✔
498
  if ((iconv_t)-1 == conv) {
220,695,653!
499
    return terrno;
×
500
  }
501

502
  size_t ucs4_input_len = ucs4_max_len;
220,695,653✔
503
  size_t outLen = ucs4_max_len;
220,695,653✔
504
  if (iconv(conv, (char **)&ucs4, &ucs4_input_len, &mbs, &outLen) == -1) {
220,695,653!
505
    code = TAOS_SYSTEM_ERROR(ERRNO);
×
506
    taosReleaseConv(idx, conv, C2M, charsetCxt);
×
507
    terrno = code;
×
508
    return code;
1,028✔
509
  }
510

511
  taosReleaseConv(idx, conv, C2M, charsetCxt);
220,691,724✔
512

513
  return (int32_t)(ucs4_max_len - outLen);
220,710,115✔
514
#endif
515
}
516

517
// if success, return the number of bytes written to mbs ( >= 0)
518
// otherwise return error code ( < 0)
519
int32_t taosUcs4ToMbsEx(TdUcs4 *ucs4, int32_t ucs4_max_len, char *mbs, iconv_t conv) {
25,484,759✔
520
  if (ucs4_max_len == 0) {
25,484,759✔
521
    return 0;
113,386✔
522
  }
523
  if (ucs4_max_len < 0 || ucs4 == NULL || mbs == NULL) {
25,371,373!
524
    terrno = TSDB_CODE_INVALID_PARA;
104✔
525
    return terrno;
×
526
  }
527
#ifdef DISALLOW_NCHAR_WITHOUT_ICONV
528
  printf("Nchar cannot be read and written without iconv, please install iconv library and recompile.\n");
529
  terrno = TSDB_CODE_APP_ERROR;
530
  return terrno;
531
#else
532

533
  size_t ucs4_input_len = ucs4_max_len;
25,371,269✔
534
  size_t outLen = ucs4_max_len;
25,371,269✔
535
  if (iconv(conv, (char **)&ucs4, &ucs4_input_len, &mbs, &outLen) == -1) {
25,371,269!
UNCOV
536
    terrno = TAOS_SYSTEM_ERROR(ERRNO);
×
537
    return terrno;
×
538
  }
539

540
  return (int32_t)(ucs4_max_len - outLen);
25,371,592✔
541
#endif
542
}
543

544
bool taosValidateEncodec(const char *encodec) {
5,435✔
545
  if (encodec == NULL) {
5,435✔
546
    terrno = TSDB_CODE_INVALID_PARA;
1✔
547
    return false;
1✔
548
  }
549
#ifdef DISALLOW_NCHAR_WITHOUT_ICONV
550
  printf("Nchar cannot be read and written without iconv, please install iconv library and recompile.\n");
551
  terrno = TSDB_CODE_APP_ERROR;
552
  return false;
553
#else
554
  iconv_t cd = iconv_open(encodec, DEFAULT_UNICODE_ENCODEC);
5,434✔
555
  if (cd == (iconv_t)(-1)) {
5,434✔
556
    terrno = TAOS_SYSTEM_ERROR(ERRNO);
1✔
557
    return false;
1✔
558
  }
559

560
  (void)iconv_close(cd);
5,433✔
561
  return true;
5,433✔
562
#endif
563
}
564

565
int32_t taosUcs4len(TdUcs4 *ucs4) {
4✔
566
  TdUcs4 *wstr = (TdUcs4 *)ucs4;
4✔
567
  if (NULL == wstr) {
4✔
568
    return 0;
1✔
569
  }
570

571
  int32_t n = 0;
3✔
572
  while (1) {
573
    if (0 == *wstr++) {
15✔
574
      break;
3✔
575
    }
576
    n++;
12✔
577
  }
578

579
  return n;
3✔
580
}
581

582
// dst buffer size should be at least 2*len + 1
583
int32_t taosHexEncode(const unsigned char *src, char *dst, int32_t len, int32_t bufSize) {
4✔
584
  if (!dst || !src || bufSize <= 0) {
4!
585
    terrno = TSDB_CODE_INVALID_PARA;
3✔
586
    return terrno;
3✔
587
  }
588

589
  for (int32_t i = 0; i < len; ++i) {
6✔
590
    (void)snprintf(dst + i * 2, bufSize - i * 2, "%02x", src[i]);
5✔
591
  }
592

593
  return 0;
1✔
594
}
595

596
int32_t taosHexDecode(const char *src, char *dst, int32_t len) {
4✔
597
  if (!src || !dst || len <= 0) {
4!
598
    terrno = TSDB_CODE_INVALID_PARA;
3✔
599
    return terrno;
3✔
600
  }
601

602
  uint8_t hn, ln, out;
603
  for (int i = 0, j = 0; i < len * 2; i += 2, ++j) {
25✔
604
    hn = src[i] > '9' ? src[i] - 'a' + 10 : src[i] - '0';
24✔
605
    ln = src[i + 1] > '9' ? src[i + 1] - 'a' + 10 : src[i + 1] - '0';
24✔
606

607
    out = (hn << 4) | ln;
24✔
608
    (void)memcpy(dst + j, &out, 1);
24✔
609
  }
610

611
  return 0;
1✔
612
}
613

614
#ifdef TD_ASTRA
615
#include <wchar.h>
616
#include <stdbool.h>
617
#include <stdint.h>
618

619
typedef struct {
620
    uint32_t start;
621
    uint32_t end;
622
} SUnicodeRange;
623

624
static const SUnicodeRange __eaw_ranges[] = {
625
    {0x1100, 0x115F},   {0x2329, 0x232A}, {0x2E80, 0x303E}, {0x3040, 0xA4CF},
626
    {0xAC00, 0xD7AF},   {0xF900, 0xFAFF}, {0xFE10, 0xFE19}, {0x20000, 0x2FFFD},
627
    {0x30000, 0x3FFFD}, {0xFF00, 0xFFEF}, {0xA000, 0xA48F}, {0x13A0, 0x13FF}
628
};
629

630
static const int __n_eaw_ranges = sizeof(__eaw_ranges) / sizeof(__eaw_ranges[0]);
631

632
static bool isEawWideChar(wchar_t code_point) {
633
    int low = 0;
634
    int high = __n_eaw_ranges - 1;
635

636
    while (low <= high) {
637
        int mid = (low + high) / 2;
638
        if (code_point < __eaw_ranges[mid].start) {
639
            high = mid - 1;
640
        } else if (code_point > __eaw_ranges[mid].end) {
641
            low = mid + 1;
642
        } else {
643
            return true;
644
        }
645
    }
646
    return false;
647
}
648

649
int wcwidth(wchar_t c) {
650
    if (c < 0x20 || (c >= 0x7F && c <= 0x9F)) {
651
        return 0;
652
    }
653
    if (isEawWideChar(c)) {
654
        return 2;
655
    }
656
    if (c >= 0x0300 && c <= 0x036F) {
657
        return 0;
658
    }
659
    return 1;
660
}
661

662
#endif
663

664
int32_t taosWcharWidth(TdWchar wchar) { return wcwidth(wchar); }
46,512,225✔
665

666
int32_t taosWcharsWidth(TdWchar *pWchar, int32_t size) {
5✔
667
  if (pWchar == NULL || size <= 0) {
5✔
668
    terrno = TSDB_CODE_INVALID_PARA;
3✔
669
    return terrno;
3✔
670
  }
671
#ifndef TD_ASTRA
672
  return wcswidth(pWchar, size);
2✔
673
#else
674
  int32_t width = 0;
675
  for (int32_t i = 0; i < size; ++i) {
676
    width += wcwidth(pWchar[i]);
677
  }
678
  return width;
679
#endif
680
}
681

682
int32_t taosMbToWchar(TdWchar *pWchar, const char *pStr, int32_t size) {
46,512,191✔
683
  if (pWchar == NULL || pStr == NULL || size <= 0) {
46,512,191✔
684
    terrno = TSDB_CODE_INVALID_PARA;
3✔
685
    return terrno;
3✔
686
  }
687
#ifndef TD_ASTRA
688
  return mbtowc(pWchar, pStr, size);
46,512,188✔
689
#else
690
  return mbrtowc(pWchar, &pStr, size, NULL);
691
#endif
692
}
693

694
#ifdef TD_ASTRA
695
size_t mbstowcs(wchar_t *dest, const char *src, size_t n) {
696
  if (src == NULL) {
697
    return 0;
698
  }
699

700
  size_t count = 0;
701
  int    result;
702
  while (*src && count < n) {
703
    result = mbrtowc(dest, src, MB_CUR_MAX, NULL);
704
    if (result == -1 || result == 0) {
705
      return -1;
706
    }
707
    src += result;
708
    dest++;
709
    count++;
710
  }
711

712
  if (count < n) {
713
    *dest = L'\0';
714
  }
715
  return count;
716
}
717
#endif
718

719
int32_t taosMbsToWchars(TdWchar *pWchars, const char *pStrs, int32_t size) {
4✔
720
  if (pWchars == NULL || pStrs == NULL || size <= 0) {
4✔
721
    terrno = TSDB_CODE_INVALID_PARA;
3✔
722
    return terrno;
3✔
723
  }
724
  return mbstowcs(pWchars, pStrs, size);
1✔
725
}
726

727
int32_t taosWcharToMb(char *pStr, TdWchar wchar) {
1✔
728
  OS_PARAM_CHECK(pStr);
1!
729
#ifndef TD_ASTRA
730
  return wctomb(pStr, wchar);
1✔
731
#else
732
  return wcrtomb(pStr, wchar, NULL);
733
#endif
734
}
735

736
char *taosStrCaseStr(const char *str, const char *pattern) {
8✔
737
  if (str == NULL) {
8✔
738
    terrno = TSDB_CODE_INVALID_PARA;
1✔
739
    return NULL;
1✔
740
  }
741
  if (!pattern || !*pattern) return (char *)str;
7!
742

743
  size_t i;
744
  for (; *str; str++) {
180✔
745
    if (toupper(*str) == toupper(*pattern)) {
174✔
746
      for (i = 1;; i++) {
24✔
747
        if (!pattern[i]) return (char *)str;
24!
748
        if (toupper(str[i]) != toupper(pattern[i])) break;
24!
749
      }
750
    }
751
  }
752
  return NULL;
6✔
753
}
754

755
int64_t taosStr2Int64(const char *str, char **pEnd, int32_t radix) {
2,061,446,073✔
756
  if (str == NULL) {
2,061,446,073✔
757
    terrno = TSDB_CODE_INVALID_PARA;
1✔
758
    return 0;
1✔
759
  }
760
  int64_t tmp = strtoll(str, pEnd, radix);
2,061,446,072✔
761
#if defined(DARWIN) || defined(_ALPINE)
762
  if (ERRNO == EINVAL) SET_ERRNO(0);
763
#endif
764
  return tmp;
2,127,669,461✔
765
}
766

767
uint64_t taosStr2UInt64(const char *str, char **pEnd, int32_t radix) {
229,683,865✔
768
  if (str == NULL) {
229,683,865✔
769
    terrno = TSDB_CODE_INVALID_PARA;
1✔
770
    return 0;
1✔
771
  }
772
  uint64_t tmp = strtoull(str, pEnd, radix);
229,683,864✔
773
#if defined(DARWIN) || defined(_ALPINE)
774
  if (ERRNO == EINVAL) SET_ERRNO(0);
775
#endif
776
  return tmp;
232,429,873✔
777
}
778

779
int32_t taosStr2Int32(const char *str, char **pEnd, int32_t radix) {
15,928,217✔
780
  if (str == NULL) {
15,928,217✔
781
    terrno = TSDB_CODE_INVALID_PARA;
1✔
782
    return 0;
1✔
783
  }
784
  int32_t tmp = strtol(str, pEnd, radix);
15,928,216✔
785
#if defined(DARWIN) || defined(_ALPINE)
786
  if (ERRNO == EINVAL) SET_ERRNO(0);
787
#endif
788
  return tmp;
15,928,995✔
789
}
790

791
uint32_t taosStr2UInt32(const char *str, char **pEnd, int32_t radix) {
6,518✔
792
  if (str == NULL) {
6,518✔
793
    terrno = TSDB_CODE_INVALID_PARA;
1✔
794
    return 0;
1✔
795
  }
796
  uint32_t tmp = strtol(str, pEnd, radix);
6,517✔
797
#if defined(DARWIN) || defined(_ALPINE)
798
  if (ERRNO == EINVAL) SET_ERRNO(0);
799
#endif
800
  return tmp;
6,517✔
801
}
802

803
int16_t taosStr2Int16(const char *str, char **pEnd, int32_t radix) {
14,320✔
804
  if (str == NULL) {
14,320✔
805
    terrno = TSDB_CODE_INVALID_PARA;
1✔
806
    return 0;
1✔
807
  }
808
  int32_t tmp = strtol(str, pEnd, radix);
14,319✔
809
#if defined(DARWIN) || defined(_ALPINE)
810
  if (ERRNO == EINVAL) SET_ERRNO(0);
811
#endif
812
  return (int16_t)tmp;
14,319✔
813
}
814

815
uint16_t taosStr2UInt16(const char *str, char **pEnd, int32_t radix) {
88,033✔
816
  if (str == NULL) {
88,033✔
817
    terrno = TSDB_CODE_INVALID_PARA;
1✔
818
    return 0;
1✔
819
  }
820
  uint32_t tmp = strtoul(str, pEnd, radix);
88,032✔
821
#if defined(DARWIN) || defined(_ALPINE)
822
  if (ERRNO == EINVAL) SET_ERRNO(0);
823
#endif
824
  return (uint16_t)tmp;
88,038✔
825
}
826

827
int8_t taosStr2Int8(const char *str, char **pEnd, int32_t radix) {
35,944✔
828
  if (str == NULL) {
35,944✔
829
    terrno = TSDB_CODE_INVALID_PARA;
1✔
830
    return 0;
1✔
831
  }
832
  int32_t tmp = strtol(str, pEnd, radix);
35,943✔
833
  return tmp;
35,942✔
834
}
835

836
uint8_t taosStr2UInt8(const char *str, char **pEnd, int32_t radix) {
7,610✔
837
  if (str == NULL) {
7,610✔
838
    terrno = TSDB_CODE_INVALID_PARA;
1✔
839
    return 0;
1✔
840
  }
841
  uint32_t tmp = strtoul(str, pEnd, radix);
7,609✔
842
#if defined(DARWIN) || defined(_ALPINE)
843
  if (ERRNO == EINVAL) SET_ERRNO(0);
844
#endif
845
  return tmp;
7,609✔
846
}
847

848
double taosStr2Double(const char *str, char **pEnd) {
822,749,248✔
849
  if (str == NULL) {
822,749,248✔
850
    terrno = TSDB_CODE_INVALID_PARA;
1✔
851
    return 0;
1✔
852
  }
853
  double tmp = strtod(str, pEnd);
822,749,247✔
854
  return tmp;
824,318,256✔
855
}
856

857
float taosStr2Float(const char *str, char **pEnd) {
76,372✔
858
  if (str == NULL) {
76,372✔
859
    terrno = TSDB_CODE_INVALID_PARA;
1✔
860
    return 0;
1✔
861
  }
862
  float tmp = strtof(str, pEnd);
76,371✔
863
  return tmp;
76,370✔
864
}
865

866
#define HEX_PREFIX_LEN 2  // \x
867
bool isHex(const char *z, uint32_t n) {
665,251✔
868
  if (n < HEX_PREFIX_LEN) return false;
665,251✔
869
  if (z[0] == '\\' && z[1] == 'x') return true;
564,896!
870
  return false;
560,078✔
871
}
872

873
bool isValidateHex(const char *z, uint32_t n) {
4,819✔
874
  if (!z) {
4,819✔
875
    terrno = TSDB_CODE_INVALID_PARA;
1✔
876
    return false;
1✔
877
  }
878
  if ((n & 1) != 0) return false;
4,818!
879
  for (size_t i = HEX_PREFIX_LEN; i < n; i++) {
629,000,836✔
880
    if (isxdigit(z[i]) == 0) {
628,996,018!
881
      return false;
×
882
    }
883
  }
884
  return true;
4,818✔
885
}
886

887
int32_t taosHex2Ascii(const char *z, uint32_t n, void **data, uint32_t *size) {
4,821✔
888
  OS_PARAM_CHECK(z);
4,821✔
889
  OS_PARAM_CHECK(data);
4,820✔
890
  OS_PARAM_CHECK(size);
4,819✔
891
  n -= HEX_PREFIX_LEN;  // remove 0x
4,818✔
892
  z += HEX_PREFIX_LEN;
4,818✔
893
  *size = n / HEX_PREFIX_LEN;
4,818✔
894
  if (*size == 0) {
4,818✔
895
    if (!(*data = taosStrdup(""))) {
5!
896
      return terrno;
×
897
    }
898
    return 0;
5✔
899
  }
900

901
  uint8_t *tmp = (uint8_t *)taosMemoryCalloc(*size, 1);
4,813!
902
  if (tmp == NULL) {
4,813!
903
    return terrno;
×
904
  }
905

906
  int8_t   num = 0;
4,813✔
907
  uint8_t *byte = tmp + *size - 1;
4,813✔
908

909
  for (int i = n - 1; i >= 0; i--) {
629,000,831✔
910
    if (z[i] >= 'a') {
628,996,018✔
911
      *byte |= ((uint8_t)(10 + (z[i] - 'a')) << (num * 4));
157,240,817✔
912
    } else if (z[i] >= 'A') {
471,755,201✔
913
      *byte |= ((uint8_t)(10 + (z[i] - 'A')) << (num * 4));
5✔
914
    } else {
915
      *byte |= ((uint8_t)(z[i] - '0') << (num * 4));
471,755,196✔
916
    }
917
    if (num == 1) {
628,996,018✔
918
      byte--;
314,498,009✔
919
      num = 0;
314,498,009✔
920
    } else {
921
      num++;
314,498,009✔
922
    }
923
  }
924
  *data = tmp;
4,813✔
925

926
  return 0;
4,813✔
927
}
928

929
// int32_t taosBin2Ascii(const char *z, uint32_t n, void** data, uint32_t* size){
930
//
931
//   for (i = 2; isdigit(z[i]) || (z[i] >= 'a' && z[i] <= 'f') || (z[i] >= 'A' && z[i] <= 'F'); ++i) {
932
//   }
933
//
934
//   n -= 2;   // remove 0b
935
//   z += 2;
936
//   *size = n%8 == 0 ? n/8 : n/8 + 1;
937
//   uint8_t* tmp = (uint8_t*)taosMemoryCalloc(*size, 1);
938
//   if(tmp == NULL) return -1;
939
//   int8_t   num = 0;
940
//   uint8_t *byte = tmp + *size - 1;
941
//
942
//   for (int i = n - 1; i >= 0; i--) {
943
//     *byte |= ((uint8_t)(z[i] - '0') << num);
944
//     if (num == 7) {
945
//       byte--;
946
//       num = 0;
947
//     } else {
948
//       num++;
949
//     }
950
//   }
951
//   *data = tmp;
952
//   return 0;
953
// }
954

955
static char valueOf(uint8_t symbol) {
2,215,882✔
956
  switch (symbol) {
2,215,882✔
957
    case 0:
47,604✔
958
      return '0';
47,604✔
959
    case 1:
60,586✔
960
      return '1';
60,586✔
961
    case 2:
129,742✔
962
      return '2';
129,742✔
963
    case 3:
108,317✔
964
      return '3';
108,317✔
965
    case 4:
74,305✔
966
      return '4';
74,305✔
967
    case 5:
95,597✔
968
      return '5';
95,597✔
969
    case 6:
709,078✔
970
      return '6';
709,078✔
971
    case 7:
531,748✔
972
      return '7';
531,748✔
973
    case 8:
90,854✔
974
      return '8';
90,854✔
975
    case 9:
69,219✔
976
      return '9';
69,219✔
977
    case 10:
64,957✔
978
      return 'A';
64,957✔
979
    case 11:
51,883✔
980
      return 'B';
51,883✔
981
    case 12:
17,530✔
982
      return 'C';
17,530✔
983
    case 13:
51,864✔
984
      return 'D';
51,864✔
985
    case 14:
52,059✔
986
      return 'E';
52,059✔
987
    case 15:
60,514✔
988
      return 'F';
60,514✔
989
    default: {
25✔
990
      return -1;
25✔
991
    }
992
  }
993
}
994

995
int32_t taosAscii2Hex(const char *z, uint32_t n, void **data, uint32_t *size) {
4,871✔
996
  *size = n * 2 + HEX_PREFIX_LEN;
4,871✔
997
  uint8_t *tmp = (uint8_t *)taosMemoryCalloc(*size + 1, 1);
4,871!
998
  if (tmp == NULL) {
4,871!
999
    return terrno;
×
1000
  }
1001

1002
  *data = tmp;
4,871✔
1003
  *(tmp++) = '\\';
4,871✔
1004
  *(tmp++) = 'x';
4,871✔
1005
  for (int i = 0; i < n; i++) {
1,112,812✔
1006
    uint8_t val = z[i];
1,107,941✔
1007
    tmp[i * 2] = valueOf(val >> 4);
1,107,941✔
1008
    tmp[i * 2 + 1] = valueOf(val & 0x0F);
1,107,941✔
1009
  }
1010

1011
  return 0;
4,871✔
1012
}
1013

1014
int64_t tsnprintf(char *dst, int64_t size, const char *format, ...) {
801,770,557✔
1015
  if (dst == NULL || format == NULL) {
801,770,557!
1016
    terrno = TSDB_CODE_INVALID_PARA;
×
1017
    return 0;
2✔
1018
  }
1019
  if (size <= 0) return 0;
813,921,177✔
1020
  if (size == 1) {
813,921,174✔
1021
    dst[0] = '\0';
1✔
1022
    return 0;
1✔
1023
  }
1024
  if (size > SIZE_MAX) {
1025
    size = SIZE_MAX;
1026
  }
1027

1028
  int64_t ret;
1029
  va_list args;
1030
  va_start(args, format);
813,921,173✔
1031
  ret = vsnprintf(dst, size, format, args);
813,921,173✔
1032
  va_end(args);
813,921,173✔
1033
  if (ret >= size) {
813,921,173✔
1034
    return size - 1;
2✔
1035
  } else {
1036
    return ret;
813,921,171✔
1037
  }
1038
}
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