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

taosdata / TDengine / #3839

03 Apr 2025 01:31PM UTC coverage: 62.382% (+0.4%) from 61.998%
#3839

push

travis-ci

web-flow
Merge pull request #30644 from taosdata/merge/mainto3.0

merge: from main to 3.0 branch

154072 of 315065 branches covered (48.9%)

Branch coverage included in aggregate %.

397 of 459 new or added lines in 2 files covered. (86.49%)

395 existing lines in 53 files now uncovered.

238969 of 314991 relevant lines covered (75.87%)

20218564.73 hits per line

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

60.62
/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,793✔
46
  if (arg == NULL) {
2,793!
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) {
4,680✔
52
    if (i % 1000 == 0) {
1,871✔
53
      (void)sched_yield();
1✔
54
    }
55
  }
56

57
  int ret = taos_options_imp(option, (const char *)arg);
2,757✔
58
  atomic_store_32(&lock, 0);
2,794✔
59
  return ret;
2,794✔
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() {
16,663✔
69
  pTimezoneMap = taosHashInit(0, MurmurHash3_32, false, HASH_ENTRY_LOCK);
16,663✔
70
  if (pTimezoneMap == NULL) {
16,663!
71
    return terrno;
×
72
  }
73
  taosHashSetFreeFp(pTimezoneMap, freeTz);
16,663✔
74

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

82
void tzCleanup() {
16,664✔
83
  taosHashCleanup(pTimezoneMap);
16,664✔
84
  taosHashCleanup(pTimezoneNameMap);
16,664✔
85
}
16,664✔
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) {
16,678✔
227
  tscDebug("start to cleanup client environment");
16,678✔
228
  if (atomic_val_compare_exchange_32(&sentinel, TSC_VAR_NOT_RELEASE, TSC_VAR_RELEASED) != TSC_VAR_NOT_RELEASE) {
16,678✔
229
    return;
14✔
230
  }
231

232
  monitorClose();
16,664✔
233
  tscStopCrashReport();
16,664✔
234

235
  hbMgrCleanUp();
16,664✔
236

237
  catalogDestroy();
16,664✔
238
  schedulerDestroy();
16,664✔
239

240
  fmFuncMgtDestroy();
16,664✔
241
  qCleanupKeywordsTable();
16,664✔
242

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

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

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

256
  id = clientConnRefPool;
16,664✔
257
  clientConnRefPool = -1;
16,664✔
258
  taosCloseRef(id);
16,664✔
259

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

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

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

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

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

296
  if (pass == NULL) {
31,323✔
297
    pass = TSDB_DEFAULT_PASS;
2,714✔
298
  }
299

300
  STscObj *pObj = NULL;
31,323✔
301
  int32_t  code = taos_connect_internal(ip, user, pass, NULL, db, port, CONN_TYPE__QUERY, &pObj);
31,323✔
302
  if (TSDB_CODE_SUCCESS == code) {
31,322✔
303
    int64_t *rid = taosMemoryCalloc(1, sizeof(int64_t));
31,280!
304
    if (NULL == rid) {
31,280!
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;
31,280✔
309
    return (TAOS *)rid;
31,280✔
310
  } else {
311
    terrno = code;
42✔
312
  }
313

314
  return NULL;
43✔
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) {
31,729✔
485
  if (taos == NULL) {
31,729!
486
    return;
×
487
  }
488

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

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

497
void taos_close(TAOS *taos) {
32,165✔
498
  if (taos == NULL) {
32,165✔
499
    return;
901✔
500
  }
501

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

508
  taos_close_internal(pObj);
31,264✔
509
  releaseTscObj(*(int64_t *)taos);
31,263✔
510
  taosMemoryFree(taos);
31,264!
511
}
512

513
int taos_errno(TAOS_RES *res) {
12,764,787✔
514
  if (res == NULL || TD_RES_TMQ_RAW(res) || TD_RES_TMQ_META(res) || TD_RES_TMQ_BATCH_META(res)) {
12,764,787!
515
    return terrno;
×
516
  }
517

518
  if (TD_RES_TMQ(res) || TD_RES_TMQ_METADATA(res)) {
12,775,098!
UNCOV
519
    return 0;
×
520
  }
521

522
  return ((SRequestObj *)res)->code;
12,775,890✔
523
}
524

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

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

534
  SRequestObj *pRequest = (SRequestObj *)res;
89,659✔
535
  if (NULL != pRequest->msgBuf && (strlen(pRequest->msgBuf) > 0 || pRequest->code == TSDB_CODE_RPC_FQDN_ERROR)) {
89,659!
536
    return pRequest->msgBuf;
79,739✔
537
  } else {
538
    return (const char *)tstrerror(pRequest->code);
9,920✔
539
  }
540
}
541

542
void taos_free_result(TAOS_RES *res) {
11,262,444✔
543
  if (NULL == res) {
11,262,444✔
544
    return;
41,291✔
545
  }
546

547
  tscTrace("res:%p, will be freed", res);
11,221,153✔
548

549
  if (TD_RES_QUERY(res)) {
11,230,259✔
550
    SRequestObj *pRequest = (SRequestObj *)res;
11,134,082✔
551
    tscDebug("QID:0x%" PRIx64 ", call taos_free_result to free query, res:%p", pRequest->requestId, res);
11,134,082✔
552
    destroyRequest(pRequest);
11,134,082✔
553
    return;
11,133,990✔
554
  }
555

556
  SMqRspObj *pRsp = (SMqRspObj *)res;
96,177✔
557
  if (TD_RES_TMQ(res)) {
96,177✔
558
    tDeleteMqDataRsp(&pRsp->dataRsp);
95,903✔
559
    doFreeReqResultInfo(&pRsp->resInfo);
95,901✔
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);
96,176!
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) {
58,910,121✔
587
  if (res == NULL || TD_RES_TMQ_RAW(res) || TD_RES_TMQ_META(res) || TD_RES_TMQ_BATCH_META(res)) {
58,910,121!
588
    return 0;
×
589
  }
590

591
  SReqResultInfo *pResInfo = tscGetCurResInfo(res);
58,910,487✔
592
  return pResInfo->numOfCols;
58,910,487✔
593
}
594

595
int taos_num_fields(TAOS_RES *res) { return taos_field_count(res); }
39,069,881✔
596

597
TAOS_FIELD *taos_fetch_fields(TAOS_RES *res) {
17,296,519✔
598
  if (taos_num_fields(res) == 0 || TD_RES_TMQ_RAW(res) || TD_RES_TMQ_META(res) || TD_RES_TMQ_BATCH_META(res)) {
17,296,519!
599
    return NULL;
132,335✔
600
  }
601

602
  SReqResultInfo *pResInfo = tscGetCurResInfo(res);
17,161,804✔
603
  return pResInfo->userFields;
17,161,804✔
604
}
605

606
TAOS_RES *taos_query(TAOS *taos, const char *sql) { return taosQueryImpl(taos, sql, false, TD_REQ_FROM_APP); }
11,088,330✔
607
TAOS_RES *taos_query_with_reqid(TAOS *taos, const char *sql, int64_t reqid) {
1✔
608
  return taosQueryImplWithReqid(taos, sql, false, reqid);
1✔
609
}
610

611
TAOS_FIELD_E *taos_fetch_fields_e(TAOS_RES *res) {
6✔
612
  if (taos_num_fields(res) == 0 || TD_RES_TMQ_META(res) || TD_RES_TMQ_BATCH_META(res)) {
6!
613
    return NULL;
×
614
  }
615
  SReqResultInfo* pResInfo = tscGetCurResInfo(res);
6✔
616
  return pResInfo->fields;
6✔
617
}
618

619
TAOS_ROW taos_fetch_row(TAOS_RES *res) {
34,502,097✔
620
  if (res == NULL) {
34,502,097!
621
    return NULL;
×
622
  }
623

624
  if (TD_RES_QUERY(res)) {
34,502,097✔
625
    SRequestObj *pRequest = (SRequestObj *)res;
18,725,821✔
626
    if (pRequest->type == TSDB_SQL_RETRIEVE_EMPTY_RESULT || pRequest->type == TSDB_SQL_INSERT ||
18,725,821✔
627
        pRequest->code != TSDB_CODE_SUCCESS || taos_num_fields(res) == 0 || pRequest->killed) {
18,725,538!
628
      return NULL;
162✔
629
    }
630

631
    if (pRequest->inCallback) {
18,724,198✔
632
      tscError("can not call taos_fetch_row before query callback ends.");
1!
633
      terrno = TSDB_CODE_TSC_INVALID_OPERATION;
1✔
634
      return NULL;
1✔
635
    }
636

637
    return doAsyncFetchRows(pRequest, true, true);
18,724,197✔
638
  } else if (TD_RES_TMQ(res) || TD_RES_TMQ_METADATA(res)) {
15,776,276!
639
    SMqRspObj      *msg = ((SMqRspObj *)res);
15,776,276✔
640
    SReqResultInfo *pResultInfo = NULL;
15,776,276✔
641
    if (msg->resIter == -1) {
15,776,276✔
642
      if (tmqGetNextResInfo(res, true, &pResultInfo) != 0) {
95,379!
643
        return NULL;
×
644
      }
645
    } else {
646
      pResultInfo = tmqGetCurResInfo(res);
15,680,897✔
647
    }
648

649
    if (pResultInfo->current < pResultInfo->numOfRows) {
15,776,275✔
650
      doSetOneRowPtr(pResultInfo);
15,441,230✔
651
      pResultInfo->current += 1;
15,428,801✔
652
      return pResultInfo->row;
15,428,801✔
653
    } else {
654
      if (tmqGetNextResInfo(res, true, &pResultInfo) != 0) {
335,045✔
655
        return NULL;
95,374✔
656
      }
657

658
      doSetOneRowPtr(pResultInfo);
237,831✔
659
      pResultInfo->current += 1;
237,829✔
660
      return pResultInfo->row;
237,829✔
661
    }
662
  } else if (TD_RES_TMQ_META(res) || TD_RES_TMQ_BATCH_META(res)) {
×
663
    return NULL;
×
664
  } else {
665
    tscError("invalid result passed to taos_fetch_row");
×
666
    terrno = TSDB_CODE_TMQ_INVALID_DATA;
×
667
    return NULL;
×
668
  }
669
}
670

671
int taos_print_row(char *str, TAOS_ROW row, TAOS_FIELD *fields, int num_fields) {
15,681,842✔
672
  return taos_print_row_with_size(str, INT32_MAX, row, fields, num_fields);
15,681,842✔
673
}
674
int taos_print_row_with_size(char *str, uint32_t size, TAOS_ROW row, TAOS_FIELD *fields, int num_fields) {
15,680,858✔
675
  int32_t len = 0;
15,680,858✔
676
  for (int i = 0; i < num_fields; ++i) {
93,787,284✔
677
    if (i > 0 && len < size - 1) {
78,086,150!
678
      str[len++] = ' ';
62,503,521✔
679
    }
680

681
    if (row[i] == NULL) {
78,086,150✔
682
      len += tsnprintf(str + len, size - len, "%s", TSDB_DATA_NULL_STR);
266,097✔
683
      continue;
266,103✔
684
    }
685

686
    switch (fields[i].type) {
77,820,053!
687
      case TSDB_DATA_TYPE_TINYINT:
298,512✔
688
        len += tsnprintf(str + len, size - len, "%d", *((int8_t *)row[i]));
298,512✔
689
        break;
296,791✔
690

691
      case TSDB_DATA_TYPE_UTINYINT:
300✔
692
        len += tsnprintf(str + len, size - len, "%u", *((uint8_t *)row[i]));
300✔
693
        break;
300✔
694

695
      case TSDB_DATA_TYPE_SMALLINT:
303✔
696
        len += tsnprintf(str + len, size - len, "%d", *((int16_t *)row[i]));
303✔
697
        break;
303✔
698

699
      case TSDB_DATA_TYPE_USMALLINT:
300✔
700
        len += tsnprintf(str + len, size - len, "%u", *((uint16_t *)row[i]));
300✔
701
        break;
300✔
702

703
      case TSDB_DATA_TYPE_INT:
16,600,233✔
704
        len += tsnprintf(str + len, size - len, "%d", *((int32_t *)row[i]));
16,600,233✔
705
        break;
16,603,576✔
706

707
      case TSDB_DATA_TYPE_UINT:
300✔
708
        len += tsnprintf(str + len, size - len, "%u", *((uint32_t *)row[i]));
300✔
709
        break;
300✔
710

711
      case TSDB_DATA_TYPE_BIGINT:
14,013,480✔
712
        len += tsnprintf(str + len, size - len, "%" PRId64, *((int64_t *)row[i]));
14,013,480✔
713
        break;
14,013,097✔
714

715
      case TSDB_DATA_TYPE_UBIGINT:
300✔
716
        len += tsnprintf(str + len, size - len, "%" PRIu64, *((uint64_t *)row[i]));
300✔
717
        break;
300✔
718

719
      case TSDB_DATA_TYPE_FLOAT: {
585,098✔
720
        float fv = 0;
585,098✔
721
        fv = GET_FLOAT_VAL(row[i]);
585,098✔
722
        len += snprintf(str + len, size - len, "%.*g", FLT_DIG, fv);
585,098✔
723
      } break;
585,098✔
724

725
      case TSDB_DATA_TYPE_DOUBLE: {
8,026,008✔
726
        double dv = 0;
8,026,008✔
727
        dv = GET_DOUBLE_VAL(row[i]);
8,026,008✔
728
        len += snprintf(str + len, size - len, "%.*g", DBL_DIG, dv);
8,026,008✔
729
      } break;
8,026,008✔
730

731
      case TSDB_DATA_TYPE_VARBINARY: {
200✔
732
        void    *data = NULL;
200✔
733
        uint32_t tmp = 0;
200✔
734
        int32_t  charLen = varDataLen((char *)row[i] - VARSTR_HEADER_SIZE);
200✔
735
        if (taosAscii2Hex(row[i], charLen, &data, &tmp) < 0) {
200!
736
          break;
×
737
        }
738
        uint32_t copyLen = TMIN(size - len - 1, tmp);
200✔
739
        (void)memcpy(str + len, data, copyLen);
200✔
740
        len += copyLen;
200✔
741
        taosMemoryFree(data);
200!
742
      } break;
200✔
743
      case TSDB_DATA_TYPE_BINARY:
17,337,911✔
744
      case TSDB_DATA_TYPE_NCHAR:
745
      case TSDB_DATA_TYPE_GEOMETRY: {
746
        int32_t charLen = varDataLen((char *)row[i] - VARSTR_HEADER_SIZE);
17,337,911✔
747
        if (fields[i].type == TSDB_DATA_TYPE_BINARY || fields[i].type == TSDB_DATA_TYPE_VARBINARY ||
17,337,911!
748
            fields[i].type == TSDB_DATA_TYPE_GEOMETRY) {
5,458,767✔
749
          if (charLen > fields[i].bytes || charLen < 0) {
11,879,340!
750
            tscError("taos_print_row error binary. charLen:%d, fields[i].bytes:%d", charLen, fields[i].bytes);
×
751
            break;
×
752
          }
753
        } else {
754
          if (charLen > fields[i].bytes * TSDB_NCHAR_SIZE || charLen < 0) {
5,458,571!
755
            tscError("taos_print_row error. charLen:%d, fields[i].bytes:%d", charLen, fields[i].bytes);
2,312!
756
            break;
×
757
          }
758
        }
759

760
        uint32_t copyLen = TMIN(size - len - 1, charLen);
17,336,230✔
761
        (void)memcpy(str + len, row[i], copyLen);
17,336,230✔
762
        len += copyLen;
17,336,230✔
763
      } break;
17,336,230✔
764

765
      case TSDB_DATA_TYPE_TIMESTAMP:
21,158,106✔
766
        len += tsnprintf(str + len, size - len, "%" PRId64, *((int64_t *)row[i]));
21,158,106✔
767
        break;
21,178,818✔
768

769
      case TSDB_DATA_TYPE_BOOL:
300✔
770
        len += tsnprintf(str + len, size - len, "%d", *((int8_t *)row[i]));
300✔
771
        break;
300✔
772
      case TSDB_DATA_TYPE_DECIMAL64:
×
773
      case TSDB_DATA_TYPE_DECIMAL: {
774
        uint32_t decimalLen = strlen(row[i]);
×
775
        uint32_t copyLen = TMIN(size - len - 1, decimalLen);
×
776
        (void)memcpy(str + len, row[i], copyLen);
×
777
        len += copyLen;
×
778
      } break;
×
779
      default:
×
780
        break;
×
781
    }
782

783
    if (len >= size - 1) {
77,840,323!
784
      break;
×
785
    }
786
  }
787
  if (len < size) {
15,701,134✔
788
    str[len] = 0;
15,691,258✔
789
  }
790

791
  return len;
15,701,134✔
792
}
793

794
int *taos_fetch_lengths(TAOS_RES *res) {
31,569,808✔
795
  if (res == NULL || TD_RES_TMQ_RAW(res) || TD_RES_TMQ_META(res) || TD_RES_TMQ_BATCH_META(res)) {
31,569,808!
796
    return NULL;
×
797
  }
798

799
  SReqResultInfo *pResInfo = tscGetCurResInfo(res);
31,569,907✔
800
  return pResInfo->length;
31,569,907✔
801
}
802

803
TAOS_ROW *taos_result_block(TAOS_RES *res) {
×
804
  if (res == NULL || TD_RES_TMQ_RAW(res) || TD_RES_TMQ_META(res) || TD_RES_TMQ_BATCH_META(res)) {
×
805
    terrno = TSDB_CODE_INVALID_PARA;
×
806
    return NULL;
×
807
  }
808

809
  if (taos_is_update_query(res)) {
×
810
    return NULL;
×
811
  }
812

813
  SReqResultInfo *pResInfo = tscGetCurResInfo(res);
×
814
  return &pResInfo->row;
×
815
}
816

817
// todo intergrate with tDataTypes
818
const char *taos_data_type(int type) {
×
819
  switch (type) {
×
820
    case TSDB_DATA_TYPE_NULL:
×
821
      return "TSDB_DATA_TYPE_NULL";
×
822
    case TSDB_DATA_TYPE_BOOL:
×
823
      return "TSDB_DATA_TYPE_BOOL";
×
824
    case TSDB_DATA_TYPE_TINYINT:
×
825
      return "TSDB_DATA_TYPE_TINYINT";
×
826
    case TSDB_DATA_TYPE_SMALLINT:
×
827
      return "TSDB_DATA_TYPE_SMALLINT";
×
828
    case TSDB_DATA_TYPE_INT:
×
829
      return "TSDB_DATA_TYPE_INT";
×
830
    case TSDB_DATA_TYPE_BIGINT:
×
831
      return "TSDB_DATA_TYPE_BIGINT";
×
832
    case TSDB_DATA_TYPE_FLOAT:
×
833
      return "TSDB_DATA_TYPE_FLOAT";
×
834
    case TSDB_DATA_TYPE_DOUBLE:
×
835
      return "TSDB_DATA_TYPE_DOUBLE";
×
836
    case TSDB_DATA_TYPE_VARCHAR:
×
837
      return "TSDB_DATA_TYPE_VARCHAR";
×
838
      //    case TSDB_DATA_TYPE_BINARY:          return "TSDB_DATA_TYPE_VARCHAR";
839
    case TSDB_DATA_TYPE_TIMESTAMP:
×
840
      return "TSDB_DATA_TYPE_TIMESTAMP";
×
841
    case TSDB_DATA_TYPE_NCHAR:
×
842
      return "TSDB_DATA_TYPE_NCHAR";
×
843
    case TSDB_DATA_TYPE_JSON:
×
844
      return "TSDB_DATA_TYPE_JSON";
×
845
    case TSDB_DATA_TYPE_GEOMETRY:
×
846
      return "TSDB_DATA_TYPE_GEOMETRY";
×
847
    case TSDB_DATA_TYPE_UTINYINT:
×
848
      return "TSDB_DATA_TYPE_UTINYINT";
×
849
    case TSDB_DATA_TYPE_USMALLINT:
×
850
      return "TSDB_DATA_TYPE_USMALLINT";
×
851
    case TSDB_DATA_TYPE_UINT:
×
852
      return "TSDB_DATA_TYPE_UINT";
×
853
    case TSDB_DATA_TYPE_UBIGINT:
×
854
      return "TSDB_DATA_TYPE_UBIGINT";
×
855
    case TSDB_DATA_TYPE_VARBINARY:
×
856
      return "TSDB_DATA_TYPE_VARBINARY";
×
857
    case TSDB_DATA_TYPE_DECIMAL:
×
858
      return "TSDB_DATA_TYPE_DECIMAL";
×
859
    case TSDB_DATA_TYPE_BLOB:
×
860
      return "TSDB_DATA_TYPE_BLOB";
×
861
    case TSDB_DATA_TYPE_MEDIUMBLOB:
×
862
      return "TSDB_DATA_TYPE_MEDIUMBLOB";
×
863
    default:
×
864
      return "UNKNOWN";
×
865
  }
866
}
867

868
const char *taos_get_client_info() { return td_version; }
14,418✔
869

870
// return int32_t
871
int taos_affected_rows(TAOS_RES *res) {
1,581,297✔
872
  if (res == NULL || TD_RES_TMQ_RAW(res) || TD_RES_TMQ(res) || TD_RES_TMQ_META(res) || TD_RES_TMQ_METADATA(res) ||
1,581,297!
873
      TD_RES_TMQ_BATCH_META(res)) {
1,581,326✔
874
    return 0;
×
875
  }
876

877
  SRequestObj    *pRequest = (SRequestObj *)res;
1,581,325✔
878
  SReqResultInfo *pResInfo = &pRequest->body.resInfo;
1,581,325✔
879
  return (int)pResInfo->numOfRows;
1,581,325✔
880
}
881

882
// return int64_t
883
int64_t taos_affected_rows64(TAOS_RES *res) {
125,198✔
884
  if (res == NULL || TD_RES_TMQ_RAW(res) || TD_RES_TMQ(res) || TD_RES_TMQ_META(res) || TD_RES_TMQ_METADATA(res) ||
125,198!
885
      TD_RES_TMQ_BATCH_META(res)) {
125,198!
886
    return 0;
×
887
  }
888

889
  SRequestObj    *pRequest = (SRequestObj *)res;
125,198✔
890
  SReqResultInfo *pResInfo = &pRequest->body.resInfo;
125,198✔
891
  return pResInfo->numOfRows;
125,198✔
892
}
893

894
int taos_result_precision(TAOS_RES *res) {
16,415,483✔
895
  if (res == NULL || TD_RES_TMQ_RAW(res) || TD_RES_TMQ_META(res) || TD_RES_TMQ_BATCH_META(res)) {
16,415,483!
896
    return TSDB_TIME_PRECISION_MILLI;
×
897
  }
898

899
  if (TD_RES_QUERY(res)) {
16,415,514✔
900
    SRequestObj *pRequest = (SRequestObj *)res;
1,028,595✔
901
    return pRequest->body.resInfo.precision;
1,028,595✔
902
  } else if (TD_RES_TMQ(res) || TD_RES_TMQ_METADATA(res)) {
15,386,919!
903
    SReqResultInfo *info = tmqGetCurResInfo(res);
15,386,919✔
904
    return info->precision;
15,386,919✔
905
  }
906
  return TSDB_TIME_PRECISION_MILLI;
×
907
}
908

909
int taos_select_db(TAOS *taos, const char *db) {
512✔
910
  STscObj *pObj = acquireTscObj(*(int64_t *)taos);
512✔
911
  if (pObj == NULL) {
512!
912
    releaseTscObj(*(int64_t *)taos);
×
913
    terrno = TSDB_CODE_TSC_DISCONNECTED;
×
914
    return TSDB_CODE_TSC_DISCONNECTED;
×
915
  }
916

917
  if (db == NULL || strlen(db) == 0) {
512!
918
    releaseTscObj(*(int64_t *)taos);
×
919
    tscError("invalid parameter for %s", db == NULL ? "db is NULL" : "db is empty");
×
920
    terrno = TSDB_CODE_TSC_INVALID_INPUT;
×
921
    return terrno;
×
922
  }
923

924
  char sql[256] = {0};
512✔
925
  (void)snprintf(sql, tListLen(sql), "use %s", db);
512✔
926

927
  TAOS_RES *pRequest = taos_query(taos, sql);
512✔
928
  int32_t   code = taos_errno(pRequest);
512✔
929

930
  taos_free_result(pRequest);
512✔
931
  releaseTscObj(*(int64_t *)taos);
512✔
932
  return code;
512✔
933
}
934

935
void taos_stop_query(TAOS_RES *res) {
11,157,059✔
936
  if (res == NULL || TD_RES_TMQ_RAW(res) || TD_RES_TMQ(res) || TD_RES_TMQ_META(res) || TD_RES_TMQ_METADATA(res) ||
11,157,059!
937
      TD_RES_TMQ_BATCH_META(res)) {
11,167,902!
938
    return;
×
939
  }
940

941
  stopAllQueries((SRequestObj *)res);
11,169,064✔
942
}
943

944
bool taos_is_null(TAOS_RES *res, int32_t row, int32_t col) {
320,548,336✔
945
  if (res == NULL || TD_RES_TMQ_RAW(res) || TD_RES_TMQ_META(res) || TD_RES_TMQ_BATCH_META(res)) {
320,548,336!
946
    return true;
×
947
  }
948
  SReqResultInfo *pResultInfo = tscGetCurResInfo(res);
320,548,339✔
949
  if (col >= pResultInfo->numOfCols || col < 0 || row >= pResultInfo->numOfRows || row < 0) {
320,548,339!
950
    return true;
3✔
951
  }
952

953
  SResultColumn *pCol = &pResultInfo->pCol[col];
320,548,336✔
954
  if (IS_VAR_DATA_TYPE(pResultInfo->fields[col].type)) {
320,548,336!
955
    return (pCol->offset[row] == -1);
16✔
956
  } else {
957
    return colDataIsNull_f(pCol->nullbitmap, row);
320,548,320✔
958
  }
959
}
960

961
bool taos_is_update_query(TAOS_RES *res) { return taos_num_fields(res) == 0; }
9,736✔
962

963
int taos_fetch_block(TAOS_RES *res, TAOS_ROW *rows) {
1,303,613✔
964
  int32_t numOfRows = 0;
1,303,613✔
965
  /*int32_t code = */ terrno = taos_fetch_block_s(res, &numOfRows, rows);
1,303,613✔
966
  return numOfRows;
1,303,612✔
967
}
968

969
int taos_fetch_block_s(TAOS_RES *res, int *numOfRows, TAOS_ROW *rows) {
1,303,613✔
970
  if (res == NULL || TD_RES_TMQ_RAW(res) || TD_RES_TMQ_META(res) || TD_RES_TMQ_BATCH_META(res)) {
1,303,613!
971
    return 0;
×
972
  }
973

974
  if (TD_RES_QUERY(res)) {
1,303,613✔
975
    SRequestObj *pRequest = (SRequestObj *)res;
1,299,599✔
976

977
    (*rows) = NULL;
1,299,599✔
978
    (*numOfRows) = 0;
1,299,599✔
979

980
    if (pRequest->type == TSDB_SQL_RETRIEVE_EMPTY_RESULT || pRequest->type == TSDB_SQL_INSERT ||
1,299,599!
981
        pRequest->code != TSDB_CODE_SUCCESS || taos_num_fields(res) == 0) {
1,297,073!
982
      return pRequest->code;
6,131✔
983
    }
984

985
    (void)doAsyncFetchRows(pRequest, false, true);
1,293,468✔
986

987
    // TODO refactor
988
    SReqResultInfo *pResultInfo = &pRequest->body.resInfo;
1,293,467✔
989
    pResultInfo->current = pResultInfo->numOfRows;
1,293,467✔
990

991
    (*rows) = pResultInfo->row;
1,293,467✔
992
    (*numOfRows) = pResultInfo->numOfRows;
1,293,467✔
993
    return pRequest->code;
1,293,467✔
994
  } else if (TD_RES_TMQ(res) || TD_RES_TMQ_METADATA(res)) {
4,014!
995
    SReqResultInfo *pResultInfo = NULL;
4,014✔
996
    int32_t         code = tmqGetNextResInfo(res, true, &pResultInfo);
4,014✔
997
    if (code != 0) return code;
4,014✔
998

999
    pResultInfo->current = pResultInfo->numOfRows;
3,587✔
1000
    (*rows) = pResultInfo->row;
3,587✔
1001
    (*numOfRows) = pResultInfo->numOfRows;
3,587✔
1002
    return 0;
3,587✔
1003
  } else {
1004
    tscError("taos_fetch_block_s invalid res type");
×
1005
    return TSDB_CODE_TMQ_INVALID_DATA;
×
1006
  }
1007
}
1008

1009
int taos_fetch_raw_block(TAOS_RES *res, int *numOfRows, void **pData) {
855✔
1010
  *numOfRows = 0;
855✔
1011
  *pData = NULL;
855✔
1012

1013
  if (res == NULL || TD_RES_TMQ_RAW(res) || TD_RES_TMQ_META(res) || TD_RES_TMQ_BATCH_META(res)) {
855!
1014
    return 0;
×
1015
  }
1016

1017
  if (TD_RES_TMQ(res) || TD_RES_TMQ_METADATA(res)) {
855!
1018
    SReqResultInfo *pResultInfo = NULL;
133✔
1019
    int32_t         code = tmqGetNextResInfo(res, false, &pResultInfo);
133✔
1020
    if (code != 0) {
133✔
1021
      (*numOfRows) = 0;
3✔
1022
      return 0;
3✔
1023
    }
1024

1025
    pResultInfo->current = pResultInfo->numOfRows;
130✔
1026
    (*numOfRows) = pResultInfo->numOfRows;
130✔
1027
    (*pData) = (void *)pResultInfo->pData;
130✔
1028
    return 0;
130✔
1029
  }
1030

1031
  SRequestObj *pRequest = (SRequestObj *)res;
722✔
1032

1033
  if (pRequest->type == TSDB_SQL_RETRIEVE_EMPTY_RESULT || pRequest->type == TSDB_SQL_INSERT ||
722!
1034
      pRequest->code != TSDB_CODE_SUCCESS || taos_num_fields(res) == 0) {
718!
1035
    return pRequest->code;
4✔
1036
  }
1037

1038
  (void)doAsyncFetchRows(pRequest, false, false);
718✔
1039

1040
  SReqResultInfo *pResultInfo = &pRequest->body.resInfo;
718✔
1041

1042
  pResultInfo->current = pResultInfo->numOfRows;
718✔
1043
  (*numOfRows) = pResultInfo->numOfRows;
718✔
1044
  (*pData) = (void *)pResultInfo->pData;
718✔
1045

1046
  return pRequest->code;
718✔
1047
}
1048

1049
int *taos_get_column_data_offset(TAOS_RES *res, int columnIndex) {
526,974✔
1050
  if (res == NULL || TD_RES_TMQ_RAW(res) || TD_RES_TMQ_META(res) || TD_RES_TMQ_BATCH_META(res)) {
526,974!
1051
    return 0;
×
1052
  }
1053

1054
  int32_t numOfFields = taos_num_fields(res);
526,974✔
1055
  if (columnIndex < 0 || columnIndex >= numOfFields || numOfFields == 0) {
526,974!
1056
    return 0;
×
1057
  }
1058

1059
  SReqResultInfo *pResInfo = tscGetCurResInfo(res);
526,974✔
1060
  TAOS_FIELD     *pField = &pResInfo->userFields[columnIndex];
526,974✔
1061
  if (!IS_VAR_DATA_TYPE(pField->type)) {
526,974!
1062
    return 0;
×
1063
  }
1064

1065
  return pResInfo->pCol[columnIndex].offset;
526,974✔
1066
}
1067

1068
int taos_is_null_by_column(TAOS_RES *res, int columnIndex, bool result[], int *rows) {
×
1069
  if (res == NULL || result == NULL || rows == NULL || *rows <= 0 || columnIndex < 0 || TD_RES_TMQ_META(res) ||
×
1070
      TD_RES_TMQ_RAW(res) || TD_RES_TMQ_BATCH_META(res)) {
×
1071
    return TSDB_CODE_INVALID_PARA;
×
1072
  }
1073

1074
  int32_t numOfFields = taos_num_fields(res);
×
1075
  if (columnIndex >= numOfFields || numOfFields == 0) {
×
1076
    return TSDB_CODE_INVALID_PARA;
×
1077
  }
1078

1079
  SReqResultInfo *pResInfo = tscGetCurResInfo(res);
×
1080
  TAOS_FIELD     *pField = &pResInfo->userFields[columnIndex];
×
1081
  SResultColumn  *pCol = &pResInfo->pCol[columnIndex];
×
1082

1083
  if (*rows > pResInfo->numOfRows) {
×
1084
    *rows = pResInfo->numOfRows;
×
1085
  }
1086
  if (IS_VAR_DATA_TYPE(pField->type)) {
×
1087
    for (int i = 0; i < *rows; i++) {
×
1088
      if (pCol->offset[i] == -1) {
×
1089
        result[i] = true;
×
1090
      } else {
1091
        result[i] = false;
×
1092
      }
1093
    }
1094
  } else {
1095
    for (int i = 0; i < *rows; i++) {
×
1096
      if (colDataIsNull_f(pCol->nullbitmap, i)) {
×
1097
        result[i] = true;
×
1098
      } else {
1099
        result[i] = false;
×
1100
      }
1101
    }
1102
  }
1103
  return 0;
×
1104
}
1105

1106
int taos_validate_sql(TAOS *taos, const char *sql) {
×
1107
  TAOS_RES *pObj = taosQueryImpl(taos, sql, true, TD_REQ_FROM_APP);
×
1108

1109
  int code = taos_errno(pObj);
×
1110

1111
  taos_free_result(pObj);
×
1112
  return code;
×
1113
}
1114

1115
void taos_reset_current_db(TAOS *taos) {
×
1116
  STscObj *pTscObj = acquireTscObj(*(int64_t *)taos);
×
1117
  if (pTscObj == NULL) {
×
1118
    terrno = TSDB_CODE_TSC_DISCONNECTED;
×
1119
    return;
×
1120
  }
1121

1122
  resetConnectDB(pTscObj);
×
1123

1124
  releaseTscObj(*(int64_t *)taos);
×
1125
}
1126

1127
const char *taos_get_server_info(TAOS *taos) {
156✔
1128
  STscObj *pTscObj = acquireTscObj(*(int64_t *)taos);
156✔
1129
  if (pTscObj == NULL) {
156!
1130
    terrno = TSDB_CODE_TSC_DISCONNECTED;
×
1131
    return NULL;
×
1132
  }
1133

1134
  releaseTscObj(*(int64_t *)taos);
156✔
1135

1136
  return pTscObj->sDetailVer;
156✔
1137
}
1138

1139
int taos_get_current_db(TAOS *taos, char *database, int len, int *required) {
4✔
1140
  STscObj *pTscObj = acquireTscObj(*(int64_t *)taos);
4✔
1141
  if (pTscObj == NULL) {
4!
1142
    return TSDB_CODE_TSC_DISCONNECTED;
×
1143
  }
1144

1145
  int code = TSDB_CODE_SUCCESS;
4✔
1146
  (void)taosThreadMutexLock(&pTscObj->mutex);
4✔
1147
  if (database == NULL || len <= 0) {
4!
1148
    if (required != NULL) *required = strlen(pTscObj->db) + 1;
2✔
1149
    TSC_ERR_JRET(TSDB_CODE_INVALID_PARA);
2!
1150
  } else if (len < strlen(pTscObj->db) + 1) {
2✔
1151
    tstrncpy(database, pTscObj->db, len);
1✔
1152
    if (required) *required = strlen(pTscObj->db) + 1;
1!
1153
    TSC_ERR_JRET(TSDB_CODE_INVALID_PARA);
1!
1154
  } else {
1155
    tstrncpy(database, pTscObj->db, len);
1✔
1156
    code = 0;
1✔
1157
  }
1158
_return:
4✔
1159
  (void)taosThreadMutexUnlock(&pTscObj->mutex);
4✔
1160
  releaseTscObj(*(int64_t *)taos);
4✔
1161
  return code;
4✔
1162
}
1163

1164
void destorySqlCallbackWrapper(SSqlCallbackWrapper *pWrapper) {
22,250,186✔
1165
  if (NULL == pWrapper) {
22,250,186✔
1166
    return;
11,168,462✔
1167
  }
1168
  destoryCatalogReq(pWrapper->pCatalogReq);
11,081,724✔
1169
  taosMemoryFree(pWrapper->pCatalogReq);
11,096,722!
1170
  qDestroyParseContext(pWrapper->pParseCtx);
11,117,243✔
1171
  taosMemoryFree(pWrapper);
11,115,690!
1172
}
1173

1174
void destroyCtxInRequest(SRequestObj *pRequest) {
14,984✔
1175
  schedulerFreeJob(&pRequest->body.queryJob, 0);
14,984✔
1176
  qDestroyQuery(pRequest->pQuery);
14,984✔
1177
  pRequest->pQuery = NULL;
14,984✔
1178
  destorySqlCallbackWrapper(pRequest->pWrapper);
14,984✔
1179
  pRequest->pWrapper = NULL;
14,984✔
1180
}
14,984✔
1181

1182
static void doAsyncQueryFromAnalyse(SMetaData *pResultMeta, void *param, int32_t code) {
1,432,532✔
1183
  SSqlCallbackWrapper *pWrapper = (SSqlCallbackWrapper *)param;
1,432,532✔
1184
  SRequestObj         *pRequest = pWrapper->pRequest;
1,432,532✔
1185
  SQuery              *pQuery = pRequest->pQuery;
1,432,532✔
1186

1187
  qDebug("req:0x%" PRIx64 ", start to semantic analysis, QID:0x%" PRIx64, pRequest->self, pRequest->requestId);
1,432,532✔
1188

1189
  int64_t analyseStart = taosGetTimestampUs();
1,432,532✔
1190
  pRequest->metric.ctgCostUs = analyseStart - pRequest->metric.ctgStart;
1,432,532✔
1191
  pWrapper->pParseCtx->parseOnly = pRequest->parseOnly;
1,432,532✔
1192

1193
  if (TSDB_CODE_SUCCESS == code) {
1,432,532✔
1194
    code = qAnalyseSqlSemantic(pWrapper->pParseCtx, pWrapper->pCatalogReq, pResultMeta, pQuery);
1,432,513✔
1195
  }
1196

1197
  pRequest->metric.analyseCostUs += taosGetTimestampUs() - analyseStart;
1,432,449✔
1198

1199
  if (pRequest->parseOnly) {
1,432,449✔
1200
    (void)memcpy(&pRequest->parseMeta, pResultMeta, sizeof(*pResultMeta));
639✔
1201
    (void)memset(pResultMeta, 0, sizeof(*pResultMeta));
639✔
1202
  }
1203

1204
  handleQueryAnslyseRes(pWrapper, pResultMeta, code);
1,432,449✔
1205
}
1,432,447✔
1206

1207
int32_t cloneCatalogReq(SCatalogReq **ppTarget, SCatalogReq *pSrc) {
509✔
1208
  int32_t      code = TSDB_CODE_SUCCESS;
509✔
1209
  SCatalogReq *pTarget = taosMemoryCalloc(1, sizeof(SCatalogReq));
509!
1210
  if (pTarget == NULL) {
509!
1211
    code = terrno;
×
1212
  } else {
1213
    pTarget->pDbVgroup = taosArrayDup(pSrc->pDbVgroup, NULL);
509✔
1214
    pTarget->pDbCfg = taosArrayDup(pSrc->pDbCfg, NULL);
509✔
1215
    pTarget->pDbInfo = taosArrayDup(pSrc->pDbInfo, NULL);
509✔
1216
    pTarget->pTableMeta = taosArrayDup(pSrc->pTableMeta, NULL);
509✔
1217
    pTarget->pTableHash = taosArrayDup(pSrc->pTableHash, NULL);
509✔
1218
    pTarget->pUdf = taosArrayDup(pSrc->pUdf, NULL);
509✔
1219
    pTarget->pIndex = taosArrayDup(pSrc->pIndex, NULL);
509✔
1220
    pTarget->pUser = taosArrayDup(pSrc->pUser, NULL);
509✔
1221
    pTarget->pTableIndex = taosArrayDup(pSrc->pTableIndex, NULL);
509✔
1222
    pTarget->pTableCfg = taosArrayDup(pSrc->pTableCfg, NULL);
509✔
1223
    pTarget->pTableTag = taosArrayDup(pSrc->pTableTag, NULL);
509✔
1224
    pTarget->pView = taosArrayDup(pSrc->pView, NULL);
509✔
1225
    pTarget->pTableTSMAs = taosArrayDup(pSrc->pTableTSMAs, NULL);
509✔
1226
    pTarget->pTSMAs = taosArrayDup(pSrc->pTSMAs, NULL);
509✔
1227
    pTarget->qNodeRequired = pSrc->qNodeRequired;
509✔
1228
    pTarget->dNodeRequired = pSrc->dNodeRequired;
509✔
1229
    pTarget->svrVerRequired = pSrc->svrVerRequired;
509✔
1230
    pTarget->forceUpdate = pSrc->forceUpdate;
509✔
1231
    pTarget->cloned = true;
509✔
1232

1233
    *ppTarget = pTarget;
509✔
1234
  }
1235

1236
  return code;
509✔
1237
}
1238

1239
void handleSubQueryFromAnalyse(SSqlCallbackWrapper *pWrapper, SMetaData *pResultMeta, SNode *pRoot) {
509✔
1240
  SRequestObj         *pNewRequest = NULL;
509✔
1241
  SSqlCallbackWrapper *pNewWrapper = NULL;
509✔
1242
  int32_t              code = buildPreviousRequest(pWrapper->pRequest, pWrapper->pRequest->sqlstr, &pNewRequest);
509✔
1243
  if (code) {
509!
1244
    handleQueryAnslyseRes(pWrapper, pResultMeta, code);
×
1245
    return;
×
1246
  }
1247

1248
  pNewRequest->pQuery = NULL;
509✔
1249
  code = nodesMakeNode(QUERY_NODE_QUERY, (SNode **)&pNewRequest->pQuery);
509✔
1250
  if (pNewRequest->pQuery) {
509!
1251
    pNewRequest->pQuery->pRoot = pRoot;
509✔
1252
    pRoot = NULL;
509✔
1253
    pNewRequest->pQuery->execStage = QUERY_EXEC_STAGE_ANALYSE;
509✔
1254
  }
1255
  if (TSDB_CODE_SUCCESS == code) {
509!
1256
    code = prepareAndParseSqlSyntax(&pNewWrapper, pNewRequest, false);
509✔
1257
  }
1258
  if (TSDB_CODE_SUCCESS == code) {
509!
1259
    code = cloneCatalogReq(&pNewWrapper->pCatalogReq, pWrapper->pCatalogReq);
509✔
1260
  }
1261
  if (TSDB_CODE_SUCCESS == code) {
509!
1262
    doAsyncQueryFromAnalyse(pResultMeta, pNewWrapper, code);
509✔
1263
    nodesDestroyNode(pRoot);
509✔
1264
  } else {
1265
    handleQueryAnslyseRes(pWrapper, pResultMeta, code);
×
1266
    return;
×
1267
  }
1268
}
1269

1270
void handleQueryAnslyseRes(SSqlCallbackWrapper *pWrapper, SMetaData *pResultMeta, int32_t code) {
1,432,890✔
1271
  SRequestObj *pRequest = pWrapper->pRequest;
1,432,890✔
1272
  SQuery      *pQuery = pRequest->pQuery;
1,432,890✔
1273

1274
  if (code == TSDB_CODE_SUCCESS && pQuery->pPrevRoot) {
1,432,890✔
1275
    SNode *prevRoot = pQuery->pPrevRoot;
509✔
1276
    pQuery->pPrevRoot = NULL;
509✔
1277
    handleSubQueryFromAnalyse(pWrapper, pResultMeta, prevRoot);
509✔
1278
    return;
509✔
1279
  }
1280

1281
  if (code == TSDB_CODE_SUCCESS) {
1,432,381✔
1282
    pRequest->stableQuery = pQuery->stableQuery;
1,358,559✔
1283
    if (pQuery->pRoot) {
1,358,559!
1284
      pRequest->stmtType = pQuery->pRoot->type;
1,358,566✔
1285
    }
1286

1287
    if (pQuery->haveResultSet) {
1,358,559✔
1288
      code = setResSchemaInfo(&pRequest->body.resInfo, pQuery->pResSchema, pQuery->numOfResCols, pQuery->pResExtSchema, pRequest->isStmtBind);
1,079,490✔
1289
      setResPrecision(&pRequest->body.resInfo, pQuery->precision);
1,079,494✔
1290
    }
1291
  }
1292

1293
  if (code == TSDB_CODE_SUCCESS) {
1,432,446✔
1294
    TSWAP(pRequest->dbList, (pQuery)->pDbList);
1,358,536✔
1295
    TSWAP(pRequest->tableList, (pQuery)->pTableList);
1,358,536✔
1296
    TSWAP(pRequest->targetTableList, (pQuery)->pTargetTableList);
1,358,536✔
1297

1298
    launchAsyncQuery(pRequest, pQuery, pResultMeta, pWrapper);
1,358,536✔
1299
  } else {
1300
    destorySqlCallbackWrapper(pWrapper);
73,910✔
1301
    pRequest->pWrapper = NULL;
73,910✔
1302
    qDestroyQuery(pRequest->pQuery);
73,910✔
1303
    pRequest->pQuery = NULL;
73,910✔
1304

1305
    if (NEED_CLIENT_HANDLE_ERROR(code)) {
73,910!
1306
      tscDebug("req:0x%" PRIx64 ", client retry to handle the error, code:%d - %s, tryCount:%d, QID:0x%" PRIx64,
14,665✔
1307
               pRequest->self, code, tstrerror(code), pRequest->retry, pRequest->requestId);
1308
      restartAsyncQuery(pRequest, code);
14,665✔
1309
      return;
14,665✔
1310
    }
1311

1312
    // return to app directly
1313
    tscError("req:0x%" PRIx64 ", error occurs, code:%s, return to user app, QID:0x%" PRIx64, pRequest->self, tstrerror(code),
59,245!
1314
             pRequest->requestId);
1315
    pRequest->code = code;
59,245✔
1316
    returnToUser(pRequest);
59,245✔
1317
  }
1318
}
1319

1320
static int32_t getAllMetaAsync(SSqlCallbackWrapper *pWrapper, catalogCallback fp) {
1,579,886✔
1321
  SRequestConnInfo conn = {.pTrans = pWrapper->pParseCtx->pTransporter,
1,579,886✔
1322
                           .requestId = pWrapper->pParseCtx->requestId,
1,579,886✔
1323
                           .requestObjRefId = pWrapper->pParseCtx->requestRid,
1,579,886✔
1324
                           .mgmtEps = pWrapper->pParseCtx->mgmtEpSet};
1,579,886✔
1325

1326
  pWrapper->pRequest->metric.ctgStart = taosGetTimestampUs();
1,579,886✔
1327

1328
  return catalogAsyncGetAllMeta(pWrapper->pParseCtx->pCatalog, &conn, pWrapper->pCatalogReq, fp, pWrapper,
3,159,936✔
1329
                                &pWrapper->pRequest->body.queryJob);
1,579,995✔
1330
}
1331

1332
static void doAsyncQueryFromParse(SMetaData *pResultMeta, void *param, int32_t code);
1333

1334
static int32_t phaseAsyncQuery(SSqlCallbackWrapper *pWrapper) {
11,153,690✔
1335
  int32_t code = TSDB_CODE_SUCCESS;
11,153,690✔
1336
  switch (pWrapper->pRequest->pQuery->execStage) {
11,153,690!
1337
    case QUERY_EXEC_STAGE_PARSE: {
147,981✔
1338
      // continue parse after get metadata
1339
      code = getAllMetaAsync(pWrapper, doAsyncQueryFromParse);
147,981✔
1340
      break;
147,987✔
1341
    }
1342
    case QUERY_EXEC_STAGE_ANALYSE: {
1,431,972✔
1343
      // analysis after get metadata
1344
      code = getAllMetaAsync(pWrapper, doAsyncQueryFromAnalyse);
1,431,972✔
1345
      break;
1,431,946✔
1346
    }
1347
    case QUERY_EXEC_STAGE_SCHEDULE: {
9,589,903✔
1348
      launchAsyncQuery(pWrapper->pRequest, pWrapper->pRequest->pQuery, NULL, pWrapper);
9,589,903✔
1349
      break;
9,605,685✔
1350
    }
1351
    default:
×
1352
      break;
×
1353
  }
1354
  return code;
11,169,452✔
1355
}
1356

1357
static void doAsyncQueryFromParse(SMetaData *pResultMeta, void *param, int32_t code) {
147,991✔
1358
  SSqlCallbackWrapper *pWrapper = (SSqlCallbackWrapper *)param;
147,991✔
1359
  SRequestObj         *pRequest = pWrapper->pRequest;
147,991✔
1360
  SQuery              *pQuery = pRequest->pQuery;
147,991✔
1361

1362
  pRequest->metric.ctgCostUs += taosGetTimestampUs() - pRequest->metric.ctgStart;
147,990✔
1363
  qDebug("req:0x%" PRIx64 ", continue parse query, QID:0x%" PRIx64 ", code:%s", pRequest->self, pRequest->requestId,
147,990✔
1364
         tstrerror(code));
1365

1366
  if (code == TSDB_CODE_SUCCESS) {
147,990✔
1367
    // pWrapper->pCatalogReq->forceUpdate = false;
1368
    code = qContinueParseSql(pWrapper->pParseCtx, pWrapper->pCatalogReq, pResultMeta, pQuery);
147,744✔
1369
  }
1370

1371
  if (TSDB_CODE_SUCCESS == code) {
147,980✔
1372
    code = phaseAsyncQuery(pWrapper);
146,274✔
1373
  }
1374

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

1386
void continueInsertFromCsv(SSqlCallbackWrapper *pWrapper, SRequestObj *pRequest) {
2✔
1387
  int32_t code = qParseSqlSyntax(pWrapper->pParseCtx, &pRequest->pQuery, pWrapper->pCatalogReq);
2✔
1388
  if (TSDB_CODE_SUCCESS == code) {
2!
1389
    code = phaseAsyncQuery(pWrapper);
2✔
1390
  }
1391

1392
  if (TSDB_CODE_SUCCESS != code) {
2!
1393
    tscError("req:0x%" PRIx64 ", error happens, code:%d - %s, QID:0x%" PRIx64, pWrapper->pRequest->self, code,
×
1394
             tstrerror(code), pWrapper->pRequest->requestId);
1395
    destorySqlCallbackWrapper(pWrapper);
×
1396
    pRequest->pWrapper = NULL;
×
1397
    terrno = code;
×
1398
    pRequest->code = code;
×
1399
    doRequestCallback(pRequest, code);
×
1400
  }
1401
}
2✔
1402

1403
void taos_query_a(TAOS *taos, const char *sql, __taos_async_fn_t fp, void *param) {
522✔
1404
  int64_t connId = *(int64_t *)taos;
522✔
1405
  taosAsyncQueryImpl(connId, sql, fp, param, false, TD_REQ_FROM_APP);
522✔
1406
}
522✔
1407

1408
void taos_query_a_with_reqid(TAOS *taos, const char *sql, __taos_async_fn_t fp, void *param, int64_t reqid) {
×
1409
  int64_t connId = *(int64_t *)taos;
×
1410
  taosAsyncQueryImplWithReqid(connId, sql, fp, param, false, reqid);
×
1411
}
×
1412

1413
int32_t createParseContext(const SRequestObj *pRequest, SParseContext **pCxt, SSqlCallbackWrapper *pWrapper) {
11,101,731✔
1414
  const STscObj *pTscObj = pRequest->pTscObj;
11,101,731✔
1415

1416
  *pCxt = taosMemoryCalloc(1, sizeof(SParseContext));
11,101,731!
1417
  if (*pCxt == NULL) {
11,100,978!
1418
    return terrno;
×
1419
  }
1420

1421
  **pCxt = (SParseContext){.requestId = pRequest->requestId,
11,100,978✔
1422
                           .requestRid = pRequest->self,
11,100,978✔
1423
                           .acctId = pTscObj->acctId,
11,100,978✔
1424
                           .db = pRequest->pDb,
11,100,978✔
1425
                           .topicQuery = false,
1426
                           .pSql = pRequest->sqlstr,
11,100,978✔
1427
                           .sqlLen = pRequest->sqlLen,
11,100,978✔
1428
                           .pMsg = pRequest->msgBuf,
11,100,978✔
1429
                           .msgLen = ERROR_MSG_BUF_DEFAULT_SIZE,
1430
                           .pTransporter = pTscObj->pAppInfo->pTransporter,
11,100,978✔
1431
                           .pStmtCb = NULL,
1432
                           .pUser = pTscObj->user,
11,100,978✔
1433
                           .pEffectiveUser = pRequest->effectiveUser,
11,100,978✔
1434
                           .isSuperUser = (0 == strcmp(pTscObj->user, TSDB_DEFAULT_USER)),
11,100,978✔
1435
                           .enableSysInfo = pTscObj->sysInfo,
11,100,978✔
1436
                           .async = true,
1437
                           .svrVer = pTscObj->sVer,
11,100,978✔
1438
                           .nodeOffline = (pTscObj->pAppInfo->onlineDnodes < pTscObj->pAppInfo->totalDnodes),
11,100,978✔
1439
                           .allocatorId = pRequest->allocatorRefId,
11,100,978✔
1440
                           .parseSqlFp = clientParseSql,
1441
                           .parseSqlParam = pWrapper,
1442
                           .setQueryFp = setQueryRequest,
1443
                           .timezone = pTscObj->optionInfo.timezone,
11,100,978✔
1444
                           .charsetCxt = pTscObj->optionInfo.charsetCxt,
11,100,978✔
1445
                           .streamRunHistory = pRequest->streamRunHistory};
11,100,978✔
1446
  int8_t biMode = atomic_load_8(&((STscObj *)pTscObj)->biMode);
11,100,978✔
1447
  (*pCxt)->biMode = biMode;
11,053,577✔
1448
  return TSDB_CODE_SUCCESS;
11,053,577✔
1449
}
1450

1451
int32_t prepareAndParseSqlSyntax(SSqlCallbackWrapper **ppWrapper, SRequestObj *pRequest, bool updateMetaForce) {
11,093,721✔
1452
  int32_t              code = TSDB_CODE_SUCCESS;
11,093,721✔
1453
  STscObj             *pTscObj = pRequest->pTscObj;
11,093,721✔
1454
  SSqlCallbackWrapper *pWrapper = taosMemoryCalloc(1, sizeof(SSqlCallbackWrapper));
11,093,721!
1455
  if (pWrapper == NULL) {
11,110,001!
1456
    code = terrno;
×
1457
  } else {
1458
    pWrapper->pRequest = pRequest;
11,110,001✔
1459
    pRequest->pWrapper = pWrapper;
11,110,001✔
1460
    *ppWrapper = pWrapper;
11,110,001✔
1461
  }
1462

1463
  if (TSDB_CODE_SUCCESS == code) {
11,110,001!
1464
    code = createParseContext(pRequest, &pWrapper->pParseCtx, pWrapper);
11,110,501✔
1465
  }
1466

1467
  if (TSDB_CODE_SUCCESS == code) {
11,052,911!
1468
    pWrapper->pParseCtx->mgmtEpSet = getEpSet_s(&pTscObj->pAppInfo->mgmtEp);
11,053,612✔
1469
    code = catalogGetHandle(pTscObj->pAppInfo->clusterId, &pWrapper->pParseCtx->pCatalog);
11,118,463✔
1470
  }
1471

1472
  if (TSDB_CODE_SUCCESS == code && NULL == pRequest->pQuery) {
11,087,671✔
1473
    int64_t syntaxStart = taosGetTimestampUs();
11,073,657✔
1474

1475
    pWrapper->pCatalogReq = taosMemoryCalloc(1, sizeof(SCatalogReq));
11,073,657!
1476
    if (pWrapper->pCatalogReq == NULL) {
11,110,010!
1477
      code = terrno;
×
1478
    } else {
1479
      pWrapper->pCatalogReq->forceUpdate = updateMetaForce;
11,110,010✔
1480
      TSC_ERR_RET(qnodeRequired(pRequest, &pWrapper->pCatalogReq->qNodeRequired));
11,110,010!
1481
      code = qParseSqlSyntax(pWrapper->pParseCtx, &pRequest->pQuery, pWrapper->pCatalogReq);
11,108,994✔
1482
    }
1483

1484
    pRequest->metric.parseCostUs += taosGetTimestampUs() - syntaxStart;
11,014,479✔
1485
  }
1486

1487
  return code;
11,031,146✔
1488
}
1489

1490
void doAsyncQuery(SRequestObj *pRequest, bool updateMetaForce) {
11,100,325✔
1491
  SSqlCallbackWrapper *pWrapper = NULL;
11,100,325✔
1492
  int32_t              code = TSDB_CODE_SUCCESS;
11,100,325✔
1493

1494
  if (pRequest->retry++ > REQUEST_TOTAL_EXEC_TIMES) {
11,100,325✔
1495
    code = pRequest->prevCode;
4,898✔
1496
    terrno = code;
4,898✔
1497
    pRequest->code = code;
4,898✔
1498
    tscDebug("req:0x%" PRIx64 ", call sync query cb with code:%s", pRequest->self, tstrerror(code));
4,898✔
1499
    doRequestCallback(pRequest, code);
4,898✔
1500
    return;
4,913✔
1501
  }
1502

1503
  if (TSDB_CODE_SUCCESS == code) {
11,095,427!
1504
    code = prepareAndParseSqlSyntax(&pWrapper, pRequest, updateMetaForce);
11,100,424✔
1505
  }
1506

1507
  if (TSDB_CODE_SUCCESS == code) {
11,029,745✔
1508
    pRequest->stmtType = pRequest->pQuery->pRoot->type;
11,016,242✔
1509
    code = phaseAsyncQuery(pWrapper);
11,016,242✔
1510
  }
1511

1512
  if (TSDB_CODE_SUCCESS != code) {
11,053,955✔
1513
    tscError("req:0x%" PRIx64 ", error happens, code:%d - %s, QID:0x%" PRIx64, pRequest->self, code, tstrerror(code),
26,162!
1514
             pRequest->requestId);
1515
    destorySqlCallbackWrapper(pWrapper);
26,163✔
1516
    pRequest->pWrapper = NULL;
26,163✔
1517
    qDestroyQuery(pRequest->pQuery);
26,163✔
1518
    pRequest->pQuery = NULL;
26,163✔
1519

1520
    if (NEED_CLIENT_HANDLE_ERROR(code)) {
26,163!
1521
      tscDebug("req:0x%" PRIx64 ", client retry to handle the error, code:%d - %s, tryCount:%d, QID:0x%" PRIx64,
15!
1522
               pRequest->self, code, tstrerror(code), pRequest->retry, pRequest->requestId);
1523
      code = refreshMeta(pRequest->pTscObj, pRequest);
15✔
1524
      if (code != 0) {
15!
1525
        tscWarn("req:0x%" PRIx64 ", refresh meta failed, code:%d - %s, QID:0x%" PRIx64, pRequest->self, code, tstrerror(code),
15!
1526
                pRequest->requestId);
1527
      }
1528
      pRequest->prevCode = code;
15✔
1529
      doAsyncQuery(pRequest, true);
15✔
1530
      return;
15✔
1531
    }
1532

1533
    terrno = code;
26,148✔
1534
    pRequest->code = code;
26,148✔
1535
    doRequestCallback(pRequest, code);
26,148✔
1536
  }
1537
}
1538

1539
void restartAsyncQuery(SRequestObj *pRequest, int32_t code) {
14,982✔
1540
  tscInfo("restart request:%s p:%p", pRequest->sqlstr, pRequest);
14,982!
1541
  SRequestObj *pUserReq = pRequest;
14,983✔
1542
  (void)acquireRequest(pRequest->self);
14,983✔
1543
  while (pUserReq) {
15,007!
1544
    if (pUserReq->self == pUserReq->relation.userRefId || pUserReq->relation.userRefId == 0) {
15,007!
1545
      break;
1546
    } else {
1547
      int64_t nextRefId = pUserReq->relation.nextRefId;
23✔
1548
      (void)releaseRequest(pUserReq->self);
23✔
1549
      if (nextRefId) {
23!
1550
        pUserReq = acquireRequest(nextRefId);
23✔
1551
      }
1552
    }
1553
  }
1554
  bool hasSubRequest = pUserReq != pRequest || pRequest->relation.prevRefId != 0;
14,984!
1555
  if (pUserReq) {
14,984!
1556
    destroyCtxInRequest(pUserReq);
14,984✔
1557
    pUserReq->prevCode = code;
14,984✔
1558
    (void)memset(&pUserReq->relation, 0, sizeof(pUserReq->relation));
14,984✔
1559
  } else {
1560
    tscError("User req is missing");
×
1561
    (void)removeFromMostPrevReq(pRequest);
×
1562
    return;
×
1563
  }
1564
  if (hasSubRequest)
14,984✔
1565
    (void)removeFromMostPrevReq(pRequest);
23✔
1566
  else
1567
    (void)releaseRequest(pUserReq->self);
14,961✔
1568
  doAsyncQuery(pUserReq, true);
14,984✔
1569
}
1570

1571
typedef struct SAsyncFetchParam {
1572
  SRequestObj      *pReq;
1573
  __taos_async_fn_t fp;
1574
  void             *param;
1575
} SAsyncFetchParam;
1576

1577
static int32_t doAsyncFetch(void *pParam) {
1,111,913✔
1578
  SAsyncFetchParam *param = pParam;
1,111,913✔
1579
  taosAsyncFetchImpl(param->pReq, param->fp, param->param);
1,111,913✔
1580
  taosMemoryFree(param);
1,111,907!
1581
  return TSDB_CODE_SUCCESS;
1,111,907✔
1582
}
1583

1584
void taos_fetch_rows_a(TAOS_RES *res, __taos_async_fn_t fp, void *param) {
1,111,893✔
1585
  if (res == NULL || fp == NULL) {
1,111,893!
1586
    tscError("taos_fetch_rows_a invalid paras");
×
1587
    return;
×
1588
  }
1589
  if (!TD_RES_QUERY(res)) {
1,111,909!
1590
    tscError("taos_fetch_rows_a res is NULL");
×
1591
    fp(param, res, TSDB_CODE_APP_ERROR);
×
1592
    return;
×
1593
  }
1594

1595
  SRequestObj *pRequest = res;
1,111,909✔
1596
  if (TSDB_SQL_RETRIEVE_EMPTY_RESULT == pRequest->type) {
1,111,909✔
1597
    fp(param, res, 0);
5✔
1598
    return;
5✔
1599
  }
1600

1601
  SAsyncFetchParam *pParam = taosMemoryCalloc(1, sizeof(SAsyncFetchParam));
1,111,904!
1602
  if (!pParam) {
1,111,906!
1603
    fp(param, res, terrno);
×
1604
    return;
×
1605
  }
1606
  pParam->pReq = pRequest;
1,111,906✔
1607
  pParam->fp = fp;
1,111,906✔
1608
  pParam->param = param;
1,111,906✔
1609
  int32_t code = taosAsyncExec(doAsyncFetch, pParam, NULL);
1,111,906✔
1610
  if (TSDB_CODE_SUCCESS != code) {
1,111,907!
1611
    taosMemoryFree(pParam);
×
1612
    fp(param, res, code);
×
1613
    return;
×
1614
  }
1615
}
1616

1617
void taos_fetch_raw_block_a(TAOS_RES *res, __taos_async_fn_t fp, void *param) {
4✔
1618
  if (res == NULL || fp == NULL) {
4!
1619
    tscError("taos_fetch_raw_block_a invalid paras");
×
1620
    return;
×
1621
  }
1622
  if (!TD_RES_QUERY(res)) {
4!
1623
    tscError("taos_fetch_raw_block_a res is NULL");
×
1624
    return;
×
1625
  }
1626
  SRequestObj    *pRequest = res;
4✔
1627
  SReqResultInfo *pResultInfo = &pRequest->body.resInfo;
4✔
1628

1629
  // set the current block is all consumed
1630
  pResultInfo->convertUcs4 = false;
4✔
1631

1632
  // it is a local executed query, no need to do async fetch
1633
  taos_fetch_rows_a(pRequest, fp, param);
4✔
1634
}
1635

1636
const void *taos_get_raw_block(TAOS_RES *res) {
×
1637
  if (res == NULL) {
×
1638
    tscError("taos_get_raw_block invalid paras");
×
1639
    return NULL;
×
1640
  }
1641
  if (!TD_RES_QUERY(res)) {
×
1642
    tscError("taos_get_raw_block res is NULL");
×
1643
    return NULL;
×
1644
  }
1645
  SRequestObj *pRequest = res;
×
1646

1647
  return pRequest->body.resInfo.pData;
×
1648
}
1649

1650
int taos_get_db_route_info(TAOS *taos, const char *db, TAOS_DB_ROUTE_INFO *dbInfo) {
2✔
1651
  if (NULL == taos) {
2!
1652
    terrno = TSDB_CODE_TSC_DISCONNECTED;
×
1653
    return terrno;
×
1654
  }
1655

1656
  if (NULL == db || NULL == dbInfo) {
2!
1657
    tscError("invalid input param, db:%p, dbInfo:%p", db, dbInfo);
×
1658
    terrno = TSDB_CODE_TSC_INVALID_INPUT;
×
1659
    return terrno;
×
1660
  }
1661

1662
  int64_t      connId = *(int64_t *)taos;
2✔
1663
  SRequestObj *pRequest = NULL;
2✔
1664
  char        *sql = "taos_get_db_route_info";
2✔
1665
  int32_t      code = buildRequest(connId, sql, strlen(sql), NULL, false, &pRequest, 0);
2✔
1666
  if (code != TSDB_CODE_SUCCESS) {
2!
1667
    terrno = code;
×
1668
    return terrno;
×
1669
  }
1670

1671
  STscObj  *pTscObj = pRequest->pTscObj;
2✔
1672
  SCatalog *pCtg = NULL;
2✔
1673
  code = catalogGetHandle(pTscObj->pAppInfo->clusterId, &pCtg);
2✔
1674
  if (code != TSDB_CODE_SUCCESS) {
2!
1675
    goto _return;
×
1676
  }
1677

1678
  SRequestConnInfo conn = {
2✔
1679
      .pTrans = pTscObj->pAppInfo->pTransporter, .requestId = pRequest->requestId, .requestObjRefId = pRequest->self};
2✔
1680

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

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

1686
  code = catalogGetDBVgInfo(pCtg, &conn, dbFName, dbInfo);
2✔
1687
  if (code) {
2!
1688
    goto _return;
×
1689
  }
1690

1691
_return:
2✔
1692

1693
  terrno = code;
2✔
1694

1695
  destroyRequest(pRequest);
2✔
1696
  return code;
2✔
1697
}
1698

1699
int taos_get_table_vgId(TAOS *taos, const char *db, const char *table, int *vgId) {
200✔
1700
  if (NULL == taos) {
200!
1701
    terrno = TSDB_CODE_TSC_DISCONNECTED;
×
1702
    return terrno;
×
1703
  }
1704

1705
  if (NULL == db || NULL == table || NULL == vgId) {
200!
1706
    tscError("invalid input param, db:%p, table:%p, vgId:%p", db, table, vgId);
×
1707
    terrno = TSDB_CODE_TSC_INVALID_INPUT;
×
1708
    return terrno;
×
1709
  }
1710

1711
  int64_t      connId = *(int64_t *)taos;
200✔
1712
  SRequestObj *pRequest = NULL;
200✔
1713
  char        *sql = "taos_get_table_vgId";
200✔
1714
  int32_t      code = buildRequest(connId, sql, strlen(sql), NULL, false, &pRequest, 0);
200✔
1715
  if (code != TSDB_CODE_SUCCESS) {
200!
1716
    return terrno;
×
1717
  }
1718

1719
  pRequest->syncQuery = true;
200✔
1720

1721
  STscObj  *pTscObj = pRequest->pTscObj;
200✔
1722
  SCatalog *pCtg = NULL;
200✔
1723
  code = catalogGetHandle(pTscObj->pAppInfo->clusterId, &pCtg);
200✔
1724
  if (code != TSDB_CODE_SUCCESS) {
200!
1725
    goto _return;
×
1726
  }
1727

1728
  SRequestConnInfo conn = {
200✔
1729
      .pTrans = pTscObj->pAppInfo->pTransporter, .requestId = pRequest->requestId, .requestObjRefId = pRequest->self};
200✔
1730

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

1733
  SName tableName = {0};
200✔
1734
  toName(pTscObj->acctId, db, table, &tableName);
200✔
1735

1736
  SVgroupInfo vgInfo;
1737
  code = catalogGetTableHashVgroup(pCtg, &conn, &tableName, &vgInfo);
200✔
1738
  if (code) {
200!
1739
    goto _return;
×
1740
  }
1741

1742
  *vgId = vgInfo.vgId;
200✔
1743

1744
_return:
200✔
1745

1746
  terrno = code;
200✔
1747

1748
  destroyRequest(pRequest);
200✔
1749
  return code;
200✔
1750
}
1751

1752
int taos_get_tables_vgId(TAOS *taos, const char *db, const char *table[], int tableNum, int *vgId) {
1✔
1753
  if (NULL == taos) {
1!
1754
    terrno = TSDB_CODE_TSC_DISCONNECTED;
×
1755
    return terrno;
×
1756
  }
1757

1758
  if (NULL == db || NULL == table || NULL == vgId || tableNum <= 0) {
1!
1759
    tscError("invalid input param, db:%p, table:%p, vgId:%p, tbNum:%d", db, table, vgId, tableNum);
×
1760
    terrno = TSDB_CODE_TSC_INVALID_INPUT;
×
1761
    return terrno;
×
1762
  }
1763

1764
  int64_t      connId = *(int64_t *)taos;
1✔
1765
  SRequestObj *pRequest = NULL;
1✔
1766
  char        *sql = "taos_get_table_vgId";
1✔
1767
  int32_t      code = buildRequest(connId, sql, strlen(sql), NULL, false, &pRequest, 0);
1✔
1768
  if (code != TSDB_CODE_SUCCESS) {
1!
1769
    return terrno;
×
1770
  }
1771

1772
  pRequest->syncQuery = true;
1✔
1773

1774
  STscObj  *pTscObj = pRequest->pTscObj;
1✔
1775
  SCatalog *pCtg = NULL;
1✔
1776
  code = catalogGetHandle(pTscObj->pAppInfo->clusterId, &pCtg);
1✔
1777
  if (code != TSDB_CODE_SUCCESS) {
1!
1778
    goto _return;
×
1779
  }
1780

1781
  SRequestConnInfo conn = {
1✔
1782
      .pTrans = pTscObj->pAppInfo->pTransporter, .requestId = pRequest->requestId, .requestObjRefId = pRequest->self};
1✔
1783

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

1786
  code = catalogGetTablesHashVgId(pCtg, &conn, pTscObj->acctId, db, table, tableNum, vgId);
1✔
1787
  if (code) {
1!
1788
    goto _return;
×
1789
  }
1790

1791
_return:
1✔
1792

1793
  terrno = code;
1✔
1794

1795
  destroyRequest(pRequest);
1✔
1796
  return code;
1✔
1797
}
1798

1799
int taos_load_table_info(TAOS *taos, const char *tableNameList) {
4✔
1800
  if (NULL == taos) {
4!
1801
    terrno = TSDB_CODE_TSC_DISCONNECTED;
×
1802
    return terrno;
×
1803
  }
1804

1805
  int64_t       connId = *(int64_t *)taos;
4✔
1806
  const int32_t MAX_TABLE_NAME_LENGTH = 12 * 1024 * 1024;  // 12MB list
4✔
1807
  int32_t       code = 0;
4✔
1808
  SRequestObj  *pRequest = NULL;
4✔
1809
  SCatalogReq   catalogReq = {0};
4✔
1810

1811
  if (NULL == tableNameList) {
4!
1812
    return TSDB_CODE_SUCCESS;
×
1813
  }
1814

1815
  int32_t length = (int32_t)strlen(tableNameList);
4✔
1816
  if (0 == length) {
4!
1817
    return TSDB_CODE_SUCCESS;
×
1818
  } else if (length > MAX_TABLE_NAME_LENGTH) {
4!
1819
    tscError("tableNameList too long, length:%d, maximum allowed:%d", length, MAX_TABLE_NAME_LENGTH);
×
1820
    return TSDB_CODE_TSC_INVALID_OPERATION;
×
1821
  }
1822

1823
  char *sql = "taos_load_table_info";
4✔
1824
  code = buildRequest(connId, sql, strlen(sql), NULL, false, &pRequest, 0);
4✔
1825
  if (code != TSDB_CODE_SUCCESS) {
4!
1826
    terrno = code;
×
1827
    goto _return;
×
1828
  }
1829

1830
  pRequest->syncQuery = true;
4✔
1831

1832
  STscObj *pTscObj = pRequest->pTscObj;
4✔
1833
  code = transferTableNameList(tableNameList, pTscObj->acctId, pTscObj->db, &catalogReq.pTableMeta);
4✔
1834
  if (code) {
4!
1835
    goto _return;
×
1836
  }
1837

1838
  SCatalog *pCtg = NULL;
4✔
1839
  code = catalogGetHandle(pTscObj->pAppInfo->clusterId, &pCtg);
4✔
1840
  if (code != TSDB_CODE_SUCCESS) {
4!
1841
    goto _return;
×
1842
  }
1843

1844
  SRequestConnInfo conn = {
4✔
1845
      .pTrans = pTscObj->pAppInfo->pTransporter, .requestId = pRequest->requestId, .requestObjRefId = pRequest->self};
4✔
1846

1847
  conn.mgmtEps = getEpSet_s(&pTscObj->pAppInfo->mgmtEp);
4✔
1848

1849
  code = catalogAsyncGetAllMeta(pCtg, &conn, &catalogReq, syncCatalogFn, pRequest->body.interParam, NULL);
4✔
1850
  if (code) {
4!
1851
    goto _return;
×
1852
  }
1853

1854
  SSyncQueryParam *pParam = pRequest->body.interParam;
4✔
1855
  code = tsem_wait(&pParam->sem);
4✔
1856
  if (code) {
4!
1857
    tscError("tsem wait failed, code:%d - %s", code, tstrerror(code));
×
1858
    goto _return;
×
1859
  }
1860
_return:
4✔
1861
  destoryCatalogReq(&catalogReq);
4✔
1862
  destroyRequest(pRequest);
4✔
1863
  return code;
4✔
1864
}
1865

1866
TAOS_STMT *taos_stmt_init(TAOS *taos) {
580✔
1867
  STscObj *pObj = acquireTscObj(*(int64_t *)taos);
580✔
1868
  if (NULL == pObj) {
581!
1869
    tscError("invalid parameter for %s", __FUNCTION__);
×
1870
    terrno = TSDB_CODE_TSC_DISCONNECTED;
×
1871
    return NULL;
×
1872
  }
1873

1874
  TAOS_STMT *pStmt = stmtInit(pObj, 0, NULL);
581✔
1875
  if (NULL == pStmt) {
579!
1876
    tscError("stmt init failed, errcode:%s", terrstr());
×
1877
  }
1878
  releaseTscObj(*(int64_t *)taos);
579✔
1879

1880
  return pStmt;
581✔
1881
}
1882

1883
TAOS_STMT *taos_stmt_init_with_reqid(TAOS *taos, int64_t reqid) {
×
1884
  STscObj *pObj = acquireTscObj(*(int64_t *)taos);
×
1885
  if (NULL == pObj) {
×
1886
    tscError("invalid parameter for %s", __FUNCTION__);
×
1887
    terrno = TSDB_CODE_TSC_DISCONNECTED;
×
1888
    return NULL;
×
1889
  }
1890

1891
  TAOS_STMT *pStmt = stmtInit(pObj, reqid, NULL);
×
1892
  if (NULL == pStmt) {
×
1893
    tscError("stmt init failed, errcode:%s", terrstr());
×
1894
  }
1895
  releaseTscObj(*(int64_t *)taos);
×
1896

1897
  return pStmt;
×
1898
}
1899

1900
TAOS_STMT *taos_stmt_init_with_options(TAOS *taos, TAOS_STMT_OPTIONS *options) {
110✔
1901
  STscObj *pObj = acquireTscObj(*(int64_t *)taos);
110✔
1902
  if (NULL == pObj) {
110!
1903
    tscError("invalid parameter for %s", __FUNCTION__);
×
1904
    terrno = TSDB_CODE_TSC_DISCONNECTED;
×
1905
    return NULL;
×
1906
  }
1907

1908
  TAOS_STMT *pStmt = stmtInit(pObj, options->reqId, options);
110✔
1909
  if (NULL == pStmt) {
110!
1910
    tscError("stmt init failed, errcode:%s", terrstr());
×
1911
  }
1912
  releaseTscObj(*(int64_t *)taos);
110✔
1913

1914
  return pStmt;
110✔
1915
}
1916

1917
int taos_stmt_prepare(TAOS_STMT *stmt, const char *sql, unsigned long length) {
20,664✔
1918
  if (stmt == NULL || sql == NULL) {
20,664!
1919
    tscError("NULL parameter for %s", __FUNCTION__);
×
1920
    terrno = TSDB_CODE_INVALID_PARA;
×
1921
    return terrno;
×
1922
  }
1923

1924
  return stmtPrepare(stmt, sql, length);
20,673✔
1925
}
1926

1927
int taos_stmt_set_tbname_tags(TAOS_STMT *stmt, const char *name, TAOS_MULTI_BIND *tags) {
71✔
1928
  if (stmt == NULL || name == NULL) {
71!
1929
    tscError("NULL parameter for %s", __FUNCTION__);
×
1930
    terrno = TSDB_CODE_INVALID_PARA;
×
1931
    return terrno;
×
1932
  }
1933

1934
  int32_t code = stmtSetTbName(stmt, name);
71✔
1935
  if (code) {
71✔
1936
    return code;
2✔
1937
  }
1938

1939
  if (tags) {
69!
1940
    return stmtSetTbTags(stmt, tags);
69✔
1941
  }
1942

1943
  return TSDB_CODE_SUCCESS;
×
1944
}
1945

1946
int taos_stmt_set_tbname(TAOS_STMT *stmt, const char *name) {
79,357✔
1947
  if (stmt == NULL || name == NULL) {
79,357!
1948
    tscError("NULL parameter for %s", __FUNCTION__);
×
1949
    terrno = TSDB_CODE_INVALID_PARA;
×
1950
    return terrno;
×
1951
  }
1952

1953
  return stmtSetTbName(stmt, name);
79,408✔
1954
}
1955

1956
int taos_stmt_set_tags(TAOS_STMT *stmt, TAOS_MULTI_BIND *tags) {
4✔
1957
  if (stmt == NULL || tags == NULL) {
4!
1958
    tscError("NULL parameter for %s", __FUNCTION__);
×
1959
    terrno = TSDB_CODE_INVALID_PARA;
×
1960
    return terrno;
×
1961
  }
1962

1963
  return stmtSetTbTags(stmt, tags);
4✔
1964
}
1965

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

1968
int taos_stmt_get_tag_fields(TAOS_STMT *stmt, int *fieldNum, TAOS_FIELD_E **fields) {
4✔
1969
  if (stmt == NULL || NULL == fieldNum) {
4!
1970
    tscError("NULL parameter for %s", __FUNCTION__);
×
1971
    terrno = TSDB_CODE_INVALID_PARA;
×
1972
    return terrno;
×
1973
  }
1974

1975
  return stmtGetTagFields(stmt, fieldNum, fields);
4✔
1976
}
1977

1978
int taos_stmt_get_col_fields(TAOS_STMT *stmt, int *fieldNum, TAOS_FIELD_E **fields) {
152✔
1979
  if (stmt == NULL || NULL == fieldNum) {
152!
1980
    tscError("NULL parameter for %s", __FUNCTION__);
×
1981
    terrno = TSDB_CODE_INVALID_PARA;
×
1982
    return terrno;
×
1983
  }
1984

1985
  return stmtGetColFields(stmt, fieldNum, fields);
152✔
1986
}
1987

1988
// let stmt to reclaim TAOS_FIELD_E that was allocated by `taos_stmt_get_tag_fields`/`taos_stmt_get_col_fields`
1989
void taos_stmt_reclaim_fields(TAOS_STMT *stmt, TAOS_FIELD_E *fields) {
×
1990
  (void)stmt;
1991
  if (!fields) return;
×
1992
  taosMemoryFree(fields);
×
1993
}
1994

1995
int taos_stmt_bind_param(TAOS_STMT *stmt, TAOS_MULTI_BIND *bind) {
92✔
1996
  if (stmt == NULL || bind == NULL) {
92!
1997
    tscError("NULL parameter for %s", __FUNCTION__);
×
1998
    terrno = TSDB_CODE_INVALID_PARA;
×
1999
    return terrno;
×
2000
  }
2001

2002
  if (bind->num > 1) {
92!
2003
    tscError("invalid bind number %d for %s", bind->num, __FUNCTION__);
×
2004
    terrno = TSDB_CODE_TSC_STMT_BIND_NUMBER_ERROR;
×
2005
    return terrno;
×
2006
  }
2007

2008
  return stmtBindBatch(stmt, bind, -1);
92✔
2009
}
2010

2011
int taos_stmt_bind_param_batch(TAOS_STMT *stmt, TAOS_MULTI_BIND *bind) {
1,094,694✔
2012
  if (stmt == NULL || bind == NULL) {
1,094,694!
2013
    tscError("NULL parameter for %s", __FUNCTION__);
×
2014
    terrno = TSDB_CODE_INVALID_PARA;
×
2015
    return terrno;
×
2016
  }
2017

2018
  if (bind->num <= 0 || bind->num > INT16_MAX) {
1,094,807!
2019
    tscError("invalid bind num %d", bind->num);
×
2020
    terrno = TSDB_CODE_TSC_STMT_BIND_NUMBER_ERROR;
×
2021
    return terrno;
×
2022
  }
2023

2024
  int32_t insert = 0;
1,094,812✔
2025
  int32_t code = stmtIsInsert(stmt, &insert);
1,094,812✔
2026
  if (TSDB_CODE_SUCCESS != code) {
1,092,213!
2027
    tscError("stmt insert failed, errcode:%s", tstrerror(code));
×
2028
    return code;
×
2029
  }
2030
  if (0 == insert && bind->num > 1) {
1,092,213!
2031
    tscError("only one row data allowed for query");
×
2032
    terrno = TSDB_CODE_TSC_STMT_BIND_NUMBER_ERROR;
×
2033
    return terrno;
×
2034
  }
2035

2036
  return stmtBindBatch(stmt, bind, -1);
1,092,213✔
2037
}
2038

2039
int taos_stmt_bind_single_param_batch(TAOS_STMT *stmt, TAOS_MULTI_BIND *bind, int colIdx) {
732✔
2040
  if (stmt == NULL || bind == NULL) {
732!
2041
    tscError("NULL parameter for %s", __FUNCTION__);
×
2042
    terrno = TSDB_CODE_INVALID_PARA;
×
2043
    return terrno;
×
2044
  }
2045

2046
  if (colIdx < 0) {
732!
2047
    tscError("invalid bind column idx %d", colIdx);
×
2048
    terrno = TSDB_CODE_INVALID_PARA;
×
2049
    return terrno;
×
2050
  }
2051

2052
  int32_t insert = 0;
732✔
2053
  int32_t code = stmtIsInsert(stmt, &insert);
732✔
2054
  if (TSDB_CODE_SUCCESS != code) {
732!
2055
    tscError("stmt insert failed, errcode:%s", tstrerror(code));
×
2056
    return code;
×
2057
  }
2058
  if (0 == insert && bind->num > 1) {
732!
2059
    tscError("only one row data allowed for query");
×
2060
    terrno = TSDB_CODE_TSC_STMT_BIND_NUMBER_ERROR;
×
2061
    return terrno;
×
2062
  }
2063

2064
  return stmtBindBatch(stmt, bind, colIdx);
732✔
2065
}
2066

2067
int taos_stmt_add_batch(TAOS_STMT *stmt) {
1,036,230✔
2068
  if (stmt == NULL) {
1,036,230!
2069
    tscError("NULL parameter for %s", __FUNCTION__);
×
2070
    terrno = TSDB_CODE_INVALID_PARA;
×
2071
    return terrno;
×
2072
  }
2073

2074
  return stmtAddBatch(stmt);
1,036,230✔
2075
}
2076

2077
int taos_stmt_execute(TAOS_STMT *stmt) {
46,825✔
2078
  if (stmt == NULL) {
46,825!
2079
    tscError("NULL parameter for %s", __FUNCTION__);
×
2080
    terrno = TSDB_CODE_INVALID_PARA;
×
2081
    return terrno;
×
2082
  }
2083

2084
  return stmtExec(stmt);
46,825✔
2085
}
2086

2087
int taos_stmt_is_insert(TAOS_STMT *stmt, int *insert) {
6✔
2088
  if (stmt == NULL || insert == NULL) {
6!
2089
    tscError("NULL parameter for %s", __FUNCTION__);
×
2090
    terrno = TSDB_CODE_INVALID_PARA;
×
2091
    return terrno;
×
2092
  }
2093

2094
  return stmtIsInsert(stmt, insert);
6✔
2095
}
2096

2097
int taos_stmt_num_params(TAOS_STMT *stmt, int *nums) {
×
2098
  if (stmt == NULL || nums == NULL) {
×
2099
    tscError("NULL parameter for %s", __FUNCTION__);
×
2100
    terrno = TSDB_CODE_INVALID_PARA;
×
2101
    return terrno;
×
2102
  }
2103

2104
  return stmtGetParamNum(stmt, nums);
×
2105
}
2106

2107
int taos_stmt_get_param(TAOS_STMT *stmt, int idx, int *type, int *bytes) {
906✔
2108
  if (stmt == NULL || type == NULL || NULL == bytes || idx < 0) {
906!
2109
    tscError("invalid parameter for %s", __FUNCTION__);
×
2110
    terrno = TSDB_CODE_INVALID_PARA;
×
2111
    return terrno;
×
2112
  }
2113

2114
  return stmtGetParam(stmt, idx, type, bytes);
906✔
2115
}
2116

2117
TAOS_RES *taos_stmt_use_result(TAOS_STMT *stmt) {
2✔
2118
  if (stmt == NULL) {
2!
2119
    tscError("NULL parameter for %s", __FUNCTION__);
×
2120
    terrno = TSDB_CODE_INVALID_PARA;
×
2121
    return NULL;
×
2122
  }
2123

2124
  return stmtUseResult(stmt);
2✔
2125
}
2126

2127
char *taos_stmt_errstr(TAOS_STMT *stmt) { return (char *)stmtErrstr(stmt); }
7✔
2128

2129
int taos_stmt_affected_rows(TAOS_STMT *stmt) {
6✔
2130
  if (stmt == NULL) {
6!
2131
    tscError("NULL parameter for %s", __FUNCTION__);
×
2132
    terrno = TSDB_CODE_INVALID_PARA;
×
2133
    return 0;
×
2134
  }
2135

2136
  return stmtAffectedRows(stmt);
6✔
2137
}
2138

2139
int taos_stmt_affected_rows_once(TAOS_STMT *stmt) {
28✔
2140
  if (stmt == NULL) {
28!
2141
    tscError("NULL parameter for %s", __FUNCTION__);
×
2142
    terrno = TSDB_CODE_INVALID_PARA;
×
2143
    return 0;
×
2144
  }
2145

2146
  return stmtAffectedRowsOnce(stmt);
28✔
2147
}
2148

2149
int taos_stmt_close(TAOS_STMT *stmt) {
688✔
2150
  if (stmt == NULL) {
688!
2151
    tscError("NULL parameter for %s", __FUNCTION__);
×
2152
    terrno = TSDB_CODE_INVALID_PARA;
×
2153
    return terrno;
×
2154
  }
2155

2156
  return stmtClose(stmt);
688✔
2157
}
2158

2159
TAOS_STMT2 *taos_stmt2_init(TAOS *taos, TAOS_STMT2_OPTION *option) {
141✔
2160
  if (NULL == taos) {
141✔
2161
    tscError("NULL parameter for %s", __FUNCTION__);
1!
2162
    terrno = TSDB_CODE_INVALID_PARA;
1✔
2163
    return NULL;
1✔
2164
  }
2165
  STscObj *pObj = acquireTscObj(*(int64_t *)taos);
140✔
2166
  if (NULL == pObj) {
140!
2167
    tscError("invalid parameter for %s", __FUNCTION__);
×
2168
    terrno = TSDB_CODE_TSC_DISCONNECTED;
×
2169
    return NULL;
×
2170
  }
2171

2172
  TAOS_STMT2 *pStmt = stmtInit2(pObj, option);
140✔
2173

2174
  releaseTscObj(*(int64_t *)taos);
140✔
2175

2176
  return pStmt;
140✔
2177
}
2178

2179
int taos_stmt2_prepare(TAOS_STMT2 *stmt, const char *sql, unsigned long length) {
140✔
2180
  if (stmt == NULL || sql == NULL) {
140!
2181
    tscError("NULL parameter for %s", __FUNCTION__);
1!
2182
    terrno = TSDB_CODE_INVALID_PARA;
1✔
2183
    return terrno;
1✔
2184
  }
2185

2186
  return stmtPrepare2(stmt, sql, length);
139✔
2187
}
2188

2189
int taos_stmt2_bind_param(TAOS_STMT2 *stmt, TAOS_STMT2_BINDV *bindv, int32_t col_idx) {
4,445✔
2190
  if (stmt == NULL) {
4,445!
2191
    tscError("NULL parameter for %s", __FUNCTION__);
×
2192
    terrno = TSDB_CODE_INVALID_PARA;
×
2193
    return terrno;
×
2194
  }
2195

2196
  STscStmt2 *pStmt = (STscStmt2 *)stmt;
4,445✔
2197
  if (atomic_load_8((int8_t *)&pStmt->asyncBindParam.asyncBindNum) > 1) {
4,445!
2198
    tscError("async bind param is still working, please try again later");
×
2199
    return TSDB_CODE_TSC_STMT_API_ERROR;
×
2200
  }
2201

2202
  if (pStmt->options.asyncExecFn && !pStmt->execSemWaited) {
4,445!
2203
    if (tsem_wait(&pStmt->asyncExecSem) != 0) {
12!
2204
      tscError("wait asyncExecSem failed");
×
2205
    }
2206
    pStmt->execSemWaited = true;
12✔
2207
  }
2208

2209
  SSHashObj *hashTbnames = tSimpleHashInit(100, taosGetDefaultHashFunction(TSDB_DATA_TYPE_VARCHAR));
4,445✔
2210
  if (NULL == hashTbnames) {
4,447!
2211
    tscError("stmt2 bind failed, %s", tstrerror(terrno));
×
2212
    return terrno;
×
2213
  }
2214

2215
  int32_t code = TSDB_CODE_SUCCESS;
4,447✔
2216
  for (int i = 0; i < bindv->count; ++i) {
10,290✔
2217
    if (bindv->tbnames && bindv->tbnames[i]) {
5,854!
2218
      if (pStmt->sql.stbInterlaceMode) {
5,841✔
2219
        if (tSimpleHashGet(hashTbnames, bindv->tbnames[i], strlen(bindv->tbnames[i])) != NULL) {
5,738!
2220
          code = terrno = TSDB_CODE_PAR_TBNAME_DUPLICATED;
×
2221
          tscError("stmt2 bind failed, %s %s", tstrerror(terrno), bindv->tbnames[i]);
×
2222
          goto out;
5✔
2223
        }
2224

2225
        code = tSimpleHashPut(hashTbnames, bindv->tbnames[i], strlen(bindv->tbnames[i]), NULL, 0);
5,734✔
2226
        if (code) {
5,732!
2227
          goto out;
×
2228
        }
2229
      }
2230

2231
      code = stmtSetTbName2(stmt, bindv->tbnames[i]);
5,835✔
2232
      if (code) {
5,830✔
2233
        goto out;
1✔
2234
      }
2235
    }
2236

2237
    SVCreateTbReq *pCreateTbReq = NULL;
5,842✔
2238
    if (bindv->tags && bindv->tags[i]) {
5,842!
2239
      code = stmtSetTbTags2(stmt, bindv->tags[i], &pCreateTbReq);
112✔
2240
    } else if (pStmt->bInfo.tbNameFlag & IS_FIXED_TAG) {
5,730✔
2241
      code = stmtCheckTags2(stmt, &pCreateTbReq);
11✔
2242
    } else {
2243
      pStmt->sql.autoCreateTbl = false;
5,719✔
2244
    }
2245

2246
    if (code) {
5,837✔
2247
      goto out;
1✔
2248
    }
2249

2250
    if (bindv->bind_cols && bindv->bind_cols[i]) {
5,836!
2251
      TAOS_STMT2_BIND *bind = bindv->bind_cols[i];
5,835✔
2252

2253
      if (bind->num <= 0 || bind->num > INT16_MAX) {
5,835!
2254
        tscError("invalid bind num %d", bind->num);
×
2255
        code = terrno = TSDB_CODE_TSC_STMT_BIND_NUMBER_ERROR;
×
2256
        goto out;
3✔
2257
      }
2258

2259
      int32_t insert = 0;
5,836✔
2260
      (void)stmtIsInsert2(stmt, &insert);
5,836✔
2261
      if (0 == insert && bind->num > 1) {
5,834✔
2262
        tscError("only one row data allowed for query");
1!
2263
        code = terrno = TSDB_CODE_TSC_STMT_BIND_NUMBER_ERROR;
1✔
2264
        goto out;
1✔
2265
      }
2266

2267
      code = stmtBindBatch2(stmt, bind, col_idx, pCreateTbReq);
5,833✔
2268
      if (TSDB_CODE_SUCCESS != code) {
5,844✔
2269
        goto out;
2✔
2270
      }
2271
    }
2272
  }
2273

2274
out:
4,436✔
2275
  tSimpleHashCleanup(hashTbnames);
4,441✔
2276

2277
  return code;
4,450✔
2278
}
2279

2280
int taos_stmt2_bind_param_a(TAOS_STMT2 *stmt, TAOS_STMT2_BINDV *bindv, int32_t col_idx, __taos_async_fn_t fp,
×
2281
                            void *param) {
2282
  if (stmt == NULL || bindv == NULL || fp == NULL) {
×
2283
    terrno = TSDB_CODE_INVALID_PARA;
×
2284
    return terrno;
×
2285
  }
2286

2287
  STscStmt2 *pStmt = (STscStmt2 *)stmt;
×
2288

2289
  ThreadArgs *args = (ThreadArgs *)taosMemoryMalloc(sizeof(ThreadArgs));
×
2290
  args->stmt = stmt;
×
2291
  args->bindv = bindv;
×
2292
  args->col_idx = col_idx;
×
2293
  args->fp = fp;
×
2294
  args->param = param;
×
2295

2296
  (void)taosThreadMutexLock(&(pStmt->asyncBindParam.mutex));
×
2297
  if (atomic_load_8((int8_t *)&pStmt->asyncBindParam.asyncBindNum) > 0) {
×
2298
    (void)taosThreadMutexUnlock(&(pStmt->asyncBindParam.mutex));
×
2299
    tscError("async bind param is still working, please try again later");
×
2300
    return TSDB_CODE_TSC_STMT_API_ERROR;
×
2301
  }
2302
  (void)atomic_add_fetch_8(&pStmt->asyncBindParam.asyncBindNum, 1);
×
2303
  (void)taosThreadMutexUnlock(&(pStmt->asyncBindParam.mutex));
×
2304

2305
  int code_s = taosStmt2AsyncBind(stmtAsyncBindThreadFunc, (void *)args);
×
2306
  if (code_s != TSDB_CODE_SUCCESS) {
×
2307
    (void)taosThreadMutexLock(&(pStmt->asyncBindParam.mutex));
×
2308
    (void)taosThreadCondSignal(&(pStmt->asyncBindParam.waitCond));
×
2309
    (void)atomic_sub_fetch_8(&pStmt->asyncBindParam.asyncBindNum, 1);
×
2310
    (void)taosThreadMutexUnlock(&(pStmt->asyncBindParam.mutex));
×
2311
    tscError("async bind failed, code:%d , %s", code_s, tstrerror(code_s));
×
2312
  }
2313

2314
  return code_s;
×
2315
}
2316

2317
int taos_stmt2_exec(TAOS_STMT2 *stmt, int *affected_rows) {
4,441✔
2318
  if (stmt == NULL) {
4,441!
2319
    tscError("NULL parameter for %s", __FUNCTION__);
×
2320
    terrno = TSDB_CODE_INVALID_PARA;
×
2321
    return terrno;
×
2322
  }
2323

2324
  return stmtExec2(stmt, affected_rows);
4,441✔
2325
}
2326

2327
int taos_stmt2_close(TAOS_STMT2 *stmt) {
138✔
2328
  if (stmt == NULL) {
138!
2329
    tscError("NULL parameter for %s", __FUNCTION__);
×
2330
    terrno = TSDB_CODE_INVALID_PARA;
×
2331
    return terrno;
×
2332
  }
2333

2334
  return stmtClose2(stmt);
138✔
2335
}
2336

2337
int taos_stmt2_is_insert(TAOS_STMT2 *stmt, int *insert) {
×
2338
  if (stmt == NULL || insert == NULL) {
×
2339
    tscError("NULL parameter for %s", __FUNCTION__);
×
2340
    terrno = TSDB_CODE_INVALID_PARA;
×
2341
    return terrno;
×
2342
  }
2343

2344
  return stmtIsInsert2(stmt, insert);
×
2345
}
2346

2347
int taos_stmt2_get_fields(TAOS_STMT2 *stmt, int *count, TAOS_FIELD_ALL **fields) {
57✔
2348
  if (stmt == NULL || count == NULL) {
57!
2349
    tscError("NULL parameter for %s", __FUNCTION__);
1!
2350
    terrno = TSDB_CODE_INVALID_PARA;
1✔
2351
    return terrno;
1✔
2352
  }
2353

2354
  STscStmt2 *pStmt = (STscStmt2 *)stmt;
56✔
2355
  if (pStmt->sql.type == 0) {
56✔
2356
    int isInsert = 0;
49✔
2357
    (void)stmtIsInsert2(stmt, &isInsert);
49✔
2358
    if (!isInsert) {
49✔
2359
      pStmt->sql.type = STMT_TYPE_QUERY;
9✔
2360
    }
2361
  }
2362
  if (pStmt->sql.type == STMT_TYPE_QUERY) {
56✔
2363
    return stmtGetParamNum2(stmt, count);
9✔
2364
  }
2365

2366
  return stmtGetStbColFields2(stmt, count, fields);
47✔
2367
}
2368

2369
DLL_EXPORT void taos_stmt2_free_fields(TAOS_STMT2 *stmt, TAOS_FIELD_ALL *fields) {
46✔
2370
  (void)stmt;
2371
  if (!fields) return;
46✔
2372
  taosMemoryFree(fields);
23!
2373
}
2374

2375
TAOS_RES *taos_stmt2_result(TAOS_STMT2 *stmt) {
3✔
2376
  if (stmt == NULL) {
3!
2377
    tscError("NULL parameter for %s", __FUNCTION__);
×
2378
    terrno = TSDB_CODE_INVALID_PARA;
×
2379
    return NULL;
×
2380
  }
2381

2382
  return stmtUseResult2(stmt);
3✔
2383
}
2384

2385
char *taos_stmt2_error(TAOS_STMT2 *stmt) { return (char *)stmtErrstr2(stmt); }
3✔
2386

2387
int taos_set_conn_mode(TAOS *taos, int mode, int value) {
8✔
2388
  if (taos == NULL) {
8!
2389
    terrno = TSDB_CODE_INVALID_PARA;
×
2390
    return terrno;
×
2391
  }
2392

2393
  STscObj *pObj = acquireTscObj(*(int64_t *)taos);
8✔
2394
  if (NULL == pObj) {
8!
2395
    terrno = TSDB_CODE_TSC_DISCONNECTED;
×
2396
    tscError("invalid parameter for %s", __func__);
×
2397
    return terrno;
×
2398
  }
2399
  switch (mode) {
8!
2400
    case TAOS_CONN_MODE_BI:
8✔
2401
      atomic_store_8(&pObj->biMode, value);
8✔
2402
      break;
8✔
2403
    default:
×
2404
      tscError("not supported mode.");
×
2405
      return TSDB_CODE_INVALID_PARA;
×
2406
  }
2407
  return 0;
8✔
2408
}
2409

2410
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