tscSql.c 25.1 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
    return NULL;
  }
68 69 70 71 72 73

  if (ip) {
    if (tscSetMgmtIpListFromCfg(ip, NULL) < 0) return NULL;
    if (port) tscMgmtIpSet.port[0] = port;
  } 
 
74 75
  void *pDnodeConn = NULL;
  if (tscInitRpc(user, pass, &pDnodeConn) != 0) {
H
hjxilinx 已提交
76
    terrno = TSDB_CODE_NETWORK_UNAVAIL;
S
slguan 已提交
77 78
    return NULL;
  }
79
 
80
  STscObj *pObj = (STscObj *)calloc(1, sizeof(STscObj));
S
slguan 已提交
81
  if (NULL == pObj) {
H
hjxilinx 已提交
82
    terrno = TSDB_CODE_CLI_OUT_OF_MEMORY;
83
    rpcClose(pDnodeConn);
S
slguan 已提交
84 85
    return NULL;
  }
H
hjxilinx 已提交
86

H
hzcheng 已提交
87 88 89
  pObj->signature = pObj;

  strncpy(pObj->user, user, TSDB_USER_LEN);
S
slguan 已提交
90
  taosEncryptPass((uint8_t *)pass, strlen(pass), pObj->pass);
S
Shengliang Guan 已提交
91
  pObj->mnodePort = port ? port : tsDnodeShellPort;
H
hzcheng 已提交
92 93 94 95 96

  if (db) {
    int32_t len = strlen(db);
    /* db name is too long */
    if (len > TSDB_DB_NAME_LEN) {
H
hjxilinx 已提交
97
      terrno = TSDB_CODE_INVALID_DB;
98 99
      rpcClose(pDnodeConn);
      free(pObj);
H
hzcheng 已提交
100 101 102 103 104 105 106
      return NULL;
    }

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

    strdequote(tmp);
S
slguan 已提交
107
    strtolower(pObj->db, tmp);
H
hzcheng 已提交
108 109 110 111
  }

  pthread_mutex_init(&pObj->mutex, NULL);

112
  SSqlObj *pSql = (SSqlObj *)calloc(1, sizeof(SSqlObj));
S
slguan 已提交
113
  if (NULL == pSql) {
H
hjxilinx 已提交
114
    terrno = TSDB_CODE_CLI_OUT_OF_MEMORY;
115
    rpcClose(pDnodeConn);
S
slguan 已提交
116 117 118
    free(pObj);
    return NULL;
  }
H
hjxilinx 已提交
119

H
hzcheng 已提交
120 121
  pSql->pTscObj = pObj;
  pSql->signature = pSql;
S
slguan 已提交
122
  pSql->maxRetry = TSDB_MAX_REPLICA_NUM;
123
  
S
slguan 已提交
124
  tsem_init(&pSql->rspSem, 0, 0);
H
hjxilinx 已提交
125
  
H
hzcheng 已提交
126
  pObj->pSql = pSql;
127 128
  pObj->pDnodeConn = pDnodeConn;
  
H
hzcheng 已提交
129 130 131 132 133 134 135
  pSql->fp = fp;
  pSql->param = param;
  if (taos != NULL) {
    *taos = pObj;
  }

  pSql->cmd.command = TSDB_SQL_CONNECT;
136
  if (TSDB_CODE_SUCCESS != tscAllocPayload(&pSql->cmd, TSDB_DEFAULT_PAYLOAD_SIZE)) {
H
hjxilinx 已提交
137
    terrno = TSDB_CODE_CLI_OUT_OF_MEMORY;
138
    rpcClose(pDnodeConn);
S
slguan 已提交
139 140 141 142
    free(pSql);
    free(pObj);
    return NULL;
  }
H
hzcheng 已提交
143

H
hjxilinx 已提交
144
  // tsRpcHeaderSize will be updated during RPC initialization, so only after it initialization, this value is valid
145
  tsInsertHeadSize = tsRpcHeadSize + sizeof(SMsgDesc) + sizeof(SSubmitMsg);
H
hzcheng 已提交
146 147 148
  return pObj;
}

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

L
lihui 已提交
160
TAOS *taos_connect(const char *ip, const char *user, const char *pass, const char *db, uint16_t port) {
161
  tscTrace("try to create a connection to %s:%u, user:%s db:%s", ip, port, user, db);
H
hzcheng 已提交
162

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

193
  return NULL;
H
hzcheng 已提交
194 195
}

L
lihui 已提交
196
TAOS *taos_connect_a(char *ip, char *user, char *pass, char *db, uint16_t port, void (*fp)(void *, TAOS_RES *, int),
H
hzcheng 已提交
197
                     void *param, void **taos) {
H
hjxilinx 已提交
198
  STscObj* pObj = taosConnectImpl(ip, user, pass, db, port, fp, param, taos);
199 200 201 202 203 204 205 206 207 208
  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 已提交
209 210 211 212 213
}

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

H
hjxilinx 已提交
214 215 216
  if (pObj == NULL || pObj->signature != pObj)  {
    return;
  }
H
hzcheng 已提交
217 218 219 220 221 222 223 224

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

H
hjxilinx 已提交
225
int taos_query_imp(STscObj *pObj, SSqlObj *pSql) {
H
hzcheng 已提交
226
  SSqlRes *pRes = &pSql->res;
227 228 229
  SSqlCmd *pCmd = &pSql->cmd;
  
  pRes->numOfRows  = 1;
H
hzcheng 已提交
230
  pRes->numOfTotal = 0;
H
Haojun Liao 已提交
231
  pRes->numOfClauseTotal = 0;
232

233 234 235 236
  pCmd->curSql = NULL;
  if (NULL != pCmd->pTableList) {
    taosHashCleanup(pCmd->pTableList);
    pCmd->pTableList = NULL;
L
lihui 已提交
237
  }
H
hjxilinx 已提交
238

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

241
  pRes->code = (uint8_t)tsParseSql(pSql, false);
H
hzcheng 已提交
242 243 244 245 246 247 248 249

  /*
   * 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 已提交
250 251 252
  if (pRes->code == TSDB_CODE_SUCCESS) {
    tscDoQuery(pSql);
  }
H
hzcheng 已提交
253

H
hjxilinx 已提交
254 255 256 257 258
  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 已提交
259

H
hzcheng 已提交
260
  if (pRes->code != TSDB_CODE_SUCCESS) {
H
hjxilinx 已提交
261
    tscPartiallyFreeSqlObj(pSql);
H
hzcheng 已提交
262 263 264 265 266
  }

  return pRes->code;
}

H
[td-99]  
hjxilinx 已提交
267
static void waitForQueryRsp(void *param, TAOS_RES *tres, int code) {
268
  assert(param != NULL);
H
[td-99]  
hjxilinx 已提交
269
  SSqlObj *pSql = ((STscObj *)param)->pSql;
270
  
H
[td-99]  
hjxilinx 已提交
271 272 273 274 275
  // valid error code is less than 0
  if (code < 0) {
    pSql->res.code = code;
  }
  
H
[td-99]  
hjxilinx 已提交
276
  sem_post(&pSql->rspSem);
277 278
}

S
slguan 已提交
279 280 281
int taos_query(TAOS *taos, const char *sqlstr) {
  STscObj *pObj = (STscObj *)taos;
  if (pObj == NULL || pObj->signature != pObj) {
H
[td-99]  
hjxilinx 已提交
282
    terrno = TSDB_CODE_DISCONNECTED;
S
slguan 已提交
283 284
    return TSDB_CODE_DISCONNECTED;
  }
285
  
286
  SSqlObj* pSql = pObj->pSql;
H
Haojun Liao 已提交
287
  size_t   sqlLen = strlen(sqlstr);
H
[TD-98]  
hjxilinx 已提交
288
  doAsyncQuery(pObj, pSql, waitForQueryRsp, taos, sqlstr, sqlLen);
S
slguan 已提交
289

290
  // wait for the callback function to post the semaphore
H
Haojun Liao 已提交
291
  tsem_wait(&pSql->rspSem);
292
  return pSql->res.code;
S
slguan 已提交
293 294
}

H
hzcheng 已提交
295 296 297
TAOS_RES *taos_use_result(TAOS *taos) {
  STscObj *pObj = (STscObj *)taos;
  if (pObj == NULL || pObj->signature != pObj) {
H
hjxilinx 已提交
298
    terrno = TSDB_CODE_DISCONNECTED;
H
hzcheng 已提交
299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317
    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;

H
hjxilinx 已提交
318
  int32_t num = 0;
319
  SQueryInfo *pQueryInfo = tscGetQueryInfoDetail(&pSql->cmd, 0);
320
  if (pQueryInfo == NULL) {
H
hjxilinx 已提交
321
    return num;
322
  }
323

H
hjxilinx 已提交
324 325 326 327 328 329 330 331 332
  size_t numOfCols = tscNumOfFields(pQueryInfo);
  for(int32_t i = 0; i < numOfCols; ++i) {
    SFieldSupInfo* pInfo = taosArrayGet(pQueryInfo->fieldsInfo.pSupportInfo, i);
    if (pInfo->visible) {
      num++;
    }
  }
  
  return num;
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);
H
hjxilinx 已提交
354
  if (pQueryInfo == NULL) {
sangshuduo's avatar
sangshuduo 已提交
355
    return NULL;
H
hjxilinx 已提交
356 357 358 359 360 361 362 363
  }
  
  size_t numOfCols = tscNumOfFields(pQueryInfo);
  if (numOfCols == 0) {
    return NULL;
  }
  
  return pQueryInfo->fieldsInfo.pFields->pData;
H
hzcheng 已提交
364 365 366 367 368 369 370 371 372 373
}

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

H
hzcheng 已提交
376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395
  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 已提交
396
  tscResetForNextRetrieve(pRes);
H
hzcheng 已提交
397 398 399 400 401 402 403 404 405 406
  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 已提交
407
  // secondary merge has handle this situation
H
hjxilinx 已提交
408
  if (pCmd->command != TSDB_SQL_RETRIEVE_LOCALMERGE) {
H
Haojun Liao 已提交
409
    pRes->numOfClauseTotal += pRes->numOfRows;
S
slguan 已提交
410 411
  }

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

H
hjxilinx 已提交
416
  assert(0);
H
hjxilinx 已提交
417
  for (int i = 0; i < pQueryInfo->fieldsInfo.numOfOutput; ++i) {
418
    tscGetResultColumnChr(pRes, &pQueryInfo->fieldsInfo, 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
[td-99]  
hjxilinx 已提交
426
static void waitForRetrieveRsp(void *param, TAOS_RES *tres, int numOfRows) {
427
  SSqlObj* pSql = (SSqlObj*) tres;
428
  
429
  if (numOfRows < 0) { // set the error code
430 431 432 433 434
    pSql->res.code = -numOfRows;
  }
  sem_post(&pSql->rspSem);
}

H
hzcheng 已提交
435 436 437
TAOS_ROW taos_fetch_row(TAOS_RES *res) {
  SSqlObj *pSql = (SSqlObj *)res;
  if (pSql == NULL || pSql->signature != pSql) {
H
hjxilinx 已提交
438
    terrno = TSDB_CODE_DISCONNECTED;
H
hzcheng 已提交
439 440
    return NULL;
  }
441 442 443 444
  
  SSqlCmd *pCmd = &pSql->cmd;
  SSqlRes *pRes = &pSql->res;
  
H
hjxilinx 已提交
445 446 447
  if (pRes->qhandle == 0 ||
      pCmd->command == TSDB_SQL_RETRIEVE_EMPTY_RESULT ||
      pCmd->command == TSDB_SQL_INSERT) {
448
    return NULL;
449
  }
450
  
451 452
  // current data set are exhausted, fetch more data from node
  if (pRes->row >= pRes->numOfRows && (pRes->completed != true || hasMoreVnodesToTry(pSql)) &&
H
hjxilinx 已提交
453
      (pCmd->command == TSDB_SQL_RETRIEVE ||
H
hjxilinx 已提交
454
       pCmd->command == TSDB_SQL_RETRIEVE_LOCALMERGE ||
455
       pCmd->command == TSDB_SQL_TABLE_JOIN_RETRIEVE ||
H
hjxilinx 已提交
456 457 458 459
       pCmd->command == TSDB_SQL_FETCH ||
       pCmd->command == TSDB_SQL_SHOW ||
       pCmd->command == TSDB_SQL_SELECT ||
       pCmd->command == TSDB_SQL_DESCRIBE_TABLE)) {
H
[td-99]  
hjxilinx 已提交
460
    taos_fetch_rows_a(res, waitForRetrieveRsp, pSql->pTscObj);
461
    sem_wait(&pSql->rspSem);
H
hjxilinx 已提交
462
  }
463
  
H
hjxilinx 已提交
464
  return doSetResultRowData(pSql, true);
H
hzcheng 已提交
465 466 467
}

int taos_fetch_block(TAOS_RES *res, TAOS_ROW *rows) {
H
hjxilinx 已提交
468
#if 0
H
hzcheng 已提交
469
  SSqlObj *pSql = (SSqlObj *)res;
H
hjxilinx 已提交
470
  SSqlCmd *pCmd = &pSql->cmd;
471
  SSqlRes *pRes = &pSql->res;
472

H
hzcheng 已提交
473 474 475
  int nRows = 0;

  if (pSql == NULL || pSql->signature != pSql) {
H
hjxilinx 已提交
476
    terrno = TSDB_CODE_DISCONNECTED;
H
hzcheng 已提交
477 478 479 480
    *rows = NULL;
    return 0;
  }

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

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

489
    pSql->cmd.command = pQueryInfo->command;
H
hjxilinx 已提交
490
    pCmd->clauseIndex++;
491

H
Haojun Liao 已提交
492 493
    pRes->numOfTotal += pRes->numOfClauseTotal;
    pRes->numOfClauseTotal = 0;
494
    pRes->rspType = 0;
495

496 497
    pSql->numOfSubs = 0;
    tfree(pSql->pSubs);
498

H
hjxilinx 已提交
499
    assert(pSql->fp == NULL);
500

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

H
hjxilinx 已提交
504
    nRows = taos_fetch_block_impl(res, rows);
H
hzcheng 已提交
505
  }
506

H
hzcheng 已提交
507
  return nRows;
H
hjxilinx 已提交
508 509 510 511
#endif

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

S
slguan 已提交
514
int taos_select_db(TAOS *taos, const char *db) {
515
  char sql[256] = {0};
H
hzcheng 已提交
516 517 518

  STscObj *pObj = (STscObj *)taos;
  if (pObj == NULL || pObj->signature != pObj) {
H
hjxilinx 已提交
519
    terrno = TSDB_CODE_DISCONNECTED;
H
hzcheng 已提交
520 521 522
    return TSDB_CODE_DISCONNECTED;
  }

523
  snprintf(sql, tListLen(sql), "use %s", db);
H
hzcheng 已提交
524 525 526
  return taos_query(taos, sql);
}

H
Haojun Liao 已提交
527
void taos_free_result(TAOS_RES *res) {
H
hzcheng 已提交
528 529 530 531 532 533 534 535 536
  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 已提交
537

H
Haojun Liao 已提交
538
  STscObj* pObj = pSql->pTscObj;
H
hzcheng 已提交
539 540 541
  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);
542
    
H
Haojun Liao 已提交
543 544
    // The semaphore can not be changed while freeing async sub query objects.
    if (pObj->pSql != pSql) {
545
      tscTrace("%p SqlObj is freed by app", pSql);
sangshuduo's avatar
sangshuduo 已提交
546
      tscFreeSqlObj(pSql);
H
hzcheng 已提交
547
    } else {
H
Haojun Liao 已提交
548
      tscPartiallyFreeSqlObj(pSql);
H
hzcheng 已提交
549
    }
H
Haojun Liao 已提交
550
  
H
hzcheng 已提交
551 552 553
    return;
  }

H
Haojun Liao 已提交
554
  // set freeFlag to 1 in retrieve message if there are un-retrieved results data in node
555
  SQueryInfo *pQueryInfo = tscGetQueryInfoDetail(&pSql->cmd, 0);
556
  if (pQueryInfo == NULL) {
H
hjxilinx 已提交
557
    tscPartiallyFreeSqlObj(pSql);
558 559 560
    return;
  }

561
  pQueryInfo->type = TSDB_QUERY_TYPE_FREE_RESOURCE;
562
  STscObj* pTscObj = pSql->pTscObj;
S
slguan 已提交
563

H
hjxilinx 已提交
564
  STableMetaInfo *pTableMetaInfo = tscGetMetaInfo(pQueryInfo, 0);
H
hzcheng 已提交
565 566

  /*
S
slguan 已提交
567 568
   * 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 已提交
569
   * case 2. When the query response is received from vnodes and the numOfRows is set to 0, the user calls
S
slguan 已提交
570 571 572 573 574
   *         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 已提交
575
   */
576 577 578
  if ((pCmd->command == TSDB_SQL_SELECT ||
       pCmd->command == TSDB_SQL_SHOW ||
       pCmd->command == TSDB_SQL_RETRIEVE ||
H
Haojun Liao 已提交
579 580
       pCmd->command == TSDB_SQL_FETCH) && pRes->code == TSDB_CODE_SUCCESS && pRes->completed == false &&
       (pCmd->command == TSDB_SQL_SELECT && pSql->pStream == NULL && pTableMetaInfo->pTableMeta != NULL)) {
H
hzcheng 已提交
581 582
    pCmd->command = (pCmd->command > TSDB_SQL_MGMT) ? TSDB_SQL_RETRIEVE : TSDB_SQL_FETCH;

583 584
    tscTrace("%p send msg to free qhandle in vnode, code:%d, numOfRows:%d, command:%s", pSql, pRes->code, pRes->numOfRows,
        sqlCmd[pCmd->command]);
H
hjxilinx 已提交
585

H
hjxilinx 已提交
586
    pSql->freed = 1;
S
slguan 已提交
587
    tscProcessSql(pSql);
588 589
  
    // waits for response and then goes on
590 591 592
    if (pTscObj->pSql == pSql) {
      sem_wait(&pSql->rspSem);
    }
H
hjxilinx 已提交
593
  } else { // if no free resource msg is sent to vnode, we free this object immediately.
594
    if (pTscObj->pSql != pSql) {
H
hzcheng 已提交
595
      tscFreeSqlObj(pSql);
596
      tscTrace("%p sql result is freed by app", pSql);
H
hzcheng 已提交
597
    } else {
H
Haojun Liao 已提交
598 599
      tscPartiallyFreeSqlObj(pSql);
      tscTrace("%p sql result is freed by app", pSql);
H
hzcheng 已提交
600 601 602 603
    }
  }
}

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

H
[td-99]  
hjxilinx 已提交
608 609 610
  if (pObj == NULL || pObj->signature != pObj) {
    return terrno;
  }
H
hzcheng 已提交
611

H
[td-99]  
hjxilinx 已提交
612
  return pObj->pSql->res.code;
H
hzcheng 已提交
613 614
}

H
hjxilinx 已提交
615 616 617 618
/*
 * In case of invalid sql error, additional information is attached to explain
 * why the sql is invalid
 */
H
hjxilinx 已提交
619
static bool hasAdditionalErrorInfo(int32_t code, SSqlCmd *pCmd) {
H
hjxilinx 已提交
620 621 622 623 624
  if (code != TSDB_CODE_INVALID_SQL) {
    return false;
  }

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

  char *z = NULL;
H
hjxilinx 已提交
627
  if (len > 0) {
H
hjxilinx 已提交
628
    z = strstr(pCmd->payload, "invalid SQL");
H
hjxilinx 已提交
629
  }
H
hjxilinx 已提交
630

H
hjxilinx 已提交
631 632 633
  return z != NULL;
}

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

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

641 642
  SSqlObj* pSql = pObj->pSql;
  
H
[td-32]  
hjxilinx 已提交
643
  if (hasAdditionalErrorInfo(pSql->res.code, &pSql->cmd)) {
H
hjxilinx 已提交
644
    return pSql->cmd.payload;
H
hzcheng 已提交
645
  } else {
H
[td-32]  
hjxilinx 已提交
646
    return (char*)tstrerror(pSql->res.code);
H
hzcheng 已提交
647 648 649 650 651
  }
}

void taos_config(int debug, char *log_path) {
  uDebugFlag = debug;
S
slguan 已提交
652
  strcpy(tsLogDir, log_path);
H
hzcheng 已提交
653 654 655 656 657 658 659 660 661 662
}

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

  if (pObj == NULL) return NULL;

  return pObj->sversion;
}

663 664 665 666 667 668 669 670 671
int* taos_fetch_lengths(TAOS_RES *res) {
  SSqlObj* pSql = (SSqlObj* ) res;
  if (pSql == NULL || pSql->signature != pSql) {
    return NULL;
  }
  
  return pSql->res.length;
}

H
hzcheng 已提交
672 673 674 675 676 677
char *taos_get_client_info() { return version; }

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

  SSqlObj *pSql = (SSqlObj *)res;
678 679
  SSqlCmd *pCmd = &pSql->cmd;

H
hzcheng 已提交
680 681 682 683 684
  if (pSql->signature != pSql) return;
  tscTrace("%p start to cancel query", res);

  pSql->res.code = TSDB_CODE_QUERY_CANCELLED;

685
  SQueryInfo *pQueryInfo = tscGetQueryInfoDetail(pCmd, pCmd->clauseIndex);
H
hjxilinx 已提交
686
  if (tscIsTwoStageSTableQuery(pQueryInfo, 0)) {
H
hjxilinx 已提交
687
    tscKillSTableQuery(pSql);
H
hzcheng 已提交
688 689 690 691 692 693 694
    return;
  }

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

S
slguan 已提交
695
  //taosStopRpcConn(pSql->thandle);
H
hzcheng 已提交
696 697 698 699 700 701
  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) {
702 703 704 705
    if (i > 0) {
      str[len++] = ' ';
    }

H
hzcheng 已提交
706
    if (row[i] == NULL) {
707
      len += sprintf(str + len, "%s", TSDB_DATA_NULL_STR);
H
hzcheng 已提交
708 709 710 711 712
      continue;
    }

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

      case TSDB_DATA_TYPE_SMALLINT:
717
        len += sprintf(str + len, "%d", *((short *)row[i]));
H
hzcheng 已提交
718 719 720
        break;

      case TSDB_DATA_TYPE_INT:
721
        len += sprintf(str + len, "%d", *((int *)row[i]));
H
hzcheng 已提交
722 723 724
        break;

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

L
lihui 已提交
728 729
      case TSDB_DATA_TYPE_FLOAT: {
        float fv = 0;
L
lihui 已提交
730
        fv = GET_FLOAT_VAL(row[i]);
731
        len += sprintf(str + len, "%f", fv);
732
      } break;
H
hzcheng 已提交
733

734
      case TSDB_DATA_TYPE_DOUBLE: {
L
lihui 已提交
735
        double dv = 0;
L
lihui 已提交
736
        dv = GET_DOUBLE_VAL(row[i]);
737
        len += sprintf(str + len, "%lf", dv);
738
      } break;
H
hzcheng 已提交
739 740

      case TSDB_DATA_TYPE_BINARY:
S
slguan 已提交
741
      case TSDB_DATA_TYPE_NCHAR: {
H
hjxilinx 已提交
742
        size_t xlen = 0;
743
        for (xlen = 0; xlen < fields[i].bytes - VARSTR_HEADER_SIZE; xlen++) {
H
hjxilinx 已提交
744 745 746 747 748 749
          char c = ((char *)row[i])[xlen];
          if (c == 0) break;
          str[len++] = c;
        }
        str[len] = 0;
      } break;
H
hzcheng 已提交
750 751

      case TSDB_DATA_TYPE_TIMESTAMP:
752
        len += sprintf(str + len, "%" PRId64, *((int64_t *)row[i]));
H
hzcheng 已提交
753 754 755
        break;

      case TSDB_DATA_TYPE_BOOL:
756
        len += sprintf(str + len, "%d", *((int8_t *)row[i]));
H
hzcheng 已提交
757 758 759 760 761 762 763 764
      default:
        break;
    }
  }

  return len;
}

S
slguan 已提交
765
int taos_validate_sql(TAOS *taos, const char *sql) {
H
hzcheng 已提交
766 767
  STscObj *pObj = (STscObj *)taos;
  if (pObj == NULL || pObj->signature != pObj) {
H
hjxilinx 已提交
768
    terrno = TSDB_CODE_DISCONNECTED;
H
hzcheng 已提交
769 770 771 772 773
    return TSDB_CODE_DISCONNECTED;
  }

  SSqlObj *pSql = pObj->pSql;
  SSqlRes *pRes = &pSql->res;
774 775 776
  SSqlCmd *pCmd = &pSql->cmd;
  
  pRes->numOfRows  = 1;
H
hzcheng 已提交
777
  pRes->numOfTotal = 0;
H
Haojun Liao 已提交
778
  pRes->numOfClauseTotal = 0;
779

H
hzcheng 已提交
780 781 782
  tscTrace("%p Valid SQL: %s pObj:%p", pSql, sql, pObj);

  int32_t sqlLen = strlen(sql);
H
hjxilinx 已提交
783
  if (sqlLen > tsMaxSQLStringLen) {
H
hzcheng 已提交
784 785 786 787 788 789 790 791 792 793 794 795 796
    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 已提交
797
  strtolower(pSql->sqlstr, sql);
H
hzcheng 已提交
798

799 800 801 802
  pCmd->curSql = NULL;
  if (NULL != pCmd->pTableList) {
    taosHashCleanup(pCmd->pTableList);
    pCmd->pTableList = NULL;
L
lihui 已提交
803 804
  }

805
  pRes->code = (uint8_t)tsParseSql(pSql, false);
H
hzcheng 已提交
806 807 808 809 810 811 812
  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 已提交
813

H
hjxilinx 已提交
814
static int tscParseTblNameList(SSqlObj *pSql, const char *tblNameList, int32_t tblListLen) {
S
slguan 已提交
815
  // must before clean the sqlcmd object
816
  tscResetSqlCmdObj(&pSql->cmd);
S
slguan 已提交
817 818 819 820 821 822

  SSqlCmd *pCmd = &pSql->cmd;

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

S
slguan 已提交
823
  int   code = TSDB_CODE_INVALID_TABLE_ID;
H
hjxilinx 已提交
824
  char *str = (char *)tblNameList;
S
slguan 已提交
825

826 827 828
  SQueryInfo *pQueryInfo = NULL;
  tscGetQueryInfoDetailSafely(pCmd, pCmd->clauseIndex, &pQueryInfo);

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

H
hjxilinx 已提交
831
  if ((code = tscAllocPayload(pCmd, tblListLen + 16)) != TSDB_CODE_SUCCESS) {
S
slguan 已提交
832 833 834 835
    return code;
  }

  char *nextStr;
S
slguan 已提交
836
  char  tblName[TSDB_TABLE_ID_LEN];
S
slguan 已提交
837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852
  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 已提交
853

S
slguan 已提交
854 855 856 857 858
    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 已提交
859
      code = TSDB_CODE_INVALID_TABLE_ID;
S
slguan 已提交
860 861 862 863
      sprintf(pCmd->payload, "table name is invalid");
      return code;
    }

H
hjxilinx 已提交
864
    if ((code = tscSetTableId(pTableMetaInfo, &sToken, pSql)) != TSDB_CODE_SUCCESS) {
S
slguan 已提交
865 866 867 868
      return code;
    }

    if (++pCmd->count > TSDB_MULTI_METERMETA_MAX_NUM) {
S
slguan 已提交
869
      code = TSDB_CODE_INVALID_TABLE_ID;
S
slguan 已提交
870 871 872 873
      sprintf(pCmd->payload, "tables over the max number");
      return code;
    }

H
hjxilinx 已提交
874
    if (payloadLen + strlen(pTableMetaInfo->name) + 128 >= pCmd->allocSize) {
S
slguan 已提交
875 876 877 878 879 880 881 882 883 884 885 886
      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 已提交
887
    payloadLen += sprintf(pMsg + payloadLen, "%s,", pTableMetaInfo->name);
S
slguan 已提交
888 889 890 891 892 893 894 895 896
  }

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

  return TSDB_CODE_SUCCESS;
}

int taos_load_table_info(TAOS *taos, const char *tableNameList) {
H
hjxilinx 已提交
897
  const int32_t MAX_TABLE_NAME_LENGTH = 12 * 1024 * 1024;  // 12MB list
S
slguan 已提交
898 899 900

  STscObj *pObj = (STscObj *)taos;
  if (pObj == NULL || pObj->signature != pObj) {
H
hjxilinx 已提交
901
    terrno = TSDB_CODE_DISCONNECTED;
S
slguan 已提交
902 903 904 905 906 907 908
    return TSDB_CODE_DISCONNECTED;
  }

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

  pRes->numOfTotal = 0;  // the number of getting table meta from server
H
Haojun Liao 已提交
909
  pRes->numOfClauseTotal = 0;
910

S
slguan 已提交
911 912 913 914 915 916 917 918 919 920 921 922
  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 已提交
923
  char *str = calloc(1, tblListLen + 1);
S
slguan 已提交
924 925 926 927 928 929 930
  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 已提交
931
  pRes->code = (uint8_t)tscParseTblNameList(pSql, str, tblListLen);
S
slguan 已提交
932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948

  /*
   * 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) {
H
hjxilinx 已提交
949
    tscPartiallyFreeSqlObj(pSql);
S
slguan 已提交
950 951 952 953
  }

  return pRes->code;
}