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

H
hjxilinx 已提交
16
#include "hash.h"
H
hjxilinx 已提交
17
#include "os.h"
H
hjxilinx 已提交
18
#include "qast.h"
H
hzcheng 已提交
19
#include "tcache.h"
H
hjxilinx 已提交
20
#include "tnote.h"
H
hzcheng 已提交
21
#include "trpc.h"
S
slguan 已提交
22
#include "tscLog.h"
H
hzcheng 已提交
23 24
#include "tscProfile.h"
#include "tscSecondaryMerge.h"
H
hjxilinx 已提交
25
#include "tscSubquery.h"
H
hzcheng 已提交
26 27
#include "tscUtil.h"
#include "tsclient.h"
S
slguan 已提交
28
#include "tscompression.h"
H
hzcheng 已提交
29 30
#include "tsocket.h"
#include "ttimer.h"
31
#include "ttokendef.h"
H
hjxilinx 已提交
32
#include "tutil.h"
H
hzcheng 已提交
33

34 35 36 37 38 39 40 41 42 43 44 45
static bool validImpl(const char* str, size_t maxsize) {
  if (str == NULL) {
    return false;
  }
  
  size_t len = strlen(str);
  if (len <= 0 || len > maxsize) {
    return false;
  }
  
  return true;
}
H
hzcheng 已提交
46

47 48 49
static bool validUserName(const char* user) {
  return validImpl(user, TSDB_USER_LEN);
}
S
slguan 已提交
50

51 52 53
static bool validPassword(const char* passwd) {
  return validImpl(passwd, TSDB_PASSWORD_LEN);
}
H
hzcheng 已提交
54

H
hjxilinx 已提交
55
STscObj *taosConnectImpl(const char *ip, const char *user, const char *pass, const char *db, uint16_t port,
56 57 58 59
                       void (*fp)(void *, TAOS_RES *, int), void *param, void **taos) {
  taos_init();
  
  if (!validUserName(user)) {
H
hjxilinx 已提交
60
    terrno = TSDB_CODE_INVALID_ACCT;
H
hzcheng 已提交
61 62 63
    return NULL;
  }

64
  if (!validPassword(pass)) {
H
hjxilinx 已提交
65
    terrno = TSDB_CODE_INVALID_PASS;
H
hzcheng 已提交
66 67 68
    return NULL;
  }

S
slguan 已提交
69
  if (tscInitRpc(user, pass) != 0) {
H
hjxilinx 已提交
70
    terrno = TSDB_CODE_NETWORK_UNAVAIL;
S
slguan 已提交
71 72 73
    return NULL;
  }

S
slguan 已提交
74
  if (ip && ip[0]) {
S
slguan 已提交
75 76 77 78
    tscMgmtIpSet.inUse = 0;
    tscMgmtIpSet.port = tsMnodeShellPort;
    tscMgmtIpSet.numOfIps = 1;
    tscMgmtIpSet.ip[0] = inet_addr(ip);
S
slguan 已提交
79 80

    if (tsMasterIp[0] && strcmp(ip, tsMasterIp) != 0) {
S
slguan 已提交
81 82
      tscMgmtIpSet.numOfIps = 2;
      tscMgmtIpSet.ip[1] = inet_addr(tsMasterIp);
S
slguan 已提交
83 84 85
    }

    if (tsSecondIp[0] && strcmp(tsSecondIp, tsMasterIp) != 0) {
S
slguan 已提交
86 87
      tscMgmtIpSet.numOfIps = 3;
      tscMgmtIpSet.ip[2] = inet_addr(tsSecondIp);
S
slguan 已提交
88
    }
S
slguan 已提交
89
  }
H
hzcheng 已提交
90

S
slguan 已提交
91
  tscMgmtIpSet.port = port ? port : tsMnodeShellPort;
92 93
  
  STscObj *pObj = (STscObj *)calloc(1, sizeof(STscObj));
S
slguan 已提交
94
  if (NULL == pObj) {
H
hjxilinx 已提交
95
    terrno = TSDB_CODE_CLI_OUT_OF_MEMORY;
S
slguan 已提交
96 97
    return NULL;
  }
H
hjxilinx 已提交
98

H
hzcheng 已提交
99 100 101
  pObj->signature = pObj;

  strncpy(pObj->user, user, TSDB_USER_LEN);
S
slguan 已提交
102
  taosEncryptPass((uint8_t *)pass, strlen(pass), pObj->pass);
S
slguan 已提交
103
  pObj->mgmtPort = port ? port : tsMnodeShellPort;
H
hzcheng 已提交
104 105 106 107 108 109

  if (db) {
    int32_t len = strlen(db);
    /* db name is too long */
    if (len > TSDB_DB_NAME_LEN) {
      free(pObj);
H
hjxilinx 已提交
110
      terrno = TSDB_CODE_INVALID_DB;
H
hzcheng 已提交
111 112 113 114 115 116 117
      return NULL;
    }

    char tmp[TSDB_DB_NAME_LEN + 1] = {0};
    strcpy(tmp, db);

    strdequote(tmp);
S
slguan 已提交
118
    strtolower(pObj->db, tmp);
H
hzcheng 已提交
119 120 121 122
  }

  pthread_mutex_init(&pObj->mutex, NULL);

123
  SSqlObj *pSql = (SSqlObj *)calloc(1, sizeof(SSqlObj));
S
slguan 已提交
124
  if (NULL == pSql) {
H
hjxilinx 已提交
125
    terrno = TSDB_CODE_CLI_OUT_OF_MEMORY;
S
slguan 已提交
126 127 128
    free(pObj);
    return NULL;
  }
H
hjxilinx 已提交
129

H
hzcheng 已提交
130 131
  pSql->pTscObj = pObj;
  pSql->signature = pSql;
H
hjxilinx 已提交
132
  pSql->maxRetry = TSDB_REPLICA_MAX_NUM;
133
  
S
slguan 已提交
134
  tsem_init(&pSql->rspSem, 0, 0);
H
hjxilinx 已提交
135
  
H
hzcheng 已提交
136 137 138 139 140 141 142 143
  pObj->pSql = pSql;
  pSql->fp = fp;
  pSql->param = param;
  if (taos != NULL) {
    *taos = pObj;
  }

  pSql->cmd.command = TSDB_SQL_CONNECT;
144
  if (TSDB_CODE_SUCCESS != tscAllocPayload(&pSql->cmd, TSDB_DEFAULT_PAYLOAD_SIZE)) {
H
hjxilinx 已提交
145
    terrno = TSDB_CODE_CLI_OUT_OF_MEMORY;
S
slguan 已提交
146 147 148 149
    free(pSql);
    free(pObj);
    return NULL;
  }
H
hzcheng 已提交
150

H
hjxilinx 已提交
151
  // tsRpcHeaderSize will be updated during RPC initialization, so only after it initialization, this value is valid
152
  tsInsertHeadSize = tsRpcHeadSize + sizeof(SMsgDesc) + sizeof(SSubmitMsg);
H
hzcheng 已提交
153 154 155
  return pObj;
}

156 157 158 159
static void syncConnCallback(void *param, TAOS_RES *tres, int code) {
  STscObj *pObj = (STscObj *)param;
  assert(pObj != NULL && pObj->pSql != NULL);
  
H
hjxilinx 已提交
160 161 162 163
  if (code < 0) {
    pObj->pSql->res.code = code;
  }
  
164 165 166
  sem_post(&pObj->pSql->rspSem);
}

L
lihui 已提交
167
TAOS *taos_connect(const char *ip, const char *user, const char *pass, const char *db, uint16_t port) {
168
  if (ip == NULL || (ip != NULL && (strcmp("127.0.0.1", ip) == 0 || strcasecmp("localhost", ip) == 0))) {
S
slguan 已提交
169
    ip = tsMasterIp;
H
hzcheng 已提交
170
  }
171
  
H
hzcheng 已提交
172 173
  tscTrace("try to create a connection to %s", ip);

H
hjxilinx 已提交
174
  STscObj *pObj = taosConnectImpl(ip, user, pass, db, port, NULL, NULL, NULL);
175 176 177 178 179 180 181 182 183 184 185
  if (pObj != NULL) {
    SSqlObj* pSql = pObj->pSql;
    assert(pSql != NULL);
    
    pSql->fp = syncConnCallback;
    pSql->param = pObj;
    
    tscProcessSql(pSql);
    sem_wait(&pSql->rspSem);
    
    if (pSql->res.code != TSDB_CODE_SUCCESS) {
H
hjxilinx 已提交
186
      terrno = pSql->res.code;
187 188 189 190 191
      taos_close(pObj);
      return NULL;
    }
    
    tscTrace("%p DB connection is opening", pObj);
192
    
S
slguan 已提交
193
    // version compare only requires the first 3 segments of the version string
194
    int code = taosCheckVersion(version, taos_get_server_info(pObj), 3);
S
slguan 已提交
195
    if (code != 0) {
H
hjxilinx 已提交
196
      terrno = code;
197
      taos_close(pObj);
S
slguan 已提交
198
      return NULL;
199 200
    } else {
      return pObj;
S
slguan 已提交
201
    }
H
hzcheng 已提交
202 203
  }

204
  return NULL;
H
hzcheng 已提交
205 206
}

L
lihui 已提交
207
TAOS *taos_connect_a(char *ip, char *user, char *pass, char *db, uint16_t port, void (*fp)(void *, TAOS_RES *, int),
H
hzcheng 已提交
208
                     void *param, void **taos) {
H
hjxilinx 已提交
209
  STscObj* pObj = taosConnectImpl(ip, user, pass, db, port, fp, param, taos);
210 211 212 213 214 215 216 217 218 219
  if (pObj == NULL) {
    return NULL;
  }
  
  SSqlObj* pSql = pObj->pSql;
  
  pSql->res.code = tscProcessSql(pSql);
  tscTrace("%p DB async connection is opening", pObj);
  
  return pObj;
H
hzcheng 已提交
220 221 222 223 224 225 226 227 228 229 230 231 232 233 234
}

void taos_close(TAOS *taos) {
  STscObj *pObj = (STscObj *)taos;

  if (pObj == NULL) return;
  if (pObj->signature != pObj) return;

  if (pObj->pHb != NULL) {
    tscSetFreeHeatBeat(pObj);
  } else {
    tscCloseTscObj(pObj);
  }
}

H
hjxilinx 已提交
235
int taos_query_imp(STscObj *pObj, SSqlObj *pSql) {
H
hzcheng 已提交
236
  SSqlRes *pRes = &pSql->res;
237 238 239
  SSqlCmd *pCmd = &pSql->cmd;
  
  pRes->numOfRows  = 1;
H
hzcheng 已提交
240
  pRes->numOfTotal = 0;
H
hjxilinx 已提交
241
  pRes->numOfTotalInCurrentClause = 0;
242

243 244 245 246
  pCmd->curSql = NULL;
  if (NULL != pCmd->pTableList) {
    taosHashCleanup(pCmd->pTableList);
    pCmd->pTableList = NULL;
L
lihui 已提交
247
  }
H
hjxilinx 已提交
248

L
lihui 已提交
249
  tscDump("%p pObj:%p, SQL: %s", pSql, pObj, pSql->sqlstr);
H
hzcheng 已提交
250

251
  pRes->code = (uint8_t)tsParseSql(pSql, false);
H
hzcheng 已提交
252 253 254 255 256 257 258 259

  /*
   * set the qhandle to 0 before return in order to erase the qhandle value assigned in the previous successful query.
   * If qhandle is NOT set 0, the function of taos_free_result() will send message to server by calling tscProcessSql()
   * to free connection, which may cause segment fault, when the parse phrase is not even successfully executed.
   */
  pRes->qhandle = 0;

H
hjxilinx 已提交
260 261 262
  if (pRes->code == TSDB_CODE_SUCCESS) {
    tscDoQuery(pSql);
  }
H
hzcheng 已提交
263

H
hjxilinx 已提交
264 265 266 267 268
  if (pRes->code == TSDB_CODE_SUCCESS) {
    tscTrace("%p SQL result:%d, %s pObj:%p", pSql, pRes->code, taos_errstr(pObj), pObj);
  } else {
    tscError("%p SQL result:%d, %s pObj:%p", pSql, pRes->code, taos_errstr(pObj), pObj);
  }
H
hjxilinx 已提交
269

H
hzcheng 已提交
270 271 272 273 274 275 276
  if (pRes->code != TSDB_CODE_SUCCESS) {
    tscFreeSqlObjPartial(pSql);
  }

  return pRes->code;
}

H
[td-99]  
hjxilinx 已提交
277
static void waitForQueryRsp(void *param, TAOS_RES *tres, int code) {
278
  assert(param != NULL);
H
[td-99]  
hjxilinx 已提交
279
  SSqlObj *pSql = ((STscObj *)param)->pSql;
280
  
H
[td-99]  
hjxilinx 已提交
281 282 283 284 285
  // valid error code is less than 0
  if (code < 0) {
    pSql->res.code = code;
  }
  
H
[td-99]  
hjxilinx 已提交
286
  sem_post(&pSql->rspSem);
287 288
}

S
slguan 已提交
289 290 291
int taos_query(TAOS *taos, const char *sqlstr) {
  STscObj *pObj = (STscObj *)taos;
  if (pObj == NULL || pObj->signature != pObj) {
H
[td-99]  
hjxilinx 已提交
292
    terrno = TSDB_CODE_DISCONNECTED;
S
slguan 已提交
293 294
    return TSDB_CODE_DISCONNECTED;
  }
295
  
296
  SSqlObj* pSql = pObj->pSql;
297
  
H
[td-99]  
hjxilinx 已提交
298
  size_t sqlLen = strlen(sqlstr);
H
[TD-98]  
hjxilinx 已提交
299
  doAsyncQuery(pObj, pSql, waitForQueryRsp, taos, sqlstr, sqlLen);
S
slguan 已提交
300

301 302 303
  // wait for the callback function to post the semaphore
  sem_wait(&pSql->rspSem);
  return pSql->res.code;
S
slguan 已提交
304 305
}

H
hzcheng 已提交
306 307 308
TAOS_RES *taos_use_result(TAOS *taos) {
  STscObj *pObj = (STscObj *)taos;
  if (pObj == NULL || pObj->signature != pObj) {
H
hjxilinx 已提交
309
    terrno = TSDB_CODE_DISCONNECTED;
H
hzcheng 已提交
310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328
    return NULL;
  }

  return pObj->pSql;
}

int taos_result_precision(TAOS_RES *res) {
  SSqlObj *pSql = (SSqlObj *)res;
  if (pSql == NULL || pSql->signature != pSql) return 0;

  return pSql->res.precision;
}

int taos_num_rows(TAOS_RES *res) { return 0; }

int taos_num_fields(TAOS_RES *res) {
  SSqlObj *pSql = (SSqlObj *)res;
  if (pSql == NULL || pSql->signature != pSql) return 0;

329
  SQueryInfo *pQueryInfo = tscGetQueryInfoDetail(&pSql->cmd, 0);
330 331 332
  if (pQueryInfo == NULL) {
    return 0;
  }
333

334
  SFieldInfo *pFieldsInfo = &pQueryInfo->fieldsInfo;
sangshuduo's avatar
sangshuduo 已提交
335 336 337 338
  if (pFieldsInfo)
    return (pFieldsInfo->numOfOutputCols - pFieldsInfo->numOfHiddenCols);
  else
    return 0;
H
hzcheng 已提交
339 340 341 342 343 344
}

int taos_field_count(TAOS *taos) {
  STscObj *pObj = (STscObj *)taos;
  if (pObj == NULL || pObj->signature != pObj) return 0;

S
slguan 已提交
345
  return taos_num_fields(pObj->pSql);
H
hzcheng 已提交
346 347 348 349 350 351 352 353 354 355 356 357
}

int taos_affected_rows(TAOS *taos) {
  STscObj *pObj = (STscObj *)taos;
  if (pObj == NULL || pObj->signature != pObj) return 0;

  return (pObj->pSql->res.numOfRows);
}

TAOS_FIELD *taos_fetch_fields(TAOS_RES *res) {
  SSqlObj *pSql = (SSqlObj *)res;
  if (pSql == NULL || pSql->signature != pSql) return 0;
358 359

  SQueryInfo *pQueryInfo = tscGetQueryInfoDetail(&pSql->cmd, 0);
sangshuduo's avatar
sangshuduo 已提交
360 361 362 363 364

  if (pQueryInfo)
    return pQueryInfo->fieldsInfo.pFields;
  else
    return NULL;
H
hzcheng 已提交
365 366 367 368 369 370 371 372 373 374
}

int taos_retrieve(TAOS_RES *res) {
  if (res == NULL) return 0;
  SSqlObj *pSql = (SSqlObj *)res;
  SSqlCmd *pCmd = &pSql->cmd;
  SSqlRes *pRes = &pSql->res;
  if (pSql == NULL || pSql->signature != pSql) return 0;
  if (pRes->qhandle == 0) return 0;

S
slguan 已提交
375 376
  tscResetForNextRetrieve(pRes);

H
hzcheng 已提交
377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396
  if (pCmd->command < TSDB_SQL_LOCAL) {
    pCmd->command = (pCmd->command > TSDB_SQL_MGMT) ? TSDB_SQL_RETRIEVE : TSDB_SQL_FETCH;
  }
  tscProcessSql(pSql);

  return pRes->numOfRows;
}

int taos_fetch_block_impl(TAOS_RES *res, TAOS_ROW *rows) {
  SSqlObj *pSql = (SSqlObj *)res;
  SSqlCmd *pCmd = &pSql->cmd;
  SSqlRes *pRes = &pSql->res;
  STscObj *pObj = pSql->pTscObj;

  if (pRes->qhandle == 0 || pObj->pSql != pSql) {
    *rows = NULL;
    return 0;
  }

  // Retrieve new block
S
slguan 已提交
397
  tscResetForNextRetrieve(pRes);
H
hzcheng 已提交
398 399 400 401 402 403 404 405 406 407
  if (pCmd->command < TSDB_SQL_LOCAL) {
    pCmd->command = (pCmd->command > TSDB_SQL_MGMT) ? TSDB_SQL_RETRIEVE : TSDB_SQL_FETCH;
  }

  tscProcessSql(pSql);
  if (pRes->numOfRows == 0) {
    *rows = NULL;
    return 0;
  }

S
slguan 已提交
408 409
  // secondary merge has handle this situation
  if (pCmd->command != TSDB_SQL_RETRIEVE_METRIC) {
H
hjxilinx 已提交
410
    pRes->numOfTotalInCurrentClause += pRes->numOfRows;
S
slguan 已提交
411 412
  }

413
  SQueryInfo *pQueryInfo = tscGetQueryInfoDetail(pCmd, 0);
sangshuduo's avatar
sangshuduo 已提交
414 415 416
  if (pQueryInfo == NULL)
    return 0;

417
  for (int i = 0; i < pQueryInfo->fieldsInfo.numOfOutputCols; ++i) {
H
hjxilinx 已提交
418
    pRes->tsrow[i] = TSC_GET_RESPTR_BASE(pRes, pQueryInfo, i);
H
hzcheng 已提交
419 420 421 422
  }

  *rows = pRes->tsrow;

423
  return (pQueryInfo->order.order == TSDB_ORDER_DESC) ? pRes->numOfRows : -pRes->numOfRows;
H
hzcheng 已提交
424 425
}

H
hjxilinx 已提交
426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453
static void transferNcharData(SSqlObj *pSql, int32_t columnIndex, TAOS_FIELD *pField) {
  SSqlRes *pRes = &pSql->res;

  if (isNull(pRes->tsrow[columnIndex], pField->type)) {
    pRes->tsrow[columnIndex] = NULL;
  } else if (pField->type == TSDB_DATA_TYPE_NCHAR) {
    // convert unicode to native code in a temporary buffer extra one byte for terminated symbol
    if (pRes->buffer[columnIndex] == NULL) {
      pRes->buffer[columnIndex] = malloc(pField->bytes + TSDB_NCHAR_SIZE);
    }

    /* string terminated char for binary data*/
    memset(pRes->buffer[columnIndex], 0, pField->bytes + TSDB_NCHAR_SIZE);

    if (taosUcs4ToMbs(pRes->tsrow[columnIndex], pField->bytes, pRes->buffer[columnIndex])) {
      pRes->tsrow[columnIndex] = pRes->buffer[columnIndex];
    } else {
      tscError("%p charset:%s to %s. val:%ls convert failed.", pSql, DEFAULT_UNICODE_ENCODEC, tsCharset, pRes->tsrow);
      pRes->tsrow[columnIndex] = NULL;
    }
  }
}

static char *getArithemicInputSrc(void *param, char *name, int32_t colId) {
  SArithmeticSupport *pSupport = (SArithmeticSupport *)param;
  SSqlFunctionExpr *  pExpr = pSupport->pExpr;

  int32_t index = -1;
454 455
  for (int32_t i = 0; i < pExpr->binExprInfo.numOfCols; ++i) {
    if (strcmp(name, pExpr->binExprInfo.pReqColumns[i].name) == 0) {
H
hjxilinx 已提交
456 457 458 459 460
      index = i;
      break;
    }
  }

461
  assert(index >= 0 && index < pExpr->binExprInfo.numOfCols);
H
hjxilinx 已提交
462 463 464
  return pSupport->data[index] + pSupport->offset * pSupport->elemSize[index];
}

S
slguan 已提交
465
static void **doSetResultRowData(SSqlObj *pSql) {
H
hzcheng 已提交
466 467
  SSqlCmd *pCmd = &pSql->cmd;
  SSqlRes *pRes = &pSql->res;
H
hjxilinx 已提交
468

H
hjxilinx 已提交
469
  assert(pRes->row >= 0 && pRes->row <= pRes->numOfRows);
H
hjxilinx 已提交
470

H
hjxilinx 已提交
471 472 473 474
  if (pRes->row >= pRes->numOfRows) {  // all the results has returned to invoker
    tfree(pRes->tsrow);
    return pRes->tsrow;
  }
475

H
hjxilinx 已提交
476 477 478 479 480 481 482 483 484 485 486 487
  SQueryInfo *pQueryInfo = tscGetQueryInfoDetail(pCmd, pCmd->clauseIndex);
  
  //todo refactor move away
  for(int32_t k = 0; k < pQueryInfo->exprsInfo.numOfExprs; ++k) {
    SSqlExpr* pExpr = tscSqlExprGet(pQueryInfo, k);
    
    if (k > 0) {
      SSqlExpr* pPrev = tscSqlExprGet(pQueryInfo, k - 1);
      pExpr->offset = pPrev->offset + pPrev->resBytes;
    }
  }
  
S
slguan 已提交
488
  int32_t num = 0;
H
hjxilinx 已提交
489 490
  for (int i = 0; i < tscNumOfFields(pQueryInfo); ++i) {
    if (pQueryInfo->fieldsInfo.pSqlExpr[i] != NULL) {
H
hjxilinx 已提交
491 492 493 494
      SSqlExpr* pExpr = pQueryInfo->fieldsInfo.pSqlExpr[i];
      pRes->tsrow[i] = TSC_GET_RESPTR_BASE(pRes, pQueryInfo, i) + pExpr->resBytes * pRes->row;
    } else {
      assert(0);
H
hjxilinx 已提交
495
    }
S
slguan 已提交
496

H
hzcheng 已提交
497
    // primary key column cannot be null in interval query, no need to check
498
    if (i == 0 && pQueryInfo->intervalTime > 0) {
H
hzcheng 已提交
499 500 501
      continue;
    }

502
    TAOS_FIELD *pField = tscFieldInfoGetField(pQueryInfo, i);
H
hjxilinx 已提交
503
    transferNcharData(pSql, i, pField);
H
hzcheng 已提交
504

H
hjxilinx 已提交
505 506 507 508 509 510
    // calculate the result from serveral other columns
    if (pQueryInfo->fieldsInfo.pExpr != NULL && pQueryInfo->fieldsInfo.pExpr[i] != NULL) {
      SArithmeticSupport *sas = (SArithmeticSupport *)calloc(1, sizeof(SArithmeticSupport));
      sas->offset = 0;
      sas->pExpr = pQueryInfo->fieldsInfo.pExpr[i];
      
511
      sas->numOfCols = sas->pExpr->binExprInfo.numOfCols;
H
hjxilinx 已提交
512 513 514
      
      if (pRes->buffer[i] == NULL) {
        pRes->buffer[i] = malloc(tscFieldInfoGetField(pQueryInfo, i)->bytes);
H
hzcheng 已提交
515
      }
H
hjxilinx 已提交
516
      
H
hjxilinx 已提交
517
      for(int32_t k = 0; k < sas->numOfCols; ++k) {
518
        int32_t columnIndex = sas->pExpr->binExprInfo.pReqColumns[k].colIndex;
H
hjxilinx 已提交
519 520 521 522
        SSqlExpr* pExpr = tscSqlExprGet(pQueryInfo, columnIndex);
        
        sas->elemSize[k] = pExpr->resBytes;
        sas->data[k] = (pRes->data + pRes->numOfRows* pExpr->offset) + pRes->row*pExpr->resBytes;
H
hzcheng 已提交
523
      }
H
hjxilinx 已提交
524

525
      tSQLBinaryExprCalcTraverse(sas->pExpr->binExprInfo.pBinExpr, 1, pRes->buffer[i], sas, TSDB_ORDER_ASC, getArithemicInputSrc);
H
hjxilinx 已提交
526
      pRes->tsrow[i] = pRes->buffer[i];
H
hjxilinx 已提交
527
      
H
hjxilinx 已提交
528
      free(sas); //todo optimization
H
hzcheng 已提交
529 530 531
    }
  }

532
  assert(num <= pQueryInfo->fieldsInfo.numOfOutputCols);
H
hjxilinx 已提交
533 534

  pRes->row++;  // index increase one-step
H
hzcheng 已提交
535 536 537
  return pRes->tsrow;
}

H
hjxilinx 已提交
538 539
static bool tscHashRemainDataInSubqueryResultSet(SSqlObj *pSql) {
  bool     hasData = true;
S
slguan 已提交
540 541
  SSqlCmd *pCmd = &pSql->cmd;

542
  SQueryInfo *pQueryInfo = tscGetQueryInfoDetail(pCmd, pCmd->clauseIndex);
543
  if (tscNonOrderedProjectionQueryOnSTable(pQueryInfo, 0)) {
H
hjxilinx 已提交
544
    bool allSubqueryExhausted = true;
S
slguan 已提交
545

H
hjxilinx 已提交
546
    for (int32_t i = 0; i < pSql->numOfSubs; ++i) {
547 548 549 550
      if (pSql->pSubs[i] == NULL) {
        continue;
      }

551
//      SSqlRes *pRes1 = &pSql->pSubs[i]->res;
H
hjxilinx 已提交
552 553
      SSqlCmd *pCmd1 = &pSql->pSubs[i]->cmd;

554
      SQueryInfo *    pQueryInfo1 = tscGetQueryInfoDetail(pCmd1, pCmd1->clauseIndex);
555
//      STableMetaInfo *pMetaInfo = tscGetMetaInfo(pQueryInfo1, 0);
556

H
hjxilinx 已提交
557
      assert(pQueryInfo1->numOfTables == 1);
H
hjxilinx 已提交
558 559 560

      /*
       * if the global limitation is not reached, and current result has not exhausted, or next more vnodes are
561
       * available, goes on
H
hjxilinx 已提交
562
       */
H
hjxilinx 已提交
563 564 565 566 567
//      if (pMetaInfo->vnodeIndex < pMetaInfo->pMetricMeta->numOfVnodes && pRes1->row < pRes1->numOfRows &&
//          (!tscHasReachLimitation(pQueryInfo1, pRes1))) {
//        allSubqueryExhausted = false;
//        break;
//      }
H
hjxilinx 已提交
568
    }
S
slguan 已提交
569

H
hjxilinx 已提交
570 571
    hasData = !allSubqueryExhausted;
  } else {  // otherwise, in case inner join, if any subquery exhausted, query completed.
S
slguan 已提交
572
    for (int32_t i = 0; i < pSql->numOfSubs; ++i) {
573 574 575
      if (pSql->pSubs[i] == 0) {
        continue;
      }
H
hjxilinx 已提交
576

577 578 579
      SSqlRes *   pRes1 = &pSql->pSubs[i]->res;
      SQueryInfo *pQueryInfo1 = tscGetQueryInfoDetail(&pSql->pSubs[i]->cmd, 0);

H
hjxilinx 已提交
580
      if ((pRes1->row >= pRes1->numOfRows && tscHasReachLimitation(pQueryInfo1, pRes1) &&
581 582
           tscProjectionQueryOnTable(pQueryInfo1)) ||
          (pRes1->numOfRows == 0)) {
S
slguan 已提交
583 584 585 586
        hasData = false;
        break;
      }
    }
H
hjxilinx 已提交
587 588 589 590
  }

  return hasData;
}
S
slguan 已提交
591

592
static UNUSED_FUNC void **tscBuildResFromSubqueries(SSqlObj *pSql) {
H
hjxilinx 已提交
593
  SSqlRes *pRes = &pSql->res;
S
slguan 已提交
594

H
hjxilinx 已提交
595
  while (1) {
596
    SQueryInfo *pQueryInfo = tscGetQueryInfoDetail(&pSql->cmd, pSql->cmd.clauseIndex);
S
slguan 已提交
597
    if (pRes->tsrow == NULL) {
H
hjxilinx 已提交
598
      pRes->tsrow = calloc(pQueryInfo->exprsInfo.numOfExprs, POINTER_BYTES);
S
slguan 已提交
599 600 601
    }

    bool success = false;
602 603 604 605 606 607 608 609 610

    int32_t numOfTableHasRes = 0;
    for (int32_t i = 0; i < pSql->numOfSubs; ++i) {
      if (pSql->pSubs[i] != 0) {
        numOfTableHasRes++;
      }
    }

    if (numOfTableHasRes >= 2) {  // do merge result
H
hjxilinx 已提交
611
      success = (doSetResultRowData(pSql->pSubs[0]) != NULL) && (doSetResultRowData(pSql->pSubs[1]) != NULL);
H
hjxilinx 已提交
612
    } else {  // only one subquery
613 614 615 616 617
      SSqlObj *pSub = pSql->pSubs[0];
      if (pSub == NULL) {
        pSub = pSql->pSubs[1];
      }

H
hjxilinx 已提交
618
      success = (doSetResultRowData(pSub) != NULL);
S
slguan 已提交
619 620
    }

H
hjxilinx 已提交
621
    if (success) {  // current row of final output has been built, return to app
622
      for (int32_t i = 0; i < pQueryInfo->exprsInfo.numOfExprs; ++i) {
S
slguan 已提交
623 624 625 626 627 628 629
        int32_t tableIndex = pRes->pColumnIndex[i].tableIndex;
        int32_t columnIndex = pRes->pColumnIndex[i].columnIndex;

        SSqlRes *pRes1 = &pSql->pSubs[tableIndex]->res;
        pRes->tsrow[i] = pRes1->tsrow[columnIndex];
      }

630
      pRes->numOfTotalInCurrentClause++;
H
hjxilinx 已提交
631

632
      break;
633
    } else {  // continue retrieve data from vnode
634
      if (!tscHashRemainDataInSubqueryResultSet(pSql)) {
635 636
        tscTrace("%p at least one subquery exhausted, free all other %d subqueries", pSql, pSql->numOfSubs - 1);
        SSubqueryState *pState = NULL;
637

638
        // free all sub sqlobj
639 640 641 642 643
        for (int32_t i = 0; i < pSql->numOfSubs; ++i) {
          SSqlObj *pChildObj = pSql->pSubs[i];
          if (pChildObj == NULL) {
            continue;
          }
H
hjxilinx 已提交
644

645 646
          SJoinSubquerySupporter *pSupporter = (SJoinSubquerySupporter *)pChildObj->param;
          pState = pSupporter->pState;
H
hjxilinx 已提交
647

648 649 650
          tscDestroyJoinSupporter(pChildObj->param);
          taos_free_result(pChildObj);
        }
H
hjxilinx 已提交
651

652 653 654
        free(pState);
        return NULL;
      }
H
hjxilinx 已提交
655

656 657 658 659
      tscFetchDatablockFromSubquery(pSql);
      if (pRes->code != TSDB_CODE_SUCCESS) {
        return NULL;
      }
H
hjxilinx 已提交
660 661 662
    }
  }

663
  return pRes->tsrow;
H
hjxilinx 已提交
664 665
}

H
[td-99]  
hjxilinx 已提交
666
static void waitForRetrieveRsp(void *param, TAOS_RES *tres, int numOfRows) {
667
  SSqlObj* pSql = (SSqlObj*) tres;
668
  
669
  if (numOfRows < 0) { // set the error code
670 671 672 673 674
    pSql->res.code = -numOfRows;
  }
  sem_post(&pSql->rspSem);
}

H
hzcheng 已提交
675 676 677
TAOS_ROW taos_fetch_row(TAOS_RES *res) {
  SSqlObj *pSql = (SSqlObj *)res;
  if (pSql == NULL || pSql->signature != pSql) {
H
hjxilinx 已提交
678
    terrno = TSDB_CODE_DISCONNECTED;
H
hzcheng 已提交
679 680
    return NULL;
  }
681 682 683 684
  
  SSqlCmd *pCmd = &pSql->cmd;
  SSqlRes *pRes = &pSql->res;
  
H
hjxilinx 已提交
685 686 687
  if (pRes->qhandle == 0 ||
      pCmd->command == TSDB_SQL_RETRIEVE_EMPTY_RESULT ||
      pCmd->command == TSDB_SQL_INSERT) {
688
    return NULL;
689
  }
690 691
  
  // current data are exhausted, fetch more data
692
  if (pRes->data == NULL || (pRes->data != NULL && pRes->row >= pRes->numOfRows && pRes->completed != true &&
H
hjxilinx 已提交
693 694
      (pCmd->command == TSDB_SQL_RETRIEVE || pCmd->command == TSDB_SQL_RETRIEVE_METRIC ||
      pCmd->command == TSDB_SQL_FETCH || pCmd->command == TSDB_SQL_DESCRIBE_TABLE))) {
H
[td-99]  
hjxilinx 已提交
695
    taos_fetch_rows_a(res, waitForRetrieveRsp, pSql->pTscObj);
H
hjxilinx 已提交
696
    
697
    sem_wait(&pSql->rspSem);
H
hjxilinx 已提交
698
  }
699 700
  
  return doSetResultRowData(pSql);
H
hzcheng 已提交
701 702 703
}

int taos_fetch_block(TAOS_RES *res, TAOS_ROW *rows) {
H
hjxilinx 已提交
704
#if 0
H
hzcheng 已提交
705
  SSqlObj *pSql = (SSqlObj *)res;
H
hjxilinx 已提交
706
  SSqlCmd *pCmd = &pSql->cmd;
707
  SSqlRes *pRes = &pSql->res;
708

H
hzcheng 已提交
709 710 711
  int nRows = 0;

  if (pSql == NULL || pSql->signature != pSql) {
H
hjxilinx 已提交
712
    terrno = TSDB_CODE_DISCONNECTED;
H
hzcheng 已提交
713 714 715 716
    *rows = NULL;
    return 0;
  }

S
slguan 已提交
717
  // projection query on metric, pipeline retrieve data from vnode list,
S
slguan 已提交
718
  // instead of two-stage mergednodeProcessMsgFromShell free qhandle
H
hzcheng 已提交
719
  nRows = taos_fetch_block_impl(res, rows);
720

H
hjxilinx 已提交
721 722
  // current subclause is completed, try the next subclause
  while (rows == NULL && pCmd->clauseIndex < pCmd->numOfClause - 1) {
723 724
    SQueryInfo *pQueryInfo = tscGetQueryInfoDetail(pCmd, pCmd->clauseIndex);

725
    pSql->cmd.command = pQueryInfo->command;
H
hjxilinx 已提交
726
    pCmd->clauseIndex++;
727

728 729 730
    pRes->numOfTotal += pRes->numOfTotalInCurrentClause;
    pRes->numOfTotalInCurrentClause = 0;
    pRes->rspType = 0;
731

732 733
    pSql->numOfSubs = 0;
    tfree(pSql->pSubs);
734

H
hjxilinx 已提交
735
    assert(pSql->fp == NULL);
736

H
hjxilinx 已提交
737 738
    tscTrace("%p try data in the next subclause:%d, total subclause:%d", pSql, pCmd->clauseIndex, pCmd->numOfClause);
    tscProcessSql(pSql);
739

H
hjxilinx 已提交
740
    nRows = taos_fetch_block_impl(res, rows);
H
hzcheng 已提交
741
  }
742

H
hzcheng 已提交
743
  return nRows;
H
hjxilinx 已提交
744 745 746 747
#endif

  (*rows) = taos_fetch_row(res);
  return ((*rows) != NULL)? 1:0;
H
hzcheng 已提交
748 749
}

S
slguan 已提交
750
int taos_select_db(TAOS *taos, const char *db) {
751
  char sql[256] = {0};
H
hzcheng 已提交
752 753 754

  STscObj *pObj = (STscObj *)taos;
  if (pObj == NULL || pObj->signature != pObj) {
H
hjxilinx 已提交
755
    terrno = TSDB_CODE_DISCONNECTED;
H
hzcheng 已提交
756 757 758
    return TSDB_CODE_DISCONNECTED;
  }

759
  snprintf(sql, tListLen(sql), "use %s", db);
H
hzcheng 已提交
760 761 762
  return taos_query(taos, sql);
}

H
hjxilinx 已提交
763
void taos_free_result_imp(TAOS_RES *res, int keepCmd) {
H
hzcheng 已提交
764 765 766 767 768 769 770 771 772
  if (res == NULL) return;

  SSqlObj *pSql = (SSqlObj *)res;
  SSqlRes *pRes = &pSql->res;
  SSqlCmd *pCmd = &pSql->cmd;

  tscTrace("%p start to free result", pSql);

  if (pSql->signature != pSql) return;
S
slguan 已提交
773

H
hzcheng 已提交
774 775 776
  if (pRes == NULL || pRes->qhandle == 0) {
    /* Query rsp is not received from vnode, so the qhandle is NULL */
    tscTrace("%p qhandle is null, abort free, fp:%p", pSql, pSql->fp);
777
    STscObj* pTscObj = pSql->pTscObj;
778
    
779
    if (pTscObj->pSql != pSql) {
780
      tscTrace("%p SqlObj is freed by app", pSql);
sangshuduo's avatar
sangshuduo 已提交
781
      tscFreeSqlObj(pSql);
H
hzcheng 已提交
782
    } else {
783 784 785 786 787
      if (keepCmd) {
        tscFreeSqlResult(pSql);
      } else {
        tscFreeSqlObjPartial(pSql);
      }
H
hzcheng 已提交
788
    }
789
    
H
hzcheng 已提交
790 791 792
    return;
  }

S
slguan 已提交
793
  // set freeFlag to 1 in retrieve message if there are un-retrieved results
794
  SQueryInfo *pQueryInfo = tscGetQueryInfoDetail(&pSql->cmd, 0);
795 796 797 798 799
  if (pQueryInfo == NULL) {
    tscFreeSqlObjPartial(pSql);
    return;
  }

800
  pQueryInfo->type = TSDB_QUERY_TYPE_FREE_RESOURCE;
S
slguan 已提交
801

H
hjxilinx 已提交
802
  STableMetaInfo *pTableMetaInfo = tscGetMetaInfo(pQueryInfo, 0);
H
hzcheng 已提交
803 804

  /*
S
slguan 已提交
805 806
   * case 1. Partial data have been retrieved from vnodes, but not all data has been retrieved yet.
   *         We need to recycle the connection by noticing the vnode return 0 results.
H
hzcheng 已提交
807
   * case 2. When the query response is received from vnodes and the numOfRows is set to 0, the user calls
S
slguan 已提交
808 809 810 811 812
   *         taos_free_result before the taos_fetch_row is called in non-stream computing,
   *         we need to recycle the connection.
   * case 3. If the query process is cancelled by user in stable query, tscProcessSql should not be called
   *         for each subquery. Because the failure of execution tsProcessSql may trigger the callback function
   *         be executed, and the retry efforts may result in double free the resources, e.g.,SRetrieveSupport
H
hzcheng 已提交
813
   */
H
[TD-98]  
hjxilinx 已提交
814 815 816
  if ((pCmd->command == TSDB_SQL_SELECT || pCmd->command == TSDB_SQL_SHOW || pCmd->command == TSDB_SQL_RETRIEVE ||
      pCmd->command == TSDB_SQL_FETCH) &&
      (pRes->code != TSDB_CODE_QUERY_CANCELLED && ((pRes->numOfRows > 0 && pCmd->command < TSDB_SQL_LOCAL && pRes->completed == false) ||
H
hzcheng 已提交
817
       (pRes->code == TSDB_CODE_SUCCESS && pRes->numOfRows == 0 && pCmd->command == TSDB_SQL_SELECT &&
H
[TD-98]  
hjxilinx 已提交
818
        pSql->pStream == NULL && pTableMetaInfo->pTableMeta != NULL)))) {
H
hzcheng 已提交
819 820
    pCmd->command = (pCmd->command > TSDB_SQL_MGMT) ? TSDB_SQL_RETRIEVE : TSDB_SQL_FETCH;

H
hjxilinx 已提交
821
    tscTrace("%p code:%d, numOfRows:%d, command:%d", pSql, pRes->code, pRes->numOfRows, pCmd->command);
H
hjxilinx 已提交
822

S
slguan 已提交
823 824
    void *fp = pSql->fp;
    if (fp != NULL) {
H
hzcheng 已提交
825
      pSql->freed = 1;
S
slguan 已提交
826
    }
H
hzcheng 已提交
827

S
slguan 已提交
828 829 830 831 832 833 834
    tscProcessSql(pSql);

    /*
     *  If release connection msg is sent to vnode, the corresponding SqlObj for async query can not be freed instantly,
     *  since its free operation is delegated to callback function, which is tscProcessMsgFromServer.
     */
    if (fp == NULL) {
H
hzcheng 已提交
835
      /*
S
slguan 已提交
836 837 838 839 840 841 842 843
       * fp may be released here, so we cannot use the pSql->fp
       *
       * In case of handle sync model query, the main SqlObj cannot be freed.
       * So, we only free part attributes, including allocated resources and references on metermeta/metricmeta
       * data in cache.
       *
       * Then this object will be reused and no free operation is required.
       */
weixin_48148422's avatar
weixin_48148422 已提交
844 845 846 847 848 849 850
      if (keepCmd) {
        tscFreeSqlResult(pSql);
        tscTrace("%p sql result is freed by app while sql command is kept", pSql);
      } else {
        tscFreeSqlObjPartial(pSql);
        tscTrace("%p sql result is freed by app", pSql);
      }
851 852 853 854 855
    } else {  // for async release, remove its link
      STscObj* pObj = pSql->pTscObj;
      if (pObj->pSql == pSql) {
        pObj->pSql = NULL;
      }
H
hzcheng 已提交
856 857
    }
  } else {
S
slguan 已提交
858
    // if no free resource msg is sent to vnode, we free this object immediately.
859 860 861
    STscObj* pTscObj = pSql->pTscObj;
    
    if (pTscObj->pSql != pSql) {
H
hzcheng 已提交
862
      tscFreeSqlObj(pSql);
863
      tscTrace("%p sql result is freed by app", pSql);
H
hzcheng 已提交
864
    } else {
865 866 867 868 869 870 871
      if (keepCmd) {
        tscFreeSqlResult(pSql);
        tscTrace("%p sql result is freed while sql command is kept", pSql);
      } else {
        tscFreeSqlObjPartial(pSql);
        tscTrace("%p sql result is freed by app", pSql);
      }
H
hzcheng 已提交
872 873 874 875
    }
  }
}

H
hjxilinx 已提交
876
void taos_free_result(TAOS_RES *res) { taos_free_result_imp(res, 0); }
weixin_48148422's avatar
weixin_48148422 已提交
877

H
[td-99]  
hjxilinx 已提交
878
// todo should not be used in async query
H
hzcheng 已提交
879 880 881
int taos_errno(TAOS *taos) {
  STscObj *pObj = (STscObj *)taos;

H
[td-99]  
hjxilinx 已提交
882 883 884
  if (pObj == NULL || pObj->signature != pObj) {
    return terrno;
  }
H
hzcheng 已提交
885

H
[td-99]  
hjxilinx 已提交
886
  return pObj->pSql->res.code;
H
hzcheng 已提交
887 888
}

H
hjxilinx 已提交
889 890 891 892
/*
 * In case of invalid sql error, additional information is attached to explain
 * why the sql is invalid
 */
H
hjxilinx 已提交
893
static bool hasAdditionalErrorInfo(int32_t code, SSqlCmd *pCmd) {
H
hjxilinx 已提交
894 895 896 897 898
  if (code != TSDB_CODE_INVALID_SQL) {
    return false;
  }

  size_t len = strlen(pCmd->payload);
H
hjxilinx 已提交
899 900

  char *z = NULL;
H
hjxilinx 已提交
901
  if (len > 0) {
H
hjxilinx 已提交
902
    z = strstr(pCmd->payload, "invalid SQL");
H
hjxilinx 已提交
903
  }
H
hjxilinx 已提交
904

H
hjxilinx 已提交
905 906 907
  return z != NULL;
}

H
[td-99]  
hjxilinx 已提交
908
// todo should not be used in async model
H
hzcheng 已提交
909
char *taos_errstr(TAOS *taos) {
H
hjxilinx 已提交
910
  STscObj *pObj = (STscObj *)taos;
H
hzcheng 已提交
911

S
slguan 已提交
912
  if (pObj == NULL || pObj->signature != pObj)
913
    return (char*)tstrerror(terrno);
H
hzcheng 已提交
914

915 916
  SSqlObj* pSql = pObj->pSql;
  
H
[td-32]  
hjxilinx 已提交
917
  if (hasAdditionalErrorInfo(pSql->res.code, &pSql->cmd)) {
H
hjxilinx 已提交
918
    return pSql->cmd.payload;
H
hzcheng 已提交
919
  } else {
H
[td-32]  
hjxilinx 已提交
920
    return (char*)tstrerror(pSql->res.code);
H
hzcheng 已提交
921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942
  }
}

void taos_config(int debug, char *log_path) {
  uDebugFlag = debug;
  strcpy(logDir, log_path);
}

char *taos_get_server_info(TAOS *taos) {
  STscObj *pObj = (STscObj *)taos;

  if (pObj == NULL) return NULL;

  return pObj->sversion;
}

char *taos_get_client_info() { return version; }

void taos_stop_query(TAOS_RES *res) {
  if (res == NULL) return;

  SSqlObj *pSql = (SSqlObj *)res;
943 944
  SSqlCmd *pCmd = &pSql->cmd;

H
hzcheng 已提交
945 946 947 948 949
  if (pSql->signature != pSql) return;
  tscTrace("%p start to cancel query", res);

  pSql->res.code = TSDB_CODE_QUERY_CANCELLED;

950
  SQueryInfo *pQueryInfo = tscGetQueryInfoDetail(pCmd, pCmd->clauseIndex);
H
hjxilinx 已提交
951
  if (tscIsTwoStageSTableQuery(pQueryInfo, 0)) {
H
hzcheng 已提交
952 953 954 955 956 957 958 959
    tscKillMetricQuery(pSql);
    return;
  }

  if (pSql->cmd.command >= TSDB_SQL_LOCAL) {
    return;
  }

S
slguan 已提交
960
  //taosStopRpcConn(pSql->thandle);
H
hzcheng 已提交
961 962 963 964 965 966
  tscTrace("%p query is cancelled", res);
}

int taos_print_row(char *str, TAOS_ROW row, TAOS_FIELD *fields, int num_fields) {
  int len = 0;
  for (int i = 0; i < num_fields; ++i) {
967 968 969 970
    if (i > 0) {
      str[len++] = ' ';
    }

H
hzcheng 已提交
971
    if (row[i] == NULL) {
972
      len += sprintf(str + len, "%s", TSDB_DATA_NULL_STR);
H
hzcheng 已提交
973 974 975 976 977
      continue;
    }

    switch (fields[i].type) {
      case TSDB_DATA_TYPE_TINYINT:
978
        len += sprintf(str + len, "%d", *((char *)row[i]));
H
hzcheng 已提交
979 980 981
        break;

      case TSDB_DATA_TYPE_SMALLINT:
982
        len += sprintf(str + len, "%d", *((short *)row[i]));
H
hzcheng 已提交
983 984 985
        break;

      case TSDB_DATA_TYPE_INT:
986
        len += sprintf(str + len, "%d", *((int *)row[i]));
H
hzcheng 已提交
987 988 989
        break;

      case TSDB_DATA_TYPE_BIGINT:
990
        len += sprintf(str + len, "%" PRId64, *((int64_t *)row[i]));
H
hzcheng 已提交
991 992
        break;

L
lihui 已提交
993 994
      case TSDB_DATA_TYPE_FLOAT: {
        float fv = 0;
L
lihui 已提交
995
        fv = GET_FLOAT_VAL(row[i]);
996
        len += sprintf(str + len, "%f", fv);
997
      } break;
H
hzcheng 已提交
998

999
      case TSDB_DATA_TYPE_DOUBLE: {
L
lihui 已提交
1000
        double dv = 0;
L
lihui 已提交
1001
        dv = GET_DOUBLE_VAL(row[i]);
1002
        len += sprintf(str + len, "%lf", dv);
1003
      } break;
H
hzcheng 已提交
1004 1005

      case TSDB_DATA_TYPE_BINARY:
S
slguan 已提交
1006
      case TSDB_DATA_TYPE_NCHAR: {
H
hjxilinx 已提交
1007 1008 1009 1010 1011 1012 1013 1014
        size_t xlen = 0;
        for (xlen = 0; xlen <= fields[i].bytes; xlen++) {
          char c = ((char *)row[i])[xlen];
          if (c == 0) break;
          str[len++] = c;
        }
        str[len] = 0;
      } break;
H
hzcheng 已提交
1015 1016

      case TSDB_DATA_TYPE_TIMESTAMP:
1017
        len += sprintf(str + len, "%" PRId64, *((int64_t *)row[i]));
H
hzcheng 已提交
1018 1019 1020
        break;

      case TSDB_DATA_TYPE_BOOL:
1021
        len += sprintf(str + len, "%d", *((int8_t *)row[i]));
H
hzcheng 已提交
1022 1023 1024 1025 1026 1027 1028 1029
      default:
        break;
    }
  }

  return len;
}

S
slguan 已提交
1030
int taos_validate_sql(TAOS *taos, const char *sql) {
H
hzcheng 已提交
1031 1032
  STscObj *pObj = (STscObj *)taos;
  if (pObj == NULL || pObj->signature != pObj) {
H
hjxilinx 已提交
1033
    terrno = TSDB_CODE_DISCONNECTED;
H
hzcheng 已提交
1034 1035 1036 1037 1038
    return TSDB_CODE_DISCONNECTED;
  }

  SSqlObj *pSql = pObj->pSql;
  SSqlRes *pRes = &pSql->res;
1039 1040 1041
  SSqlCmd *pCmd = &pSql->cmd;
  
  pRes->numOfRows  = 1;
H
hzcheng 已提交
1042
  pRes->numOfTotal = 0;
H
hjxilinx 已提交
1043
  pRes->numOfTotalInCurrentClause = 0;
1044

H
hzcheng 已提交
1045 1046 1047
  tscTrace("%p Valid SQL: %s pObj:%p", pSql, sql, pObj);

  int32_t sqlLen = strlen(sql);
H
hjxilinx 已提交
1048
  if (sqlLen > tsMaxSQLStringLen) {
H
hzcheng 已提交
1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061
    tscError("%p sql too long", pSql);
    pRes->code = TSDB_CODE_INVALID_SQL;
    return pRes->code;
  }

  pSql->sqlstr = realloc(pSql->sqlstr, sqlLen + 1);
  if (pSql->sqlstr == NULL) {
    pRes->code = TSDB_CODE_CLI_OUT_OF_MEMORY;
    tscError("%p failed to malloc sql string buffer", pSql);
    tscTrace("%p Valid SQL result:%d, %s pObj:%p", pSql, pRes->code, taos_errstr(taos), pObj);
    return pRes->code;
  }

S
slguan 已提交
1062
  strtolower(pSql->sqlstr, sql);
H
hzcheng 已提交
1063

1064 1065 1066 1067
  pCmd->curSql = NULL;
  if (NULL != pCmd->pTableList) {
    taosHashCleanup(pCmd->pTableList);
    pCmd->pTableList = NULL;
L
lihui 已提交
1068 1069
  }

1070
  pRes->code = (uint8_t)tsParseSql(pSql, false);
H
hzcheng 已提交
1071 1072 1073 1074 1075 1076 1077
  int code = pRes->code;

  tscTrace("%p Valid SQL result:%d, %s pObj:%p", pSql, pRes->code, taos_errstr(taos), pObj);
  taos_free_result(pSql);

  return code;
}
S
slguan 已提交
1078

H
hjxilinx 已提交
1079
static int tscParseTblNameList(SSqlObj *pSql, const char *tblNameList, int32_t tblListLen) {
S
slguan 已提交
1080 1081 1082 1083 1084 1085 1086 1087
  // must before clean the sqlcmd object
  tscCleanSqlCmd(&pSql->cmd);

  SSqlCmd *pCmd = &pSql->cmd;

  pCmd->command = TSDB_SQL_MULTI_META;
  pCmd->count = 0;

S
slguan 已提交
1088
  int   code = TSDB_CODE_INVALID_TABLE_ID;
H
hjxilinx 已提交
1089
  char *str = (char *)tblNameList;
S
slguan 已提交
1090

1091 1092 1093
  SQueryInfo *pQueryInfo = NULL;
  tscGetQueryInfoDetailSafely(pCmd, pCmd->clauseIndex, &pQueryInfo);

H
hjxilinx 已提交
1094
  STableMetaInfo *pTableMetaInfo = tscAddEmptyMetaInfo(pQueryInfo);
S
slguan 已提交
1095

H
hjxilinx 已提交
1096
  if ((code = tscAllocPayload(pCmd, tblListLen + 16)) != TSDB_CODE_SUCCESS) {
S
slguan 已提交
1097 1098 1099 1100
    return code;
  }

  char *nextStr;
S
slguan 已提交
1101
  char  tblName[TSDB_TABLE_ID_LEN];
S
slguan 已提交
1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117
  int   payloadLen = 0;
  char *pMsg = pCmd->payload;
  while (1) {
    nextStr = strchr(str, ',');
    if (nextStr == NULL) {
      break;
    }

    memcpy(tblName, str, nextStr - str);
    int32_t len = nextStr - str;
    tblName[len] = '\0';

    str = nextStr + 1;

    strtrim(tblName);
    len = (uint32_t)strlen(tblName);
H
hjxilinx 已提交
1118

S
slguan 已提交
1119 1120 1121 1122 1123
    SSQLToken sToken = {.n = len, .type = TK_ID, .z = tblName};
    tSQLGetToken(tblName, &sToken.type);

    // Check if the table name available or not
    if (tscValidateName(&sToken) != TSDB_CODE_SUCCESS) {
S
slguan 已提交
1124
      code = TSDB_CODE_INVALID_TABLE_ID;
S
slguan 已提交
1125 1126 1127 1128
      sprintf(pCmd->payload, "table name is invalid");
      return code;
    }

H
hjxilinx 已提交
1129
    if ((code = setMeterID(pTableMetaInfo, &sToken, pSql)) != TSDB_CODE_SUCCESS) {
S
slguan 已提交
1130 1131 1132 1133
      return code;
    }

    if (++pCmd->count > TSDB_MULTI_METERMETA_MAX_NUM) {
S
slguan 已提交
1134
      code = TSDB_CODE_INVALID_TABLE_ID;
S
slguan 已提交
1135 1136 1137 1138
      sprintf(pCmd->payload, "tables over the max number");
      return code;
    }

H
hjxilinx 已提交
1139
    if (payloadLen + strlen(pTableMetaInfo->name) + 128 >= pCmd->allocSize) {
S
slguan 已提交
1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151
      char *pNewMem = realloc(pCmd->payload, pCmd->allocSize + tblListLen);
      if (pNewMem == NULL) {
        code = TSDB_CODE_CLI_OUT_OF_MEMORY;
        sprintf(pCmd->payload, "failed to allocate memory");
        return code;
      }

      pCmd->payload = pNewMem;
      pCmd->allocSize = pCmd->allocSize + tblListLen;
      pMsg = pCmd->payload;
    }

H
hjxilinx 已提交
1152
    payloadLen += sprintf(pMsg + payloadLen, "%s,", pTableMetaInfo->name);
S
slguan 已提交
1153 1154 1155 1156 1157 1158 1159 1160 1161
  }

  *(pMsg + payloadLen) = '\0';
  pCmd->payloadLen = payloadLen + 1;

  return TSDB_CODE_SUCCESS;
}

int taos_load_table_info(TAOS *taos, const char *tableNameList) {
H
hjxilinx 已提交
1162
  const int32_t MAX_TABLE_NAME_LENGTH = 12 * 1024 * 1024;  // 12MB list
S
slguan 已提交
1163 1164 1165

  STscObj *pObj = (STscObj *)taos;
  if (pObj == NULL || pObj->signature != pObj) {
H
hjxilinx 已提交
1166
    terrno = TSDB_CODE_DISCONNECTED;
S
slguan 已提交
1167 1168 1169 1170 1171 1172 1173
    return TSDB_CODE_DISCONNECTED;
  }

  SSqlObj *pSql = pObj->pSql;
  SSqlRes *pRes = &pSql->res;

  pRes->numOfTotal = 0;  // the number of getting table meta from server
H
hjxilinx 已提交
1174
  pRes->numOfTotalInCurrentClause = 0;
1175

S
slguan 已提交
1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187
  pRes->code = 0;

  assert(pSql->fp == NULL);
  tscTrace("%p tableNameList: %s pObj:%p", pSql, tableNameList, pObj);

  int32_t tblListLen = strlen(tableNameList);
  if (tblListLen > MAX_TABLE_NAME_LENGTH) {
    tscError("%p tableNameList too long, length:%d, maximum allowed:%d", pSql, tblListLen, MAX_TABLE_NAME_LENGTH);
    pRes->code = TSDB_CODE_INVALID_SQL;
    return pRes->code;
  }

H
hjxilinx 已提交
1188
  char *str = calloc(1, tblListLen + 1);
S
slguan 已提交
1189 1190 1191 1192 1193 1194 1195
  if (str == NULL) {
    pRes->code = TSDB_CODE_CLI_OUT_OF_MEMORY;
    tscError("%p failed to malloc sql string buffer", pSql);
    return pRes->code;
  }

  strtolower(str, tableNameList);
H
hjxilinx 已提交
1196
  pRes->code = (uint8_t)tscParseTblNameList(pSql, str, tblListLen);
S
slguan 已提交
1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218

  /*
   * set the qhandle to 0 before return in order to erase the qhandle value assigned in the previous successful query.
   * If qhandle is NOT set 0, the function of taos_free_result() will send message to server by calling tscProcessSql()
   * to free connection, which may cause segment fault, when the parse phrase is not even successfully executed.
   */
  pRes->qhandle = 0;
  free(str);

  if (pRes->code != TSDB_CODE_SUCCESS) {
    return pRes->code;
  }

  tscDoQuery(pSql);

  tscTrace("%p load multi metermeta result:%d %s pObj:%p", pSql, pRes->code, taos_errstr(taos), pObj);
  if (pRes->code != TSDB_CODE_SUCCESS) {
    tscFreeSqlObjPartial(pSql);
  }

  return pRes->code;
}