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

taosdata / TDengine / #3656

14 Mar 2025 08:10AM UTC coverage: 62.841% (+3.3%) from 59.532%
#3656

push

travis-ci

web-flow
feat(keep): support keep on super table level. (#30097)

* Feat: support use keep while create super table.

* Test(keep): add test for create super table with keep option.

* Feat(keep): Add tmsg for create keep.

* Feat(keep): support alter table option keep.

* Fix(keep): Add baisc test for alter table option.

* Fix(keep): memory leek.

* Feat(keep): add keep to metaEntry&metaCache and fix earliestTs with stn keep.

* Test(keep): add some cases for select with stb keep.

* Fix: fix ci core while alter stb.

* Feat(keep): delete expired data in super table level.

* Feat: remove get stb keep while query.

* Fix : build error.

* Revert "Fix : build error."

This reverts commit 0ed66e4e8.

* Revert "Feat(keep): delete expired data in super table level."

This reverts commit 36330f6b4.

* Fix : build errors.

* Feat : support restart taosd.

* Fix : alter table comment problems.

* Test : add tests for super table keep.

* Fix: change sdb stb reserve size.

* Test: add more tests.

* Feat: Disable normal tables and sub tables from setting the keep parameter

* Fix: add more checks to avoid unknown address.

* Docs: Add docs for stable keep.

* Fix: some review changes.

* Fix: review errors.

147682 of 302527 branches covered (48.82%)

Branch coverage included in aggregate %.

88 of 99 new or added lines in 12 files covered. (88.89%)

3177 existing lines in 34 files now uncovered.

232747 of 302857 relevant lines covered (76.85%)

5880306.3 hits per line

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

57.52
/source/client/src/clientMain.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
#include "catalog.h"
17
#include "clientInt.h"
18
#include "clientLog.h"
19
#include "clientMonitor.h"
20
#include "clientStmt.h"
21
#include "clientStmt2.h"
22
#include "functionMgt.h"
23
#include "os.h"
24
#include "query.h"
25
#include "scheduler.h"
26
#include "tcompare.h"
27
#include "tconv.h"
28
#include "tdatablock.h"
29
#include "tglobal.h"
30
#include "tmsg.h"
31
#include "tref.h"
32
#include "trpc.h"
33
#include "version.h"
34

35
#define TSC_VAR_NOT_RELEASE 1
36
#define TSC_VAR_RELEASED    0
37

38
#ifdef TAOSD_INTEGRATED
39
extern void shellStopDaemon();
40
#endif
41

42
static int32_t sentinel = TSC_VAR_NOT_RELEASE;
43
static int32_t createParseContext(const SRequestObj *pRequest, SParseContext **pCxt, SSqlCallbackWrapper *pWrapper);
44

45
int taos_options(TSDB_OPTION option, const void *arg, ...) {
2,110✔
46
  if (arg == NULL) {
2,110!
47
    return TSDB_CODE_INVALID_PARA;
×
48
  }
49
  static int32_t lock = 0;
50

51
  for (int i = 1; atomic_val_compare_exchange_32(&lock, 0, 1) != 0; ++i) {
186,107✔
52
    if (i % 1000 == 0) {
183,997✔
53
      (void)sched_yield();
183✔
54
    }
55
  }
56

57
  int ret = taos_options_imp(option, (const char *)arg);
2,110✔
58
  atomic_store_32(&lock, 0);
2,110✔
59
  return ret;
2,110✔
60
}
61

62
#if !defined(WINDOWS) && !defined(TD_ASTRA)
63
static void freeTz(void *p) {
10✔
64
  timezone_t tz = *(timezone_t *)p;
10✔
65
  tzfree(tz);
10✔
66
}
10✔
67

68
int32_t tzInit() {
2,443✔
69
  pTimezoneMap = taosHashInit(0, MurmurHash3_32, false, HASH_ENTRY_LOCK);
2,443✔
70
  if (pTimezoneMap == NULL) {
2,443!
71
    return terrno;
×
72
  }
73
  taosHashSetFreeFp(pTimezoneMap, freeTz);
2,443✔
74

75
  pTimezoneNameMap = taosHashInit(0, taosIntHash_64, false, HASH_ENTRY_LOCK);
2,443✔
76
  if (pTimezoneNameMap == NULL) {
2,443!
77
    return terrno;
×
78
  }
79
  return 0;
2,443✔
80
}
81

82
void tzCleanup() {
2,444✔
83
  taosHashCleanup(pTimezoneMap);
2,444✔
84
  taosHashCleanup(pTimezoneNameMap);
2,444✔
85
}
2,444✔
86

87
static timezone_t setConnnectionTz(const char *val) {
17✔
88
  timezone_t  tz = NULL;
17✔
89
  timezone_t *tmp = taosHashGet(pTimezoneMap, val, strlen(val));
17✔
90
  if (tmp != NULL && *tmp != NULL) {
17!
91
    tz = *tmp;
7✔
92
    goto END;
7✔
93
  }
94

95
  tscDebug("set timezone to %s", val);
10!
96
  tz = tzalloc(val);
10✔
97
  if (tz == NULL) {
10✔
98
    tscWarn("%s unknown timezone %s change to UTC", __func__, val);
1!
99
    tz = tzalloc("UTC");
1✔
100
    if (tz == NULL) {
1!
101
      tscError("%s set timezone UTC error", __func__);
×
102
      terrno = TAOS_SYSTEM_ERROR(ERRNO);
×
103
      goto END;
×
104
    }
105
  }
106
  int32_t code = taosHashPut(pTimezoneMap, val, strlen(val), &tz, sizeof(timezone_t));
10✔
107
  if (code != 0) {
10!
108
    tscError("%s put timezone to tz map error:%d", __func__, code);
×
109
    tzfree(tz);
×
110
    tz = NULL;
×
111
    goto END;
×
112
  }
113

114
  time_t tx1 = taosGetTimestampSec();
10✔
115
  char   output[TD_TIMEZONE_LEN] = {0};
10✔
116
  code = taosFormatTimezoneStr(tx1, val, tz, output);
10✔
117
  if (code == 0) {
10!
118
    code = taosHashPut(pTimezoneNameMap, &tz, sizeof(timezone_t), output, strlen(output) + 1);
10✔
119
  }
120
  if (code != 0) {
10!
121
    tscError("failed to put timezone %s to map", val);
×
122
  }
123

124
END:
10✔
125
  return tz;
17✔
126
}
127
#endif
128

129
static int32_t setConnectionOption(TAOS *taos, TSDB_OPTION_CONNECTION option, const char *val) {
38✔
130
  if (taos == NULL) {
38✔
131
    return terrno = TSDB_CODE_INVALID_PARA;
1✔
132
  }
133

134
#ifdef WINDOWS
135
  if (option == TSDB_OPTION_CONNECTION_TIMEZONE) {
136
    return terrno = TSDB_CODE_NOT_SUPPORTTED_IN_WINDOWS;
137
  }
138
#endif
139

140
  if (option < TSDB_OPTION_CONNECTION_CLEAR || option >= TSDB_MAX_OPTIONS_CONNECTION) {
37!
141
    return terrno = TSDB_CODE_INVALID_PARA;
1✔
142
  }
143

144
  int32_t code = taos_init();
36✔
145
  // initialize global config
146
  if (code != 0) {
36!
147
    return terrno = code;
×
148
  }
149

150
  STscObj *pObj = acquireTscObj(*(int64_t *)taos);
36✔
151
  if (NULL == pObj) {
36!
152
    tscError("invalid parameter for %s", __func__);
×
153
    return terrno;
×
154
  }
155

156
  if (option == TSDB_OPTION_CONNECTION_CLEAR) {
36✔
157
    val = NULL;
1✔
158
  }
159

160
#ifndef DISALLOW_NCHAR_WITHOUT_ICONV
161
  if (option == TSDB_OPTION_CONNECTION_CHARSET || option == TSDB_OPTION_CONNECTION_CLEAR) {
36✔
162
    if (val != NULL) {
8✔
163
      if (!taosValidateEncodec(val)) {
5✔
164
        code = terrno;
1✔
165
        goto END;
1✔
166
      }
167
      void *tmp = taosConvInit(val);
4✔
168
      if (tmp == NULL) {
4✔
169
        code = terrno;
1✔
170
        goto END;
1✔
171
      }
172
      pObj->optionInfo.charsetCxt = tmp;
3✔
173
    } else {
174
      pObj->optionInfo.charsetCxt = NULL;
3✔
175
    }
176
  }
177
#endif
178
  if (option == TSDB_OPTION_CONNECTION_TIMEZONE || option == TSDB_OPTION_CONNECTION_CLEAR) {
34✔
179
#if !defined(WINDOWS) && !defined(TD_ASTRA)
180
    if (val != NULL) {
19✔
181
      if (val[0] == 0) {
17✔
182
        val = "UTC";
1✔
183
      }
184
      timezone_t tz = setConnnectionTz(val);
17✔
185
      if (tz == NULL) {
17!
186
        code = terrno;
×
187
        goto END;
×
188
      }
189
      pObj->optionInfo.timezone = tz;
17✔
190
    } else {
191
      pObj->optionInfo.timezone = NULL;
2✔
192
    }
193
#endif
194
  }
195

196
  if (option == TSDB_OPTION_CONNECTION_USER_APP || option == TSDB_OPTION_CONNECTION_CLEAR) {
34✔
197
    if (val != NULL) {
5✔
198
      tstrncpy(pObj->optionInfo.userApp, val, sizeof(pObj->optionInfo.userApp));
3✔
199
    } else {
200
      pObj->optionInfo.userApp[0] = 0;
2✔
201
    }
202
  }
203

204
  if (option == TSDB_OPTION_CONNECTION_USER_IP || option == TSDB_OPTION_CONNECTION_CLEAR) {
34✔
205
    if (val != NULL) {
7✔
206
      pObj->optionInfo.userIp = taosInetAddr(val);
5✔
207
      if (pObj->optionInfo.userIp == INADDR_NONE) {
5✔
208
        code = TSDB_CODE_INVALID_PARA;
3✔
209
        goto END;
3✔
210
      }
211
    } else {
212
      pObj->optionInfo.userIp = INADDR_NONE;
2✔
213
    }
214
  }
215

216
END:
27✔
217
  releaseTscObj(*(int64_t *)taos);
36✔
218
  return terrno = code;
36✔
219
}
220

221
int taos_options_connection(TAOS *taos, TSDB_OPTION_CONNECTION option, const void *arg, ...) {
38✔
222
  return setConnectionOption(taos, option, (const char *)arg);
38✔
223
}
224

225
// this function may be called by user or system, or by both simultaneously.
226
void taos_cleanup(void) {
2,462✔
227
  tscDebug("start to cleanup client environment");
2,462✔
228
  if (atomic_val_compare_exchange_32(&sentinel, TSC_VAR_NOT_RELEASE, TSC_VAR_RELEASED) != TSC_VAR_NOT_RELEASE) {
2,462✔
229
    return;
18✔
230
  }
231

232
  monitorClose();
2,444✔
233
  tscStopCrashReport();
2,444✔
234

235
  hbMgrCleanUp();
2,444✔
236

237
  catalogDestroy();
2,444✔
238
  schedulerDestroy();
2,444✔
239

240
  fmFuncMgtDestroy();
2,444✔
241
  qCleanupKeywordsTable();
2,444✔
242

243
  if (TSDB_CODE_SUCCESS != cleanupTaskQueue()) {
2,444!
244
    tscWarn("failed to cleanup task queue");
×
245
  }
246

247
#if !defined(WINDOWS) && !defined(TD_ASTRA)
248
  tzCleanup();
2,444✔
249
#endif
250
  tmqMgmtClose();
2,444✔
251

252
  int32_t id = clientReqRefPool;
2,444✔
253
  clientReqRefPool = -1;
2,444✔
254
  taosCloseRef(id);
2,444✔
255

256
  id = clientConnRefPool;
2,444✔
257
  clientConnRefPool = -1;
2,444✔
258
  taosCloseRef(id);
2,444✔
259

260
  nodesDestroyAllocatorSet();
2,444✔
261
  cleanupAppInfo();
2,444✔
262
  rpcCleanup();
2,444✔
263
  tscDebug("rpc cleanup");
2,444✔
264

265
  taosConvDestroy();
2,444✔
266
  DestroyRegexCache();
2,444✔
267
#ifdef TAOSD_INTEGRATED
268
  shellStopDaemon();
269
#endif
270
  tscInfo("all local resources released");
2,444!
271
  taosCleanupCfg();
2,444✔
272
#ifndef TAOSD_INTEGRATED
273
  taosCloseLog();
2,444✔
274
#endif
275
}
276

277
static setConfRet taos_set_config_imp(const char *config) {
×
278
  setConfRet ret = {SET_CONF_RET_SUCC, {0}};
×
279
  // TODO: need re-implementation
280
  return ret;
×
281
}
282

283
setConfRet taos_set_config(const char *config) {
×
284
  // TODO  pthread_mutex_lock(&setConfMutex);
285
  setConfRet ret = taos_set_config_imp(config);
×
286
  //  pthread_mutex_unlock(&setConfMutex);
287
  return ret;
×
288
}
289

290
TAOS *taos_connect(const char *ip, const char *user, const char *pass, const char *db, uint16_t port) {
11,201✔
291
  tscInfo("try to connect to %s:%u, user:%s db:%s", ip, port, user, db);
11,201!
292
  if (user == NULL) {
11,202!
293
    user = TSDB_DEFAULT_USER;
×
294
  }
295

296
  if (pass == NULL) {
11,202!
297
    pass = TSDB_DEFAULT_PASS;
×
298
  }
299

300
  STscObj *pObj = NULL;
11,202✔
301
  int32_t  code = taos_connect_internal(ip, user, pass, NULL, db, port, CONN_TYPE__QUERY, &pObj);
11,202✔
302
  if (TSDB_CODE_SUCCESS == code) {
11,202✔
303
    int64_t *rid = taosMemoryCalloc(1, sizeof(int64_t));
11,160!
304
    if (NULL == rid) {
11,160!
305
      tscError("out of memory when taos connect to %s:%u, user:%s db:%s", ip, port, user, db);
×
306
      return NULL;
×
307
    }
308
    *rid = pObj->id;
11,160✔
309
    return (TAOS *)rid;
11,160✔
310
  } else {
311
    terrno = code;
42✔
312
  }
313

314
  return NULL;
42✔
315
}
316

317
int taos_set_notify_cb(TAOS *taos, __taos_notify_fn_t fp, void *param, int type) {
150✔
318
  if (taos == NULL) {
150!
319
    terrno = TSDB_CODE_INVALID_PARA;
×
320
    return terrno;
×
321
  }
322

323
  STscObj *pObj = acquireTscObj(*(int64_t *)taos);
150✔
324
  if (NULL == pObj) {
150!
325
    terrno = TSDB_CODE_TSC_DISCONNECTED;
×
326
    tscError("invalid parameter for %s", __func__);
×
327
    return terrno;
×
328
  }
329

330
  switch (type) {
150!
331
    case TAOS_NOTIFY_PASSVER: {
40✔
332
      TSC_ERR_RET(taosThreadMutexLock(&pObj->mutex));
40!
333
      pObj->passInfo.fp = fp;
40✔
334
      pObj->passInfo.param = param;
40✔
335
      TSC_ERR_RET(taosThreadMutexUnlock(&pObj->mutex));
40!
336
      break;
40✔
337
    }
338
    case TAOS_NOTIFY_WHITELIST_VER: {
10✔
339
      TSC_ERR_RET(taosThreadMutexLock(&pObj->mutex));
10!
340
      pObj->whiteListInfo.fp = fp;
10✔
341
      pObj->whiteListInfo.param = param;
10✔
342
      TSC_ERR_RET(taosThreadMutexUnlock(&pObj->mutex));
10!
343
      break;
10✔
344
    }
345
    case TAOS_NOTIFY_USER_DROPPED: {
100✔
346
      TSC_ERR_RET(taosThreadMutexLock(&pObj->mutex));
100!
347
      pObj->userDroppedInfo.fp = fp;
100✔
348
      pObj->userDroppedInfo.param = param;
100✔
349
      TSC_ERR_RET(taosThreadMutexUnlock(&pObj->mutex));
100!
350
      break;
100✔
351
    }
352
    default: {
×
353
      terrno = TSDB_CODE_INVALID_PARA;
×
354
      releaseTscObj(*(int64_t *)taos);
×
355
      return terrno;
×
356
    }
357
  }
358

359
  releaseTscObj(*(int64_t *)taos);
150✔
360
  return 0;
150✔
361
}
362

363
typedef struct SFetchWhiteListInfo {
364
  int64_t                     connId;
365
  __taos_async_whitelist_fn_t userCbFn;
366
  void                       *userParam;
367
} SFetchWhiteListInfo;
368

369
int32_t fetchWhiteListCallbackFn(void *param, SDataBuf *pMsg, int32_t code) {
10✔
370
  SFetchWhiteListInfo *pInfo = (SFetchWhiteListInfo *)param;
10✔
371
  TAOS                *taos = &pInfo->connId;
10✔
372
  if (code != TSDB_CODE_SUCCESS) {
10!
373
    pInfo->userCbFn(pInfo->userParam, code, taos, 0, NULL);
×
374
    taosMemoryFree(pMsg->pData);
×
375
    taosMemoryFree(pMsg->pEpSet);
×
376
    taosMemoryFree(pInfo);
×
377
    return code;
×
378
  }
379

380
  SGetUserWhiteListRsp wlRsp;
381
  if (TSDB_CODE_SUCCESS != tDeserializeSGetUserWhiteListRsp(pMsg->pData, pMsg->len, &wlRsp)) {
10!
382
    taosMemoryFree(pMsg->pData);
×
383
    taosMemoryFree(pMsg->pEpSet);
×
384
    taosMemoryFree(pInfo);
×
385
    tFreeSGetUserWhiteListRsp(&wlRsp);
×
386
    return terrno;
×
387
  }
388

389
  uint64_t *pWhiteLists = taosMemoryMalloc(wlRsp.numWhiteLists * sizeof(uint64_t));
10!
390
  if (pWhiteLists == NULL) {
10!
391
    taosMemoryFree(pMsg->pData);
×
392
    taosMemoryFree(pMsg->pEpSet);
×
393
    taosMemoryFree(pInfo);
×
394
    tFreeSGetUserWhiteListRsp(&wlRsp);
×
395
    return terrno;
×
396
  }
397

398
  for (int i = 0; i < wlRsp.numWhiteLists; ++i) {
20✔
399
    pWhiteLists[i] = ((uint64_t)wlRsp.pWhiteLists[i].mask << 32) | wlRsp.pWhiteLists[i].ip;
10✔
400
  }
401

402
  pInfo->userCbFn(pInfo->userParam, code, taos, wlRsp.numWhiteLists, pWhiteLists);
10✔
403

404
  taosMemoryFree(pWhiteLists);
10!
405
  taosMemoryFree(pMsg->pData);
10!
406
  taosMemoryFree(pMsg->pEpSet);
10!
407
  taosMemoryFree(pInfo);
10!
408
  tFreeSGetUserWhiteListRsp(&wlRsp);
10✔
409
  return code;
10✔
410
}
411

412
void taos_fetch_whitelist_a(TAOS *taos, __taos_async_whitelist_fn_t fp, void *param) {
10✔
413
  if (NULL == taos) {
10!
414
    fp(param, TSDB_CODE_INVALID_PARA, taos, 0, NULL);
×
415
    return;
×
416
  }
417

418
  int64_t connId = *(int64_t *)taos;
10✔
419

420
  STscObj *pTsc = acquireTscObj(connId);
10✔
421
  if (NULL == pTsc) {
10!
422
    fp(param, TSDB_CODE_TSC_DISCONNECTED, taos, 0, NULL);
×
423
    return;
×
424
  }
425

426
  SGetUserWhiteListReq req;
427
  (void)memcpy(req.user, pTsc->user, TSDB_USER_LEN);
10✔
428
  int32_t msgLen = tSerializeSGetUserWhiteListReq(NULL, 0, &req);
10✔
429
  if (msgLen < 0) {
10!
430
    fp(param, TSDB_CODE_INVALID_PARA, taos, 0, NULL);
×
431
    releaseTscObj(connId);
×
432
    return;
×
433
  }
434

435
  void *pReq = taosMemoryMalloc(msgLen);
10!
436
  if (pReq == NULL) {
10!
437
    fp(param, terrno, taos, 0, NULL);
×
438
    releaseTscObj(connId);
×
439
    return;
×
440
  }
441

442
  if (tSerializeSGetUserWhiteListReq(pReq, msgLen, &req) < 0) {
10!
443
    fp(param, TSDB_CODE_INVALID_PARA, taos, 0, NULL);
×
444
    taosMemoryFree(pReq);
×
445
    releaseTscObj(connId);
×
446
    return;
×
447
  }
448

449
  SFetchWhiteListInfo *pParam = taosMemoryMalloc(sizeof(SFetchWhiteListInfo));
10!
450
  if (pParam == NULL) {
10!
451
    fp(param, terrno, taos, 0, NULL);
×
452
    taosMemoryFree(pReq);
×
453
    releaseTscObj(connId);
×
454
    return;
×
455
  }
456

457
  pParam->connId = connId;
10✔
458
  pParam->userCbFn = fp;
10✔
459
  pParam->userParam = param;
10✔
460
  SMsgSendInfo *pSendInfo = taosMemoryCalloc(1, sizeof(SMsgSendInfo));
10!
461
  if (pSendInfo == NULL) {
10!
462
    fp(param, terrno, taos, 0, NULL);
×
463
    taosMemoryFree(pParam);
×
464
    taosMemoryFree(pReq);
×
465
    releaseTscObj(connId);
×
466
    return;
×
467
  }
468

469
  pSendInfo->msgInfo = (SDataBuf){.pData = pReq, .len = msgLen, .handle = NULL};
10✔
470
  pSendInfo->requestId = generateRequestId();
10✔
471
  pSendInfo->requestObjRefId = 0;
10✔
472
  pSendInfo->param = pParam;
10✔
473
  pSendInfo->fp = fetchWhiteListCallbackFn;
10✔
474
  pSendInfo->msgType = TDMT_MND_GET_USER_WHITELIST;
10✔
475

476
  SEpSet epSet = getEpSet_s(&pTsc->pAppInfo->mgmtEp);
10✔
477
  if (TSDB_CODE_SUCCESS != asyncSendMsgToServer(pTsc->pAppInfo->pTransporter, &epSet, NULL, pSendInfo)) {
10!
478
    tscWarn("failed to async send msg to server");
×
479
  }
480
  releaseTscObj(connId);
10✔
481
  return;
10✔
482
}
483

484
void taos_close_internal(void *taos) {
11,610✔
485
  if (taos == NULL) {
11,610!
486
    return;
×
487
  }
488

489
  STscObj *pTscObj = (STscObj *)taos;
11,610✔
490
  tscDebug("connObj:0x%" PRIx64 ", try to close connection, numOfReq:%d", pTscObj->id, pTscObj->numOfReqs);
11,610✔
491

492
  if (TSDB_CODE_SUCCESS != taosRemoveRef(clientConnRefPool, pTscObj->id)) {
11,610!
493
    tscError("connObj:0x%" PRIx64 ", failed to remove ref from conn pool", pTscObj->id);
×
494
  }
495
}
496

497
void taos_close(TAOS *taos) {
12,043✔
498
  if (taos == NULL) {
12,043✔
499
    return;
888✔
500
  }
501

502
  STscObj *pObj = acquireTscObj(*(int64_t *)taos);
11,155✔
503
  if (NULL == pObj) {
11,155!
504
    taosMemoryFree(taos);
×
505
    return;
×
506
  }
507

508
  taos_close_internal(pObj);
11,155✔
509
  releaseTscObj(*(int64_t *)taos);
11,155✔
510
  taosMemoryFree(taos);
11,155!
511
}
512

513
int taos_errno(TAOS_RES *res) {
4,019,404✔
514
  if (res == NULL || TD_RES_TMQ_RAW(res) || TD_RES_TMQ_META(res) || TD_RES_TMQ_BATCH_META(res)) {
4,019,404!
515
    return terrno;
6✔
516
  }
517

518
  if (TD_RES_TMQ(res) || TD_RES_TMQ_METADATA(res)) {
4,019,398✔
519
    return 0;
462✔
520
  }
521

522
  return ((SRequestObj *)res)->code;
4,018,936✔
523
}
524

525
const char *taos_errstr(TAOS_RES *res) {
91,698✔
526
  if (res == NULL || TD_RES_TMQ_RAW(res) || TD_RES_TMQ_META(res) || TD_RES_TMQ_BATCH_META(res)) {
91,698!
527
    return (const char *)tstrerror(terrno);
108✔
528
  }
529

530
  if (TD_RES_TMQ(res) || TD_RES_TMQ_METADATA(res)) {
91,590!
531
    return "success";
×
532
  }
533

534
  SRequestObj *pRequest = (SRequestObj *)res;
91,590✔
535
  if (NULL != pRequest->msgBuf && (strlen(pRequest->msgBuf) > 0 || pRequest->code == TSDB_CODE_RPC_FQDN_ERROR)) {
91,590!
536
    return pRequest->msgBuf;
84,304✔
537
  } else {
538
    return (const char *)tstrerror(pRequest->code);
7,286✔
539
  }
540
}
541

542
void taos_free_result(TAOS_RES *res) {
2,928,286✔
543
  if (NULL == res) {
2,928,286✔
544
    return;
21,948✔
545
  }
546

547
  tscTrace("res:%p, will be freed", res);
2,906,338✔
548

549
  if (TD_RES_QUERY(res)) {
2,906,378✔
550
    SRequestObj *pRequest = (SRequestObj *)res;
2,796,592✔
551
    tscDebug("QID:0x%" PRIx64 ", call taos_free_result to free query", pRequest->requestId);
2,796,592✔
552
    destroyRequest(pRequest);
2,796,592✔
553
    return;
2,796,590✔
554
  }
555

556
  SMqRspObj *pRsp = (SMqRspObj *)res;
109,786✔
557
  if (TD_RES_TMQ(res)) {
109,786✔
558
    tDeleteMqDataRsp(&pRsp->dataRsp);
109,512✔
559
    doFreeReqResultInfo(&pRsp->resInfo);
109,511✔
560
  } else if (TD_RES_TMQ_METADATA(res)) {
274✔
561
    tDeleteSTaosxRsp(&pRsp->dataRsp);
12✔
562
    doFreeReqResultInfo(&pRsp->resInfo);
12✔
563
  } else if (TD_RES_TMQ_META(res)) {
262✔
564
    tDeleteMqMetaRsp(&pRsp->metaRsp);
227✔
565
  } else if (TD_RES_TMQ_BATCH_META(res)) {
35✔
566
    tDeleteMqBatchMetaRsp(&pRsp->batchMetaRsp);
18✔
567
  } else if (TD_RES_TMQ_RAW(res)) {
17!
568
    tDeleteMqRawDataRsp(&pRsp->dataRsp);
17✔
569
  }
570
  taosMemoryFree(pRsp);
109,784!
571
}
572

573
void taos_kill_query(TAOS *taos) {
10✔
574
  if (NULL == taos) {
10✔
575
    return;
5✔
576
  }
577

578
  int64_t  rid = *(int64_t *)taos;
5✔
579
  STscObj *pTscObj = acquireTscObj(rid);
5✔
580
  if (pTscObj) {
5!
581
    stopAllRequests(pTscObj->pRequests);
5✔
582
  }
583
  releaseTscObj(rid);
5✔
584
}
585

586
int taos_field_count(TAOS_RES *res) {
67,460,642✔
587
  if (res == NULL || TD_RES_TMQ_RAW(res) || TD_RES_TMQ_META(res) || TD_RES_TMQ_BATCH_META(res)) {
67,460,642!
UNCOV
588
    return 0;
×
589
  }
590

591
  SReqResultInfo *pResInfo = tscGetCurResInfo(res);
67,461,118✔
592
  return pResInfo->numOfCols;
67,461,118✔
593
}
594

595
int taos_num_fields(TAOS_RES *res) { return taos_field_count(res); }
48,002,658✔
596

597
TAOS_FIELD *taos_fetch_fields(TAOS_RES *res) {
16,687,653✔
598
  if (taos_num_fields(res) == 0 || TD_RES_TMQ_RAW(res) || TD_RES_TMQ_META(res) || TD_RES_TMQ_BATCH_META(res)) {
16,687,653!
599
    return NULL;
132,584✔
600
  }
601

602
  SReqResultInfo *pResInfo = tscGetCurResInfo(res);
16,554,751✔
603
  return pResInfo->userFields;
16,554,751✔
604
}
605

606
TAOS_RES *taos_query(TAOS *taos, const char *sql) { return taosQueryImpl(taos, sql, false, TD_REQ_FROM_APP); }
2,651,977✔
607
TAOS_RES *taos_query_with_reqid(TAOS *taos, const char *sql, int64_t reqid) {
×
608
  return taosQueryImplWithReqid(taos, sql, false, reqid);
×
609
}
610

611
TAOS_ROW taos_fetch_row(TAOS_RES *res) {
43,953,091✔
612
  if (res == NULL) {
43,953,091!
613
    return NULL;
×
614
  }
615

616
  if (TD_RES_QUERY(res)) {
43,953,091✔
617
    SRequestObj *pRequest = (SRequestObj *)res;
28,512,650✔
618
    if (pRequest->type == TSDB_SQL_RETRIEVE_EMPTY_RESULT || pRequest->type == TSDB_SQL_INSERT ||
28,512,650✔
619
        pRequest->code != TSDB_CODE_SUCCESS || taos_num_fields(res) == 0 || pRequest->killed) {
28,511,502!
620
      return NULL;
1,160✔
621
    }
622

623
    if (pRequest->inCallback) {
28,508,556✔
624
      tscError("can not call taos_fetch_row before query callback ends.");
1!
625
      terrno = TSDB_CODE_TSC_INVALID_OPERATION;
1✔
626
      return NULL;
1✔
627
    }
628

629
    return doAsyncFetchRows(pRequest, true, true);
28,508,555✔
630
  } else if (TD_RES_TMQ(res) || TD_RES_TMQ_METADATA(res)) {
15,440,441!
631
    SMqRspObj      *msg = ((SMqRspObj *)res);
15,440,441✔
632
    SReqResultInfo *pResultInfo = NULL;
15,440,441✔
633
    if (msg->resIter == -1) {
15,440,441✔
634
      if (tmqGetNextResInfo(res, true, &pResultInfo) != 0) {
109,021!
635
        return NULL;
×
636
      }
637
    } else {
638
      pResultInfo = tmqGetCurResInfo(res);
15,331,420✔
639
    }
640

641
    if (pResultInfo->current < pResultInfo->numOfRows) {
15,440,441✔
642
      doSetOneRowPtr(pResultInfo);
15,106,915✔
643
      pResultInfo->current += 1;
15,106,351✔
644
      return pResultInfo->row;
15,106,351✔
645
    } else {
646
      if (tmqGetNextResInfo(res, true, &pResultInfo) != 0) {
333,526✔
647
        return NULL;
109,016✔
648
      }
649

650
      doSetOneRowPtr(pResultInfo);
224,673✔
651
      pResultInfo->current += 1;
224,665✔
652
      return pResultInfo->row;
224,665✔
653
    }
654
  } else if (TD_RES_TMQ_META(res) || TD_RES_TMQ_BATCH_META(res)) {
×
655
    return NULL;
×
656
  } else {
657
    tscError("invalid result passed to taos_fetch_row");
×
658
    terrno = TSDB_CODE_TMQ_INVALID_DATA;
×
659
    return NULL;
×
660
  }
661
}
662

663
int taos_print_row(char *str, TAOS_ROW row, TAOS_FIELD *fields, int num_fields) {
15,416,296✔
664
  return taos_print_row_with_size(str, INT32_MAX, row, fields, num_fields);
15,416,296✔
665
}
666
int taos_print_row_with_size(char *str, uint32_t size, TAOS_ROW row, TAOS_FIELD *fields, int num_fields) {
15,416,218✔
667
  int32_t len = 0;
15,416,218✔
668
  for (int i = 0; i < num_fields; ++i) {
92,560,611✔
669
    if (i > 0 && len < size - 1) {
77,142,577!
670
      str[len++] = ' ';
61,747,897✔
671
    }
672

673
    if (row[i] == NULL) {
77,142,577✔
674
      len += tsnprintf(str + len, size - len, "%s", TSDB_DATA_NULL_STR);
536,708✔
675
      continue;
536,708✔
676
    }
677

678
    switch (fields[i].type) {
76,605,869!
679
      case TSDB_DATA_TYPE_TINYINT:
27,189✔
680
        len += tsnprintf(str + len, size - len, "%d", *((int8_t *)row[i]));
27,189✔
681
        break;
27,189✔
682

683
      case TSDB_DATA_TYPE_UTINYINT:
27,038✔
684
        len += tsnprintf(str + len, size - len, "%u", *((uint8_t *)row[i]));
27,038✔
685
        break;
27,038✔
686

687
      case TSDB_DATA_TYPE_SMALLINT:
29,389✔
688
        len += tsnprintf(str + len, size - len, "%d", *((int16_t *)row[i]));
29,389✔
689
        break;
29,389✔
690

691
      case TSDB_DATA_TYPE_USMALLINT:
26,138✔
692
        len += tsnprintf(str + len, size - len, "%u", *((uint16_t *)row[i]));
26,138✔
693
        break;
26,138✔
694

695
      case TSDB_DATA_TYPE_INT:
16,317,419✔
696
        len += tsnprintf(str + len, size - len, "%d", *((int32_t *)row[i]));
16,317,419✔
697
        break;
16,318,482✔
698

699
      case TSDB_DATA_TYPE_UINT:
27,948✔
700
        len += tsnprintf(str + len, size - len, "%u", *((uint32_t *)row[i]));
27,948✔
701
        break;
27,948✔
702

703
      case TSDB_DATA_TYPE_BIGINT:
13,978,603✔
704
        len += tsnprintf(str + len, size - len, "%" PRId64, *((int64_t *)row[i]));
13,978,603✔
705
        break;
13,977,806✔
706

707
      case TSDB_DATA_TYPE_UBIGINT:
27,538✔
708
        len += tsnprintf(str + len, size - len, "%" PRIu64, *((uint64_t *)row[i]));
27,538✔
709
        break;
27,538✔
710

711
      case TSDB_DATA_TYPE_FLOAT: {
28,070✔
712
        float fv = 0;
28,070✔
713
        fv = GET_FLOAT_VAL(row[i]);
28,070✔
714
        len += snprintf(str + len, size - len, "%.*g", FLT_DIG, fv);
28,070✔
715
      } break;
28,070✔
716

717
      case TSDB_DATA_TYPE_DOUBLE: {
8,084,195✔
718
        double dv = 0;
8,084,195✔
719
        dv = GET_DOUBLE_VAL(row[i]);
8,084,195✔
720
        len += snprintf(str + len, size - len, "%.*g", DBL_DIG, dv);
8,084,195✔
721
      } break;
8,084,195✔
722

723
      case TSDB_DATA_TYPE_VARBINARY: {
202✔
724
        void    *data = NULL;
202✔
725
        uint32_t tmp = 0;
202✔
726
        int32_t  charLen = varDataLen((char *)row[i] - VARSTR_HEADER_SIZE);
202✔
727
        if (taosAscii2Hex(row[i], charLen, &data, &tmp) < 0) {
202!
728
          break;
×
729
        }
730
        uint32_t copyLen = TMIN(size - len - 1, tmp);
202✔
731
        (void)memcpy(str + len, data, copyLen);
202✔
732
        len += copyLen;
202✔
733
        taosMemoryFree(data);
202!
734
      } break;
202✔
735
      case TSDB_DATA_TYPE_BINARY:
17,105,256✔
736
      case TSDB_DATA_TYPE_NCHAR:
737
      case TSDB_DATA_TYPE_GEOMETRY: {
738
        int32_t charLen = varDataLen((char *)row[i] - VARSTR_HEADER_SIZE);
17,105,256✔
739
        if (fields[i].type == TSDB_DATA_TYPE_BINARY || fields[i].type == TSDB_DATA_TYPE_VARBINARY ||
17,105,256!
740
            fields[i].type == TSDB_DATA_TYPE_GEOMETRY) {
5,496,342✔
741
          if (charLen > fields[i].bytes || charLen < 0) {
11,609,105!
742
            tscError("taos_print_row error binary. charLen:%d, fields[i].bytes:%d", charLen, fields[i].bytes);
×
743
            break;
×
744
          }
745
        } else {
746
          if (charLen > fields[i].bytes * TSDB_NCHAR_SIZE || charLen < 0) {
5,496,151!
747
            tscError("taos_print_row error. charLen:%d, fields[i].bytes:%d", charLen, fields[i].bytes);
1,313!
748
            break;
×
749
          }
750
        }
751

752
        uint32_t copyLen = TMIN(size - len - 1, charLen);
17,104,964✔
753
        (void)memcpy(str + len, row[i], copyLen);
17,104,964✔
754
        len += copyLen;
17,104,964✔
755
      } break;
17,104,964✔
756

757
      case TSDB_DATA_TYPE_TIMESTAMP:
20,887,789✔
758
        len += tsnprintf(str + len, size - len, "%" PRId64, *((int64_t *)row[i]));
20,887,789✔
759
        break;
20,889,631✔
760

761
      case TSDB_DATA_TYPE_BOOL:
81,678✔
762
        len += tsnprintf(str + len, size - len, "%d", *((int8_t *)row[i]));
81,678✔
763
      default:
39,095✔
764
        break;
39,095✔
765
    }
766

767
    if (len >= size - 1) {
76,607,685!
768
      break;
×
769
    }
770
  }
771
  if (len < size) {
15,418,034✔
772
    str[len] = 0;
15,414,551✔
773
  }
774

775
  return len;
15,418,034✔
776
}
777

778
int *taos_fetch_lengths(TAOS_RES *res) {
19,854,350✔
779
  if (res == NULL || TD_RES_TMQ_RAW(res) || TD_RES_TMQ_META(res) || TD_RES_TMQ_BATCH_META(res)) {
19,854,350!
780
    return NULL;
×
781
  }
782

783
  SReqResultInfo *pResInfo = tscGetCurResInfo(res);
19,854,359✔
784
  return pResInfo->length;
19,854,359✔
785
}
786

787
TAOS_ROW *taos_result_block(TAOS_RES *res) {
×
788
  if (res == NULL || TD_RES_TMQ_RAW(res) || TD_RES_TMQ_META(res) || TD_RES_TMQ_BATCH_META(res)) {
×
789
    terrno = TSDB_CODE_INVALID_PARA;
×
790
    return NULL;
×
791
  }
792

793
  if (taos_is_update_query(res)) {
×
794
    return NULL;
×
795
  }
796

797
  SReqResultInfo *pResInfo = tscGetCurResInfo(res);
×
798
  return &pResInfo->row;
×
799
}
800

801
// todo intergrate with tDataTypes
802
const char *taos_data_type(int type) {
×
803
  switch (type) {
×
804
    case TSDB_DATA_TYPE_NULL:
×
805
      return "TSDB_DATA_TYPE_NULL";
×
806
    case TSDB_DATA_TYPE_BOOL:
×
807
      return "TSDB_DATA_TYPE_BOOL";
×
808
    case TSDB_DATA_TYPE_TINYINT:
×
809
      return "TSDB_DATA_TYPE_TINYINT";
×
810
    case TSDB_DATA_TYPE_SMALLINT:
×
811
      return "TSDB_DATA_TYPE_SMALLINT";
×
812
    case TSDB_DATA_TYPE_INT:
×
813
      return "TSDB_DATA_TYPE_INT";
×
814
    case TSDB_DATA_TYPE_BIGINT:
×
815
      return "TSDB_DATA_TYPE_BIGINT";
×
816
    case TSDB_DATA_TYPE_FLOAT:
×
817
      return "TSDB_DATA_TYPE_FLOAT";
×
818
    case TSDB_DATA_TYPE_DOUBLE:
×
819
      return "TSDB_DATA_TYPE_DOUBLE";
×
820
    case TSDB_DATA_TYPE_VARCHAR:
×
821
      return "TSDB_DATA_TYPE_VARCHAR";
×
822
      //    case TSDB_DATA_TYPE_BINARY:          return "TSDB_DATA_TYPE_VARCHAR";
823
    case TSDB_DATA_TYPE_TIMESTAMP:
×
824
      return "TSDB_DATA_TYPE_TIMESTAMP";
×
825
    case TSDB_DATA_TYPE_NCHAR:
×
826
      return "TSDB_DATA_TYPE_NCHAR";
×
827
    case TSDB_DATA_TYPE_JSON:
×
828
      return "TSDB_DATA_TYPE_JSON";
×
829
    case TSDB_DATA_TYPE_GEOMETRY:
×
830
      return "TSDB_DATA_TYPE_GEOMETRY";
×
831
    case TSDB_DATA_TYPE_UTINYINT:
×
832
      return "TSDB_DATA_TYPE_UTINYINT";
×
833
    case TSDB_DATA_TYPE_USMALLINT:
×
834
      return "TSDB_DATA_TYPE_USMALLINT";
×
835
    case TSDB_DATA_TYPE_UINT:
×
836
      return "TSDB_DATA_TYPE_UINT";
×
837
    case TSDB_DATA_TYPE_UBIGINT:
×
838
      return "TSDB_DATA_TYPE_UBIGINT";
×
839
    case TSDB_DATA_TYPE_VARBINARY:
×
840
      return "TSDB_DATA_TYPE_VARBINARY";
×
841
    case TSDB_DATA_TYPE_DECIMAL:
×
842
      return "TSDB_DATA_TYPE_DECIMAL";
×
843
    case TSDB_DATA_TYPE_BLOB:
×
844
      return "TSDB_DATA_TYPE_BLOB";
×
845
    case TSDB_DATA_TYPE_MEDIUMBLOB:
×
846
      return "TSDB_DATA_TYPE_MEDIUMBLOB";
×
847
    default:
×
848
      return "UNKNOWN";
×
849
  }
850
}
851

852
const char *taos_get_client_info() { return td_version; }
2,243✔
853

854
// return int32_t
855
int taos_affected_rows(TAOS_RES *res) {
1,626,774✔
856
  if (res == NULL || TD_RES_TMQ_RAW(res) || TD_RES_TMQ(res) || TD_RES_TMQ_META(res) || TD_RES_TMQ_METADATA(res) ||
1,626,774!
857
      TD_RES_TMQ_BATCH_META(res)) {
1,626,789!
858
    return 0;
×
859
  }
860

861
  SRequestObj    *pRequest = (SRequestObj *)res;
1,626,789✔
862
  SReqResultInfo *pResInfo = &pRequest->body.resInfo;
1,626,789✔
863
  return (int)pResInfo->numOfRows;
1,626,789✔
864
}
865

866
// return int64_t
867
int64_t taos_affected_rows64(TAOS_RES *res) {
125,060✔
868
  if (res == NULL || TD_RES_TMQ_RAW(res) || TD_RES_TMQ(res) || TD_RES_TMQ_META(res) || TD_RES_TMQ_METADATA(res) ||
125,060!
869
      TD_RES_TMQ_BATCH_META(res)) {
125,060!
870
    return 0;
×
871
  }
872

873
  SRequestObj    *pRequest = (SRequestObj *)res;
125,060✔
874
  SReqResultInfo *pResInfo = &pRequest->body.resInfo;
125,060✔
875
  return pResInfo->numOfRows;
125,060✔
876
}
877

878
int taos_result_precision(TAOS_RES *res) {
16,334,494✔
879
  if (res == NULL || TD_RES_TMQ_RAW(res) || TD_RES_TMQ_META(res) || TD_RES_TMQ_BATCH_META(res)) {
16,334,494!
880
    return TSDB_TIME_PRECISION_MILLI;
×
881
  }
882

883
  if (TD_RES_QUERY(res)) {
16,334,518✔
884
    SRequestObj *pRequest = (SRequestObj *)res;
1,001,256✔
885
    return pRequest->body.resInfo.precision;
1,001,256✔
886
  } else if (TD_RES_TMQ(res) || TD_RES_TMQ_METADATA(res)) {
15,333,262!
887
    SReqResultInfo *info = tmqGetCurResInfo(res);
15,333,262✔
888
    return info->precision;
15,333,262✔
889
  }
890
  return TSDB_TIME_PRECISION_MILLI;
×
891
}
892

893
int taos_select_db(TAOS *taos, const char *db) {
404✔
894
  STscObj *pObj = acquireTscObj(*(int64_t *)taos);
404✔
895
  if (pObj == NULL) {
404!
896
    releaseTscObj(*(int64_t *)taos);
×
897
    terrno = TSDB_CODE_TSC_DISCONNECTED;
×
898
    return TSDB_CODE_TSC_DISCONNECTED;
×
899
  }
900

901
  if (db == NULL || strlen(db) == 0) {
404!
902
    releaseTscObj(*(int64_t *)taos);
×
903
    tscError("invalid parameter for %s", db == NULL ? "db is NULL" : "db is empty");
×
904
    terrno = TSDB_CODE_TSC_INVALID_INPUT;
×
905
    return terrno;
×
906
  }
907

908
  char sql[256] = {0};
404✔
909
  (void)snprintf(sql, tListLen(sql), "use %s", db);
404✔
910

911
  TAOS_RES *pRequest = taos_query(taos, sql);
404✔
912
  int32_t   code = taos_errno(pRequest);
404✔
913

914
  taos_free_result(pRequest);
404✔
915
  releaseTscObj(*(int64_t *)taos);
404✔
916
  return code;
404✔
917
}
918

919
void taos_stop_query(TAOS_RES *res) {
2,810,191✔
920
  if (res == NULL || TD_RES_TMQ_RAW(res) || TD_RES_TMQ(res) || TD_RES_TMQ_META(res) || TD_RES_TMQ_METADATA(res) ||
2,810,191!
921
      TD_RES_TMQ_BATCH_META(res)) {
2,810,232!
922
    return;
×
923
  }
924

925
  stopAllQueries((SRequestObj *)res);
2,810,233✔
926
}
927

928
bool taos_is_null(TAOS_RES *res, int32_t row, int32_t col) {
303,032,280✔
929
  if (res == NULL || TD_RES_TMQ_RAW(res) || TD_RES_TMQ_META(res) || TD_RES_TMQ_BATCH_META(res)) {
303,032,280!
930
    return true;
×
931
  }
932
  SReqResultInfo *pResultInfo = tscGetCurResInfo(res);
303,032,292✔
933
  if (col >= pResultInfo->numOfCols || col < 0 || row >= pResultInfo->numOfRows || row < 0) {
303,032,292!
934
    return true;
×
935
  }
936

937
  SResultColumn *pCol = &pResultInfo->pCol[col];
303,032,297✔
938
  if (IS_VAR_DATA_TYPE(pResultInfo->fields[col].type)) {
303,032,297!
939
    return (pCol->offset[row] == -1);
13✔
940
  } else {
941
    return colDataIsNull_f(pCol->nullbitmap, row);
303,032,284✔
942
  }
943
}
944

945
bool taos_is_update_query(TAOS_RES *res) { return taos_num_fields(res) == 0; }
×
946

947
int taos_fetch_block(TAOS_RES *res, TAOS_ROW *rows) {
1,289,050✔
948
  int32_t numOfRows = 0;
1,289,050✔
949
  /*int32_t code = */ terrno = taos_fetch_block_s(res, &numOfRows, rows);
1,289,050✔
950
  return numOfRows;
1,289,049✔
951
}
952

953
int taos_fetch_block_s(TAOS_RES *res, int *numOfRows, TAOS_ROW *rows) {
1,289,050✔
954
  if (res == NULL || TD_RES_TMQ_RAW(res) || TD_RES_TMQ_META(res) || TD_RES_TMQ_BATCH_META(res)) {
1,289,050!
955
    return 0;
×
956
  }
957

958
  if (TD_RES_QUERY(res)) {
1,289,050✔
959
    SRequestObj *pRequest = (SRequestObj *)res;
1,285,051✔
960

961
    (*rows) = NULL;
1,285,051✔
962
    (*numOfRows) = 0;
1,285,051✔
963

964
    if (pRequest->type == TSDB_SQL_RETRIEVE_EMPTY_RESULT || pRequest->type == TSDB_SQL_INSERT ||
1,285,051!
965
        pRequest->code != TSDB_CODE_SUCCESS || taos_num_fields(res) == 0) {
1,282,533!
966
      return pRequest->code;
6,291✔
967
    }
968

969
    (void)doAsyncFetchRows(pRequest, false, true);
1,278,760✔
970

971
    // TODO refactor
972
    SReqResultInfo *pResultInfo = &pRequest->body.resInfo;
1,278,760✔
973
    pResultInfo->current = pResultInfo->numOfRows;
1,278,760✔
974

975
    (*rows) = pResultInfo->row;
1,278,760✔
976
    (*numOfRows) = pResultInfo->numOfRows;
1,278,760✔
977
    return pRequest->code;
1,278,760✔
978
  } else if (TD_RES_TMQ(res) || TD_RES_TMQ_METADATA(res)) {
3,999!
979
    SReqResultInfo *pResultInfo = NULL;
3,999✔
980
    int32_t         code = tmqGetNextResInfo(res, true, &pResultInfo);
3,999✔
981
    if (code != 0) return code;
3,999✔
982

983
    pResultInfo->current = pResultInfo->numOfRows;
3,571✔
984
    (*rows) = pResultInfo->row;
3,571✔
985
    (*numOfRows) = pResultInfo->numOfRows;
3,571✔
986
    return 0;
3,571✔
987
  } else {
988
    tscError("taos_fetch_block_s invalid res type");
×
989
    return TSDB_CODE_TMQ_INVALID_DATA;
×
990
  }
991
}
992

993
int taos_fetch_raw_block(TAOS_RES *res, int *numOfRows, void **pData) {
8✔
994
  *numOfRows = 0;
8✔
995
  *pData = NULL;
8✔
996

997
  if (res == NULL || TD_RES_TMQ_RAW(res) || TD_RES_TMQ_META(res) || TD_RES_TMQ_BATCH_META(res)) {
8!
998
    return 0;
×
999
  }
1000

1001
  if (TD_RES_TMQ(res) || TD_RES_TMQ_METADATA(res)) {
8!
1002
    SReqResultInfo *pResultInfo = NULL;
×
1003
    int32_t         code = tmqGetNextResInfo(res, false, &pResultInfo);
×
1004
    if (code != 0) {
×
1005
      (*numOfRows) = 0;
×
1006
      return 0;
×
1007
    }
1008

1009
    pResultInfo->current = pResultInfo->numOfRows;
×
1010
    (*numOfRows) = pResultInfo->numOfRows;
×
1011
    (*pData) = (void *)pResultInfo->pData;
×
1012
    return 0;
×
1013
  }
1014

1015
  SRequestObj *pRequest = (SRequestObj *)res;
8✔
1016

1017
  if (pRequest->type == TSDB_SQL_RETRIEVE_EMPTY_RESULT || pRequest->type == TSDB_SQL_INSERT ||
8!
1018
      pRequest->code != TSDB_CODE_SUCCESS || taos_num_fields(res) == 0) {
8!
1019
    return pRequest->code;
×
1020
  }
1021

1022
  (void)doAsyncFetchRows(pRequest, false, false);
8✔
1023

1024
  SReqResultInfo *pResultInfo = &pRequest->body.resInfo;
8✔
1025

1026
  pResultInfo->current = pResultInfo->numOfRows;
8✔
1027
  (*numOfRows) = pResultInfo->numOfRows;
8✔
1028
  (*pData) = (void *)pResultInfo->pData;
8✔
1029

1030
  return pRequest->code;
8✔
1031
}
1032

1033
int *taos_get_column_data_offset(TAOS_RES *res, int columnIndex) {
521,981✔
1034
  if (res == NULL || TD_RES_TMQ_RAW(res) || TD_RES_TMQ_META(res) || TD_RES_TMQ_BATCH_META(res)) {
521,981!
1035
    return 0;
×
1036
  }
1037

1038
  int32_t numOfFields = taos_num_fields(res);
521,981✔
1039
  if (columnIndex < 0 || columnIndex >= numOfFields || numOfFields == 0) {
521,981!
1040
    return 0;
×
1041
  }
1042

1043
  SReqResultInfo *pResInfo = tscGetCurResInfo(res);
521,981✔
1044
  TAOS_FIELD     *pField = &pResInfo->userFields[columnIndex];
521,981✔
1045
  if (!IS_VAR_DATA_TYPE(pField->type)) {
521,981!
1046
    return 0;
×
1047
  }
1048

1049
  return pResInfo->pCol[columnIndex].offset;
521,981✔
1050
}
1051

1052
int taos_is_null_by_column(TAOS_RES *res, int columnIndex, bool result[], int *rows) {
×
1053
  if (res == NULL || result == NULL || rows == NULL || *rows <= 0 || columnIndex < 0 || TD_RES_TMQ_META(res) ||
×
1054
      TD_RES_TMQ_RAW(res) || TD_RES_TMQ_BATCH_META(res)) {
×
1055
    return TSDB_CODE_INVALID_PARA;
×
1056
  }
1057

1058
  int32_t numOfFields = taos_num_fields(res);
×
1059
  if (columnIndex >= numOfFields || numOfFields == 0) {
×
1060
    return TSDB_CODE_INVALID_PARA;
×
1061
  }
1062

1063
  SReqResultInfo *pResInfo = tscGetCurResInfo(res);
×
1064
  TAOS_FIELD     *pField = &pResInfo->userFields[columnIndex];
×
1065
  SResultColumn  *pCol = &pResInfo->pCol[columnIndex];
×
1066

1067
  if (*rows > pResInfo->numOfRows) {
×
1068
    *rows = pResInfo->numOfRows;
×
1069
  }
1070
  if (IS_VAR_DATA_TYPE(pField->type)) {
×
1071
    for (int i = 0; i < *rows; i++) {
×
1072
      if (pCol->offset[i] == -1) {
×
1073
        result[i] = true;
×
1074
      } else {
1075
        result[i] = false;
×
1076
      }
1077
    }
1078
  } else {
1079
    for (int i = 0; i < *rows; i++) {
×
1080
      if (colDataIsNull_f(pCol->nullbitmap, i)) {
×
1081
        result[i] = true;
×
1082
      } else {
1083
        result[i] = false;
×
1084
      }
1085
    }
1086
  }
1087
  return 0;
×
1088
}
1089

1090
int taos_validate_sql(TAOS *taos, const char *sql) {
×
1091
  TAOS_RES *pObj = taosQueryImpl(taos, sql, true, TD_REQ_FROM_APP);
×
1092

1093
  int code = taos_errno(pObj);
×
1094

1095
  taos_free_result(pObj);
×
1096
  return code;
×
1097
}
1098

1099
void taos_reset_current_db(TAOS *taos) {
×
1100
  STscObj *pTscObj = acquireTscObj(*(int64_t *)taos);
×
1101
  if (pTscObj == NULL) {
×
1102
    terrno = TSDB_CODE_TSC_DISCONNECTED;
×
1103
    return;
×
1104
  }
1105

1106
  resetConnectDB(pTscObj);
×
1107

1108
  releaseTscObj(*(int64_t *)taos);
×
1109
}
1110

1111
const char *taos_get_server_info(TAOS *taos) {
120✔
1112
  STscObj *pTscObj = acquireTscObj(*(int64_t *)taos);
120✔
1113
  if (pTscObj == NULL) {
120!
1114
    terrno = TSDB_CODE_TSC_DISCONNECTED;
×
1115
    return NULL;
×
1116
  }
1117

1118
  releaseTscObj(*(int64_t *)taos);
120✔
1119

1120
  return pTscObj->sDetailVer;
120✔
1121
}
1122

1123
int taos_get_current_db(TAOS *taos, char *database, int len, int *required) {
4✔
1124
  STscObj *pTscObj = acquireTscObj(*(int64_t *)taos);
4✔
1125
  if (pTscObj == NULL) {
4!
1126
    return TSDB_CODE_TSC_DISCONNECTED;
×
1127
  }
1128

1129
  int code = TSDB_CODE_SUCCESS;
4✔
1130
  (void)taosThreadMutexLock(&pTscObj->mutex);
4✔
1131
  if (database == NULL || len <= 0) {
4!
1132
    if (required != NULL) *required = strlen(pTscObj->db) + 1;
2✔
1133
    TSC_ERR_JRET(TSDB_CODE_INVALID_PARA);
2!
1134
  } else if (len < strlen(pTscObj->db) + 1) {
2✔
1135
    tstrncpy(database, pTscObj->db, len);
1✔
1136
    if (required) *required = strlen(pTscObj->db) + 1;
1!
1137
    TSC_ERR_JRET(TSDB_CODE_INVALID_PARA);
1!
1138
  } else {
1139
    tstrncpy(database, pTscObj->db, len);
1✔
1140
    code = 0;
1✔
1141
  }
1142
_return:
4✔
1143
  (void)taosThreadMutexUnlock(&pTscObj->mutex);
4✔
1144
  releaseTscObj(*(int64_t *)taos);
4✔
1145
  return code;
4✔
1146
}
1147

1148
void destorySqlCallbackWrapper(SSqlCallbackWrapper *pWrapper) {
5,490,724✔
1149
  if (NULL == pWrapper) {
5,490,724✔
1150
    return;
2,825,738✔
1151
  }
1152
  destoryCatalogReq(pWrapper->pCatalogReq);
2,664,986✔
1153
  taosMemoryFree(pWrapper->pCatalogReq);
2,665,037!
1154
  qDestroyParseContext(pWrapper->pParseCtx);
2,665,051✔
1155
  taosMemoryFree(pWrapper);
2,665,048!
1156
}
1157

1158
void destroyCtxInRequest(SRequestObj *pRequest) {
16,412✔
1159
  schedulerFreeJob(&pRequest->body.queryJob, 0);
16,412✔
1160
  qDestroyQuery(pRequest->pQuery);
16,412✔
1161
  pRequest->pQuery = NULL;
16,412✔
1162
  destorySqlCallbackWrapper(pRequest->pWrapper);
16,412✔
1163
  pRequest->pWrapper = NULL;
16,412✔
1164
}
16,412✔
1165

1166
static void doAsyncQueryFromAnalyse(SMetaData *pResultMeta, void *param, int32_t code) {
1,016,992✔
1167
  SSqlCallbackWrapper *pWrapper = (SSqlCallbackWrapper *)param;
1,016,992✔
1168
  SRequestObj         *pRequest = pWrapper->pRequest;
1,016,992✔
1169
  SQuery              *pQuery = pRequest->pQuery;
1,016,992✔
1170

1171
  qDebug("req:0x%" PRIx64 ", start to semantic analysis, QID:0x%" PRIx64, pRequest->self, pRequest->requestId);
1,016,992✔
1172

1173
  int64_t analyseStart = taosGetTimestampUs();
1,016,991✔
1174
  pRequest->metric.ctgCostUs = analyseStart - pRequest->metric.ctgStart;
1,016,991✔
1175
  pWrapper->pParseCtx->parseOnly = pRequest->parseOnly;
1,016,991✔
1176

1177
  if (TSDB_CODE_SUCCESS == code) {
1,016,991✔
1178
    code = qAnalyseSqlSemantic(pWrapper->pParseCtx, pWrapper->pCatalogReq, pResultMeta, pQuery);
1,016,983✔
1179
  }
1180

1181
  pRequest->metric.analyseCostUs += taosGetTimestampUs() - analyseStart;
1,016,983✔
1182

1183
  if (pRequest->parseOnly) {
1,016,983✔
1184
    (void)memcpy(&pRequest->parseMeta, pResultMeta, sizeof(*pResultMeta));
617✔
1185
    (void)memset(pResultMeta, 0, sizeof(*pResultMeta));
617✔
1186
  }
1187

1188
  handleQueryAnslyseRes(pWrapper, pResultMeta, code);
1,016,983✔
1189
}
1,016,965✔
1190

1191
int32_t cloneCatalogReq(SCatalogReq **ppTarget, SCatalogReq *pSrc) {
529✔
1192
  int32_t      code = TSDB_CODE_SUCCESS;
529✔
1193
  SCatalogReq *pTarget = taosMemoryCalloc(1, sizeof(SCatalogReq));
529!
1194
  if (pTarget == NULL) {
529!
1195
    code = terrno;
×
1196
  } else {
1197
    pTarget->pDbVgroup = taosArrayDup(pSrc->pDbVgroup, NULL);
529✔
1198
    pTarget->pDbCfg = taosArrayDup(pSrc->pDbCfg, NULL);
529✔
1199
    pTarget->pDbInfo = taosArrayDup(pSrc->pDbInfo, NULL);
529✔
1200
    pTarget->pTableMeta = taosArrayDup(pSrc->pTableMeta, NULL);
529✔
1201
    pTarget->pTableHash = taosArrayDup(pSrc->pTableHash, NULL);
529✔
1202
    pTarget->pUdf = taosArrayDup(pSrc->pUdf, NULL);
529✔
1203
    pTarget->pIndex = taosArrayDup(pSrc->pIndex, NULL);
529✔
1204
    pTarget->pUser = taosArrayDup(pSrc->pUser, NULL);
529✔
1205
    pTarget->pTableIndex = taosArrayDup(pSrc->pTableIndex, NULL);
529✔
1206
    pTarget->pTableCfg = taosArrayDup(pSrc->pTableCfg, NULL);
529✔
1207
    pTarget->pTableTag = taosArrayDup(pSrc->pTableTag, NULL);
529✔
1208
    pTarget->pView = taosArrayDup(pSrc->pView, NULL);
529✔
1209
    pTarget->pTableTSMAs = taosArrayDup(pSrc->pTableTSMAs, NULL);
529✔
1210
    pTarget->pTSMAs = taosArrayDup(pSrc->pTSMAs, NULL);
529✔
1211
    pTarget->qNodeRequired = pSrc->qNodeRequired;
529✔
1212
    pTarget->dNodeRequired = pSrc->dNodeRequired;
529✔
1213
    pTarget->svrVerRequired = pSrc->svrVerRequired;
529✔
1214
    pTarget->forceUpdate = pSrc->forceUpdate;
529✔
1215
    pTarget->cloned = true;
529✔
1216

1217
    *ppTarget = pTarget;
529✔
1218
  }
1219

1220
  return code;
529✔
1221
}
1222

1223
void handleSubQueryFromAnalyse(SSqlCallbackWrapper *pWrapper, SMetaData *pResultMeta, SNode *pRoot) {
529✔
1224
  SRequestObj         *pNewRequest = NULL;
529✔
1225
  SSqlCallbackWrapper *pNewWrapper = NULL;
529✔
1226
  int32_t              code = buildPreviousRequest(pWrapper->pRequest, pWrapper->pRequest->sqlstr, &pNewRequest);
529✔
1227
  if (code) {
529!
1228
    handleQueryAnslyseRes(pWrapper, pResultMeta, code);
×
1229
    return;
×
1230
  }
1231

1232
  pNewRequest->pQuery = NULL;
529✔
1233
  code = nodesMakeNode(QUERY_NODE_QUERY, (SNode **)&pNewRequest->pQuery);
529✔
1234
  if (pNewRequest->pQuery) {
529!
1235
    pNewRequest->pQuery->pRoot = pRoot;
529✔
1236
    pRoot = NULL;
529✔
1237
    pNewRequest->pQuery->execStage = QUERY_EXEC_STAGE_ANALYSE;
529✔
1238
  }
1239
  if (TSDB_CODE_SUCCESS == code) {
529!
1240
    code = prepareAndParseSqlSyntax(&pNewWrapper, pNewRequest, false);
529✔
1241
  }
1242
  if (TSDB_CODE_SUCCESS == code) {
529!
1243
    code = cloneCatalogReq(&pNewWrapper->pCatalogReq, pWrapper->pCatalogReq);
529✔
1244
  }
1245
  if (TSDB_CODE_SUCCESS == code) {
529!
1246
    doAsyncQueryFromAnalyse(pResultMeta, pNewWrapper, code);
529✔
1247
    nodesDestroyNode(pRoot);
529✔
1248
  } else {
1249
    handleQueryAnslyseRes(pWrapper, pResultMeta, code);
×
1250
    return;
×
1251
  }
1252
}
1253

1254
void handleQueryAnslyseRes(SSqlCallbackWrapper *pWrapper, SMetaData *pResultMeta, int32_t code) {
1,017,463✔
1255
  SRequestObj *pRequest = pWrapper->pRequest;
1,017,463✔
1256
  SQuery      *pQuery = pRequest->pQuery;
1,017,463✔
1257

1258
  if (code == TSDB_CODE_SUCCESS && pQuery->pPrevRoot) {
1,017,463✔
1259
    SNode *prevRoot = pQuery->pPrevRoot;
529✔
1260
    pQuery->pPrevRoot = NULL;
529✔
1261
    handleSubQueryFromAnalyse(pWrapper, pResultMeta, prevRoot);
529✔
1262
    return;
529✔
1263
  }
1264

1265
  if (code == TSDB_CODE_SUCCESS) {
1,016,934✔
1266
    pRequest->stableQuery = pQuery->stableQuery;
938,453✔
1267
    if (pQuery->pRoot) {
938,453!
1268
      pRequest->stmtType = pQuery->pRoot->type;
938,462✔
1269
    }
1270

1271
    if (pQuery->haveResultSet) {
938,453✔
1272
      code = setResSchemaInfo(&pRequest->body.resInfo, pQuery->pResSchema, pQuery->numOfResCols);
800,540✔
1273
      setResPrecision(&pRequest->body.resInfo, pQuery->precision);
800,541✔
1274
    }
1275
  }
1276

1277
  if (code == TSDB_CODE_SUCCESS) {
1,016,957✔
1278
    TSWAP(pRequest->dbList, (pQuery)->pDbList);
938,459✔
1279
    TSWAP(pRequest->tableList, (pQuery)->pTableList);
938,459✔
1280
    TSWAP(pRequest->targetTableList, (pQuery)->pTargetTableList);
938,459✔
1281

1282
    launchAsyncQuery(pRequest, pQuery, pResultMeta, pWrapper);
938,459✔
1283
  } else {
1284
    destorySqlCallbackWrapper(pWrapper);
78,498✔
1285
    pRequest->pWrapper = NULL;
78,498✔
1286
    qDestroyQuery(pRequest->pQuery);
78,498✔
1287
    pRequest->pQuery = NULL;
78,498✔
1288

1289
    if (NEED_CLIENT_HANDLE_ERROR(code)) {
78,498!
1290
      tscDebug("req:0x%" PRIx64 ", client retry to handle the error, code:%d - %s, tryCount:%d, QID:0x%" PRIx64,
16,153✔
1291
               pRequest->self, code, tstrerror(code), pRequest->retry, pRequest->requestId);
1292
      restartAsyncQuery(pRequest, code);
16,153✔
1293
      return;
16,153✔
1294
    }
1295

1296
    // return to app directly
1297
    tscError("req:0x%" PRIx64 ", error occurs, code:%s, return to user app, QID:0x%" PRIx64, pRequest->self, tstrerror(code),
62,345!
1298
             pRequest->requestId);
1299
    pRequest->code = code;
62,345✔
1300
    returnToUser(pRequest);
62,345✔
1301
  }
1302
}
1303

1304
static int32_t getAllMetaAsync(SSqlCallbackWrapper *pWrapper, catalogCallback fp) {
1,044,382✔
1305
  SRequestConnInfo conn = {.pTrans = pWrapper->pParseCtx->pTransporter,
1,044,382✔
1306
                           .requestId = pWrapper->pParseCtx->requestId,
1,044,382✔
1307
                           .requestObjRefId = pWrapper->pParseCtx->requestRid,
1,044,382✔
1308
                           .mgmtEps = pWrapper->pParseCtx->mgmtEpSet};
1,044,382✔
1309

1310
  pWrapper->pRequest->metric.ctgStart = taosGetTimestampUs();
1,044,382✔
1311

1312
  return catalogAsyncGetAllMeta(pWrapper->pParseCtx->pCatalog, &conn, pWrapper->pCatalogReq, fp, pWrapper,
2,088,803✔
1313
                                &pWrapper->pRequest->body.queryJob);
1,044,407✔
1314
}
1315

1316
static void doAsyncQueryFromParse(SMetaData *pResultMeta, void *param, int32_t code);
1317

1318
static int32_t phaseAsyncQuery(SSqlCallbackWrapper *pWrapper) {
2,664,428✔
1319
  int32_t code = TSDB_CODE_SUCCESS;
2,664,428✔
1320
  switch (pWrapper->pRequest->pQuery->execStage) {
2,664,428!
1321
    case QUERY_EXEC_STAGE_PARSE: {
27,951✔
1322
      // continue parse after get metadata
1323
      code = getAllMetaAsync(pWrapper, doAsyncQueryFromParse);
27,951✔
1324
      break;
27,950✔
1325
    }
1326
    case QUERY_EXEC_STAGE_ANALYSE: {
1,016,449✔
1327
      // analysis after get metadata
1328
      code = getAllMetaAsync(pWrapper, doAsyncQueryFromAnalyse);
1,016,449✔
1329
      break;
1,016,440✔
1330
    }
1331
    case QUERY_EXEC_STAGE_SCHEDULE: {
1,620,133✔
1332
      launchAsyncQuery(pWrapper->pRequest, pWrapper->pRequest->pQuery, NULL, pWrapper);
1,620,133✔
1333
      break;
1,620,190✔
1334
    }
1335
    default:
×
1336
      break;
×
1337
  }
1338
  return code;
2,664,475✔
1339
}
1340

1341
static void doAsyncQueryFromParse(SMetaData *pResultMeta, void *param, int32_t code) {
27,951✔
1342
  SSqlCallbackWrapper *pWrapper = (SSqlCallbackWrapper *)param;
27,951✔
1343
  SRequestObj         *pRequest = pWrapper->pRequest;
27,951✔
1344
  SQuery              *pQuery = pRequest->pQuery;
27,951✔
1345

1346
  pRequest->metric.ctgCostUs += taosGetTimestampUs() - pRequest->metric.ctgStart;
27,951✔
1347
  qDebug("req:0x%" PRIx64 ", start to continue parse, QID:0x%" PRIx64 ", code:%s", pRequest->self, pRequest->requestId,
27,951✔
1348
         tstrerror(code));
1349

1350
  if (code == TSDB_CODE_SUCCESS) {
27,951✔
1351
    // pWrapper->pCatalogReq->forceUpdate = false;
1352
    code = qContinueParseSql(pWrapper->pParseCtx, pWrapper->pCatalogReq, pResultMeta, pQuery);
27,758✔
1353
  }
1354

1355
  if (TSDB_CODE_SUCCESS == code) {
27,951✔
1356
    code = phaseAsyncQuery(pWrapper);
26,807✔
1357
  }
1358

1359
  if (TSDB_CODE_SUCCESS != code) {
27,951✔
1360
    tscError("req:0x%" PRIx64 ", error happens, code:%d - %s, QID:0x%" PRIx64, pWrapper->pRequest->self, code,
1,144!
1361
             tstrerror(code), pWrapper->pRequest->requestId);
1362
    destorySqlCallbackWrapper(pWrapper);
1,144✔
1363
    pRequest->pWrapper = NULL;
1,144✔
1364
    terrno = code;
1,144✔
1365
    pRequest->code = code;
1,144✔
1366
    doRequestCallback(pRequest, code);
1,144✔
1367
  }
1368
}
27,951✔
1369

1370
void continueInsertFromCsv(SSqlCallbackWrapper *pWrapper, SRequestObj *pRequest) {
×
1371
  int32_t code = qParseSqlSyntax(pWrapper->pParseCtx, &pRequest->pQuery, pWrapper->pCatalogReq);
×
1372
  if (TSDB_CODE_SUCCESS == code) {
×
1373
    code = phaseAsyncQuery(pWrapper);
×
1374
  }
1375

1376
  if (TSDB_CODE_SUCCESS != code) {
×
1377
    tscError("req:0x%" PRIx64 ", error happens, code:%d - %s, QID:0x%" PRIx64, pWrapper->pRequest->self, code,
×
1378
             tstrerror(code), pWrapper->pRequest->requestId);
1379
    destorySqlCallbackWrapper(pWrapper);
×
1380
    pRequest->pWrapper = NULL;
×
1381
    terrno = code;
×
1382
    pRequest->code = code;
×
1383
    doRequestCallback(pRequest, code);
×
1384
  }
1385
}
×
1386

1387
void taos_query_a(TAOS *taos, const char *sql, __taos_async_fn_t fp, void *param) {
519✔
1388
  int64_t connId = *(int64_t *)taos;
519✔
1389
  tscDebug("taos_query_a start with sql:%s", sql);
519✔
1390
  taosAsyncQueryImpl(connId, sql, fp, param, false, TD_REQ_FROM_APP);
519✔
1391
  tscDebug("taos_query_a end with sql:%s", sql);
519✔
1392
}
519✔
1393

1394
void taos_query_a_with_reqid(TAOS *taos, const char *sql, __taos_async_fn_t fp, void *param, int64_t reqid) {
×
1395
  int64_t connId = *(int64_t *)taos;
×
1396
  taosAsyncQueryImplWithReqid(connId, sql, fp, param, false, reqid);
×
1397
}
×
1398

1399
int32_t createParseContext(const SRequestObj *pRequest, SParseContext **pCxt, SSqlCallbackWrapper *pWrapper) {
2,664,947✔
1400
  const STscObj *pTscObj = pRequest->pTscObj;
2,664,947✔
1401

1402
  *pCxt = taosMemoryCalloc(1, sizeof(SParseContext));
2,664,947!
1403
  if (*pCxt == NULL) {
2,665,000!
1404
    return terrno;
×
1405
  }
1406

1407
  **pCxt = (SParseContext){.requestId = pRequest->requestId,
2,665,000✔
1408
                           .requestRid = pRequest->self,
2,665,000✔
1409
                           .acctId = pTscObj->acctId,
2,665,000✔
1410
                           .db = pRequest->pDb,
2,665,000✔
1411
                           .topicQuery = false,
1412
                           .pSql = pRequest->sqlstr,
2,665,000✔
1413
                           .sqlLen = pRequest->sqlLen,
2,665,000✔
1414
                           .pMsg = pRequest->msgBuf,
2,665,000✔
1415
                           .msgLen = ERROR_MSG_BUF_DEFAULT_SIZE,
1416
                           .pTransporter = pTscObj->pAppInfo->pTransporter,
2,665,000✔
1417
                           .pStmtCb = NULL,
1418
                           .pUser = pTscObj->user,
2,665,000✔
1419
                           .pEffectiveUser = pRequest->effectiveUser,
2,665,000✔
1420
                           .isSuperUser = (0 == strcmp(pTscObj->user, TSDB_DEFAULT_USER)),
2,665,000✔
1421
                           .enableSysInfo = pTscObj->sysInfo,
2,665,000✔
1422
                           .async = true,
1423
                           .svrVer = pTscObj->sVer,
2,665,000✔
1424
                           .nodeOffline = (pTscObj->pAppInfo->onlineDnodes < pTscObj->pAppInfo->totalDnodes),
2,665,000✔
1425
                           .allocatorId = pRequest->allocatorRefId,
2,665,000✔
1426
                           .parseSqlFp = clientParseSql,
1427
                           .parseSqlParam = pWrapper,
1428
                           .setQueryFp = setQueryRequest,
1429
                           .timezone = pTscObj->optionInfo.timezone,
2,665,000✔
1430
                           .charsetCxt = pTscObj->optionInfo.charsetCxt,
2,665,000✔
1431
                           .streamRunHistory = pRequest->streamRunHistory};
2,665,000✔
1432
  int8_t biMode = atomic_load_8(&((STscObj *)pTscObj)->biMode);
2,665,000✔
1433
  (*pCxt)->biMode = biMode;
2,664,958✔
1434
  return TSDB_CODE_SUCCESS;
2,664,958✔
1435
}
1436

1437
int32_t prepareAndParseSqlSyntax(SSqlCallbackWrapper **ppWrapper, SRequestObj *pRequest, bool updateMetaForce) {
2,664,935✔
1438
  int32_t              code = TSDB_CODE_SUCCESS;
2,664,935✔
1439
  STscObj             *pTscObj = pRequest->pTscObj;
2,664,935✔
1440
  SSqlCallbackWrapper *pWrapper = taosMemoryCalloc(1, sizeof(SSqlCallbackWrapper));
2,664,935!
1441
  if (pWrapper == NULL) {
2,665,030!
1442
    code = terrno;
×
1443
  } else {
1444
    pWrapper->pRequest = pRequest;
2,665,030✔
1445
    pRequest->pWrapper = pWrapper;
2,665,030✔
1446
    *ppWrapper = pWrapper;
2,665,030✔
1447
  }
1448

1449
  if (TSDB_CODE_SUCCESS == code) {
2,665,030!
1450
    code = createParseContext(pRequest, &pWrapper->pParseCtx, pWrapper);
2,665,033✔
1451
  }
1452

1453
  if (TSDB_CODE_SUCCESS == code) {
2,664,987!
1454
    pWrapper->pParseCtx->mgmtEpSet = getEpSet_s(&pTscObj->pAppInfo->mgmtEp);
2,665,020✔
1455
    code = catalogGetHandle(pTscObj->pAppInfo->clusterId, &pWrapper->pParseCtx->pCatalog);
2,665,046✔
1456
  }
1457

1458
  if (TSDB_CODE_SUCCESS == code && NULL == pRequest->pQuery) {
2,665,013✔
1459
    int64_t syntaxStart = taosGetTimestampUs();
2,664,488✔
1460

1461
    pWrapper->pCatalogReq = taosMemoryCalloc(1, sizeof(SCatalogReq));
2,664,488!
1462
    if (pWrapper->pCatalogReq == NULL) {
2,664,468!
1463
      code = terrno;
×
1464
    } else {
1465
      pWrapper->pCatalogReq->forceUpdate = updateMetaForce;
2,664,468✔
1466
      TSC_ERR_RET(qnodeRequired(pRequest, &pWrapper->pCatalogReq->qNodeRequired));
2,664,468!
1467
      code = qParseSqlSyntax(pWrapper->pParseCtx, &pRequest->pQuery, pWrapper->pCatalogReq);
2,664,422✔
1468
    }
1469

1470
    pRequest->metric.parseCostUs += taosGetTimestampUs() - syntaxStart;
2,664,421✔
1471
  }
1472

1473
  return code;
2,665,009✔
1474
}
1475

1476
void doAsyncQuery(SRequestObj *pRequest, bool updateMetaForce) {
2,669,805✔
1477
  SSqlCallbackWrapper *pWrapper = NULL;
2,669,805✔
1478
  int32_t              code = TSDB_CODE_SUCCESS;
2,669,805✔
1479

1480
  if (pRequest->retry++ > REQUEST_TOTAL_EXEC_TIMES) {
2,669,805✔
1481
    code = pRequest->prevCode;
5,393✔
1482
    terrno = code;
5,393✔
1483
    pRequest->code = code;
5,393✔
1484
    tscDebug("req:0x%" PRIx64 ", call sync query cb with code:%s", pRequest->self, tstrerror(code));
5,393✔
1485
    doRequestCallback(pRequest, code);
5,393✔
1486
    return;
5,408✔
1487
  }
1488

1489
  if (TSDB_CODE_SUCCESS == code) {
2,664,412!
1490
    code = prepareAndParseSqlSyntax(&pWrapper, pRequest, updateMetaForce);
2,664,467✔
1491
  }
1492

1493
  if (TSDB_CODE_SUCCESS == code) {
2,664,255✔
1494
    pRequest->stmtType = pRequest->pQuery->pRoot->type;
2,637,705✔
1495
    code = phaseAsyncQuery(pWrapper);
2,637,705✔
1496
  }
1497

1498
  if (TSDB_CODE_SUCCESS != code) {
2,664,305✔
1499
    tscError("req:0x%" PRIx64 ", error happens, code:%d - %s, QID:0x%" PRIx64, pRequest->self, code, tstrerror(code),
26,661!
1500
             pRequest->requestId);
1501
    destorySqlCallbackWrapper(pWrapper);
26,661✔
1502
    pRequest->pWrapper = NULL;
26,661✔
1503
    qDestroyQuery(pRequest->pQuery);
26,661✔
1504
    pRequest->pQuery = NULL;
26,661✔
1505

1506
    if (NEED_CLIENT_HANDLE_ERROR(code)) {
26,661!
1507
      tscDebug("req:0x%" PRIx64 ", client retry to handle the error, code:%d - %s, tryCount:%d, QID:0x%" PRIx64,
15!
1508
               pRequest->self, code, tstrerror(code), pRequest->retry, pRequest->requestId);
1509
      code = refreshMeta(pRequest->pTscObj, pRequest);
15✔
1510
      if (code != 0) {
15!
1511
        tscWarn("req:0x%" PRIx64 ", refresh meta failed, code:%d - %s, QID:0x%" PRIx64, pRequest->self, code, tstrerror(code),
15!
1512
                pRequest->requestId);
1513
      }
1514
      pRequest->prevCode = code;
15✔
1515
      doAsyncQuery(pRequest, true);
15✔
1516
      return;
15✔
1517
    }
1518

1519
    terrno = code;
26,646✔
1520
    pRequest->code = code;
26,646✔
1521
    doRequestCallback(pRequest, code);
26,646✔
1522
  }
1523
}
1524

1525
void restartAsyncQuery(SRequestObj *pRequest, int32_t code) {
16,412✔
1526
  tscInfo("restart request:%s p:%p", pRequest->sqlstr, pRequest);
16,412!
1527
  SRequestObj *pUserReq = pRequest;
16,412✔
1528
  (void)acquireRequest(pRequest->self);
16,412✔
1529
  while (pUserReq) {
16,436!
1530
    if (pUserReq->self == pUserReq->relation.userRefId || pUserReq->relation.userRefId == 0) {
16,436!
1531
      break;
1532
    } else {
1533
      int64_t nextRefId = pUserReq->relation.nextRefId;
24✔
1534
      (void)releaseRequest(pUserReq->self);
24✔
1535
      if (nextRefId) {
24!
1536
        pUserReq = acquireRequest(nextRefId);
24✔
1537
      }
1538
    }
1539
  }
1540
  bool hasSubRequest = pUserReq != pRequest || pRequest->relation.prevRefId != 0;
16,412!
1541
  if (pUserReq) {
16,412!
1542
    destroyCtxInRequest(pUserReq);
16,412✔
1543
    pUserReq->prevCode = code;
16,412✔
1544
    (void)memset(&pUserReq->relation, 0, sizeof(pUserReq->relation));
16,412✔
1545
  } else {
1546
    tscError("User req is missing");
×
1547
    (void)removeFromMostPrevReq(pRequest);
×
1548
    return;
×
1549
  }
1550
  if (hasSubRequest)
16,412✔
1551
    (void)removeFromMostPrevReq(pRequest);
24✔
1552
  else
1553
    (void)releaseRequest(pUserReq->self);
16,388✔
1554
  doAsyncQuery(pUserReq, true);
16,412✔
1555
}
1556

1557
typedef struct SAsyncFetchParam {
1558
  SRequestObj      *pReq;
1559
  __taos_async_fn_t fp;
1560
  void             *param;
1561
} SAsyncFetchParam;
1562

1563
static int32_t doAsyncFetch(void *pParam) {
869,781✔
1564
  SAsyncFetchParam *param = pParam;
869,781✔
1565
  taosAsyncFetchImpl(param->pReq, param->fp, param->param);
869,781✔
1566
  taosMemoryFree(param);
869,778!
1567
  return TSDB_CODE_SUCCESS;
869,779✔
1568
}
1569

1570
void taos_fetch_rows_a(TAOS_RES *res, __taos_async_fn_t fp, void *param) {
869,782✔
1571
  if (res == NULL || fp == NULL) {
869,782!
1572
    tscError("taos_fetch_rows_a invalid paras");
×
1573
    return;
×
1574
  }
1575
  if (!TD_RES_QUERY(res)) {
869,784!
1576
    tscError("taos_fetch_rows_a res is NULL");
×
1577
    fp(param, res, TSDB_CODE_APP_ERROR);
×
1578
    return;
×
1579
  }
1580

1581
  SRequestObj *pRequest = res;
869,784✔
1582
  if (TSDB_SQL_RETRIEVE_EMPTY_RESULT == pRequest->type) {
869,784✔
1583
    fp(param, res, 0);
5✔
1584
    return;
5✔
1585
  }
1586

1587
  SAsyncFetchParam *pParam = taosMemoryCalloc(1, sizeof(SAsyncFetchParam));
869,779!
1588
  if (!pParam) {
869,780!
1589
    fp(param, res, terrno);
×
1590
    return;
×
1591
  }
1592
  pParam->pReq = pRequest;
869,780✔
1593
  pParam->fp = fp;
869,780✔
1594
  pParam->param = param;
869,780✔
1595
  int32_t code = taosAsyncExec(doAsyncFetch, pParam, NULL);
869,780✔
1596
  if (TSDB_CODE_SUCCESS != code) {
869,779!
1597
    taosMemoryFree(pParam);
×
1598
    fp(param, res, code);
×
1599
    return;
×
1600
  }
1601
}
1602

1603
void taos_fetch_raw_block_a(TAOS_RES *res, __taos_async_fn_t fp, void *param) {
4✔
1604
  if (res == NULL || fp == NULL) {
4!
1605
    tscError("taos_fetch_raw_block_a invalid paras");
×
1606
    return;
×
1607
  }
1608
  if (!TD_RES_QUERY(res)) {
4!
1609
    tscError("taos_fetch_raw_block_a res is NULL");
×
1610
    return;
×
1611
  }
1612
  SRequestObj    *pRequest = res;
4✔
1613
  SReqResultInfo *pResultInfo = &pRequest->body.resInfo;
4✔
1614

1615
  // set the current block is all consumed
1616
  pResultInfo->convertUcs4 = false;
4✔
1617

1618
  // it is a local executed query, no need to do async fetch
1619
  taos_fetch_rows_a(pRequest, fp, param);
4✔
1620
}
1621

1622
const void *taos_get_raw_block(TAOS_RES *res) {
×
1623
  if (res == NULL) {
×
1624
    tscError("taos_get_raw_block invalid paras");
×
1625
    return NULL;
×
1626
  }
1627
  if (!TD_RES_QUERY(res)) {
×
1628
    tscError("taos_get_raw_block res is NULL");
×
1629
    return NULL;
×
1630
  }
1631
  SRequestObj *pRequest = res;
×
1632

1633
  return pRequest->body.resInfo.pData;
×
1634
}
1635

1636
int taos_get_db_route_info(TAOS *taos, const char *db, TAOS_DB_ROUTE_INFO *dbInfo) {
2✔
1637
  if (NULL == taos) {
2!
1638
    terrno = TSDB_CODE_TSC_DISCONNECTED;
×
1639
    return terrno;
×
1640
  }
1641

1642
  if (NULL == db || NULL == dbInfo) {
2!
1643
    tscError("invalid input param, db:%p, dbInfo:%p", db, dbInfo);
×
1644
    terrno = TSDB_CODE_TSC_INVALID_INPUT;
×
1645
    return terrno;
×
1646
  }
1647

1648
  int64_t      connId = *(int64_t *)taos;
2✔
1649
  SRequestObj *pRequest = NULL;
2✔
1650
  char        *sql = "taos_get_db_route_info";
2✔
1651
  int32_t      code = buildRequest(connId, sql, strlen(sql), NULL, false, &pRequest, 0);
2✔
1652
  if (code != TSDB_CODE_SUCCESS) {
2!
1653
    terrno = code;
×
1654
    return terrno;
×
1655
  }
1656

1657
  STscObj  *pTscObj = pRequest->pTscObj;
2✔
1658
  SCatalog *pCtg = NULL;
2✔
1659
  code = catalogGetHandle(pTscObj->pAppInfo->clusterId, &pCtg);
2✔
1660
  if (code != TSDB_CODE_SUCCESS) {
2!
1661
    goto _return;
×
1662
  }
1663

1664
  SRequestConnInfo conn = {
2✔
1665
      .pTrans = pTscObj->pAppInfo->pTransporter, .requestId = pRequest->requestId, .requestObjRefId = pRequest->self};
2✔
1666

1667
  conn.mgmtEps = getEpSet_s(&pTscObj->pAppInfo->mgmtEp);
2✔
1668

1669
  char dbFName[TSDB_DB_FNAME_LEN] = {0};
2✔
1670
  (void)snprintf(dbFName, sizeof(dbFName), "%d.%s", pTscObj->acctId, db);
2✔
1671

1672
  code = catalogGetDBVgInfo(pCtg, &conn, dbFName, dbInfo);
2✔
1673
  if (code) {
2!
1674
    goto _return;
×
1675
  }
1676

1677
_return:
2✔
1678

1679
  terrno = code;
2✔
1680

1681
  destroyRequest(pRequest);
2✔
1682
  return code;
2✔
1683
}
1684

1685
int taos_get_table_vgId(TAOS *taos, const char *db, const char *table, int *vgId) {
200✔
1686
  if (NULL == taos) {
200!
1687
    terrno = TSDB_CODE_TSC_DISCONNECTED;
×
1688
    return terrno;
×
1689
  }
1690

1691
  if (NULL == db || NULL == table || NULL == vgId) {
200!
1692
    tscError("invalid input param, db:%p, table:%p, vgId:%p", db, table, vgId);
×
1693
    terrno = TSDB_CODE_TSC_INVALID_INPUT;
×
1694
    return terrno;
×
1695
  }
1696

1697
  int64_t      connId = *(int64_t *)taos;
200✔
1698
  SRequestObj *pRequest = NULL;
200✔
1699
  char        *sql = "taos_get_table_vgId";
200✔
1700
  int32_t      code = buildRequest(connId, sql, strlen(sql), NULL, false, &pRequest, 0);
200✔
1701
  if (code != TSDB_CODE_SUCCESS) {
200!
1702
    return terrno;
×
1703
  }
1704

1705
  pRequest->syncQuery = true;
200✔
1706

1707
  STscObj  *pTscObj = pRequest->pTscObj;
200✔
1708
  SCatalog *pCtg = NULL;
200✔
1709
  code = catalogGetHandle(pTscObj->pAppInfo->clusterId, &pCtg);
200✔
1710
  if (code != TSDB_CODE_SUCCESS) {
200!
1711
    goto _return;
×
1712
  }
1713

1714
  SRequestConnInfo conn = {
200✔
1715
      .pTrans = pTscObj->pAppInfo->pTransporter, .requestId = pRequest->requestId, .requestObjRefId = pRequest->self};
200✔
1716

1717
  conn.mgmtEps = getEpSet_s(&pTscObj->pAppInfo->mgmtEp);
200✔
1718

1719
  SName tableName = {0};
200✔
1720
  toName(pTscObj->acctId, db, table, &tableName);
200✔
1721

1722
  SVgroupInfo vgInfo;
1723
  code = catalogGetTableHashVgroup(pCtg, &conn, &tableName, &vgInfo);
200✔
1724
  if (code) {
200!
1725
    goto _return;
×
1726
  }
1727

1728
  *vgId = vgInfo.vgId;
200✔
1729

1730
_return:
200✔
1731

1732
  terrno = code;
200✔
1733

1734
  destroyRequest(pRequest);
200✔
1735
  return code;
200✔
1736
}
1737

1738
int taos_get_tables_vgId(TAOS *taos, const char *db, const char *table[], int tableNum, int *vgId) {
1✔
1739
  if (NULL == taos) {
1!
1740
    terrno = TSDB_CODE_TSC_DISCONNECTED;
×
1741
    return terrno;
×
1742
  }
1743

1744
  if (NULL == db || NULL == table || NULL == vgId || tableNum <= 0) {
1!
1745
    tscError("invalid input param, db:%p, table:%p, vgId:%p, tbNum:%d", db, table, vgId, tableNum);
×
1746
    terrno = TSDB_CODE_TSC_INVALID_INPUT;
×
1747
    return terrno;
×
1748
  }
1749

1750
  int64_t      connId = *(int64_t *)taos;
1✔
1751
  SRequestObj *pRequest = NULL;
1✔
1752
  char        *sql = "taos_get_table_vgId";
1✔
1753
  int32_t      code = buildRequest(connId, sql, strlen(sql), NULL, false, &pRequest, 0);
1✔
1754
  if (code != TSDB_CODE_SUCCESS) {
1!
1755
    return terrno;
×
1756
  }
1757

1758
  pRequest->syncQuery = true;
1✔
1759

1760
  STscObj  *pTscObj = pRequest->pTscObj;
1✔
1761
  SCatalog *pCtg = NULL;
1✔
1762
  code = catalogGetHandle(pTscObj->pAppInfo->clusterId, &pCtg);
1✔
1763
  if (code != TSDB_CODE_SUCCESS) {
1!
1764
    goto _return;
×
1765
  }
1766

1767
  SRequestConnInfo conn = {
1✔
1768
      .pTrans = pTscObj->pAppInfo->pTransporter, .requestId = pRequest->requestId, .requestObjRefId = pRequest->self};
1✔
1769

1770
  conn.mgmtEps = getEpSet_s(&pTscObj->pAppInfo->mgmtEp);
1✔
1771

1772
  code = catalogGetTablesHashVgId(pCtg, &conn, pTscObj->acctId, db, table, tableNum, vgId);
1✔
1773
  if (code) {
1!
1774
    goto _return;
×
1775
  }
1776

1777
_return:
1✔
1778

1779
  terrno = code;
1✔
1780

1781
  destroyRequest(pRequest);
1✔
1782
  return code;
1✔
1783
}
1784

1785
int taos_load_table_info(TAOS *taos, const char *tableNameList) {
3✔
1786
  if (NULL == taos) {
3!
1787
    terrno = TSDB_CODE_TSC_DISCONNECTED;
×
1788
    return terrno;
×
1789
  }
1790

1791
  int64_t       connId = *(int64_t *)taos;
3✔
1792
  const int32_t MAX_TABLE_NAME_LENGTH = 12 * 1024 * 1024;  // 12MB list
3✔
1793
  int32_t       code = 0;
3✔
1794
  SRequestObj  *pRequest = NULL;
3✔
1795
  SCatalogReq   catalogReq = {0};
3✔
1796

1797
  if (NULL == tableNameList) {
3!
1798
    return TSDB_CODE_SUCCESS;
×
1799
  }
1800

1801
  int32_t length = (int32_t)strlen(tableNameList);
3✔
1802
  if (0 == length) {
3!
1803
    return TSDB_CODE_SUCCESS;
×
1804
  } else if (length > MAX_TABLE_NAME_LENGTH) {
3!
1805
    tscError("tableNameList too long, length:%d, maximum allowed:%d", length, MAX_TABLE_NAME_LENGTH);
×
1806
    return TSDB_CODE_TSC_INVALID_OPERATION;
×
1807
  }
1808

1809
  char *sql = "taos_load_table_info";
3✔
1810
  code = buildRequest(connId, sql, strlen(sql), NULL, false, &pRequest, 0);
3✔
1811
  if (code != TSDB_CODE_SUCCESS) {
3!
1812
    terrno = code;
×
1813
    goto _return;
×
1814
  }
1815

1816
  pRequest->syncQuery = true;
3✔
1817

1818
  STscObj *pTscObj = pRequest->pTscObj;
3✔
1819
  code = transferTableNameList(tableNameList, pTscObj->acctId, pTscObj->db, &catalogReq.pTableMeta);
3✔
1820
  if (code) {
3!
1821
    goto _return;
×
1822
  }
1823

1824
  SCatalog *pCtg = NULL;
3✔
1825
  code = catalogGetHandle(pTscObj->pAppInfo->clusterId, &pCtg);
3✔
1826
  if (code != TSDB_CODE_SUCCESS) {
3!
1827
    goto _return;
×
1828
  }
1829

1830
  SRequestConnInfo conn = {
3✔
1831
      .pTrans = pTscObj->pAppInfo->pTransporter, .requestId = pRequest->requestId, .requestObjRefId = pRequest->self};
3✔
1832

1833
  conn.mgmtEps = getEpSet_s(&pTscObj->pAppInfo->mgmtEp);
3✔
1834

1835
  code = catalogAsyncGetAllMeta(pCtg, &conn, &catalogReq, syncCatalogFn, pRequest->body.interParam, NULL);
3✔
1836
  if (code) {
3!
1837
    goto _return;
×
1838
  }
1839

1840
  SSyncQueryParam *pParam = pRequest->body.interParam;
3✔
1841
  code = tsem_wait(&pParam->sem);
3✔
1842
  if (code) {
3!
1843
    tscError("tsem wait failed, code:%d - %s", code, tstrerror(code));
×
1844
    goto _return;
×
1845
  }
1846
_return:
3✔
1847
  destoryCatalogReq(&catalogReq);
3✔
1848
  destroyRequest(pRequest);
3✔
1849
  return code;
3✔
1850
}
1851

1852
TAOS_STMT *taos_stmt_init(TAOS *taos) {
621✔
1853
  STscObj *pObj = acquireTscObj(*(int64_t *)taos);
621✔
1854
  if (NULL == pObj) {
621!
1855
    tscError("invalid parameter for %s", __FUNCTION__);
×
1856
    terrno = TSDB_CODE_TSC_DISCONNECTED;
×
1857
    return NULL;
×
1858
  }
1859

1860
  TAOS_STMT *pStmt = stmtInit(pObj, 0, NULL);
621✔
1861
  if (NULL == pStmt) {
621!
1862
    tscError("stmt init failed, errcode:%s", terrstr());
×
1863
  }
1864
  releaseTscObj(*(int64_t *)taos);
621✔
1865

1866
  return pStmt;
621✔
1867
}
1868

1869
TAOS_STMT *taos_stmt_init_with_reqid(TAOS *taos, int64_t reqid) {
×
1870
  STscObj *pObj = acquireTscObj(*(int64_t *)taos);
×
1871
  if (NULL == pObj) {
×
1872
    tscError("invalid parameter for %s", __FUNCTION__);
×
1873
    terrno = TSDB_CODE_TSC_DISCONNECTED;
×
1874
    return NULL;
×
1875
  }
1876

1877
  TAOS_STMT *pStmt = stmtInit(pObj, reqid, NULL);
×
1878
  if (NULL == pStmt) {
×
1879
    tscError("stmt init failed, errcode:%s", terrstr());
×
1880
  }
1881
  releaseTscObj(*(int64_t *)taos);
×
1882

1883
  return pStmt;
×
1884
}
1885

1886
TAOS_STMT *taos_stmt_init_with_options(TAOS *taos, TAOS_STMT_OPTIONS *options) {
87✔
1887
  STscObj *pObj = acquireTscObj(*(int64_t *)taos);
87✔
1888
  if (NULL == pObj) {
87!
1889
    tscError("invalid parameter for %s", __FUNCTION__);
×
1890
    terrno = TSDB_CODE_TSC_DISCONNECTED;
×
1891
    return NULL;
×
1892
  }
1893

1894
  TAOS_STMT *pStmt = stmtInit(pObj, options->reqId, options);
87✔
1895
  if (NULL == pStmt) {
87!
1896
    tscError("stmt init failed, errcode:%s", terrstr());
×
1897
  }
1898
  releaseTscObj(*(int64_t *)taos);
87✔
1899

1900
  return pStmt;
87✔
1901
}
1902

1903
int taos_stmt_prepare(TAOS_STMT *stmt, const char *sql, unsigned long length) {
11,123✔
1904
  if (stmt == NULL || sql == NULL) {
11,123!
1905
    tscError("NULL parameter for %s", __FUNCTION__);
×
1906
    terrno = TSDB_CODE_INVALID_PARA;
×
1907
    return terrno;
×
1908
  }
1909

1910
  return stmtPrepare(stmt, sql, length);
11,123✔
1911
}
1912

1913
int taos_stmt_set_tbname_tags(TAOS_STMT *stmt, const char *name, TAOS_MULTI_BIND *tags) {
20,005✔
1914
  if (stmt == NULL || name == NULL) {
20,005!
1915
    tscError("NULL parameter for %s", __FUNCTION__);
×
1916
    terrno = TSDB_CODE_INVALID_PARA;
×
1917
    return terrno;
×
1918
  }
1919

1920
  int32_t code = stmtSetTbName(stmt, name);
20,005✔
1921
  if (code) {
20,005✔
1922
    return code;
7✔
1923
  }
1924

1925
  if (tags) {
19,998!
1926
    return stmtSetTbTags(stmt, tags);
19,998✔
1927
  }
1928

1929
  return TSDB_CODE_SUCCESS;
×
1930
}
1931

1932
int taos_stmt_set_tbname(TAOS_STMT *stmt, const char *name) {
137,055✔
1933
  if (stmt == NULL || name == NULL) {
137,055!
1934
    tscError("NULL parameter for %s", __FUNCTION__);
×
1935
    terrno = TSDB_CODE_INVALID_PARA;
×
1936
    return terrno;
×
1937
  }
1938

1939
  return stmtSetTbName(stmt, name);
137,130✔
1940
}
1941

1942
int taos_stmt_set_tags(TAOS_STMT *stmt, TAOS_MULTI_BIND *tags) {
20,129✔
1943
  if (stmt == NULL || tags == NULL) {
20,129!
1944
    tscError("NULL parameter for %s", __FUNCTION__);
×
1945
    terrno = TSDB_CODE_INVALID_PARA;
×
1946
    return terrno;
×
1947
  }
1948

1949
  return stmtSetTbTags(stmt, tags);
20,129✔
1950
}
1951

1952
int taos_stmt_set_sub_tbname(TAOS_STMT *stmt, const char *name) { return taos_stmt_set_tbname(stmt, name); }
2✔
1953

1954
int taos_stmt_get_tag_fields(TAOS_STMT *stmt, int *fieldNum, TAOS_FIELD_E **fields) {
20,127✔
1955
  if (stmt == NULL || NULL == fieldNum) {
20,127!
1956
    tscError("NULL parameter for %s", __FUNCTION__);
×
1957
    terrno = TSDB_CODE_INVALID_PARA;
×
1958
    return terrno;
×
1959
  }
1960

1961
  return stmtGetTagFields(stmt, fieldNum, fields);
20,127✔
1962
}
1963

1964
int taos_stmt_get_col_fields(TAOS_STMT *stmt, int *fieldNum, TAOS_FIELD_E **fields) {
268,567✔
1965
  if (stmt == NULL || NULL == fieldNum) {
268,567!
1966
    tscError("NULL parameter for %s", __FUNCTION__);
×
1967
    terrno = TSDB_CODE_INVALID_PARA;
×
1968
    return terrno;
×
1969
  }
1970

1971
  return stmtGetColFields(stmt, fieldNum, fields);
268,567✔
1972
}
1973

1974
// let stmt to reclaim TAOS_FIELD_E that was allocated by `taos_stmt_get_tag_fields`/`taos_stmt_get_col_fields`
1975
void taos_stmt_reclaim_fields(TAOS_STMT *stmt, TAOS_FIELD_E *fields) {
×
1976
  (void)stmt;
1977
  if (!fields) return;
×
1978
  taosMemoryFree(fields);
×
1979
}
1980

1981
int taos_stmt_bind_param(TAOS_STMT *stmt, TAOS_MULTI_BIND *bind) {
13,915✔
1982
  if (stmt == NULL || bind == NULL) {
13,915!
1983
    tscError("NULL parameter for %s", __FUNCTION__);
×
1984
    terrno = TSDB_CODE_INVALID_PARA;
×
1985
    return terrno;
×
1986
  }
1987

1988
  if (bind->num > 1) {
13,915!
1989
    tscError("invalid bind number %d for %s", bind->num, __FUNCTION__);
×
1990
    terrno = TSDB_CODE_TSC_STMT_BIND_NUMBER_ERROR;
×
1991
    return terrno;
×
1992
  }
1993

1994
  return stmtBindBatch(stmt, bind, -1);
13,915✔
1995
}
1996

1997
int taos_stmt_bind_param_batch(TAOS_STMT *stmt, TAOS_MULTI_BIND *bind) {
1,225,748✔
1998
  if (stmt == NULL || bind == NULL) {
1,225,748!
1999
    tscError("NULL parameter for %s", __FUNCTION__);
×
2000
    terrno = TSDB_CODE_INVALID_PARA;
×
2001
    return terrno;
×
2002
  }
2003

2004
  if (bind->num <= 0 || bind->num > INT16_MAX) {
1,226,188!
2005
    tscError("invalid bind num %d", bind->num);
×
2006
    terrno = TSDB_CODE_TSC_STMT_BIND_NUMBER_ERROR;
×
2007
    return terrno;
×
2008
  }
2009

2010
  int32_t insert = 0;
1,226,273✔
2011
  int32_t code = stmtIsInsert(stmt, &insert);
1,226,273✔
2012
  if (TSDB_CODE_SUCCESS != code) {
1,224,877!
2013
    tscError("stmt insert failed, errcode:%s", tstrerror(code));
×
2014
    return code;
×
2015
  }
2016
  if (0 == insert && bind->num > 1) {
1,224,877!
2017
    tscError("only one row data allowed for query");
×
2018
    terrno = TSDB_CODE_TSC_STMT_BIND_NUMBER_ERROR;
×
2019
    return terrno;
×
2020
  }
2021

2022
  return stmtBindBatch(stmt, bind, -1);
1,224,877✔
2023
}
2024

2025
int taos_stmt_bind_single_param_batch(TAOS_STMT *stmt, TAOS_MULTI_BIND *bind, int colIdx) {
1,102,302✔
2026
  if (stmt == NULL || bind == NULL) {
1,102,302!
2027
    tscError("NULL parameter for %s", __FUNCTION__);
×
2028
    terrno = TSDB_CODE_INVALID_PARA;
×
2029
    return terrno;
×
2030
  }
2031

2032
  if (colIdx < 0) {
1,102,302!
2033
    tscError("invalid bind column idx %d", colIdx);
×
2034
    terrno = TSDB_CODE_INVALID_PARA;
×
2035
    return terrno;
×
2036
  }
2037

2038
  int32_t insert = 0;
1,102,302✔
2039
  int32_t code = stmtIsInsert(stmt, &insert);
1,102,302✔
2040
  if (TSDB_CODE_SUCCESS != code) {
1,102,302!
2041
    tscError("stmt insert failed, errcode:%s", tstrerror(code));
×
2042
    return code;
×
2043
  }
2044
  if (0 == insert && bind->num > 1) {
1,102,302!
2045
    tscError("only one row data allowed for query");
×
2046
    terrno = TSDB_CODE_TSC_STMT_BIND_NUMBER_ERROR;
×
2047
    return terrno;
×
2048
  }
2049

2050
  return stmtBindBatch(stmt, bind, colIdx);
1,102,302✔
2051
}
2052

2053
int taos_stmt_add_batch(TAOS_STMT *stmt) {
1,298,455✔
2054
  if (stmt == NULL) {
1,298,455!
2055
    tscError("NULL parameter for %s", __FUNCTION__);
×
2056
    terrno = TSDB_CODE_INVALID_PARA;
×
2057
    return terrno;
×
2058
  }
2059

2060
  return stmtAddBatch(stmt);
1,298,455✔
2061
}
2062

2063
int taos_stmt_execute(TAOS_STMT *stmt) {
145,712✔
2064
  if (stmt == NULL) {
145,712!
2065
    tscError("NULL parameter for %s", __FUNCTION__);
×
2066
    terrno = TSDB_CODE_INVALID_PARA;
×
2067
    return terrno;
×
2068
  }
2069

2070
  return stmtExec(stmt);
145,712✔
2071
}
2072

2073
int taos_stmt_is_insert(TAOS_STMT *stmt, int *insert) {
23,084✔
2074
  if (stmt == NULL || insert == NULL) {
23,084!
2075
    tscError("NULL parameter for %s", __FUNCTION__);
×
2076
    terrno = TSDB_CODE_INVALID_PARA;
×
2077
    return terrno;
×
2078
  }
2079

2080
  return stmtIsInsert(stmt, insert);
23,084✔
2081
}
2082

2083
int taos_stmt_num_params(TAOS_STMT *stmt, int *nums) {
1,331✔
2084
  if (stmt == NULL || nums == NULL) {
1,331!
2085
    tscError("NULL parameter for %s", __FUNCTION__);
×
2086
    terrno = TSDB_CODE_INVALID_PARA;
×
2087
    return terrno;
×
2088
  }
2089

2090
  return stmtGetParamNum(stmt, nums);
1,331✔
2091
}
2092

2093
int taos_stmt_get_param(TAOS_STMT *stmt, int idx, int *type, int *bytes) {
2,324,534✔
2094
  if (stmt == NULL || type == NULL || NULL == bytes || idx < 0) {
2,324,534!
2095
    tscError("invalid parameter for %s", __FUNCTION__);
×
2096
    terrno = TSDB_CODE_INVALID_PARA;
×
2097
    return terrno;
×
2098
  }
2099

2100
  return stmtGetParam(stmt, idx, type, bytes);
2,324,534✔
2101
}
2102

2103
TAOS_RES *taos_stmt_use_result(TAOS_STMT *stmt) {
21,804✔
2104
  if (stmt == NULL) {
21,804!
2105
    tscError("NULL parameter for %s", __FUNCTION__);
×
2106
    terrno = TSDB_CODE_INVALID_PARA;
×
2107
    return NULL;
×
2108
  }
2109

2110
  return stmtUseResult(stmt);
21,804✔
2111
}
2112

2113
char *taos_stmt_errstr(TAOS_STMT *stmt) { return (char *)stmtErrstr(stmt); }
183✔
2114

2115
int taos_stmt_affected_rows(TAOS_STMT *stmt) {
297✔
2116
  if (stmt == NULL) {
297!
2117
    tscError("NULL parameter for %s", __FUNCTION__);
×
2118
    terrno = TSDB_CODE_INVALID_PARA;
×
2119
    return 0;
×
2120
  }
2121

2122
  return stmtAffectedRows(stmt);
297✔
2123
}
2124

2125
int taos_stmt_affected_rows_once(TAOS_STMT *stmt) {
28✔
2126
  if (stmt == NULL) {
28!
2127
    tscError("NULL parameter for %s", __FUNCTION__);
×
2128
    terrno = TSDB_CODE_INVALID_PARA;
×
2129
    return 0;
×
2130
  }
2131

2132
  return stmtAffectedRowsOnce(stmt);
28✔
2133
}
2134

2135
int taos_stmt_close(TAOS_STMT *stmt) {
699✔
2136
  if (stmt == NULL) {
699!
2137
    tscError("NULL parameter for %s", __FUNCTION__);
×
2138
    terrno = TSDB_CODE_INVALID_PARA;
×
2139
    return terrno;
×
2140
  }
2141

2142
  return stmtClose(stmt);
699✔
2143
}
2144

2145
TAOS_STMT2 *taos_stmt2_init(TAOS *taos, TAOS_STMT2_OPTION *option) {
24✔
2146
  if (NULL == taos) {
24!
2147
    tscError("NULL parameter for %s", __FUNCTION__);
×
2148
    terrno = TSDB_CODE_INVALID_PARA;
×
2149
    return NULL;
×
2150
  }
2151
  STscObj *pObj = acquireTscObj(*(int64_t *)taos);
24✔
2152
  if (NULL == pObj) {
24!
2153
    tscError("invalid parameter for %s", __FUNCTION__);
×
2154
    terrno = TSDB_CODE_TSC_DISCONNECTED;
×
2155
    return NULL;
×
2156
  }
2157

2158
  TAOS_STMT2 *pStmt = stmtInit2(pObj, option);
24✔
2159

2160
  releaseTscObj(*(int64_t *)taos);
24✔
2161

2162
  return pStmt;
24✔
2163
}
2164

2165
int taos_stmt2_prepare(TAOS_STMT2 *stmt, const char *sql, unsigned long length) {
24✔
2166
  if (stmt == NULL || sql == NULL) {
24!
2167
    tscError("NULL parameter for %s", __FUNCTION__);
×
2168
    terrno = TSDB_CODE_INVALID_PARA;
×
2169
    return terrno;
×
2170
  }
2171

2172
  return stmtPrepare2(stmt, sql, length);
24✔
2173
}
2174

2175
int taos_stmt2_bind_param(TAOS_STMT2 *stmt, TAOS_STMT2_BINDV *bindv, int32_t col_idx) {
252✔
2176
  if (stmt == NULL) {
252!
2177
    tscError("NULL parameter for %s", __FUNCTION__);
×
2178
    terrno = TSDB_CODE_INVALID_PARA;
×
2179
    return terrno;
×
2180
  }
2181

2182
  STscStmt2 *pStmt = (STscStmt2 *)stmt;
252✔
2183
  if (atomic_load_8((int8_t *)&pStmt->asyncBindParam.asyncBindNum) > 1) {
252!
2184
    tscError("async bind param is still working, please try again later");
×
2185
    return TSDB_CODE_TSC_STMT_API_ERROR;
×
2186
  }
2187

2188
  if (pStmt->options.asyncExecFn && !pStmt->execSemWaited) {
253!
2189
    if (tsem_wait(&pStmt->asyncExecSem) != 0) {
×
2190
      tscError("wait asyncExecSem failed");
×
2191
    }
2192
    pStmt->execSemWaited = true;
×
2193
  }
2194

2195
  SSHashObj *hashTbnames = tSimpleHashInit(100, taosGetDefaultHashFunction(TSDB_DATA_TYPE_VARCHAR));
253✔
2196
  if (NULL == hashTbnames) {
253!
2197
    tscError("stmt2 bind failed, %s", tstrerror(terrno));
×
2198
    return terrno;
×
2199
  }
2200

2201
  int32_t code = TSDB_CODE_SUCCESS;
253✔
2202
  for (int i = 0; i < bindv->count; ++i) {
801✔
2203
    if (bindv->tbnames && bindv->tbnames[i]) {
552!
2204
      if (pStmt->sql.stbInterlaceMode) {
552!
2205
        if (tSimpleHashGet(hashTbnames, bindv->tbnames[i], strlen(bindv->tbnames[i])) != NULL) {
552!
2206
          code = terrno = TSDB_CODE_PAR_TBNAME_DUPLICATED;
×
2207
          tscError("stmt2 bind failed, %s %s", tstrerror(terrno), bindv->tbnames[i]);
×
2208
          goto out;
×
2209
        }
2210

2211
        code = tSimpleHashPut(hashTbnames, bindv->tbnames[i], strlen(bindv->tbnames[i]), NULL, 0);
552✔
2212
        if (code) {
552!
2213
          goto out;
×
2214
        }
2215
      }
2216

2217
      code = stmtSetTbName2(stmt, bindv->tbnames[i]);
552✔
2218
      if (code) {
551!
2219
        goto out;
×
2220
      }
2221
    }
2222

2223
    SVCreateTbReq *pCreateTbReq = NULL;
551✔
2224
    if (bindv->tags && bindv->tags[i]) {
551!
2225
      code = stmtSetTbTags2(stmt, bindv->tags[i], &pCreateTbReq);
×
2226
    } else if (pStmt->sql.autoCreateTbl || pStmt->bInfo.needParse) {
551!
2227
      code = stmtCheckTags2(stmt, &pCreateTbReq);
×
2228
    } else {
2229
      pStmt->sql.autoCreateTbl = false;
552✔
2230
    }
2231

2232
    if (code) {
550!
2233
      goto out;
×
2234
    }
2235

2236
    if (bindv->bind_cols && bindv->bind_cols[i]) {
550!
2237
      TAOS_STMT2_BIND *bind = bindv->bind_cols[i];
553✔
2238

2239
      if (bind->num <= 0 || bind->num > INT16_MAX) {
553!
2240
        tscError("invalid bind num %d", bind->num);
1!
2241
        code = terrno = TSDB_CODE_TSC_STMT_BIND_NUMBER_ERROR;
1✔
2242
        goto out;
×
2243
      }
2244

2245
      int32_t insert = 0;
552✔
2246
      (void)stmtIsInsert2(stmt, &insert);
552✔
2247
      if (0 == insert && bind->num > 1) {
552!
2248
        tscError("only one row data allowed for query");
×
2249
        code = terrno = TSDB_CODE_TSC_STMT_BIND_NUMBER_ERROR;
×
2250
        goto out;
×
2251
      }
2252

2253
      code = stmtBindBatch2(stmt, bind, col_idx, pCreateTbReq);
552✔
2254
      if (TSDB_CODE_SUCCESS != code) {
551!
2255
        goto out;
×
2256
      }
2257
    }
2258
  }
2259

2260
out:
249✔
2261
  tSimpleHashCleanup(hashTbnames);
249✔
2262

2263
  return code;
253✔
2264
}
2265

2266
int taos_stmt2_bind_param_a(TAOS_STMT2 *stmt, TAOS_STMT2_BINDV *bindv, int32_t col_idx, __taos_async_fn_t fp,
×
2267
                            void *param) {
2268
  if (stmt == NULL || bindv == NULL || fp == NULL) {
×
2269
    terrno = TSDB_CODE_INVALID_PARA;
×
2270
    return terrno;
×
2271
  }
2272

2273
  STscStmt2 *pStmt = (STscStmt2 *)stmt;
×
2274

2275
  ThreadArgs *args = (ThreadArgs *)taosMemoryMalloc(sizeof(ThreadArgs));
×
2276
  args->stmt = stmt;
×
2277
  args->bindv = bindv;
×
2278
  args->col_idx = col_idx;
×
2279
  args->fp = fp;
×
2280
  args->param = param;
×
2281

2282
  (void)taosThreadMutexLock(&(pStmt->asyncBindParam.mutex));
×
2283
  if (atomic_load_8((int8_t *)&pStmt->asyncBindParam.asyncBindNum) > 0) {
×
2284
    (void)taosThreadMutexUnlock(&(pStmt->asyncBindParam.mutex));
×
2285
    tscError("async bind param is still working, please try again later");
×
2286
    return TSDB_CODE_TSC_STMT_API_ERROR;
×
2287
  }
2288
  (void)atomic_add_fetch_8(&pStmt->asyncBindParam.asyncBindNum, 1);
×
2289
  (void)taosThreadMutexUnlock(&(pStmt->asyncBindParam.mutex));
×
2290

2291
  int code_s = taosStmt2AsyncBind(stmtAsyncBindThreadFunc, (void *)args);
×
2292
  if (code_s != TSDB_CODE_SUCCESS) {
×
2293
    (void)taosThreadMutexLock(&(pStmt->asyncBindParam.mutex));
×
2294
    (void)taosThreadCondSignal(&(pStmt->asyncBindParam.waitCond));
×
2295
    (void)atomic_sub_fetch_8(&pStmt->asyncBindParam.asyncBindNum, 1);
×
2296
    (void)taosThreadMutexUnlock(&(pStmt->asyncBindParam.mutex));
×
2297
    tscError("async bind failed, code:%d , %s", code_s, tstrerror(code_s));
×
2298
  }
2299

2300
  return code_s;
×
2301
}
2302

2303
int taos_stmt2_exec(TAOS_STMT2 *stmt, int *affected_rows) {
253✔
2304
  if (stmt == NULL) {
253!
2305
    tscError("NULL parameter for %s", __FUNCTION__);
×
2306
    terrno = TSDB_CODE_INVALID_PARA;
×
2307
    return terrno;
×
2308
  }
2309

2310
  return stmtExec2(stmt, affected_rows);
253✔
2311
}
2312

2313
int taos_stmt2_close(TAOS_STMT2 *stmt) {
24✔
2314
  if (stmt == NULL) {
24!
2315
    tscError("NULL parameter for %s", __FUNCTION__);
×
2316
    terrno = TSDB_CODE_INVALID_PARA;
×
2317
    return terrno;
×
2318
  }
2319

2320
  return stmtClose2(stmt);
24✔
2321
}
2322

2323
int taos_stmt2_is_insert(TAOS_STMT2 *stmt, int *insert) {
×
2324
  if (stmt == NULL || insert == NULL) {
×
2325
    tscError("NULL parameter for %s", __FUNCTION__);
×
2326
    terrno = TSDB_CODE_INVALID_PARA;
×
2327
    return terrno;
×
2328
  }
2329

2330
  return stmtIsInsert2(stmt, insert);
×
2331
}
2332

2333
int taos_stmt2_get_fields(TAOS_STMT2 *stmt, int *count, TAOS_FIELD_ALL **fields) {
×
2334
  if (stmt == NULL || count == NULL) {
×
2335
    tscError("NULL parameter for %s", __FUNCTION__);
×
2336
    terrno = TSDB_CODE_INVALID_PARA;
×
2337
    return terrno;
×
2338
  }
2339

2340
  STscStmt2 *pStmt = (STscStmt2 *)stmt;
×
2341
  if (pStmt->sql.type == 0) {
×
2342
    int isInsert = 0;
×
2343
    (void)stmtIsInsert2(stmt, &isInsert);
×
2344
    if (!isInsert) {
×
2345
      pStmt->sql.type = STMT_TYPE_QUERY;
×
2346
    }
2347
  }
2348
  if (pStmt->sql.type == STMT_TYPE_QUERY) {
×
2349
    return stmtGetParamNum2(stmt, count);
×
2350
  }
2351

2352
  return stmtGetStbColFields2(stmt, count, fields);
×
2353
}
2354

2355
DLL_EXPORT void taos_stmt2_free_fields(TAOS_STMT2 *stmt, TAOS_FIELD_ALL *fields) {
×
2356
  (void)stmt;
2357
  if (!fields) return;
×
2358
  taosMemoryFree(fields);
×
2359
}
2360

2361
TAOS_RES *taos_stmt2_result(TAOS_STMT2 *stmt) {
×
2362
  if (stmt == NULL) {
×
2363
    tscError("NULL parameter for %s", __FUNCTION__);
×
2364
    terrno = TSDB_CODE_INVALID_PARA;
×
2365
    return NULL;
×
2366
  }
2367

2368
  return stmtUseResult2(stmt);
×
2369
}
2370

2371
char *taos_stmt2_error(TAOS_STMT2 *stmt) { return (char *)stmtErrstr2(stmt); }
×
2372

2373
int taos_set_conn_mode(TAOS *taos, int mode, int value) {
4✔
2374
  if (taos == NULL) {
4!
2375
    terrno = TSDB_CODE_INVALID_PARA;
×
2376
    return terrno;
×
2377
  }
2378

2379
  STscObj *pObj = acquireTscObj(*(int64_t *)taos);
4✔
2380
  if (NULL == pObj) {
4!
2381
    terrno = TSDB_CODE_TSC_DISCONNECTED;
×
2382
    tscError("invalid parameter for %s", __func__);
×
2383
    return terrno;
×
2384
  }
2385
  switch (mode) {
4!
2386
    case TAOS_CONN_MODE_BI:
4✔
2387
      atomic_store_8(&pObj->biMode, value);
4✔
2388
      break;
4✔
2389
    default:
×
2390
      tscError("not supported mode.");
×
2391
      return TSDB_CODE_INVALID_PARA;
×
2392
  }
2393
  return 0;
4✔
2394
}
2395

2396
char *getBuildInfo() { return td_buildinfo; }
×
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