tscSql.c 33.6 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 20
#include "tcache.h"
#include "tlog.h"
H
hjxilinx 已提交
21
#include "tnote.h"
H
hzcheng 已提交
22 23 24
#include "trpc.h"
#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
    tscMgmtIpList.inUse = 0;
S
slguan 已提交
76
    tscMgmtIpList.port = tsMnodeShellPort;
S
slguan 已提交
77
    tscMgmtIpList.numOfIps = 1;
S
slguan 已提交
78
    tscMgmtIpList.ip[0] = inet_addr(ip);
S
slguan 已提交
79 80 81 82 83 84 85

    if (tsMasterIp[0] && strcmp(ip, tsMasterIp) != 0) {
      tscMgmtIpList.numOfIps = 2;
      tscMgmtIpList.ip[1] = inet_addr(tsMasterIp);
    }

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

S
slguan 已提交
91
  tscMgmtIpList.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;
S
slguan 已提交
132
  tsem_init(&pSql->rspSem, 0, 0);
H
hjxilinx 已提交
133
  
H
hzcheng 已提交
134 135 136 137 138 139 140 141
  pObj->pSql = pSql;
  pSql->fp = fp;
  pSql->param = param;
  if (taos != NULL) {
    *taos = pObj;
  }

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

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

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

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

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

202
  return NULL;
H
hzcheng 已提交
203 204
}

L
lihui 已提交
205
TAOS *taos_connect_a(char *ip, char *user, char *pass, char *db, uint16_t port, void (*fp)(void *, TAOS_RES *, int),
H
hzcheng 已提交
206
                     void *param, void **taos) {
H
hjxilinx 已提交
207
  STscObj* pObj = taosConnectImpl(ip, user, pass, db, port, fp, param, taos);
208 209 210 211 212 213 214 215 216 217
  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 已提交
218 219 220 221 222 223 224 225 226 227 228 229 230 231 232
}

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 已提交
233
int taos_query_imp(STscObj *pObj, SSqlObj *pSql) {
H
hzcheng 已提交
234 235 236 237
  SSqlRes *pRes = &pSql->res;

  pRes->numOfRows = 1;
  pRes->numOfTotal = 0;
H
hjxilinx 已提交
238
  pRes->numOfTotalInCurrentClause = 0;
239

L
lihui 已提交
240 241
  pSql->asyncTblPos = NULL;
  if (NULL != pSql->pTableHashList) {
H
hjxilinx 已提交
242
    taosHashCleanup(pSql->pTableHashList);
L
lihui 已提交
243 244
    pSql->pTableHashList = NULL;
  }
H
hjxilinx 已提交
245

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

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

  /*
   * 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 已提交
257 258 259
  if (pRes->code == TSDB_CODE_SUCCESS) {
    tscDoQuery(pSql);
  }
H
hzcheng 已提交
260

H
hjxilinx 已提交
261 262 263 264 265
  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 已提交
266

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

  return pRes->code;
}

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

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

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

H
hzcheng 已提交
303 304 305
TAOS_RES *taos_use_result(TAOS *taos) {
  STscObj *pObj = (STscObj *)taos;
  if (pObj == NULL || pObj->signature != pObj) {
H
hjxilinx 已提交
306
    terrno = TSDB_CODE_DISCONNECTED;
H
hzcheng 已提交
307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325
    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;

326
  SQueryInfo *pQueryInfo = tscGetQueryInfoDetail(&pSql->cmd, 0);
327 328 329
  if (pQueryInfo == NULL) {
    return 0;
  }
330

331
  SFieldInfo *pFieldsInfo = &pQueryInfo->fieldsInfo;
S
slguan 已提交
332
  return (pFieldsInfo->numOfOutputCols - pFieldsInfo->numOfHiddenCols);
H
hzcheng 已提交
333 334 335 336 337 338
}

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

S
slguan 已提交
339
  return taos_num_fields(pObj->pSql);
H
hzcheng 已提交
340 341 342 343 344 345 346 347 348 349 350 351
}

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;
352 353

  SQueryInfo *pQueryInfo = tscGetQueryInfoDetail(&pSql->cmd, 0);
354
  return pQueryInfo->fieldsInfo.pFields;
H
hzcheng 已提交
355 356 357 358 359 360 361 362 363 364
}

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 已提交
365 366
  tscResetForNextRetrieve(pRes);

H
hzcheng 已提交
367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386
  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 已提交
387
  tscResetForNextRetrieve(pRes);
H
hzcheng 已提交
388 389 390 391 392 393 394 395 396 397
  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 已提交
398 399
  // secondary merge has handle this situation
  if (pCmd->command != TSDB_SQL_RETRIEVE_METRIC) {
H
hjxilinx 已提交
400
    pRes->numOfTotalInCurrentClause += pRes->numOfRows;
S
slguan 已提交
401 402
  }

403
  SQueryInfo *pQueryInfo = tscGetQueryInfoDetail(pCmd, 0);
404
  for (int i = 0; i < pQueryInfo->fieldsInfo.numOfOutputCols; ++i) {
H
hjxilinx 已提交
405
    pRes->tsrow[i] = TSC_GET_RESPTR_BASE(pRes, pQueryInfo, i);
H
hzcheng 已提交
406 407 408 409
  }

  *rows = pRes->tsrow;

410
  return (pQueryInfo->order.order == TSQL_SO_DESC) ? pRes->numOfRows : -pRes->numOfRows;
H
hzcheng 已提交
411 412
}

H
hjxilinx 已提交
413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440
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;
441 442
  for (int32_t i = 0; i < pExpr->binExprInfo.numOfCols; ++i) {
    if (strcmp(name, pExpr->binExprInfo.pReqColumns[i].name) == 0) {
H
hjxilinx 已提交
443 444 445 446 447
      index = i;
      break;
    }
  }

448
  assert(index >= 0 && index < pExpr->binExprInfo.numOfCols);
H
hjxilinx 已提交
449 450 451
  return pSupport->data[index] + pSupport->offset * pSupport->elemSize[index];
}

S
slguan 已提交
452
static void **doSetResultRowData(SSqlObj *pSql) {
H
hzcheng 已提交
453 454
  SSqlCmd *pCmd = &pSql->cmd;
  SSqlRes *pRes = &pSql->res;
H
hjxilinx 已提交
455

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

H
hjxilinx 已提交
458 459 460 461
  if (pRes->row >= pRes->numOfRows) {  // all the results has returned to invoker
    tfree(pRes->tsrow);
    return pRes->tsrow;
  }
462

H
hjxilinx 已提交
463 464 465 466 467 468 469 470 471 472 473 474
  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 已提交
475
  int32_t num = 0;
H
hjxilinx 已提交
476 477
  for (int i = 0; i < tscNumOfFields(pQueryInfo); ++i) {
    if (pQueryInfo->fieldsInfo.pSqlExpr[i] != NULL) {
H
hjxilinx 已提交
478 479 480 481
      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 已提交
482
    }
S
slguan 已提交
483

H
hzcheng 已提交
484
    // primary key column cannot be null in interval query, no need to check
485
    if (i == 0 && pQueryInfo->intervalTime > 0) {
H
hzcheng 已提交
486 487 488
      continue;
    }

489
    TAOS_FIELD *pField = tscFieldInfoGetField(pQueryInfo, i);
H
hjxilinx 已提交
490
    transferNcharData(pSql, i, pField);
H
hzcheng 已提交
491

H
hjxilinx 已提交
492 493 494 495 496 497
    // 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];
      
498
      sas->numOfCols = sas->pExpr->binExprInfo.numOfCols;
H
hjxilinx 已提交
499 500 501
      
      if (pRes->buffer[i] == NULL) {
        pRes->buffer[i] = malloc(tscFieldInfoGetField(pQueryInfo, i)->bytes);
H
hzcheng 已提交
502
      }
H
hjxilinx 已提交
503
      
H
hjxilinx 已提交
504
      for(int32_t k = 0; k < sas->numOfCols; ++k) {
505
        int32_t columnIndex = sas->pExpr->binExprInfo.pReqColumns[k].colIdxInBuf;
H
hjxilinx 已提交
506 507 508 509
        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 已提交
510
      }
H
hjxilinx 已提交
511

512
      tSQLBinaryExprCalcTraverse(sas->pExpr->binExprInfo.pBinExpr, 1, pRes->buffer[i], sas, TSQL_SO_ASC, getArithemicInputSrc);
H
hjxilinx 已提交
513
      pRes->tsrow[i] = pRes->buffer[i];
H
hjxilinx 已提交
514
      
H
hjxilinx 已提交
515
      free(sas); //todo optimization
H
hzcheng 已提交
516 517 518
    }
  }

519
  assert(num <= pQueryInfo->fieldsInfo.numOfOutputCols);
H
hjxilinx 已提交
520 521

  pRes->row++;  // index increase one-step
H
hzcheng 已提交
522 523 524
  return pRes->tsrow;
}

H
hjxilinx 已提交
525 526
static bool tscHashRemainDataInSubqueryResultSet(SSqlObj *pSql) {
  bool     hasData = true;
S
slguan 已提交
527 528
  SSqlCmd *pCmd = &pSql->cmd;

529
  SQueryInfo *pQueryInfo = tscGetQueryInfoDetail(pCmd, pCmd->clauseIndex);
530
  if (tscNonOrderedProjectionQueryOnSTable(pQueryInfo, 0)) {
H
hjxilinx 已提交
531
    bool allSubqueryExhausted = true;
S
slguan 已提交
532

H
hjxilinx 已提交
533
    for (int32_t i = 0; i < pSql->numOfSubs; ++i) {
534 535 536 537
      if (pSql->pSubs[i] == NULL) {
        continue;
      }

538
//      SSqlRes *pRes1 = &pSql->pSubs[i]->res;
H
hjxilinx 已提交
539 540
      SSqlCmd *pCmd1 = &pSql->pSubs[i]->cmd;

541
      SQueryInfo *    pQueryInfo1 = tscGetQueryInfoDetail(pCmd1, pCmd1->clauseIndex);
542
//      STableMetaInfo *pMetaInfo = tscGetMetaInfo(pQueryInfo1, 0);
543

H
hjxilinx 已提交
544
      assert(pQueryInfo1->numOfTables == 1);
H
hjxilinx 已提交
545 546 547

      /*
       * if the global limitation is not reached, and current result has not exhausted, or next more vnodes are
548
       * available, goes on
H
hjxilinx 已提交
549
       */
H
hjxilinx 已提交
550 551 552 553 554
//      if (pMetaInfo->vnodeIndex < pMetaInfo->pMetricMeta->numOfVnodes && pRes1->row < pRes1->numOfRows &&
//          (!tscHasReachLimitation(pQueryInfo1, pRes1))) {
//        allSubqueryExhausted = false;
//        break;
//      }
H
hjxilinx 已提交
555
    }
S
slguan 已提交
556

H
hjxilinx 已提交
557 558
    hasData = !allSubqueryExhausted;
  } else {  // otherwise, in case inner join, if any subquery exhausted, query completed.
S
slguan 已提交
559
    for (int32_t i = 0; i < pSql->numOfSubs; ++i) {
560 561 562
      if (pSql->pSubs[i] == 0) {
        continue;
      }
H
hjxilinx 已提交
563

564 565 566
      SSqlRes *   pRes1 = &pSql->pSubs[i]->res;
      SQueryInfo *pQueryInfo1 = tscGetQueryInfoDetail(&pSql->pSubs[i]->cmd, 0);

H
hjxilinx 已提交
567
      if ((pRes1->row >= pRes1->numOfRows && tscHasReachLimitation(pQueryInfo1, pRes1) &&
568 569
           tscProjectionQueryOnTable(pQueryInfo1)) ||
          (pRes1->numOfRows == 0)) {
S
slguan 已提交
570 571 572 573
        hasData = false;
        break;
      }
    }
H
hjxilinx 已提交
574 575 576 577
  }

  return hasData;
}
S
slguan 已提交
578

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

H
hjxilinx 已提交
582
  while (1) {
583
    SQueryInfo *pQueryInfo = tscGetQueryInfoDetail(&pSql->cmd, pSql->cmd.clauseIndex);
S
slguan 已提交
584
    if (pRes->tsrow == NULL) {
H
hjxilinx 已提交
585
      pRes->tsrow = calloc(pQueryInfo->exprsInfo.numOfExprs, POINTER_BYTES);
S
slguan 已提交
586 587 588
    }

    bool success = false;
589 590 591 592 593 594 595 596 597

    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 已提交
598
      success = (doSetResultRowData(pSql->pSubs[0]) != NULL) && (doSetResultRowData(pSql->pSubs[1]) != NULL);
H
hjxilinx 已提交
599
    } else {  // only one subquery
600 601 602 603 604
      SSqlObj *pSub = pSql->pSubs[0];
      if (pSub == NULL) {
        pSub = pSql->pSubs[1];
      }

H
hjxilinx 已提交
605
      success = (doSetResultRowData(pSub) != NULL);
S
slguan 已提交
606 607
    }

H
hjxilinx 已提交
608
    if (success) {  // current row of final output has been built, return to app
609
      for (int32_t i = 0; i < pQueryInfo->exprsInfo.numOfExprs; ++i) {
S
slguan 已提交
610 611 612 613 614 615 616
        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];
      }

617
      pRes->numOfTotalInCurrentClause++;
H
hjxilinx 已提交
618

619
      break;
620
    } else {  // continue retrieve data from vnode
621
      if (!tscHashRemainDataInSubqueryResultSet(pSql)) {
622 623
        tscTrace("%p at least one subquery exhausted, free all other %d subqueries", pSql, pSql->numOfSubs - 1);
        SSubqueryState *pState = NULL;
624

625
        // free all sub sqlobj
626 627 628 629 630
        for (int32_t i = 0; i < pSql->numOfSubs; ++i) {
          SSqlObj *pChildObj = pSql->pSubs[i];
          if (pChildObj == NULL) {
            continue;
          }
H
hjxilinx 已提交
631

632 633
          SJoinSubquerySupporter *pSupporter = (SJoinSubquerySupporter *)pChildObj->param;
          pState = pSupporter->pState;
H
hjxilinx 已提交
634

635 636 637
          tscDestroyJoinSupporter(pChildObj->param);
          taos_free_result(pChildObj);
        }
H
hjxilinx 已提交
638

639 640 641
        free(pState);
        return NULL;
      }
H
hjxilinx 已提交
642

643 644 645 646
      tscFetchDatablockFromSubquery(pSql);
      if (pRes->code != TSDB_CODE_SUCCESS) {
        return NULL;
      }
H
hjxilinx 已提交
647 648 649
    }
  }

650
  return pRes->tsrow;
H
hjxilinx 已提交
651 652
}

H
[td-99]  
hjxilinx 已提交
653
static void waitForRetrieveRsp(void *param, TAOS_RES *tres, int numOfRows) {
654
  SSqlObj* pSql = (SSqlObj*) tres;
655
  
656
  if (numOfRows < 0) { // set the error code
657 658 659 660 661
    pSql->res.code = -numOfRows;
  }
  sem_post(&pSql->rspSem);
}

H
hzcheng 已提交
662 663 664
TAOS_ROW taos_fetch_row(TAOS_RES *res) {
  SSqlObj *pSql = (SSqlObj *)res;
  if (pSql == NULL || pSql->signature != pSql) {
H
hjxilinx 已提交
665
    terrno = TSDB_CODE_DISCONNECTED;
H
hzcheng 已提交
666 667
    return NULL;
  }
668 669 670 671
  
  SSqlCmd *pCmd = &pSql->cmd;
  SSqlRes *pRes = &pSql->res;
  
H
hjxilinx 已提交
672 673 674
  if (pRes->qhandle == 0 ||
      pCmd->command == TSDB_SQL_RETRIEVE_EMPTY_RESULT ||
      pCmd->command == TSDB_SQL_INSERT) {
675
    return NULL;
676
  }
677 678
  
  // current data are exhausted, fetch more data
679
  if (pRes->data == NULL || (pRes->data != NULL && pRes->row >= pRes->numOfRows && pRes->completed != true &&
H
hjxilinx 已提交
680
      (pCmd->command == TSDB_SQL_RETRIEVE || pCmd->command == TSDB_SQL_RETRIEVE_METRIC || pCmd->command == TSDB_SQL_FETCH))) {
H
[td-99]  
hjxilinx 已提交
681
    taos_fetch_rows_a(res, waitForRetrieveRsp, pSql->pTscObj);
H
hjxilinx 已提交
682
    
683
    sem_wait(&pSql->rspSem);
H
hjxilinx 已提交
684
  }
685 686
  
  return doSetResultRowData(pSql);
H
hzcheng 已提交
687 688 689 690
}

int taos_fetch_block(TAOS_RES *res, TAOS_ROW *rows) {
  SSqlObj *pSql = (SSqlObj *)res;
H
hjxilinx 已提交
691
  SSqlCmd *pCmd = &pSql->cmd;
692
  SSqlRes *pRes = &pSql->res;
693

H
hzcheng 已提交
694 695 696
  int nRows = 0;

  if (pSql == NULL || pSql->signature != pSql) {
H
hjxilinx 已提交
697
    terrno = TSDB_CODE_DISCONNECTED;
H
hzcheng 已提交
698 699 700 701
    *rows = NULL;
    return 0;
  }

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

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

710
    pSql->cmd.command = pQueryInfo->command;
H
hjxilinx 已提交
711
    pCmd->clauseIndex++;
712

713 714 715
    pRes->numOfTotal += pRes->numOfTotalInCurrentClause;
    pRes->numOfTotalInCurrentClause = 0;
    pRes->rspType = 0;
716

717 718
    pSql->numOfSubs = 0;
    tfree(pSql->pSubs);
719

H
hjxilinx 已提交
720
    assert(pSql->fp == NULL);
721

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

H
hjxilinx 已提交
725
    nRows = taos_fetch_block_impl(res, rows);
H
hzcheng 已提交
726
  }
727

H
hzcheng 已提交
728 729 730
  return nRows;
}

S
slguan 已提交
731
int taos_select_db(TAOS *taos, const char *db) {
732
  char sql[256] = {0};
H
hzcheng 已提交
733 734 735

  STscObj *pObj = (STscObj *)taos;
  if (pObj == NULL || pObj->signature != pObj) {
H
hjxilinx 已提交
736
    terrno = TSDB_CODE_DISCONNECTED;
H
hzcheng 已提交
737 738 739
    return TSDB_CODE_DISCONNECTED;
  }

740
  snprintf(sql, tListLen(sql), "use %s", db);
H
hzcheng 已提交
741 742 743
  return taos_query(taos, sql);
}

H
hjxilinx 已提交
744
void taos_free_result_imp(TAOS_RES *res, int keepCmd) {
H
hzcheng 已提交
745 746 747 748 749 750 751 752 753
  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 已提交
754

H
hzcheng 已提交
755 756 757
  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);
758 759
    
    if (tscShouldFreeAsyncSqlObj(pSql)) {
H
hzcheng 已提交
760
      tscTrace("%p Async SqlObj is freed by app", pSql);
sangshuduo's avatar
sangshuduo 已提交
761
      tscFreeSqlObj(pSql);
H
hzcheng 已提交
762
    } else {
763 764 765 766 767
      if (keepCmd) {
        tscFreeSqlResult(pSql);
      } else {
        tscFreeSqlObjPartial(pSql);
      }
H
hzcheng 已提交
768
    }
769
    
H
hzcheng 已提交
770 771 772
    return;
  }

S
slguan 已提交
773
  // set freeFlag to 1 in retrieve message if there are un-retrieved results
774
  SQueryInfo *pQueryInfo = tscGetQueryInfoDetail(&pSql->cmd, 0);
775 776 777 778 779
  if (pQueryInfo == NULL) {
    tscFreeSqlObjPartial(pSql);
    return;
  }

780
  pQueryInfo->type = TSDB_QUERY_TYPE_FREE_RESOURCE;
S
slguan 已提交
781

H
hjxilinx 已提交
782
  STableMetaInfo *pTableMetaInfo = tscGetMetaInfo(pQueryInfo, 0);
H
hzcheng 已提交
783 784

  /*
S
slguan 已提交
785 786
   * 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 已提交
787
   * case 2. When the query response is received from vnodes and the numOfRows is set to 0, the user calls
S
slguan 已提交
788 789 790 791 792
   *         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 已提交
793
   */
H
[TD-98]  
hjxilinx 已提交
794 795 796
  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 已提交
797
       (pRes->code == TSDB_CODE_SUCCESS && pRes->numOfRows == 0 && pCmd->command == TSDB_SQL_SELECT &&
H
[TD-98]  
hjxilinx 已提交
798
        pSql->pStream == NULL && pTableMetaInfo->pTableMeta != NULL)))) {
H
hzcheng 已提交
799 800
    pCmd->command = (pCmd->command > TSDB_SQL_MGMT) ? TSDB_SQL_RETRIEVE : TSDB_SQL_FETCH;

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

S
slguan 已提交
803 804
    void *fp = pSql->fp;
    if (fp != NULL) {
H
hzcheng 已提交
805
      pSql->freed = 1;
S
slguan 已提交
806
    }
H
hzcheng 已提交
807

S
slguan 已提交
808 809 810 811 812 813 814
    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 已提交
815
      /*
S
slguan 已提交
816 817 818 819 820 821 822 823
       * 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 已提交
824 825 826 827 828 829 830
      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);
      }
831 832 833 834 835
    } else {  // for async release, remove its link
      STscObj* pObj = pSql->pTscObj;
      if (pObj->pSql == pSql) {
        pObj->pSql = NULL;
      }
H
hzcheng 已提交
836 837
    }
  } else {
S
slguan 已提交
838
    // if no free resource msg is sent to vnode, we free this object immediately.
839 840
    bool free = tscShouldFreeAsyncSqlObj(pSql);
    if (free) {
H
hzcheng 已提交
841
      assert(pRes->numOfRows == 0 || (pCmd->command > TSDB_SQL_LOCAL));
842
  
H
hzcheng 已提交
843
      tscFreeSqlObj(pSql);
S
slguan 已提交
844
      tscTrace("%p Async sql result is freed by app", pSql);
H
hzcheng 已提交
845
    } else {
846 847 848 849 850 851 852
      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 已提交
853 854 855 856
    }
  }
}

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

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

H
[td-99]  
hjxilinx 已提交
863 864 865
  if (pObj == NULL || pObj->signature != pObj) {
    return terrno;
  }
H
hzcheng 已提交
866

H
[td-99]  
hjxilinx 已提交
867
  return pObj->pSql->res.code;
H
hzcheng 已提交
868 869
}

H
hjxilinx 已提交
870 871 872 873
/*
 * In case of invalid sql error, additional information is attached to explain
 * why the sql is invalid
 */
H
hjxilinx 已提交
874
static bool hasAdditionalErrorInfo(int32_t code, SSqlCmd *pCmd) {
H
hjxilinx 已提交
875 876 877 878 879
  if (code != TSDB_CODE_INVALID_SQL) {
    return false;
  }

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

  char *z = NULL;
H
hjxilinx 已提交
882
  if (len > 0) {
H
hjxilinx 已提交
883
    z = strstr(pCmd->payload, "invalid SQL");
H
hjxilinx 已提交
884
  }
H
hjxilinx 已提交
885

H
hjxilinx 已提交
886 887 888
  return z != NULL;
}

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

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

896 897
  SSqlObj* pSql = pObj->pSql;
  
H
[td-32]  
hjxilinx 已提交
898
  if (hasAdditionalErrorInfo(pSql->res.code, &pSql->cmd)) {
H
hjxilinx 已提交
899
    return pSql->cmd.payload;
H
hzcheng 已提交
900
  } else {
H
[td-32]  
hjxilinx 已提交
901
    return (char*)tstrerror(pSql->res.code);
H
hzcheng 已提交
902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923
  }
}

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;
924 925
  SSqlCmd *pCmd = &pSql->cmd;

H
hzcheng 已提交
926 927 928 929 930
  if (pSql->signature != pSql) return;
  tscTrace("%p start to cancel query", res);

  pSql->res.code = TSDB_CODE_QUERY_CANCELLED;

931
  SQueryInfo *pQueryInfo = tscGetQueryInfoDetail(pCmd, pCmd->clauseIndex);
H
hjxilinx 已提交
932
  if (tscIsTwoStageSTableQuery(pQueryInfo, 0)) {
H
hzcheng 已提交
933 934 935 936 937 938 939 940
    tscKillMetricQuery(pSql);
    return;
  }

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

S
slguan 已提交
941
  //taosStopRpcConn(pSql->thandle);
H
hzcheng 已提交
942 943 944 945 946 947
  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) {
948 949 950 951
    if (i > 0) {
      str[len++] = ' ';
    }

H
hzcheng 已提交
952
    if (row[i] == NULL) {
953
      len += sprintf(str + len, "%s", TSDB_DATA_NULL_STR);
H
hzcheng 已提交
954 955 956 957 958
      continue;
    }

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

      case TSDB_DATA_TYPE_SMALLINT:
963
        len += sprintf(str + len, "%d", *((short *)row[i]));
H
hzcheng 已提交
964 965 966
        break;

      case TSDB_DATA_TYPE_INT:
967
        len += sprintf(str + len, "%d", *((int *)row[i]));
H
hzcheng 已提交
968 969 970
        break;

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

L
lihui 已提交
974 975
      case TSDB_DATA_TYPE_FLOAT: {
        float fv = 0;
L
lihui 已提交
976
        fv = GET_FLOAT_VAL(row[i]);
977
        len += sprintf(str + len, "%f", fv);
978
      } break;
H
hzcheng 已提交
979

980
      case TSDB_DATA_TYPE_DOUBLE: {
L
lihui 已提交
981
        double dv = 0;
L
lihui 已提交
982
        dv = GET_DOUBLE_VAL(row[i]);
983
        len += sprintf(str + len, "%lf", dv);
984
      } break;
H
hzcheng 已提交
985 986

      case TSDB_DATA_TYPE_BINARY:
S
slguan 已提交
987
      case TSDB_DATA_TYPE_NCHAR: {
H
hjxilinx 已提交
988 989 990 991 992 993 994 995
        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 已提交
996 997

      case TSDB_DATA_TYPE_TIMESTAMP:
998
        len += sprintf(str + len, "%" PRId64, *((int64_t *)row[i]));
H
hzcheng 已提交
999 1000 1001
        break;

      case TSDB_DATA_TYPE_BOOL:
1002
        len += sprintf(str + len, "%d", *((int8_t *)row[i]));
H
hzcheng 已提交
1003 1004 1005 1006 1007 1008 1009 1010
      default:
        break;
    }
  }

  return len;
}

S
slguan 已提交
1011
int taos_validate_sql(TAOS *taos, const char *sql) {
H
hzcheng 已提交
1012 1013
  STscObj *pObj = (STscObj *)taos;
  if (pObj == NULL || pObj->signature != pObj) {
H
hjxilinx 已提交
1014
    terrno = TSDB_CODE_DISCONNECTED;
H
hzcheng 已提交
1015 1016 1017 1018 1019 1020 1021 1022
    return TSDB_CODE_DISCONNECTED;
  }

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

  pRes->numOfRows = 1;
  pRes->numOfTotal = 0;
H
hjxilinx 已提交
1023
  pRes->numOfTotalInCurrentClause = 0;
1024

H
hzcheng 已提交
1025 1026 1027
  tscTrace("%p Valid SQL: %s pObj:%p", pSql, sql, pObj);

  int32_t sqlLen = strlen(sql);
H
hjxilinx 已提交
1028
  if (sqlLen > tsMaxSQLStringLen) {
H
hzcheng 已提交
1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041
    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 已提交
1042
  strtolower(pSql->sqlstr, sql);
H
hzcheng 已提交
1043

L
lihui 已提交
1044 1045
  pSql->asyncTblPos = NULL;
  if (NULL != pSql->pTableHashList) {
H
hjxilinx 已提交
1046
    taosHashCleanup(pSql->pTableHashList);
L
lihui 已提交
1047 1048 1049
    pSql->pTableHashList = NULL;
  }

1050
  pRes->code = (uint8_t)tsParseSql(pSql, false);
H
hzcheng 已提交
1051 1052 1053 1054 1055 1056 1057
  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 已提交
1058

H
hjxilinx 已提交
1059
static int tscParseTblNameList(SSqlObj *pSql, const char *tblNameList, int32_t tblListLen) {
S
slguan 已提交
1060 1061 1062 1063 1064 1065 1066 1067
  // must before clean the sqlcmd object
  tscCleanSqlCmd(&pSql->cmd);

  SSqlCmd *pCmd = &pSql->cmd;

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

S
slguan 已提交
1068
  int   code = TSDB_CODE_INVALID_TABLE_ID;
H
hjxilinx 已提交
1069
  char *str = (char *)tblNameList;
S
slguan 已提交
1070

1071 1072 1073
  SQueryInfo *pQueryInfo = NULL;
  tscGetQueryInfoDetailSafely(pCmd, pCmd->clauseIndex, &pQueryInfo);

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

H
hjxilinx 已提交
1076
  if ((code = tscAllocPayload(pCmd, tblListLen + 16)) != TSDB_CODE_SUCCESS) {
S
slguan 已提交
1077 1078 1079 1080
    return code;
  }

  char *nextStr;
S
slguan 已提交
1081
  char  tblName[TSDB_TABLE_ID_LEN];
S
slguan 已提交
1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097
  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 已提交
1098

S
slguan 已提交
1099 1100 1101 1102 1103
    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 已提交
1104
      code = TSDB_CODE_INVALID_TABLE_ID;
S
slguan 已提交
1105 1106 1107 1108
      sprintf(pCmd->payload, "table name is invalid");
      return code;
    }

H
hjxilinx 已提交
1109
    if ((code = setMeterID(pTableMetaInfo, &sToken, pSql)) != TSDB_CODE_SUCCESS) {
S
slguan 已提交
1110 1111 1112 1113
      return code;
    }

    if (++pCmd->count > TSDB_MULTI_METERMETA_MAX_NUM) {
S
slguan 已提交
1114
      code = TSDB_CODE_INVALID_TABLE_ID;
S
slguan 已提交
1115 1116 1117 1118
      sprintf(pCmd->payload, "tables over the max number");
      return code;
    }

H
hjxilinx 已提交
1119
    if (payloadLen + strlen(pTableMetaInfo->name) + 128 >= pCmd->allocSize) {
S
slguan 已提交
1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131
      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 已提交
1132
    payloadLen += sprintf(pMsg + payloadLen, "%s,", pTableMetaInfo->name);
S
slguan 已提交
1133 1134 1135 1136 1137 1138 1139 1140 1141
  }

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

  return TSDB_CODE_SUCCESS;
}

int taos_load_table_info(TAOS *taos, const char *tableNameList) {
H
hjxilinx 已提交
1142
  const int32_t MAX_TABLE_NAME_LENGTH = 12 * 1024 * 1024;  // 12MB list
S
slguan 已提交
1143 1144 1145

  STscObj *pObj = (STscObj *)taos;
  if (pObj == NULL || pObj->signature != pObj) {
H
hjxilinx 已提交
1146
    terrno = TSDB_CODE_DISCONNECTED;
S
slguan 已提交
1147 1148 1149 1150 1151 1152 1153
    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 已提交
1154
  pRes->numOfTotalInCurrentClause = 0;
1155

S
slguan 已提交
1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167
  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 已提交
1168
  char *str = calloc(1, tblListLen + 1);
S
slguan 已提交
1169 1170 1171 1172 1173 1174 1175
  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 已提交
1176
  pRes->code = (uint8_t)tscParseTblNameList(pSql, str, tblListLen);
S
slguan 已提交
1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198

  /*
   * 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;
}