parInsertSql.c 71.3 KB
Newer Older
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/>.
 */

X
Xiaoyu Wang 已提交
16
#include "parInsertUtil.h"
X
Xiaoyu Wang 已提交
17
#include "parToken.h"
18
#include "scalar.h"
19 20 21
#include "tglobal.h"
#include "ttime.h"

X
Xiaoyu Wang 已提交
22 23 24 25 26
#define NEXT_TOKEN_WITH_PREV(pSql, token)           \
  do {                                              \
    int32_t index = 0;                              \
    token = tStrGetToken(pSql, &index, true, NULL); \
    pSql += index;                                  \
X
Xiaoyu Wang 已提交
27 28
  } while (0)

X
Xiaoyu Wang 已提交
29 30 31 32 33 34 35 36 37 38
#define NEXT_TOKEN_WITH_PREV_EXT(pSql, token, pIgnoreComma) \
  do {                                                      \
    int32_t index = 0;                                      \
    token = tStrGetToken(pSql, &index, true, pIgnoreComma); \
    pSql += index;                                          \
  } while (0)

#define NEXT_TOKEN_KEEP_SQL(pSql, token, index)      \
  do {                                               \
    token = tStrGetToken(pSql, &index, false, NULL); \
39 40
  } while (0)

X
Xiaoyu Wang 已提交
41 42 43 44 45 46 47 48
#define NEXT_VALID_TOKEN(pSql, token)           \
  do {                                          \
    (token).n = tGetToken(pSql, &(token).type); \
    (token).z = (char*)pSql;                    \
    pSql += (token).n;                          \
  } while (TK_NK_SPACE == (token).type)

typedef struct SInsertParseContext {
X
Xiaoyu Wang 已提交
49 50 51 52 53 54 55
  SParseContext* pComCxt;
  SMsgBuf        msg;
  char           tmpTokenBuf[TSDB_MAX_BYTES_PER_ROW];
  SBoundColInfo  tags;  // for stmt
  bool           missCache;
  bool           usingDuplicateTable;
  bool           forceUpdate;
X
Xiaoyu Wang 已提交
56
} SInsertParseContext;
57

H
refact  
Hongze Cheng 已提交
58
typedef int32_t (*_row_append_fn_t)(SMsgBuf* pMsgBuf, const void* value, int32_t len, void* param);
X
Xiaoyu Wang 已提交
59 60 61 62

static uint8_t TRUE_VALUE = (uint8_t)TSDB_TRUE;
static uint8_t FALSE_VALUE = (uint8_t)TSDB_FALSE;

X
Xiaoyu Wang 已提交
63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88
static bool isNullStr(SToken* pToken) {
  return ((pToken->type == TK_NK_STRING) && (strlen(TSDB_DATA_NULL_STR_L) == pToken->n) &&
          (strncasecmp(TSDB_DATA_NULL_STR_L, pToken->z, pToken->n) == 0));
}

static bool isNullValue(int8_t dataType, SToken* pToken) {
  return TK_NULL == pToken->type || (!IS_STR_DATA_TYPE(dataType) && isNullStr(pToken));
}

static FORCE_INLINE int32_t toDouble(SToken* pToken, double* value, char** endPtr) {
  errno = 0;
  *value = taosStr2Double(pToken->z, endPtr);

  // not a valid integer number, return error
  if ((*endPtr - pToken->z) != pToken->n) {
    return TK_NK_ILLEGAL;
  }

  return pToken->type;
}

static int32_t skipInsertInto(const char** pSql, SMsgBuf* pMsg) {
  SToken token;
  NEXT_TOKEN(*pSql, token);
  if (TK_INSERT != token.type && TK_IMPORT != token.type) {
    return buildSyntaxErrMsg(pMsg, "keyword INSERT is expected", token.z);
89
  }
X
Xiaoyu Wang 已提交
90 91 92
  NEXT_TOKEN(*pSql, token);
  if (TK_INTO != token.type) {
    return buildSyntaxErrMsg(pMsg, "keyword INTO is expected", token.z);
93 94 95 96
  }
  return TSDB_CODE_SUCCESS;
}

X
Xiaoyu Wang 已提交
97 98 99 100 101 102 103 104 105 106 107 108 109
static int32_t skipParentheses(SInsertParseContext* pCxt, const char** pSql) {
  SToken  token;
  int32_t expectRightParenthesis = 1;
  while (1) {
    NEXT_TOKEN(*pSql, token);
    if (TK_NK_LP == token.type) {
      ++expectRightParenthesis;
    } else if (TK_NK_RP == token.type && 0 == --expectRightParenthesis) {
      break;
    }
    if (0 == token.n) {
      return buildSyntaxErrMsg(&pCxt->msg, ") expected", NULL);
    }
110
  }
X
Xiaoyu Wang 已提交
111 112
  return TSDB_CODE_SUCCESS;
}
D
dapan1121 已提交
113

X
Xiaoyu Wang 已提交
114 115 116 117 118 119 120 121 122 123 124 125 126
static int32_t skipTableOptions(SInsertParseContext* pCxt, const char** pSql) {
  do {
    int32_t index = 0;
    SToken  token;
    NEXT_TOKEN_KEEP_SQL(*pSql, token, index);
    if (TK_TTL == token.type || TK_COMMENT == token.type) {
      *pSql += index;
      NEXT_TOKEN_WITH_PREV(*pSql, token);
    } else {
      break;
    }
  } while (1);
  return TSDB_CODE_SUCCESS;
127 128
}

X
Xiaoyu Wang 已提交
129 130 131 132 133 134 135 136 137 138 139 140
// pSql -> stb_name [(tag1_name, ...)] TAGS (tag1_value, ...)
static int32_t ignoreUsingClause(SInsertParseContext* pCxt, const char** pSql) {
  int32_t code = TSDB_CODE_SUCCESS;
  SToken  token;
  NEXT_TOKEN(*pSql, token);

  NEXT_TOKEN(*pSql, token);
  if (TK_NK_LP == token.type) {
    code = skipParentheses(pCxt, pSql);
    if (TSDB_CODE_SUCCESS == code) {
      NEXT_TOKEN(*pSql, token);
    }
141
  }
X
Xiaoyu Wang 已提交
142

X
Xiaoyu Wang 已提交
143 144 145 146 147 148 149 150 151 152 153 154 155 156
  // pSql -> TAGS (tag1_value, ...)
  if (TSDB_CODE_SUCCESS == code) {
    if (TK_TAGS != token.type) {
      code = buildSyntaxErrMsg(&pCxt->msg, "TAGS is expected", token.z);
    } else {
      NEXT_TOKEN(*pSql, token);
    }
  }
  if (TSDB_CODE_SUCCESS == code) {
    if (TK_NK_LP != token.type) {
      code = buildSyntaxErrMsg(&pCxt->msg, "( is expected", token.z);
    } else {
      code = skipParentheses(pCxt, pSql);
    }
157 158
  }

X
Xiaoyu Wang 已提交
159 160
  if (TSDB_CODE_SUCCESS == code) {
    code = skipTableOptions(pCxt, pSql);
161
  }
X
Xiaoyu Wang 已提交
162 163

  return code;
164
}
D
dapan 已提交
165

X
Xiaoyu Wang 已提交
166
static int32_t parseDuplicateUsingClause(SInsertParseContext* pCxt, SVnodeModifyOpStmt* pStmt, bool* pDuplicate) {
X
Xiaoyu Wang 已提交
167 168 169 170 171 172 173 174 175 176 177
  *pDuplicate = false;

  char tbFName[TSDB_TABLE_FNAME_LEN];
  tNameExtractFullName(&pStmt->targetTableName, tbFName);
  STableMeta** pMeta = taosHashGet(pStmt->pSubTableHashObj, tbFName, strlen(tbFName));
  if (NULL != pMeta) {
    *pDuplicate = true;
    int32_t code = ignoreUsingClause(pCxt, &pStmt->pSql);
    if (TSDB_CODE_SUCCESS == code) {
      return cloneTableMeta(*pMeta, &pStmt->pTableMeta);
    }
D
stmt  
dapan1121 已提交
178
  }
X
Xiaoyu Wang 已提交
179

H
refact  
Hongze Cheng 已提交
180
  return TSDB_CODE_SUCCESS;
D
stmt  
dapan1121 已提交
181 182
}

X
Xiaoyu Wang 已提交
183
// pStmt->pSql -> field1_name, ...)
X
Xiaoyu Wang 已提交
184 185 186 187 188
static int32_t parseBoundColumns(SInsertParseContext* pCxt, const char** pSql, bool isTags, SSchema* pSchema,
                                 SBoundColInfo* pBoundInfo) {
  bool* pUseCols = taosMemoryCalloc(pBoundInfo->numOfCols, sizeof(bool));
  if (NULL == pUseCols) {
    return TSDB_CODE_OUT_OF_MEMORY;
X
Xiaoyu Wang 已提交
189
  }
D
stmt  
dapan1121 已提交
190

X
Xiaoyu Wang 已提交
191 192
  pBoundInfo->numOfBound = 0;

D
dapan1121 已提交
193
  int16_t lastColIdx = -1;  // last column found
X
Xiaoyu Wang 已提交
194 195 196
  int32_t code = TSDB_CODE_SUCCESS;
  while (TSDB_CODE_SUCCESS == code) {
    SToken token;
X
Xiaoyu Wang 已提交
197 198 199 200 201 202 203 204 205 206 207
    NEXT_TOKEN(*pSql, token);

    if (TK_NK_RP == token.type) {
      break;
    }

    char tmpTokenBuf[TSDB_COL_NAME_LEN + 2] = {0};  // used for deleting Escape character backstick(`)
    strncpy(tmpTokenBuf, token.z, token.n);
    token.z = tmpTokenBuf;
    token.n = strdequote(token.z);

D
dapan1121 已提交
208 209
    int16_t t = lastColIdx + 1;
    int16_t index = insFindCol(&token, t, pBoundInfo->numOfCols, pSchema);
X
Xiaoyu Wang 已提交
210 211 212 213
    if (index < 0 && t > 0) {
      index = insFindCol(&token, 0, t, pSchema);
    }
    if (index < 0) {
X
Xiaoyu Wang 已提交
214 215 216 217 218 219 220 221
      code = generateSyntaxErrMsg(&pCxt->msg, TSDB_CODE_PAR_INVALID_COLUMN, token.z);
    } else if (pUseCols[index]) {
      code = buildSyntaxErrMsg(&pCxt->msg, "duplicated column name", token.z);
    } else {
      lastColIdx = index;
      pUseCols[index] = true;
      pBoundInfo->pColIndex[pBoundInfo->numOfBound] = index;
      ++pBoundInfo->numOfBound;
X
Xiaoyu Wang 已提交
222 223 224
    }
  }

X
Xiaoyu Wang 已提交
225 226
  if (TSDB_CODE_SUCCESS == code && !isTags && !pUseCols[0]) {
    code = buildInvalidOperationMsg(&pCxt->msg, "primary timestamp column can not be null");
X
Xiaoyu Wang 已提交
227 228
  }

X
Xiaoyu Wang 已提交
229
  taosMemoryFree(pUseCols);
X
Xiaoyu Wang 已提交
230

X
Xiaoyu Wang 已提交
231
  return code;
X
Xiaoyu Wang 已提交
232 233
}

X
Xiaoyu Wang 已提交
234 235 236 237 238
static int parseTime(const char** end, SToken* pToken, int16_t timePrec, int64_t* time, SMsgBuf* pMsgBuf) {
  int32_t     index = 0;
  int64_t     interval;
  int64_t     ts = 0;
  const char* pTokenEnd = *end;
239 240

  if (pToken->type == TK_NOW) {
241
    ts = taosGetTimestamp(timePrec);
242 243
  } else if (pToken->type == TK_TODAY) {
    ts = taosGetTimestampToday(timePrec);
244
  } else if (pToken->type == TK_NK_INTEGER) {
X
Xiaoyu Wang 已提交
245 246 247
    if (TSDB_CODE_SUCCESS != toInteger(pToken->z, pToken->n, 10, &ts)) {
      return buildSyntaxErrMsg(pMsgBuf, "invalid timestamp format", pToken->z);
    }
H
refact  
Hongze Cheng 已提交
248
  } else {  // parse the RFC-3339/ISO-8601 timestamp format string
S
os env  
Shengliang Guan 已提交
249
    if (taosParseTime(pToken->z, time, pToken->n, timePrec, tsDaylight) != TSDB_CODE_SUCCESS) {
250
      return buildSyntaxErrMsg(pMsgBuf, "invalid timestamp format", pToken->z);
251 252 253 254 255 256 257
    }

    return TSDB_CODE_SUCCESS;
  }

  for (int k = pToken->n; pToken->z[k] != '\0'; k++) {
    if (pToken->z[k] == ' ' || pToken->z[k] == '\t') continue;
H
refact  
Hongze Cheng 已提交
258
    if (pToken->z[k] == '(' && pToken->z[k + 1] == ')') {  // for insert NOW()/TODAY()
259 260 261 262
      *end = pTokenEnd = &pToken->z[k + 2];
      k++;
      continue;
    }
263
    if (pToken->z[k] == ',') {
264 265
      *end = pTokenEnd;
      *time = ts;
266 267 268 269 270 271 272 273 274 275 276
      return 0;
    }

    break;
  }

  /*
   * time expression:
   * e.g., now+12a, now-5h
   */
  index = 0;
X
Xiaoyu Wang 已提交
277
  SToken token = tStrGetToken(pTokenEnd, &index, false, NULL);
278 279
  pTokenEnd += index;

X
Xiaoyu Wang 已提交
280
  if (token.type == TK_NK_MINUS || token.type == TK_NK_PLUS) {
281
    index = 0;
X
Xiaoyu Wang 已提交
282
    SToken valueToken = tStrGetToken(pTokenEnd, &index, false, NULL);
283 284 285
    pTokenEnd += index;

    if (valueToken.n < 2) {
X
Xiaoyu Wang 已提交
286
      return buildSyntaxErrMsg(pMsgBuf, "value expected in timestamp", token.z);
287 288 289 290 291 292 293
    }

    char unit = 0;
    if (parseAbsoluteDuration(valueToken.z, valueToken.n, &interval, &unit, timePrec) != TSDB_CODE_SUCCESS) {
      return TSDB_CODE_TSC_INVALID_OPERATION;
    }

X
Xiaoyu Wang 已提交
294
    if (token.type == TK_NK_PLUS) {
295
      ts += interval;
296
    } else {
297
      ts = ts - interval;
298 299
    }

300
    *end = pTokenEnd;
301 302
  }

303
  *time = ts;
304 305
  return TSDB_CODE_SUCCESS;
}
306

X
Xiaoyu Wang 已提交
307 308
static int32_t parseTagToken(const char** end, SToken* pToken, SSchema* pSchema, int16_t timePrec, STagVal* val,
                             SMsgBuf* pMsgBuf) {
X
Xiaoyu Wang 已提交
309 310 311
  int64_t  iv;
  uint64_t uv;
  char*    endptr = NULL;
X
Xiaoyu Wang 已提交
312

313
  if (isNullValue(pSchema->type, pToken)) {
X
Xiaoyu Wang 已提交
314
    if (TSDB_DATA_TYPE_TIMESTAMP == pSchema->type && PRIMARYKEY_TIMESTAMP_COL_ID == pSchema->colId) {
D
stmt  
dapan1121 已提交
315
      return buildSyntaxErrMsg(pMsgBuf, "primary timestamp should not be null", pToken->z);
X
Xiaoyu Wang 已提交
316 317
    }

X
Xiaoyu Wang 已提交
318
    return TSDB_CODE_SUCCESS;
X
Xiaoyu Wang 已提交
319 320
  }

X
Xiaoyu Wang 已提交
321 322 323
  //  strcpy(val->colName, pSchema->name);
  val->cid = pSchema->colId;
  val->type = pSchema->type;
X
Xiaoyu Wang 已提交
324

X
Xiaoyu Wang 已提交
325 326
  switch (pSchema->type) {
    case TSDB_DATA_TYPE_BOOL: {
327
      if ((pToken->type == TK_NK_BOOL || pToken->type == TK_NK_STRING) && (pToken->n != 0)) {
X
Xiaoyu Wang 已提交
328
        if (strncmp(pToken->z, "true", pToken->n) == 0) {
X
Xiaoyu Wang 已提交
329
          *(int8_t*)(&val->i64) = TRUE_VALUE;
X
Xiaoyu Wang 已提交
330
        } else if (strncmp(pToken->z, "false", pToken->n) == 0) {
X
Xiaoyu Wang 已提交
331
          *(int8_t*)(&val->i64) = FALSE_VALUE;
X
Xiaoyu Wang 已提交
332 333 334
        } else {
          return buildSyntaxErrMsg(pMsgBuf, "invalid bool data", pToken->z);
        }
335
      } else if (pToken->type == TK_NK_INTEGER) {
X
Xiaoyu Wang 已提交
336
        *(int8_t*)(&val->i64) = ((taosStr2Int64(pToken->z, NULL, 10) == 0) ? FALSE_VALUE : TRUE_VALUE);
337
      } else if (pToken->type == TK_NK_FLOAT) {
X
Xiaoyu Wang 已提交
338
        *(int8_t*)(&val->i64) = ((taosStr2Double(pToken->z, NULL) == 0) ? FALSE_VALUE : TRUE_VALUE);
X
Xiaoyu Wang 已提交
339 340 341
      } else {
        return buildSyntaxErrMsg(pMsgBuf, "invalid bool data", pToken->z);
      }
X
Xiaoyu Wang 已提交
342
      break;
X
Xiaoyu Wang 已提交
343 344 345
    }

    case TSDB_DATA_TYPE_TINYINT: {
X
Xiaoyu Wang 已提交
346
      if (TSDB_CODE_SUCCESS != toInteger(pToken->z, pToken->n, 10, &iv)) {
X
Xiaoyu Wang 已提交
347 348 349 350 351
        return buildSyntaxErrMsg(pMsgBuf, "invalid tinyint data", pToken->z);
      } else if (!IS_VALID_TINYINT(iv)) {
        return buildSyntaxErrMsg(pMsgBuf, "tinyint data overflow", pToken->z);
      }

X
Xiaoyu Wang 已提交
352 353
      *(int8_t*)(&val->i64) = iv;
      break;
X
Xiaoyu Wang 已提交
354 355
    }

H
refact  
Hongze Cheng 已提交
356
    case TSDB_DATA_TYPE_UTINYINT: {
X
Xiaoyu Wang 已提交
357
      if (TSDB_CODE_SUCCESS != toUInteger(pToken->z, pToken->n, 10, &uv)) {
X
Xiaoyu Wang 已提交
358
        return buildSyntaxErrMsg(pMsgBuf, "invalid unsigned tinyint data", pToken->z);
X
Xiaoyu Wang 已提交
359
      } else if (uv > UINT8_MAX) {
X
Xiaoyu Wang 已提交
360 361
        return buildSyntaxErrMsg(pMsgBuf, "unsigned tinyint data overflow", pToken->z);
      }
X
Xiaoyu Wang 已提交
362 363
      *(uint8_t*)(&val->i64) = uv;
      break;
X
Xiaoyu Wang 已提交
364 365 366
    }

    case TSDB_DATA_TYPE_SMALLINT: {
X
Xiaoyu Wang 已提交
367
      if (TSDB_CODE_SUCCESS != toInteger(pToken->z, pToken->n, 10, &iv)) {
X
Xiaoyu Wang 已提交
368 369 370 371
        return buildSyntaxErrMsg(pMsgBuf, "invalid smallint data", pToken->z);
      } else if (!IS_VALID_SMALLINT(iv)) {
        return buildSyntaxErrMsg(pMsgBuf, "smallint data overflow", pToken->z);
      }
X
Xiaoyu Wang 已提交
372 373
      *(int16_t*)(&val->i64) = iv;
      break;
X
Xiaoyu Wang 已提交
374 375 376
    }

    case TSDB_DATA_TYPE_USMALLINT: {
X
Xiaoyu Wang 已提交
377
      if (TSDB_CODE_SUCCESS != toUInteger(pToken->z, pToken->n, 10, &uv)) {
X
Xiaoyu Wang 已提交
378
        return buildSyntaxErrMsg(pMsgBuf, "invalid unsigned smallint data", pToken->z);
X
Xiaoyu Wang 已提交
379
      } else if (uv > UINT16_MAX) {
X
Xiaoyu Wang 已提交
380 381
        return buildSyntaxErrMsg(pMsgBuf, "unsigned smallint data overflow", pToken->z);
      }
X
Xiaoyu Wang 已提交
382 383
      *(uint16_t*)(&val->i64) = uv;
      break;
X
Xiaoyu Wang 已提交
384 385 386
    }

    case TSDB_DATA_TYPE_INT: {
X
Xiaoyu Wang 已提交
387
      if (TSDB_CODE_SUCCESS != toInteger(pToken->z, pToken->n, 10, &iv)) {
X
Xiaoyu Wang 已提交
388 389 390 391
        return buildSyntaxErrMsg(pMsgBuf, "invalid int data", pToken->z);
      } else if (!IS_VALID_INT(iv)) {
        return buildSyntaxErrMsg(pMsgBuf, "int data overflow", pToken->z);
      }
X
Xiaoyu Wang 已提交
392 393
      *(int32_t*)(&val->i64) = iv;
      break;
X
Xiaoyu Wang 已提交
394 395 396
    }

    case TSDB_DATA_TYPE_UINT: {
X
Xiaoyu Wang 已提交
397
      if (TSDB_CODE_SUCCESS != toUInteger(pToken->z, pToken->n, 10, &uv)) {
X
Xiaoyu Wang 已提交
398
        return buildSyntaxErrMsg(pMsgBuf, "invalid unsigned int data", pToken->z);
X
Xiaoyu Wang 已提交
399
      } else if (uv > UINT32_MAX) {
X
Xiaoyu Wang 已提交
400 401
        return buildSyntaxErrMsg(pMsgBuf, "unsigned int data overflow", pToken->z);
      }
X
Xiaoyu Wang 已提交
402 403
      *(uint32_t*)(&val->i64) = uv;
      break;
X
Xiaoyu Wang 已提交
404 405 406
    }

    case TSDB_DATA_TYPE_BIGINT: {
X
Xiaoyu Wang 已提交
407
      if (TSDB_CODE_SUCCESS != toInteger(pToken->z, pToken->n, 10, &iv)) {
X
Xiaoyu Wang 已提交
408 409
        return buildSyntaxErrMsg(pMsgBuf, "invalid bigint data", pToken->z);
      }
X
Xiaoyu Wang 已提交
410 411
      val->i64 = iv;
      break;
X
Xiaoyu Wang 已提交
412 413 414
    }

    case TSDB_DATA_TYPE_UBIGINT: {
X
Xiaoyu Wang 已提交
415
      if (TSDB_CODE_SUCCESS != toUInteger(pToken->z, pToken->n, 10, &uv)) {
X
Xiaoyu Wang 已提交
416 417
        return buildSyntaxErrMsg(pMsgBuf, "invalid unsigned bigint data", pToken->z);
      }
X
Xiaoyu Wang 已提交
418 419
      *(uint64_t*)(&val->i64) = uv;
      break;
X
Xiaoyu Wang 已提交
420 421 422 423
    }

    case TSDB_DATA_TYPE_FLOAT: {
      double dv;
424
      if (TK_NK_ILLEGAL == toDouble(pToken, &dv, &endptr)) {
X
Xiaoyu Wang 已提交
425 426
        return buildSyntaxErrMsg(pMsgBuf, "illegal float data", pToken->z);
      }
H
refact  
Hongze Cheng 已提交
427 428
      if (((dv == HUGE_VAL || dv == -HUGE_VAL) && errno == ERANGE) || dv > FLT_MAX || dv < -FLT_MAX || isinf(dv) ||
          isnan(dv)) {
X
Xiaoyu Wang 已提交
429 430
        return buildSyntaxErrMsg(pMsgBuf, "illegal float data", pToken->z);
      }
X
Xiaoyu Wang 已提交
431 432
      *(float*)(&val->i64) = dv;
      break;
X
Xiaoyu Wang 已提交
433 434 435 436
    }

    case TSDB_DATA_TYPE_DOUBLE: {
      double dv;
437
      if (TK_NK_ILLEGAL == toDouble(pToken, &dv, &endptr)) {
X
Xiaoyu Wang 已提交
438 439 440 441 442
        return buildSyntaxErrMsg(pMsgBuf, "illegal double data", pToken->z);
      }
      if (((dv == HUGE_VAL || dv == -HUGE_VAL) && errno == ERANGE) || isinf(dv) || isnan(dv)) {
        return buildSyntaxErrMsg(pMsgBuf, "illegal double data", pToken->z);
      }
X
Xiaoyu Wang 已提交
443 444 445

      *(double*)(&val->i64) = dv;
      break;
X
Xiaoyu Wang 已提交
446 447 448 449 450
    }

    case TSDB_DATA_TYPE_BINARY: {
      // Too long values will raise the invalid sql error message
      if (pToken->n + VARSTR_HEADER_SIZE > pSchema->bytes) {
D
dapan1121 已提交
451
        return generateSyntaxErrMsg(pMsgBuf, TSDB_CODE_PAR_VALUE_TOO_LONG, pSchema->name);
X
Xiaoyu Wang 已提交
452
      }
453
      val->pData = taosStrdup(pToken->z);
X
Xiaoyu Wang 已提交
454 455
      val->nData = pToken->n;
      break;
X
Xiaoyu Wang 已提交
456 457 458
    }

    case TSDB_DATA_TYPE_NCHAR: {
X
Xiaoyu Wang 已提交
459 460 461 462 463 464 465 466 467 468 469 470 471 472
      int32_t output = 0;
      void*   p = taosMemoryCalloc(1, pSchema->bytes - VARSTR_HEADER_SIZE);
      if (p == NULL) {
        return TSDB_CODE_OUT_OF_MEMORY;
      }
      if (!taosMbsToUcs4(pToken->z, pToken->n, (TdUcs4*)(p), pSchema->bytes - VARSTR_HEADER_SIZE, &output)) {
        if (errno == E2BIG) {
          taosMemoryFree(p);
          return generateSyntaxErrMsg(pMsgBuf, TSDB_CODE_PAR_VALUE_TOO_LONG, pSchema->name);
        }
        char buf[512] = {0};
        snprintf(buf, tListLen(buf), " taosMbsToUcs4 error:%s", strerror(errno));
        taosMemoryFree(p);
        return buildSyntaxErrMsg(pMsgBuf, buf, pToken->z);
473
      }
X
Xiaoyu Wang 已提交
474 475 476
      val->pData = p;
      val->nData = output;
      break;
477
    }
X
Xiaoyu Wang 已提交
478
    case TSDB_DATA_TYPE_TIMESTAMP: {
X
Xiaoyu Wang 已提交
479
      if (parseTime(end, pToken, timePrec, &iv, pMsgBuf) != TSDB_CODE_SUCCESS) {
X
Xiaoyu Wang 已提交
480 481 482
        return buildSyntaxErrMsg(pMsgBuf, "invalid timestamp", pToken->z);
      }

X
Xiaoyu Wang 已提交
483 484
      val->i64 = iv;
      break;
X
Xiaoyu Wang 已提交
485 486 487
    }
  }

X
Xiaoyu Wang 已提交
488
  return TSDB_CODE_SUCCESS;
X
Xiaoyu Wang 已提交
489 490
}

X
Xiaoyu Wang 已提交
491 492
// input pStmt->pSql:  [(tag1_name, ...)] TAGS (tag1_value, ...) ...
// output pStmt->pSql: TAGS (tag1_value, ...) ...
X
Xiaoyu Wang 已提交
493
static int32_t parseBoundTagsClause(SInsertParseContext* pCxt, SVnodeModifyOpStmt* pStmt) {
X
Xiaoyu Wang 已提交
494
  insInitBoundColsInfo(getNumOfTags(pStmt->pTableMeta), &pCxt->tags);
495

X
Xiaoyu Wang 已提交
496 497 498 499 500
  SToken  token;
  int32_t index = 0;
  NEXT_TOKEN_KEEP_SQL(pStmt->pSql, token, index);
  if (TK_NK_LP != token.type) {
    return TSDB_CODE_SUCCESS;
501 502
  }

X
Xiaoyu Wang 已提交
503
  pStmt->pSql += index;
X
Xiaoyu Wang 已提交
504
  return parseBoundColumns(pCxt, &pStmt->pSql, true, getTableTagSchema(pStmt->pTableMeta), &pCxt->tags);
X
Xiaoyu Wang 已提交
505
}
506

X
Xiaoyu Wang 已提交
507
static int32_t parseTagValue(SInsertParseContext* pCxt, SVnodeModifyOpStmt* pStmt, SSchema* pTagSchema, SToken* pToken,
X
Xiaoyu Wang 已提交
508 509 510 511 512 513 514 515
                             SArray* pTagName, SArray* pTagVals, STag** pTag) {
  if (!isNullValue(pTagSchema->type, pToken)) {
    taosArrayPush(pTagName, pTagSchema->name);
  }

  if (pTagSchema->type == TSDB_DATA_TYPE_JSON) {
    if (pToken->n > (TSDB_MAX_JSON_TAG_LEN - VARSTR_HEADER_SIZE) / TSDB_NCHAR_SIZE) {
      return buildSyntaxErrMsg(&pCxt->msg, "json string too long than 4095", pToken->z);
516 517
    }

X
Xiaoyu Wang 已提交
518 519 520 521 522 523
    if (isNullValue(pTagSchema->type, pToken)) {
      return tTagNew(pTagVals, 1, true, pTag);
    } else {
      return parseJsontoTagData(pToken->z, pTagVals, pTag, &pCxt->msg);
    }
  }
524

X
Xiaoyu Wang 已提交
525 526 527 528 529 530 531 532 533 534
  STagVal val = {0};
  int32_t code =
      parseTagToken(&pStmt->pSql, pToken, pTagSchema, pStmt->pTableMeta->tableInfo.precision, &val, &pCxt->msg);
  if (TSDB_CODE_SUCCESS == code) {
    taosArrayPush(pTagVals, &val);
  }

  return code;
}

X
Xiaoyu Wang 已提交
535
static int32_t buildCreateTbReq(SVnodeModifyOpStmt* pStmt, STag* pTag, SArray* pTagName) {
X
Xiaoyu Wang 已提交
536 537 538 539
  pStmt->pCreateTblReq = taosMemoryCalloc(1, sizeof(SVCreateTbReq));
  if (NULL == pStmt->pCreateTblReq) {
    return TSDB_CODE_OUT_OF_MEMORY;
  }
X
Xiaoyu Wang 已提交
540
  insBuildCreateTbReq(pStmt->pCreateTblReq, pStmt->targetTableName.tname, pTag, pStmt->pTableMeta->suid,
X
Xiaoyu Wang 已提交
541 542
                      pStmt->usingTableName.tname, pTagName, pStmt->pTableMeta->tableInfo.numOfTags,
                      TSDB_DEFAULT_TABLE_TTL);
X
Xiaoyu Wang 已提交
543
  return TSDB_CODE_SUCCESS;
X
Xiaoyu Wang 已提交
544 545 546 547 548 549 550 551 552 553 554 555 556 557 558
}

static int32_t checkAndTrimValue(SToken* pToken, char* tmpTokenBuf, SMsgBuf* pMsgBuf) {
  if ((pToken->type != TK_NOW && pToken->type != TK_TODAY && pToken->type != TK_NK_INTEGER &&
       pToken->type != TK_NK_STRING && pToken->type != TK_NK_FLOAT && pToken->type != TK_NK_BOOL &&
       pToken->type != TK_NULL && pToken->type != TK_NK_HEX && pToken->type != TK_NK_OCT &&
       pToken->type != TK_NK_BIN) ||
      (pToken->n == 0) || (pToken->type == TK_NK_RP)) {
    return buildSyntaxErrMsg(pMsgBuf, "invalid data or symbol", pToken->z);
  }

  // Remove quotation marks
  if (TK_NK_STRING == pToken->type) {
    if (pToken->n >= TSDB_MAX_BYTES_PER_ROW) {
      return buildSyntaxErrMsg(pMsgBuf, "too long string", pToken->z);
559
    }
X
Xiaoyu Wang 已提交
560 561 562 563 564 565 566 567 568

    int32_t len = trimString(pToken->z, pToken->n, tmpTokenBuf, TSDB_MAX_BYTES_PER_ROW);
    pToken->z = tmpTokenBuf;
    pToken->n = len;
  }

  return TSDB_CODE_SUCCESS;
}

569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682
typedef struct SRewriteTagCondCxt {
  SArray* pTagVals;
  SArray* pTagName;
  int32_t code;
} SRewriteTagCondCxt;

static int32_t rewriteTagCondColumnImpl(STagVal* pVal, SNode** pNode) {
  SValueNode* pValue = (SValueNode*)nodesMakeNode(QUERY_NODE_VALUE);
  if (NULL == pValue) {
    return TSDB_CODE_OUT_OF_MEMORY;
  }
  pValue->node.resType.type = pVal->type;
  switch (pVal->type) {
    case TSDB_DATA_TYPE_BOOL:
      pValue->datum.b = *(int8_t*)(&pVal->i64);
      break;
    case TSDB_DATA_TYPE_TINYINT:
      pValue->datum.i = *(int8_t*)(&pVal->i64);
      break;
    case TSDB_DATA_TYPE_SMALLINT:
      pValue->datum.i = *(int16_t*)(&pVal->i64);
      break;
    case TSDB_DATA_TYPE_INT:
      pValue->datum.i = *(int32_t*)(&pVal->i64);
      break;
    case TSDB_DATA_TYPE_BIGINT:
      pValue->datum.i = pVal->i64;
      break;
    case TSDB_DATA_TYPE_FLOAT:
      pValue->datum.d = *(float*)(&pVal->i64);
      break;
    case TSDB_DATA_TYPE_DOUBLE:
      pValue->datum.d = *(double*)(&pVal->i64);
      break;
    case TSDB_DATA_TYPE_VARCHAR:
    case TSDB_DATA_TYPE_NCHAR:
      pValue->datum.p = taosMemoryCalloc(1, pVal->nData + VARSTR_HEADER_SIZE);
      if (NULL == pValue->datum.p) {
        return TSDB_CODE_OUT_OF_MEMORY;
      }
      varDataSetLen(pValue->datum.p, pVal->nData);
      memcpy(varDataVal(pValue->datum.p), pVal->pData, pVal->nData);
      break;
    case TSDB_DATA_TYPE_TIMESTAMP:
      pValue->datum.i = pVal->i64;
      break;
    case TSDB_DATA_TYPE_UTINYINT:
      pValue->datum.i = *(uint8_t*)(&pVal->i64);
      break;
    case TSDB_DATA_TYPE_USMALLINT:
      pValue->datum.i = *(uint16_t*)(&pVal->i64);
      break;
    case TSDB_DATA_TYPE_UINT:
      pValue->datum.i = *(uint32_t*)(&pVal->i64);
      break;
    case TSDB_DATA_TYPE_UBIGINT:
      pValue->datum.i = *(uint64_t*)(&pVal->i64);
      break;
    case TSDB_DATA_TYPE_JSON:
    case TSDB_DATA_TYPE_VARBINARY:
    case TSDB_DATA_TYPE_DECIMAL:
    case TSDB_DATA_TYPE_BLOB:
    case TSDB_DATA_TYPE_MEDIUMBLOB:
    default:
      return TSDB_CODE_FAILED;
  }
  return TSDB_CODE_SUCCESS;
}

static int32_t rewriteTagCondColumn(SArray* pTagVals, SArray* pTagName, SNode** pNode) {
  SColumnNode* pCol = (SColumnNode*)*pNode;
  int32_t      ntags = taosArrayGetSize(pTagName);
  for (int32_t i = 0; i < ntags; ++i) {
    char* pTagColName = taosArrayGet(pTagName, i);
    if (0 == strcmp(pTagColName, pCol->colName)) {
      return rewriteTagCondColumnImpl(taosArrayGet(pTagVals, i), pNode);
    }
  }
  return TSDB_CODE_PAR_PERMISSION_DENIED;
}

static EDealRes rewriteTagCond(SNode** pNode, void* pContext) {
  if (QUERY_NODE_COLUMN == nodeType(*pNode)) {
    SRewriteTagCondCxt* pCxt = pContext;
    pCxt->code = rewriteTagCondColumn(pCxt->pTagVals, pCxt->pTagName, pNode);
    return (TSDB_CODE_SUCCESS == pCxt->code ? DEAL_RES_IGNORE_CHILD : DEAL_RES_ERROR);
  }
  return DEAL_RES_CONTINUE;
}

static int32_t setTagVal(SArray* pTagVals, SArray* pTagName, SNode* pCond) {
  SRewriteTagCondCxt cxt = {.code = TSDB_CODE_SUCCESS, .pTagVals = pTagVals, .pTagName = pTagName};
  nodesRewriteExpr(&pCond, rewriteTagCond, &cxt);
  return cxt.code;
}

static int32_t checkTagCondResult(SNode* pResult) {
  return (QUERY_NODE_VALUE == nodeType(pResult) && ((SValueNode*)pResult)->datum.b) ? TSDB_CODE_SUCCESS
                                                                                    : TSDB_CODE_PAR_PERMISSION_DENIED;
}

int32_t checkSubtablePrivilege(SArray* pTagVals, SArray* pTagName, SNode* pCond) {
  int32_t code = setTagVal(pTagVals, pTagName, pCond);
  SNode*  pNew = NULL;
  if (TSDB_CODE_SUCCESS == code) {
    code = scalarCalculateConstants(pCond, &pNew);
  }
  if (TSDB_CODE_SUCCESS == code) {
    code = checkTagCondResult(pNew);
  }
  nodesDestroyNode(pNew);
  return code;
}

X
Xiaoyu Wang 已提交
683
// pSql -> tag1_value, ...)
X
Xiaoyu Wang 已提交
684
static int32_t parseTagsClauseImpl(SInsertParseContext* pCxt, SVnodeModifyOpStmt* pStmt) {
X
Xiaoyu Wang 已提交
685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703
  int32_t  code = TSDB_CODE_SUCCESS;
  SSchema* pSchema = getTableTagSchema(pStmt->pTableMeta);
  SArray*  pTagVals = taosArrayInit(pCxt->tags.numOfBound, sizeof(STagVal));
  SArray*  pTagName = taosArrayInit(8, TSDB_COL_NAME_LEN);
  SToken   token;
  bool     isParseBindParam = false;
  bool     isJson = false;
  STag*    pTag = NULL;
  for (int i = 0; TSDB_CODE_SUCCESS == code && i < pCxt->tags.numOfBound; ++i) {
    NEXT_TOKEN_WITH_PREV(pStmt->pSql, token);

    if (token.type == TK_NK_QUESTION) {
      isParseBindParam = true;
      if (NULL == pCxt->pComCxt->pStmtCb) {
        code = buildSyntaxErrMsg(&pCxt->msg, "? only used in stmt", token.z);
        break;
      }

      continue;
704
    }
X
Xiaoyu Wang 已提交
705 706 707 708

    if (isParseBindParam) {
      code = buildInvalidOperationMsg(&pCxt->msg, "no mix usage for ? and tag values");
      break;
709
    }
X
Xiaoyu Wang 已提交
710

X
Xiaoyu Wang 已提交
711
    SSchema* pTagSchema = &pSchema[pCxt->tags.pColIndex[i]];
X
Xiaoyu Wang 已提交
712 713 714 715
    isJson = pTagSchema->type == TSDB_DATA_TYPE_JSON;
    code = checkAndTrimValue(&token, pCxt->tmpTokenBuf, &pCxt->msg);
    if (TSDB_CODE_SUCCESS == code) {
      code = parseTagValue(pCxt, pStmt, pTagSchema, &token, pTagName, pTagVals, &pTag);
C
Cary Xu 已提交
716
    }
717 718
  }

X
Xiaoyu Wang 已提交
719 720 721
  if (TSDB_CODE_SUCCESS == code && !isParseBindParam && !isJson) {
    code = tTagNew(pTagVals, 1, false, &pTag);
  }
722

X
Xiaoyu Wang 已提交
723
  if (TSDB_CODE_SUCCESS == code && !isParseBindParam) {
X
Xiaoyu Wang 已提交
724
    code = buildCreateTbReq(pStmt, pTag, pTagName);
X
Xiaoyu Wang 已提交
725 726 727 728 729 730 731
    pTag = NULL;
  }

  for (int i = 0; i < taosArrayGetSize(pTagVals); ++i) {
    STagVal* p = (STagVal*)taosArrayGet(pTagVals, i);
    if (IS_VAR_DATA_TYPE(p->type)) {
      taosMemoryFreeClear(p->pData);
732
    }
X
Xiaoyu Wang 已提交
733 734 735 736 737 738 739 740 741
  }
  taosArrayDestroy(pTagVals);
  taosArrayDestroy(pTagName);
  tTagFree(pTag);
  return code;
}

// input pStmt->pSql:  TAGS (tag1_value, ...) [table_options] ...
// output pStmt->pSql: [table_options] ...
X
Xiaoyu Wang 已提交
742
static int32_t parseTagsClause(SInsertParseContext* pCxt, SVnodeModifyOpStmt* pStmt) {
X
Xiaoyu Wang 已提交
743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760
  SToken token;
  NEXT_TOKEN(pStmt->pSql, token);
  if (TK_TAGS != token.type) {
    return buildSyntaxErrMsg(&pCxt->msg, "TAGS is expected", token.z);
  }

  NEXT_TOKEN(pStmt->pSql, token);
  if (TK_NK_LP != token.type) {
    return buildSyntaxErrMsg(&pCxt->msg, "( is expected", token.z);
  }

  int32_t code = parseTagsClauseImpl(pCxt, pStmt);
  if (TSDB_CODE_SUCCESS == code) {
    NEXT_VALID_TOKEN(pStmt->pSql, token);
    if (TK_NK_COMMA == token.type) {
      code = generateSyntaxErrMsg(&pCxt->msg, TSDB_CODE_PAR_TAGS_NOT_MATCHED);
    } else if (TK_NK_RP != token.type) {
      code = buildSyntaxErrMsg(&pCxt->msg, ") is expected", token.z);
761 762
    }
  }
X
Xiaoyu Wang 已提交
763 764
  return code;
}
765

X
Xiaoyu Wang 已提交
766
static int32_t storeTableMeta(SInsertParseContext* pCxt, SVnodeModifyOpStmt* pStmt) {
X
Xiaoyu Wang 已提交
767
  pStmt->pTableMeta->suid = pStmt->pTableMeta->uid;
X
Xiaoyu Wang 已提交
768 769 770 771 772 773
  pStmt->pTableMeta->uid = pStmt->totalTbNum;
  pStmt->pTableMeta->tableType = TSDB_CHILD_TABLE;

  STableMeta* pBackup = NULL;
  if (TSDB_CODE_SUCCESS != cloneTableMeta(pStmt->pTableMeta, &pBackup)) {
    return TSDB_CODE_OUT_OF_MEMORY;
774
  }
775

X
Xiaoyu Wang 已提交
776 777 778 779 780
  char tbFName[TSDB_TABLE_FNAME_LEN];
  tNameExtractFullName(&pStmt->targetTableName, tbFName);
  return taosHashPut(pStmt->pSubTableHashObj, tbFName, strlen(tbFName), &pBackup, POINTER_BYTES);
}

X
Xiaoyu Wang 已提交
781
static int32_t parseTableOptions(SInsertParseContext* pCxt, SVnodeModifyOpStmt* pStmt) {
X
Xiaoyu Wang 已提交
782 783 784 785 786 787 788 789 790 791
  do {
    int32_t index = 0;
    SToken  token;
    NEXT_TOKEN_KEEP_SQL(pStmt->pSql, token, index);
    if (TK_TTL == token.type) {
      pStmt->pSql += index;
      NEXT_TOKEN_WITH_PREV(pStmt->pSql, token);
      if (TK_NK_INTEGER != token.type) {
        return buildSyntaxErrMsg(&pCxt->msg, "Invalid option ttl", token.z);
      }
X
Xiaoyu Wang 已提交
792 793
      pStmt->pCreateTblReq->ttl = taosStr2Int32(token.z, NULL, 10);
      if (pStmt->pCreateTblReq->ttl < 0) {
X
Xiaoyu Wang 已提交
794 795 796 797 798 799 800 801 802 803 804 805
        return buildSyntaxErrMsg(&pCxt->msg, "Invalid option ttl", token.z);
      }
    } else if (TK_COMMENT == token.type) {
      pStmt->pSql += index;
      NEXT_TOKEN(pStmt->pSql, token);
      if (TK_NK_STRING != token.type) {
        return buildSyntaxErrMsg(&pCxt->msg, "Invalid option comment", token.z);
      }
      if (token.n >= TSDB_TB_COMMENT_LEN) {
        return buildSyntaxErrMsg(&pCxt->msg, "comment too long", token.z);
      }
      int32_t len = trimString(token.z, token.n, pCxt->tmpTokenBuf, TSDB_TB_COMMENT_LEN);
X
Xiaoyu Wang 已提交
806 807
      pStmt->pCreateTblReq->comment = strndup(pCxt->tmpTokenBuf, len);
      if (NULL == pStmt->pCreateTblReq->comment) {
X
Xiaoyu Wang 已提交
808 809
        return TSDB_CODE_OUT_OF_MEMORY;
      }
X
Xiaoyu Wang 已提交
810
      pStmt->pCreateTblReq->commentLen = len;
X
Xiaoyu Wang 已提交
811 812 813 814
    } else {
      break;
    }
  } while (1);
815 816 817
  return TSDB_CODE_SUCCESS;
}

X
Xiaoyu Wang 已提交
818 819 820 821 822 823
// input pStmt->pSql:
//   1. [(tag1_name, ...)] ...
//   2. VALUES ... | FILE ...
// output pStmt->pSql:
//   1. [(field1_name, ...)]
//   2. VALUES ... | FILE ...
X
Xiaoyu Wang 已提交
824
static int32_t parseUsingClauseBottom(SInsertParseContext* pCxt, SVnodeModifyOpStmt* pStmt) {
X
Xiaoyu Wang 已提交
825
  if (!pStmt->usingTableProcessing || pCxt->usingDuplicateTable) {
X
Xiaoyu Wang 已提交
826 827
    return TSDB_CODE_SUCCESS;
  }
wmmhello's avatar
wmmhello 已提交
828

X
Xiaoyu Wang 已提交
829 830 831 832 833 834 835 836 837 838 839
  int32_t code = parseBoundTagsClause(pCxt, pStmt);
  if (TSDB_CODE_SUCCESS == code) {
    code = parseTagsClause(pCxt, pStmt);
  }
  if (TSDB_CODE_SUCCESS == code) {
    code = parseTableOptions(pCxt, pStmt);
  }

  return code;
}

X
Xiaoyu Wang 已提交
840
static int32_t checkAuth(SParseContext* pCxt, SName* pTbName, bool* pMissCache) {
X
Xiaoyu Wang 已提交
841 842
  char dbFName[TSDB_DB_FNAME_LEN];
  tNameGetFullDbName(pTbName, dbFName);
X
Xiaoyu Wang 已提交
843 844 845
  int32_t code = TSDB_CODE_SUCCESS;
  bool    pass = true;
  bool    exists = true;
X
Xiaoyu Wang 已提交
846
  if (pCxt->async) {
X
Xiaoyu Wang 已提交
847
    code = catalogChkAuthFromCache(pCxt->pCatalog, pCxt->pUser, dbFName, AUTH_TYPE_WRITE, &pass, &exists);
X
Xiaoyu Wang 已提交
848
  } else {
X
Xiaoyu Wang 已提交
849 850 851 852
    SRequestConnInfo conn = {.pTrans = pCxt->pTransporter,
                             .requestId = pCxt->requestId,
                             .requestObjRefId = pCxt->requestRid,
                             .mgmtEps = pCxt->mgmtEpSet};
X
Xiaoyu Wang 已提交
853 854
    code = catalogChkAuth(pCxt->pCatalog, &conn, pCxt->pUser, dbFName, AUTH_TYPE_WRITE, &pass);
  }
X
Xiaoyu Wang 已提交
855 856 857 858 859 860
  if (TSDB_CODE_SUCCESS == code) {
    if (!exists) {
      *pMissCache = true;
    } else if (!pass) {
      code = TSDB_CODE_PAR_PERMISSION_DENIED;
    }
X
Xiaoyu Wang 已提交
861 862 863 864 865 866
  }
  return code;
}

static int32_t getTableMeta(SInsertParseContext* pCxt, SName* pTbName, bool isStb, STableMeta** pTableMeta,
                            bool* pMissCache) {
X
Xiaoyu Wang 已提交
867 868
  SParseContext* pComCxt = pCxt->pComCxt;
  int32_t        code = TSDB_CODE_SUCCESS;
X
Xiaoyu Wang 已提交
869 870
  if (pComCxt->async) {
    if (isStb) {
X
Xiaoyu Wang 已提交
871
      code = catalogGetCachedSTableMeta(pComCxt->pCatalog, pTbName, pTableMeta);
X
Xiaoyu Wang 已提交
872
    } else {
X
Xiaoyu Wang 已提交
873
      code = catalogGetCachedTableMeta(pComCxt->pCatalog, pTbName, pTableMeta);
X
Xiaoyu Wang 已提交
874 875
    }
  } else {
X
Xiaoyu Wang 已提交
876 877 878 879
    SRequestConnInfo conn = {.pTrans = pComCxt->pTransporter,
                             .requestId = pComCxt->requestId,
                             .requestObjRefId = pComCxt->requestRid,
                             .mgmtEps = pComCxt->mgmtEpSet};
X
Xiaoyu Wang 已提交
880 881 882 883
    if (isStb) {
      code = catalogGetSTableMeta(pComCxt->pCatalog, &conn, pTbName, pTableMeta);
    } else {
      code = catalogGetTableMeta(pComCxt->pCatalog, &conn, pTbName, pTableMeta);
wmmhello's avatar
wmmhello 已提交
884
    }
X
Xiaoyu Wang 已提交
885 886 887 888 889 890
  }
  if (TSDB_CODE_SUCCESS == code) {
    if (NULL == *pTableMeta) {
      *pMissCache = true;
    } else if (isStb && TSDB_SUPER_TABLE != (*pTableMeta)->tableType) {
      code = buildInvalidOperationMsg(&pCxt->msg, "create table only from super table is allowed");
X
Xiaoyu Wang 已提交
891 892
    } else if (!isStb && TSDB_SUPER_TABLE == (*pTableMeta)->tableType) {
      code = buildInvalidOperationMsg(&pCxt->msg, "insert data into super table is not supported");
X
Xiaoyu Wang 已提交
893 894 895 896 897
    }
  }
  return code;
}

X
Xiaoyu Wang 已提交
898
static int32_t getTableVgroup(SParseContext* pCxt, SVnodeModifyOpStmt* pStmt, bool isStb, bool* pMissCache) {
X
Xiaoyu Wang 已提交
899 900 901
  int32_t     code = TSDB_CODE_SUCCESS;
  SVgroupInfo vg;
  bool        exists = true;
X
Xiaoyu Wang 已提交
902
  if (pCxt->async) {
X
Xiaoyu Wang 已提交
903
    code = catalogGetCachedTableHashVgroup(pCxt->pCatalog, &pStmt->targetTableName, &vg, &exists);
X
Xiaoyu Wang 已提交
904
  } else {
X
Xiaoyu Wang 已提交
905 906 907 908
    SRequestConnInfo conn = {.pTrans = pCxt->pTransporter,
                             .requestId = pCxt->requestId,
                             .requestObjRefId = pCxt->requestRid,
                             .mgmtEps = pCxt->mgmtEpSet};
X
Xiaoyu Wang 已提交
909 910 911 912 913 914 915 916 917 918 919 920 921
    code = catalogGetTableHashVgroup(pCxt->pCatalog, &conn, &pStmt->targetTableName, &vg);
  }
  if (TSDB_CODE_SUCCESS == code) {
    if (exists) {
      if (isStb) {
        pStmt->pTableMeta->vgId = vg.vgId;
      }
      code = taosHashPut(pStmt->pVgroupsHashObj, (const char*)&vg.vgId, sizeof(vg.vgId), (char*)&vg, sizeof(vg));
    }
    *pMissCache = !exists;
  }
  return code;
}
922

X
Xiaoyu Wang 已提交
923
static int32_t getTableMetaAndVgroupImpl(SParseContext* pCxt, SVnodeModifyOpStmt* pStmt, bool* pMissCache) {
924
  SVgroupInfo vg;
925
  int32_t     code = catalogGetCachedTableVgMeta(pCxt->pCatalog, &pStmt->targetTableName, &vg, &pStmt->pTableMeta);
926
  if (TSDB_CODE_SUCCESS == code) {
927
    if (NULL != pStmt->pTableMeta) {
928 929
      code = taosHashPut(pStmt->pVgroupsHashObj, (const char*)&vg.vgId, sizeof(vg.vgId), (char*)&vg, sizeof(vg));
    }
930
    *pMissCache = (NULL == pStmt->pTableMeta);
931 932 933 934
  }
  return code;
}

X
Xiaoyu Wang 已提交
935
static int32_t getTableMetaAndVgroup(SInsertParseContext* pCxt, SVnodeModifyOpStmt* pStmt, bool* pMissCache) {
936 937 938
  SParseContext* pComCxt = pCxt->pComCxt;
  int32_t        code = TSDB_CODE_SUCCESS;
  if (pComCxt->async) {
D
dapan1121 已提交
939
    code = getTableMetaAndVgroupImpl(pComCxt, pStmt, pMissCache);
940 941 942 943 944 945 946 947 948
  } else {
    code = getTableMeta(pCxt, &pStmt->targetTableName, false, &pStmt->pTableMeta, pMissCache);
    if (TSDB_CODE_SUCCESS == code && !pCxt->missCache) {
      code = getTableVgroup(pCxt->pComCxt, pStmt, false, &pCxt->missCache);
    }
  }
  return code;
}

949 950 951 952 953 954 955 956 957 958 959 960
static int32_t collectUseTable(const SName* pName, SHashObj* pTable) {
  char fullName[TSDB_TABLE_FNAME_LEN];
  tNameExtractFullName(pName, fullName);
  return taosHashPut(pTable, fullName, strlen(fullName), pName, sizeof(SName));
}

static int32_t collectUseDatabase(const SName* pName, SHashObj* pDbs) {
  char dbFName[TSDB_DB_FNAME_LEN] = {0};
  tNameGetFullDbName(pName, dbFName);
  return taosHashPut(pDbs, dbFName, strlen(dbFName), dbFName, sizeof(dbFName));
}

X
Xiaoyu Wang 已提交
961
static int32_t getTargetTableSchema(SInsertParseContext* pCxt, SVnodeModifyOpStmt* pStmt) {
962 963 964 965 966
  if (pCxt->forceUpdate) {
    pCxt->missCache = true;
    return TSDB_CODE_SUCCESS;
  }

X
Xiaoyu Wang 已提交
967 968
  int32_t code = checkAuth(pCxt->pComCxt, &pStmt->targetTableName, &pCxt->missCache);
  if (TSDB_CODE_SUCCESS == code && !pCxt->missCache) {
969
    code = getTableMetaAndVgroup(pCxt, pStmt, &pCxt->missCache);
X
Xiaoyu Wang 已提交
970
  }
971
  if (TSDB_CODE_SUCCESS == code && !pCxt->pComCxt->async) {
972
    code = collectUseDatabase(&pStmt->targetTableName, pStmt->pDbFNameHashObj);
973 974 975
    if (TSDB_CODE_SUCCESS == code) {
      code = collectUseTable(&pStmt->targetTableName, pStmt->pTableNameHashObj);
    }
976
  }
X
Xiaoyu Wang 已提交
977 978 979
  return code;
}

X
Xiaoyu Wang 已提交
980
static int32_t preParseUsingTableName(SInsertParseContext* pCxt, SVnodeModifyOpStmt* pStmt, SToken* pTbName) {
X
Xiaoyu Wang 已提交
981 982 983
  return insCreateSName(&pStmt->usingTableName, pTbName, pCxt->pComCxt->acctId, pCxt->pComCxt->db, &pCxt->msg);
}

X
Xiaoyu Wang 已提交
984
static int32_t getUsingTableSchema(SInsertParseContext* pCxt, SVnodeModifyOpStmt* pStmt) {
985 986 987 988 989
  if (pCxt->forceUpdate) {
    pCxt->missCache = true;
    return TSDB_CODE_SUCCESS;
  }

X
Xiaoyu Wang 已提交
990 991
  int32_t code = checkAuth(pCxt->pComCxt, &pStmt->targetTableName, &pCxt->missCache);
  if (TSDB_CODE_SUCCESS == code && !pCxt->missCache) {
X
Xiaoyu Wang 已提交
992 993 994 995 996
    code = getTableMeta(pCxt, &pStmt->usingTableName, true, &pStmt->pTableMeta, &pCxt->missCache);
  }
  if (TSDB_CODE_SUCCESS == code && !pCxt->missCache) {
    code = getTableVgroup(pCxt->pComCxt, pStmt, true, &pCxt->missCache);
  }
997 998 999 1000 1001 1002
  if (TSDB_CODE_SUCCESS == code && !pCxt->pComCxt->async) {
    code = collectUseDatabase(&pStmt->usingTableName, pStmt->pDbFNameHashObj);
    if (TSDB_CODE_SUCCESS == code) {
      code = collectUseTable(&pStmt->usingTableName, pStmt->pTableNameHashObj);
    }
  }
X
Xiaoyu Wang 已提交
1003 1004 1005
  return code;
}

X
Xiaoyu Wang 已提交
1006
static int32_t parseUsingTableNameImpl(SInsertParseContext* pCxt, SVnodeModifyOpStmt* pStmt) {
X
Xiaoyu Wang 已提交
1007 1008 1009 1010 1011 1012
  SToken token;
  NEXT_TOKEN(pStmt->pSql, token);
  int32_t code = preParseUsingTableName(pCxt, pStmt, &token);
  if (TSDB_CODE_SUCCESS == code) {
    code = getUsingTableSchema(pCxt, pStmt);
  }
X
Xiaoyu Wang 已提交
1013
  if (TSDB_CODE_SUCCESS == code && !pCxt->missCache) {
X
Xiaoyu Wang 已提交
1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024
    code = storeTableMeta(pCxt, pStmt);
  }
  return code;
}

// input pStmt->pSql:
//   1(care). [USING stb_name [(tag1_name, ...)] TAGS (tag1_value, ...) [table_options]] ...
//   2. VALUES ... | FILE ...
// output pStmt->pSql:
//   1. [(tag1_name, ...)] TAGS (tag1_value, ...) [table_options]] ...
//   2. VALUES ... | FILE ...
X
Xiaoyu Wang 已提交
1025
static int32_t parseUsingTableName(SInsertParseContext* pCxt, SVnodeModifyOpStmt* pStmt) {
X
Xiaoyu Wang 已提交
1026 1027 1028 1029 1030 1031 1032
  SToken  token;
  int32_t index = 0;
  NEXT_TOKEN_KEEP_SQL(pStmt->pSql, token, index);
  if (TK_USING != token.type) {
    return getTargetTableSchema(pCxt, pStmt);
  }

X
Xiaoyu Wang 已提交
1033
  pStmt->usingTableProcessing = true;
X
Xiaoyu Wang 已提交
1034 1035
  // pStmt->pSql -> stb_name [(tag1_name, ...)
  pStmt->pSql += index;
X
Xiaoyu Wang 已提交
1036 1037
  int32_t code = parseDuplicateUsingClause(pCxt, pStmt, &pCxt->usingDuplicateTable);
  if (TSDB_CODE_SUCCESS == code && !pCxt->usingDuplicateTable) {
X
Xiaoyu Wang 已提交
1038 1039 1040 1041 1042
    return parseUsingTableNameImpl(pCxt, pStmt);
  }
  return code;
}

X
Xiaoyu Wang 已提交
1043
static int32_t preParseTargetTableName(SInsertParseContext* pCxt, SVnodeModifyOpStmt* pStmt, SToken* pTbName) {
X
Xiaoyu Wang 已提交
1044 1045 1046 1047 1048 1049 1050 1051 1052 1053
  return insCreateSName(&pStmt->targetTableName, pTbName, pCxt->pComCxt->acctId, pCxt->pComCxt->db, &pCxt->msg);
}

// input pStmt->pSql:
//   1(care). [(field1_name, ...)] ...
//   2. [ USING ... ] ...
//   3. VALUES ... | FILE ...
// output pStmt->pSql:
//   1. [ USING ... ] ...
//   2. VALUES ... | FILE ...
X
Xiaoyu Wang 已提交
1054
static int32_t preParseBoundColumnsClause(SInsertParseContext* pCxt, SVnodeModifyOpStmt* pStmt) {
X
Xiaoyu Wang 已提交
1055 1056 1057 1058
  SToken  token;
  int32_t index = 0;
  NEXT_TOKEN_KEEP_SQL(pStmt->pSql, token, index);
  if (TK_NK_LP != token.type) {
1059 1060 1061
    return TSDB_CODE_SUCCESS;
  }

X
Xiaoyu Wang 已提交
1062 1063 1064 1065 1066 1067
  // pStmt->pSql -> field1_name, ...)
  pStmt->pSql += index;
  pStmt->pBoundCols = pStmt->pSql;
  return skipParentheses(pCxt, &pStmt->pSql);
}

X
Xiaoyu Wang 已提交
1068
static int32_t getTableDataCxt(SInsertParseContext* pCxt, SVnodeModifyOpStmt* pStmt, STableDataCxt** pTableCxt) {
X
Xiaoyu Wang 已提交
1069
  if (pCxt->pComCxt->async) {
X
Xiaoyu Wang 已提交
1070 1071
    return insGetTableDataCxt(pStmt->pTableBlockHashObj, &pStmt->pTableMeta->uid, sizeof(pStmt->pTableMeta->uid),
                              pStmt->pTableMeta, &pStmt->pCreateTblReq, pTableCxt, false);
X
Xiaoyu Wang 已提交
1072
  }
X
Xiaoyu Wang 已提交
1073

X
Xiaoyu Wang 已提交
1074 1075
  char tbFName[TSDB_TABLE_FNAME_LEN];
  tNameExtractFullName(&pStmt->targetTableName, tbFName);
D
dapan1121 已提交
1076 1077 1078
  if (pStmt->usingTableProcessing) {
    pStmt->pTableMeta->uid = 0;
  }
X
Xiaoyu Wang 已提交
1079
  return insGetTableDataCxt(pStmt->pTableBlockHashObj, tbFName, strlen(tbFName), pStmt->pTableMeta,
D
dapan1121 已提交
1080
                            &pStmt->pCreateTblReq, pTableCxt, NULL != pCxt->pComCxt->pStmtCb);
X
Xiaoyu Wang 已提交
1081 1082
}

X
Xiaoyu Wang 已提交
1083
static int32_t parseBoundColumnsClause(SInsertParseContext* pCxt, SVnodeModifyOpStmt* pStmt, STableDataCxt* pTableCxt) {
X
Xiaoyu Wang 已提交
1084 1085 1086 1087 1088 1089 1090 1091 1092
  SToken  token;
  int32_t index = 0;
  NEXT_TOKEN_KEEP_SQL(pStmt->pSql, token, index);
  if (TK_NK_LP == token.type) {
    pStmt->pSql += index;
    if (NULL != pStmt->pBoundCols) {
      return buildSyntaxErrMsg(&pCxt->msg, "keyword VALUES or FILE is expected", token.z);
    }
    // pStmt->pSql -> field1_name, ...)
X
Xiaoyu Wang 已提交
1093 1094
    return parseBoundColumns(pCxt, &pStmt->pSql, false, getTableColumnSchema(pStmt->pTableMeta),
                             &pTableCxt->boundColsInfo);
X
Xiaoyu Wang 已提交
1095 1096 1097
  }

  if (NULL != pStmt->pBoundCols) {
X
Xiaoyu Wang 已提交
1098 1099
    return parseBoundColumns(pCxt, &pStmt->pBoundCols, false, getTableColumnSchema(pStmt->pTableMeta),
                             &pTableCxt->boundColsInfo);
X
Xiaoyu Wang 已提交
1100 1101 1102 1103 1104
  }

  return TSDB_CODE_SUCCESS;
}

D
dapan1121 已提交
1105 1106 1107 1108 1109 1110
int32_t initTableColSubmitData(STableDataCxt* pTableCxt) {
  if (0 == (pTableCxt->pData->flags & SUBMIT_REQ_COLUMN_DATA_FORMAT)) {
    return TSDB_CODE_SUCCESS;
  }

  for (int32_t i = 0; i < pTableCxt->boundColsInfo.numOfBound; ++i) {
X
Xiaoyu Wang 已提交
1111
    SSchema*  pSchema = &pTableCxt->pMeta->schema[pTableCxt->boundColsInfo.pColIndex[i]];
D
dapan1121 已提交
1112 1113 1114 1115 1116 1117 1118 1119 1120 1121
    SColData* pCol = taosArrayReserve(pTableCxt->pData->aCol, 1);
    if (NULL == pCol) {
      return TSDB_CODE_OUT_OF_MEMORY;
    }
    tColDataInit(pCol, pSchema->colId, pSchema->type, 0);
  }

  return TSDB_CODE_SUCCESS;
}

X
Xiaoyu Wang 已提交
1122 1123 1124 1125
// input pStmt->pSql:
//   1. [(tag1_name, ...)] ...
//   2. VALUES ... | FILE ...
// output pStmt->pSql: VALUES ... | FILE ...
X
Xiaoyu Wang 已提交
1126
static int32_t parseSchemaClauseBottom(SInsertParseContext* pCxt, SVnodeModifyOpStmt* pStmt,
X
Xiaoyu Wang 已提交
1127
                                       STableDataCxt** pTableCxt) {
X
Xiaoyu Wang 已提交
1128 1129
  int32_t code = parseUsingClauseBottom(pCxt, pStmt);
  if (TSDB_CODE_SUCCESS == code) {
X
Xiaoyu Wang 已提交
1130
    code = getTableDataCxt(pCxt, pStmt, pTableCxt);
X
Xiaoyu Wang 已提交
1131 1132
  }
  if (TSDB_CODE_SUCCESS == code) {
X
Xiaoyu Wang 已提交
1133
    code = parseBoundColumnsClause(pCxt, pStmt, *pTableCxt);
X
Xiaoyu Wang 已提交
1134
  }
D
dapan1121 已提交
1135 1136 1137
  if (TSDB_CODE_SUCCESS == code) {
    code = initTableColSubmitData(*pTableCxt);
  }
X
Xiaoyu Wang 已提交
1138 1139 1140 1141 1142 1143 1144
  return code;
}

// input pStmt->pSql: [(field1_name, ...)] [ USING ... ] VALUES ... | FILE ...
// output pStmt->pSql:
//   1. [(tag1_name, ...)] ...
//   2. VALUES ... | FILE ...
X
Xiaoyu Wang 已提交
1145
static int32_t parseSchemaClauseTop(SInsertParseContext* pCxt, SVnodeModifyOpStmt* pStmt, SToken* pTbName) {
X
Xiaoyu Wang 已提交
1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158
  int32_t code = preParseTargetTableName(pCxt, pStmt, pTbName);
  if (TSDB_CODE_SUCCESS == code) {
    // option: [(field1_name, ...)]
    code = preParseBoundColumnsClause(pCxt, pStmt);
  }
  if (TSDB_CODE_SUCCESS == code) {
    // option: [USING stb_name]
    code = parseUsingTableName(pCxt, pStmt);
  }
  return code;
}

static int32_t parseValueTokenImpl(SInsertParseContext* pCxt, const char** pSql, SToken* pToken, SSchema* pSchema,
X
Xiaoyu Wang 已提交
1159
                                   int16_t timePrec, SColVal* pVal) {
wmmhello's avatar
wmmhello 已提交
1160 1161 1162 1163
  switch (pSchema->type) {
    case TSDB_DATA_TYPE_BOOL: {
      if ((pToken->type == TK_NK_BOOL || pToken->type == TK_NK_STRING) && (pToken->n != 0)) {
        if (strncmp(pToken->z, "true", pToken->n) == 0) {
X
Xiaoyu Wang 已提交
1164
          pVal->value.val = TRUE_VALUE;
wmmhello's avatar
wmmhello 已提交
1165
        } else if (strncmp(pToken->z, "false", pToken->n) == 0) {
X
Xiaoyu Wang 已提交
1166
          pVal->value.val = FALSE_VALUE;
wmmhello's avatar
wmmhello 已提交
1167
        } else {
X
Xiaoyu Wang 已提交
1168
          return buildSyntaxErrMsg(&pCxt->msg, "invalid bool data", pToken->z);
wmmhello's avatar
wmmhello 已提交
1169 1170
        }
      } else if (pToken->type == TK_NK_INTEGER) {
X
Xiaoyu Wang 已提交
1171
        pVal->value.val = ((taosStr2Int64(pToken->z, NULL, 10) == 0) ? FALSE_VALUE : TRUE_VALUE);
wmmhello's avatar
wmmhello 已提交
1172
      } else if (pToken->type == TK_NK_FLOAT) {
X
Xiaoyu Wang 已提交
1173
        pVal->value.val = ((taosStr2Double(pToken->z, NULL) == 0) ? FALSE_VALUE : TRUE_VALUE);
wmmhello's avatar
wmmhello 已提交
1174
      } else {
X
Xiaoyu Wang 已提交
1175
        return buildSyntaxErrMsg(&pCxt->msg, "invalid bool data", pToken->z);
D
dapan1121 已提交
1176
      }
X
Xiaoyu Wang 已提交
1177
      break;
wmmhello's avatar
wmmhello 已提交
1178 1179
    }
    case TSDB_DATA_TYPE_TINYINT: {
X
Xiaoyu Wang 已提交
1180
      if (TSDB_CODE_SUCCESS != toInteger(pToken->z, pToken->n, 10, &pVal->value.val)) {
X
Xiaoyu Wang 已提交
1181
        return buildSyntaxErrMsg(&pCxt->msg, "invalid tinyint data", pToken->z);
X
Xiaoyu Wang 已提交
1182
      } else if (!IS_VALID_TINYINT(pVal->value.val)) {
X
Xiaoyu Wang 已提交
1183
        return buildSyntaxErrMsg(&pCxt->msg, "tinyint data overflow", pToken->z);
D
dapan1121 已提交
1184
      }
X
Xiaoyu Wang 已提交
1185
      break;
1186
    }
wmmhello's avatar
wmmhello 已提交
1187
    case TSDB_DATA_TYPE_UTINYINT: {
X
Xiaoyu Wang 已提交
1188
      if (TSDB_CODE_SUCCESS != toUInteger(pToken->z, pToken->n, 10, &pVal->value.val)) {
X
Xiaoyu Wang 已提交
1189
        return buildSyntaxErrMsg(&pCxt->msg, "invalid unsigned tinyint data", pToken->z);
X
Xiaoyu Wang 已提交
1190
      } else if (pVal->value.val > UINT8_MAX) {
X
Xiaoyu Wang 已提交
1191
        return buildSyntaxErrMsg(&pCxt->msg, "unsigned tinyint data overflow", pToken->z);
wmmhello's avatar
wmmhello 已提交
1192
      }
X
Xiaoyu Wang 已提交
1193
      break;
wmmhello's avatar
wmmhello 已提交
1194 1195
    }
    case TSDB_DATA_TYPE_SMALLINT: {
X
Xiaoyu Wang 已提交
1196
      if (TSDB_CODE_SUCCESS != toInteger(pToken->z, pToken->n, 10, &pVal->value.val)) {
X
Xiaoyu Wang 已提交
1197
        return buildSyntaxErrMsg(&pCxt->msg, "invalid smallint data", pToken->z);
X
Xiaoyu Wang 已提交
1198
      } else if (!IS_VALID_SMALLINT(pVal->value.val)) {
X
Xiaoyu Wang 已提交
1199
        return buildSyntaxErrMsg(&pCxt->msg, "smallint data overflow", pToken->z);
wmmhello's avatar
wmmhello 已提交
1200
      }
X
Xiaoyu Wang 已提交
1201
      break;
wmmhello's avatar
wmmhello 已提交
1202 1203
    }
    case TSDB_DATA_TYPE_USMALLINT: {
X
Xiaoyu Wang 已提交
1204
      if (TSDB_CODE_SUCCESS != toUInteger(pToken->z, pToken->n, 10, &pVal->value.val)) {
X
Xiaoyu Wang 已提交
1205
        return buildSyntaxErrMsg(&pCxt->msg, "invalid unsigned smallint data", pToken->z);
X
Xiaoyu Wang 已提交
1206
      } else if (pVal->value.val > UINT16_MAX) {
X
Xiaoyu Wang 已提交
1207
        return buildSyntaxErrMsg(&pCxt->msg, "unsigned smallint data overflow", pToken->z);
wmmhello's avatar
wmmhello 已提交
1208
      }
X
Xiaoyu Wang 已提交
1209
      break;
wmmhello's avatar
wmmhello 已提交
1210 1211
    }
    case TSDB_DATA_TYPE_INT: {
X
Xiaoyu Wang 已提交
1212
      if (TSDB_CODE_SUCCESS != toInteger(pToken->z, pToken->n, 10, &pVal->value.val)) {
X
Xiaoyu Wang 已提交
1213
        return buildSyntaxErrMsg(&pCxt->msg, "invalid int data", pToken->z);
X
Xiaoyu Wang 已提交
1214
      } else if (!IS_VALID_INT(pVal->value.val)) {
X
Xiaoyu Wang 已提交
1215
        return buildSyntaxErrMsg(&pCxt->msg, "int data overflow", pToken->z);
wmmhello's avatar
wmmhello 已提交
1216
      }
X
Xiaoyu Wang 已提交
1217
      break;
wmmhello's avatar
wmmhello 已提交
1218 1219
    }
    case TSDB_DATA_TYPE_UINT: {
X
Xiaoyu Wang 已提交
1220
      if (TSDB_CODE_SUCCESS != toUInteger(pToken->z, pToken->n, 10, &pVal->value.val)) {
X
Xiaoyu Wang 已提交
1221
        return buildSyntaxErrMsg(&pCxt->msg, "invalid unsigned int data", pToken->z);
X
Xiaoyu Wang 已提交
1222
      } else if (pVal->value.val > UINT32_MAX) {
X
Xiaoyu Wang 已提交
1223
        return buildSyntaxErrMsg(&pCxt->msg, "unsigned int data overflow", pToken->z);
wmmhello's avatar
wmmhello 已提交
1224
      }
X
Xiaoyu Wang 已提交
1225
      break;
wmmhello's avatar
wmmhello 已提交
1226 1227
    }
    case TSDB_DATA_TYPE_BIGINT: {
X
Xiaoyu Wang 已提交
1228
      if (TSDB_CODE_SUCCESS != toInteger(pToken->z, pToken->n, 10, &pVal->value.val)) {
X
Xiaoyu Wang 已提交
1229
        return buildSyntaxErrMsg(&pCxt->msg, "invalid bigint data", pToken->z);
wmmhello's avatar
wmmhello 已提交
1230
      }
X
Xiaoyu Wang 已提交
1231
      break;
wmmhello's avatar
wmmhello 已提交
1232 1233
    }
    case TSDB_DATA_TYPE_UBIGINT: {
X
Xiaoyu Wang 已提交
1234
      if (TSDB_CODE_SUCCESS != toUInteger(pToken->z, pToken->n, 10, &pVal->value.val)) {
X
Xiaoyu Wang 已提交
1235
        return buildSyntaxErrMsg(&pCxt->msg, "invalid unsigned bigint data", pToken->z);
wmmhello's avatar
wmmhello 已提交
1236
      }
X
Xiaoyu Wang 已提交
1237
      break;
wmmhello's avatar
wmmhello 已提交
1238 1239
    }
    case TSDB_DATA_TYPE_FLOAT: {
X
Xiaoyu Wang 已提交
1240
      char*  endptr = NULL;
wmmhello's avatar
wmmhello 已提交
1241 1242
      double dv;
      if (TK_NK_ILLEGAL == toDouble(pToken, &dv, &endptr)) {
X
Xiaoyu Wang 已提交
1243
        return buildSyntaxErrMsg(&pCxt->msg, "illegal float data", pToken->z);
wmmhello's avatar
wmmhello 已提交
1244 1245 1246
      }
      if (((dv == HUGE_VAL || dv == -HUGE_VAL) && errno == ERANGE) || dv > FLT_MAX || dv < -FLT_MAX || isinf(dv) ||
          isnan(dv)) {
X
Xiaoyu Wang 已提交
1247
        return buildSyntaxErrMsg(&pCxt->msg, "illegal float data", pToken->z);
wmmhello's avatar
wmmhello 已提交
1248
      }
X
Xiaoyu Wang 已提交
1249 1250
      float f = dv;
      memcpy(&pVal->value.val, &f, sizeof(f));
X
Xiaoyu Wang 已提交
1251
      break;
wmmhello's avatar
wmmhello 已提交
1252 1253
    }
    case TSDB_DATA_TYPE_DOUBLE: {
X
Xiaoyu Wang 已提交
1254
      char*  endptr = NULL;
wmmhello's avatar
wmmhello 已提交
1255 1256
      double dv;
      if (TK_NK_ILLEGAL == toDouble(pToken, &dv, &endptr)) {
X
Xiaoyu Wang 已提交
1257
        return buildSyntaxErrMsg(&pCxt->msg, "illegal double data", pToken->z);
wmmhello's avatar
wmmhello 已提交
1258 1259
      }
      if (((dv == HUGE_VAL || dv == -HUGE_VAL) && errno == ERANGE) || isinf(dv) || isnan(dv)) {
X
Xiaoyu Wang 已提交
1260
        return buildSyntaxErrMsg(&pCxt->msg, "illegal double data", pToken->z);
wmmhello's avatar
wmmhello 已提交
1261
      }
X
Xiaoyu Wang 已提交
1262 1263
      pVal->value.val = *(int64_t*)&dv;
      break;
wmmhello's avatar
wmmhello 已提交
1264 1265 1266 1267
    }
    case TSDB_DATA_TYPE_BINARY: {
      // Too long values will raise the invalid sql error message
      if (pToken->n + VARSTR_HEADER_SIZE > pSchema->bytes) {
X
Xiaoyu Wang 已提交
1268
        return generateSyntaxErrMsg(&pCxt->msg, TSDB_CODE_PAR_VALUE_TOO_LONG, pSchema->name);
D
stmt  
dapan1121 已提交
1269
      }
X
Xiaoyu Wang 已提交
1270 1271 1272 1273 1274
      pVal->value.pData = taosMemoryMalloc(pToken->n);
      if (NULL == pVal->value.pData) {
        return TSDB_CODE_OUT_OF_MEMORY;
      }
      memcpy(pVal->value.pData, pToken->z, pToken->n);
X
Xiaoyu Wang 已提交
1275 1276
      pVal->value.nData = pToken->n;
      break;
X
Xiaoyu Wang 已提交
1277
    }
X
Xiaoyu Wang 已提交
1278
    case TSDB_DATA_TYPE_NCHAR: {
X
Xiaoyu Wang 已提交
1279 1280 1281 1282 1283 1284 1285
      // if the converted output len is over than pColumnModel->bytes, return error: 'Argument list too long'
      int32_t len = 0;
      char*   pUcs4 = taosMemoryCalloc(1, pSchema->bytes - VARSTR_HEADER_SIZE);
      if (NULL == pUcs4) {
        return TSDB_CODE_OUT_OF_MEMORY;
      }
      if (!taosMbsToUcs4(pToken->z, pToken->n, (TdUcs4*)pUcs4, pSchema->bytes - VARSTR_HEADER_SIZE, &len)) {
1286
        taosMemoryFree(pUcs4);
X
Xiaoyu Wang 已提交
1287 1288 1289 1290 1291 1292 1293 1294 1295 1296
        if (errno == E2BIG) {
          return generateSyntaxErrMsg(&pCxt->msg, TSDB_CODE_PAR_VALUE_TOO_LONG, pSchema->name);
        }
        char buf[512] = {0};
        snprintf(buf, tListLen(buf), "%s", strerror(errno));
        return buildSyntaxErrMsg(&pCxt->msg, buf, pToken->z);
      }
      pVal->value.pData = pUcs4;
      pVal->value.nData = len;
      break;
1297
    }
X
Xiaoyu Wang 已提交
1298 1299 1300
    case TSDB_DATA_TYPE_JSON: {
      if (pToken->n > (TSDB_MAX_JSON_TAG_LEN - VARSTR_HEADER_SIZE) / TSDB_NCHAR_SIZE) {
        return buildSyntaxErrMsg(&pCxt->msg, "json string too long than 4095", pToken->z);
1301
      }
X
Xiaoyu Wang 已提交
1302 1303 1304 1305 1306
      pVal->value.pData = taosMemoryMalloc(pToken->n);
      if (NULL == pVal->value.pData) {
        return TSDB_CODE_OUT_OF_MEMORY;
      }
      memcpy(pVal->value.pData, pToken->z, pToken->n);
X
Xiaoyu Wang 已提交
1307 1308
      pVal->value.nData = pToken->n;
      break;
1309
    }
X
Xiaoyu Wang 已提交
1310
    case TSDB_DATA_TYPE_TIMESTAMP: {
X
Xiaoyu Wang 已提交
1311
      if (parseTime(pSql, pToken, timePrec, &pVal->value.val, &pCxt->msg) != TSDB_CODE_SUCCESS) {
X
Xiaoyu Wang 已提交
1312 1313
        return buildSyntaxErrMsg(&pCxt->msg, "invalid timestamp", pToken->z);
      }
X
Xiaoyu Wang 已提交
1314
      break;
X
Xiaoyu Wang 已提交
1315
    }
X
Xiaoyu Wang 已提交
1316 1317
    default:
      return TSDB_CODE_FAILED;
X
Xiaoyu Wang 已提交
1318
  }
1319

X
Xiaoyu Wang 已提交
1320
  pVal->flag = CV_FLAG_VALUE;
X
Xiaoyu Wang 已提交
1321
  return TSDB_CODE_SUCCESS;
X
Xiaoyu Wang 已提交
1322
}
D
dapan 已提交
1323

X
Xiaoyu Wang 已提交
1324
static int32_t parseValueToken(SInsertParseContext* pCxt, const char** pSql, SToken* pToken, SSchema* pSchema,
X
Xiaoyu Wang 已提交
1325
                               int16_t timePrec, SColVal* pVal) {
X
Xiaoyu Wang 已提交
1326 1327 1328 1329 1330
  int32_t code = checkAndTrimValue(pToken, pCxt->tmpTokenBuf, &pCxt->msg);
  if (TSDB_CODE_SUCCESS == code && isNullValue(pSchema->type, pToken)) {
    if (TSDB_DATA_TYPE_TIMESTAMP == pSchema->type && PRIMARYKEY_TIMESTAMP_COL_ID == pSchema->colId) {
      return buildSyntaxErrMsg(&pCxt->msg, "primary timestamp should not be null", pToken->z);
    }
X
Xiaoyu Wang 已提交
1331 1332
    pVal->flag = CV_FLAG_NULL;
    return TSDB_CODE_SUCCESS;
1333 1334
  }

X
Xiaoyu Wang 已提交
1335 1336
  if (TSDB_CODE_SUCCESS == code && IS_NUMERIC_TYPE(pSchema->type) && pToken->n == 0) {
    return buildSyntaxErrMsg(&pCxt->msg, "invalid numeric data", pToken->z);
1337 1338
  }

X
Xiaoyu Wang 已提交
1339
  if (TSDB_CODE_SUCCESS == code) {
X
Xiaoyu Wang 已提交
1340
    code = parseValueTokenImpl(pCxt, pSql, pToken, pSchema, timePrec, pVal);
X
Xiaoyu Wang 已提交
1341
  }
1342

X
Xiaoyu Wang 已提交
1343
  return code;
1344 1345
}

X
Xiaoyu Wang 已提交
1346 1347 1348 1349
static void clearColValArray(SArray* pCols) {
  int32_t num = taosArrayGetSize(pCols);
  for (int32_t i = 0; i < num; ++i) {
    SColVal* pCol = taosArrayGet(pCols, i);
X
Xiaoyu Wang 已提交
1350
    if (IS_VAR_DATA_TYPE(pCol->type)) {
X
Xiaoyu Wang 已提交
1351 1352 1353 1354 1355
      taosMemoryFreeClear(pCol->value.pData);
    }
  }
}

X
Xiaoyu Wang 已提交
1356
static int parseOneRow(SInsertParseContext* pCxt, const char** pSql, STableDataCxt* pTableCxt, bool* pGotRow,
X
Xiaoyu Wang 已提交
1357
                       SToken* pToken) {
X
Xiaoyu Wang 已提交
1358 1359 1360 1361 1362
  SBoundColInfo* pCols = &pTableCxt->boundColsInfo;
  bool           isParseBindParam = false;
  SSchema*       pSchemas = getTableColumnSchema(pTableCxt->pMeta);

  int32_t code = TSDB_CODE_SUCCESS;
1363
  // 1. set the parsed value from sql string
X
Xiaoyu Wang 已提交
1364
  for (int i = 0; i < pCols->numOfBound && TSDB_CODE_SUCCESS == code; ++i) {
X
Xiaoyu Wang 已提交
1365 1366 1367 1368 1369
    const char* pOrigSql = *pSql;
    bool        ignoreComma = false;
    NEXT_TOKEN_WITH_PREV_EXT(*pSql, *pToken, &ignoreComma);
    if (ignoreComma) {
      code = buildSyntaxErrMsg(&pCxt->msg, "invalid data or symbol", pOrigSql);
X
Xiaoyu Wang 已提交
1370
      break;
X
Xiaoyu Wang 已提交
1371
    }
D
stmt  
dapan1121 已提交
1372

X
Xiaoyu Wang 已提交
1373 1374
    SSchema* pSchema = &pSchemas[pCols->pColIndex[i]];
    SColVal* pVal = taosArrayGet(pTableCxt->pValues, pCols->pColIndex[i]);
D
stmt  
dapan1121 已提交
1375

X
Xiaoyu Wang 已提交
1376
    if (pToken->type == TK_NK_QUESTION) {
D
stmt  
dapan1121 已提交
1377
      isParseBindParam = true;
X
Xiaoyu Wang 已提交
1378 1379
      if (NULL == pCxt->pComCxt->pStmtCb) {
        code = buildSyntaxErrMsg(&pCxt->msg, "? only used in stmt", pToken->z);
X
Xiaoyu Wang 已提交
1380 1381 1382 1383 1384 1385
        break;
      }
    } else {
      if (TK_NK_RP == pToken->type) {
        code = generateSyntaxErrMsg(&pCxt->msg, TSDB_CODE_PAR_INVALID_COLUMNS_NUM);
        break;
D
stmt  
dapan1121 已提交
1386
      }
D
dapan1121 已提交
1387

X
Xiaoyu Wang 已提交
1388 1389 1390 1391
      if (isParseBindParam) {
        code = buildInvalidOperationMsg(&pCxt->msg, "no mix usage for ? and values");
        break;
      }
X
Xiaoyu Wang 已提交
1392

X
Xiaoyu Wang 已提交
1393 1394 1395
      if (TSDB_CODE_SUCCESS == code) {
        code = parseValueToken(pCxt, pSql, pToken, pSchema, getTableInfo(pTableCxt->pMeta).precision, pVal);
      }
X
Xiaoyu Wang 已提交
1396
    }
1397

X
Xiaoyu Wang 已提交
1398 1399 1400 1401
    if (TSDB_CODE_SUCCESS == code && i < pCols->numOfBound - 1) {
      NEXT_VALID_TOKEN(*pSql, *pToken);
      if (TK_NK_COMMA != pToken->type) {
        code = buildSyntaxErrMsg(&pCxt->msg, ", expected", pToken->z);
X
Xiaoyu Wang 已提交
1402 1403
      }
    }
1404 1405
  }

D
dapan1121 已提交
1406
  if (TSDB_CODE_SUCCESS == code && !isParseBindParam) {
X
Xiaoyu Wang 已提交
1407
    SRow** pRow = taosArrayReserve(pTableCxt->pData->aRowP, 1);
X
Xiaoyu Wang 已提交
1408
    code = tRowBuild(pTableCxt->pValues, pTableCxt->pSchema, pRow);
X
Xiaoyu Wang 已提交
1409 1410 1411
    if (TSDB_CODE_SUCCESS == code) {
      insCheckTableDataOrder(pTableCxt, TD_ROW_KEY(*pRow));
    }
X
Xiaoyu Wang 已提交
1412
  }
1413

X
Xiaoyu Wang 已提交
1414 1415
  if (TSDB_CODE_SUCCESS == code && !isParseBindParam) {
    *pGotRow = true;
1416 1417
  }

X
Xiaoyu Wang 已提交
1418 1419
  clearColValArray(pTableCxt->pValues);

X
Xiaoyu Wang 已提交
1420
  return code;
1421 1422 1423
}

// pSql -> (field1_value, ...) [(field1_value2, ...) ...]
X
Xiaoyu Wang 已提交
1424
static int32_t parseValues(SInsertParseContext* pCxt, SVnodeModifyOpStmt* pStmt, STableDataCxt* pTableCxt,
X
Xiaoyu Wang 已提交
1425 1426
                           int32_t* pNumOfRows, SToken* pToken) {
  int32_t code = TSDB_CODE_SUCCESS;
X
Xiaoyu Wang 已提交
1427 1428 1429

  (*pNumOfRows) = 0;
  while (TSDB_CODE_SUCCESS == code) {
1430
    int32_t index = 0;
X
Xiaoyu Wang 已提交
1431 1432
    NEXT_TOKEN_KEEP_SQL(pStmt->pSql, *pToken, index);
    if (TK_NK_LP != pToken->type) {
1433 1434
      break;
    }
X
Xiaoyu Wang 已提交
1435
    pStmt->pSql += index;
1436

D
stmt  
dapan1121 已提交
1437
    bool gotRow = false;
X
Xiaoyu Wang 已提交
1438
    if (TSDB_CODE_SUCCESS == code) {
X
Xiaoyu Wang 已提交
1439
      code = parseOneRow(pCxt, &pStmt->pSql, pTableCxt, &gotRow, pToken);
D
stmt  
dapan1121 已提交
1440
    }
1441

X
Xiaoyu Wang 已提交
1442 1443 1444 1445 1446 1447 1448
    if (TSDB_CODE_SUCCESS == code) {
      NEXT_VALID_TOKEN(pStmt->pSql, *pToken);
      if (TK_NK_COMMA == pToken->type) {
        code = generateSyntaxErrMsg(&pCxt->msg, TSDB_CODE_PAR_INVALID_COLUMNS_NUM);
      } else if (TK_NK_RP != pToken->type) {
        code = buildSyntaxErrMsg(&pCxt->msg, ") expected", pToken->z);
      }
1449 1450
    }

X
Xiaoyu Wang 已提交
1451 1452
    if (TSDB_CODE_SUCCESS == code && gotRow) {
      (*pNumOfRows)++;
D
stmt  
dapan1121 已提交
1453
    }
1454 1455
  }

X
Xiaoyu Wang 已提交
1456 1457 1458
  if (TSDB_CODE_SUCCESS == code && 0 == (*pNumOfRows) &&
      (!TSDB_QUERY_HAS_TYPE(pStmt->insertType, TSDB_QUERY_TYPE_STMT_INSERT))) {
    code = buildSyntaxErrMsg(&pCxt->msg, "no any data points", NULL);
1459
  }
X
Xiaoyu Wang 已提交
1460
  return code;
1461 1462
}

X
Xiaoyu Wang 已提交
1463
// VALUES (field1_value, ...) [(field1_value2, ...) ...]
X
Xiaoyu Wang 已提交
1464
static int32_t parseValuesClause(SInsertParseContext* pCxt, SVnodeModifyOpStmt* pStmt, STableDataCxt* pTableCxt,
X
Xiaoyu Wang 已提交
1465
                                 SToken* pToken) {
1466
  int32_t numOfRows = 0;
X
Xiaoyu Wang 已提交
1467
  int32_t code = parseValues(pCxt, pStmt, pTableCxt, &numOfRows, pToken);
X
Xiaoyu Wang 已提交
1468 1469 1470 1471 1472 1473
  if (TSDB_CODE_SUCCESS == code) {
    pStmt->totalRowsNum += numOfRows;
    pStmt->totalTbNum += 1;
    TSDB_QUERY_SET_TYPE(pStmt->insertType, TSDB_QUERY_TYPE_INSERT);
  }
  return code;
1474 1475
}

X
Xiaoyu Wang 已提交
1476
static int32_t parseCsvFile(SInsertParseContext* pCxt, SVnodeModifyOpStmt* pStmt, STableDataCxt* pTableCxt,
X
Xiaoyu Wang 已提交
1477 1478
                            int32_t* pNumOfRows) {
  int32_t code = TSDB_CODE_SUCCESS;
X
Xiaoyu Wang 已提交
1479
  (*pNumOfRows) = 0;
X
Xiaoyu Wang 已提交
1480 1481
  char*   pLine = NULL;
  int64_t readLen = 0;
D
dapan1121 已提交
1482
  bool    firstLine = (pStmt->fileProcessing == false);
X
Xiaoyu Wang 已提交
1483
  pStmt->fileProcessing = false;
X
Xiaoyu Wang 已提交
1484
  while (TSDB_CODE_SUCCESS == code && (readLen = taosGetLineFile(pStmt->fp, &pLine)) != -1) {
X
Xiaoyu Wang 已提交
1485 1486 1487 1488 1489
    if (('\r' == pLine[readLen - 1]) || ('\n' == pLine[readLen - 1])) {
      pLine[--readLen] = '\0';
    }

    if (readLen == 0) {
D
dapan1121 已提交
1490
      firstLine = false;
X
Xiaoyu Wang 已提交
1491 1492 1493
      continue;
    }

X
Xiaoyu Wang 已提交
1494 1495 1496 1497
    bool gotRow = false;
    if (TSDB_CODE_SUCCESS == code) {
      SToken token;
      strtolower(pLine, pLine);
X
Xiaoyu Wang 已提交
1498
      const char* pRow = pLine;
1499

H
Haojun Liao 已提交
1500
      code = parseOneRow(pCxt, (const char**)&pRow, pTableCxt, &gotRow, &token);
D
dapan1121 已提交
1501 1502 1503 1504 1505
      if (code && firstLine) {
        firstLine = false;
        code = 0;
        continue;
      }
X
Xiaoyu Wang 已提交
1506
    }
X
Xiaoyu Wang 已提交
1507 1508 1509

    if (TSDB_CODE_SUCCESS == code && gotRow) {
      (*pNumOfRows)++;
X
Xiaoyu Wang 已提交
1510
    }
1511

X
Xiaoyu Wang 已提交
1512
    if (TSDB_CODE_SUCCESS == code && (*pNumOfRows) > tsMaxMemUsedByInsert * 1024 * 1024) {
X
Xiaoyu Wang 已提交
1513
      pStmt->fileProcessing = true;
1514 1515
      break;
    }
D
dapan1121 已提交
1516 1517

    firstLine = false;
X
Xiaoyu Wang 已提交
1518
  }
X
Xiaoyu Wang 已提交
1519
  taosMemoryFree(pLine);
X
Xiaoyu Wang 已提交
1520

X
Xiaoyu Wang 已提交
1521
  if (TSDB_CODE_SUCCESS == code && 0 == (*pNumOfRows) &&
X
Xiaoyu Wang 已提交
1522
      (!TSDB_QUERY_HAS_TYPE(pStmt->insertType, TSDB_QUERY_TYPE_STMT_INSERT)) && !pStmt->fileProcessing) {
X
Xiaoyu Wang 已提交
1523
    code = buildSyntaxErrMsg(&pCxt->msg, "no any data points", NULL);
X
Xiaoyu Wang 已提交
1524
  }
X
Xiaoyu Wang 已提交
1525
  return code;
X
Xiaoyu Wang 已提交
1526 1527
}

X
Xiaoyu Wang 已提交
1528
static int32_t parseDataFromFileImpl(SInsertParseContext* pCxt, SVnodeModifyOpStmt* pStmt, STableDataCxt* pTableCxt) {
X
Xiaoyu Wang 已提交
1529
  int32_t numOfRows = 0;
X
Xiaoyu Wang 已提交
1530
  int32_t code = parseCsvFile(pCxt, pStmt, pTableCxt, &numOfRows);
X
Xiaoyu Wang 已提交
1531 1532 1533 1534
  if (TSDB_CODE_SUCCESS == code) {
    pStmt->totalRowsNum += numOfRows;
    pStmt->totalTbNum += 1;
    TSDB_QUERY_SET_TYPE(pStmt->insertType, TSDB_QUERY_TYPE_FILE_INSERT);
X
Xiaoyu Wang 已提交
1535
    if (!pStmt->fileProcessing) {
X
Xiaoyu Wang 已提交
1536 1537 1538 1539
      taosCloseFile(&pStmt->fp);
    } else {
      parserDebug("0x%" PRIx64 " insert from csv. File is too large, do it in batches.", pCxt->pComCxt->requestId);
    }
1540
  }
X
Xiaoyu Wang 已提交
1541
  return code;
X
Xiaoyu Wang 已提交
1542 1543
}

X
Xiaoyu Wang 已提交
1544
static int32_t parseDataFromFile(SInsertParseContext* pCxt, SVnodeModifyOpStmt* pStmt, SToken* pFilePath,
X
Xiaoyu Wang 已提交
1545
                                 STableDataCxt* pTableCxt) {
1546
  char filePathStr[TSDB_FILENAME_LEN] = {0};
X
Xiaoyu Wang 已提交
1547 1548
  if (TK_NK_STRING == pFilePath->type) {
    trimString(pFilePath->z, pFilePath->n, filePathStr, sizeof(filePathStr));
1549
  } else {
X
Xiaoyu Wang 已提交
1550
    strncpy(filePathStr, pFilePath->z, pFilePath->n);
1551
  }
X
Xiaoyu Wang 已提交
1552 1553
  pStmt->fp = taosOpenFile(filePathStr, TD_FILE_READ | TD_FILE_STREAM);
  if (NULL == pStmt->fp) {
1554 1555 1556
    return TAOS_SYSTEM_ERROR(errno);
  }

X
Xiaoyu Wang 已提交
1557
  return parseDataFromFileImpl(pCxt, pStmt, pTableCxt);
1558 1559
}

X
Xiaoyu Wang 已提交
1560
static int32_t parseFileClause(SInsertParseContext* pCxt, SVnodeModifyOpStmt* pStmt, STableDataCxt* pTableCxt,
X
Xiaoyu Wang 已提交
1561
                               SToken* pToken) {
1562 1563 1564 1565
  if (tsUseAdapter) {
    return buildInvalidOperationMsg(&pCxt->msg, "proxy mode does not support csv loading");
  }

X
Xiaoyu Wang 已提交
1566 1567 1568
  NEXT_TOKEN(pStmt->pSql, *pToken);
  if (0 == pToken->n || (TK_NK_STRING != pToken->type && TK_NK_ID != pToken->type)) {
    return buildSyntaxErrMsg(&pCxt->msg, "file path is required following keyword FILE", pToken->z);
1569
  }
X
Xiaoyu Wang 已提交
1570
  return parseDataFromFile(pCxt, pStmt, pToken, pTableCxt);
X
Xiaoyu Wang 已提交
1571 1572
}

X
Xiaoyu Wang 已提交
1573
// VALUES (field1_value, ...) [(field1_value2, ...) ...] | FILE csv_file_path
X
Xiaoyu Wang 已提交
1574
static int32_t parseDataClause(SInsertParseContext* pCxt, SVnodeModifyOpStmt* pStmt, STableDataCxt* pTableCxt) {
X
Xiaoyu Wang 已提交
1575 1576 1577 1578
  SToken token;
  NEXT_TOKEN(pStmt->pSql, token);
  switch (token.type) {
    case TK_VALUES:
X
Xiaoyu Wang 已提交
1579
      return parseValuesClause(pCxt, pStmt, pTableCxt, &token);
X
Xiaoyu Wang 已提交
1580
    case TK_FILE:
X
Xiaoyu Wang 已提交
1581
      return parseFileClause(pCxt, pStmt, pTableCxt, &token);
X
Xiaoyu Wang 已提交
1582 1583 1584 1585
    default:
      break;
  }
  return buildSyntaxErrMsg(&pCxt->msg, "keyword VALUES or FILE is expected", token.z);
X
Xiaoyu Wang 已提交
1586 1587
}

X
Xiaoyu Wang 已提交
1588 1589 1590
// input pStmt->pSql:
//   1. [(tag1_name, ...)] ...
//   2. VALUES ... | FILE ...
X
Xiaoyu Wang 已提交
1591
static int32_t parseInsertTableClauseBottom(SInsertParseContext* pCxt, SVnodeModifyOpStmt* pStmt) {
X
Xiaoyu Wang 已提交
1592 1593
  STableDataCxt* pTableCxt = NULL;
  int32_t        code = parseSchemaClauseBottom(pCxt, pStmt, &pTableCxt);
X
Xiaoyu Wang 已提交
1594
  if (TSDB_CODE_SUCCESS == code) {
X
Xiaoyu Wang 已提交
1595
    code = parseDataClause(pCxt, pStmt, pTableCxt);
X
Xiaoyu Wang 已提交
1596 1597 1598 1599
  }
  return code;
}

X
Xiaoyu Wang 已提交
1600
static void resetEnvPreTable(SInsertParseContext* pCxt, SVnodeModifyOpStmt* pStmt) {
X
Xiaoyu Wang 已提交
1601
  insDestroyBoundColInfo(&pCxt->tags);
X
Xiaoyu Wang 已提交
1602
  taosMemoryFreeClear(pStmt->pTableMeta);
X
Xiaoyu Wang 已提交
1603 1604
  tdDestroySVCreateTbReq(pStmt->pCreateTblReq);
  taosMemoryFreeClear(pStmt->pCreateTblReq);
X
Xiaoyu Wang 已提交
1605 1606
  pCxt->missCache = false;
  pCxt->usingDuplicateTable = false;
X
Xiaoyu Wang 已提交
1607
  pStmt->pBoundCols = NULL;
X
Xiaoyu Wang 已提交
1608 1609 1610 1611
  pStmt->usingTableProcessing = false;
  pStmt->fileProcessing = false;
}

X
Xiaoyu Wang 已提交
1612
// input pStmt->pSql: [(field1_name, ...)] [ USING ... ] VALUES ... | FILE ...
X
Xiaoyu Wang 已提交
1613
static int32_t parseInsertTableClause(SInsertParseContext* pCxt, SVnodeModifyOpStmt* pStmt, SToken* pTbName) {
X
Xiaoyu Wang 已提交
1614
  resetEnvPreTable(pCxt, pStmt);
X
Xiaoyu Wang 已提交
1615 1616 1617 1618 1619 1620
  int32_t code = parseSchemaClauseTop(pCxt, pStmt, pTbName);
  if (TSDB_CODE_SUCCESS == code && !pCxt->missCache) {
    code = parseInsertTableClauseBottom(pCxt, pStmt);
  }
  return code;
}
X
Xiaoyu Wang 已提交
1621

X
Xiaoyu Wang 已提交
1622
static int32_t checkTableClauseFirstToken(SInsertParseContext* pCxt, SVnodeModifyOpStmt* pStmt, SToken* pTbName,
X
Xiaoyu Wang 已提交
1623 1624 1625 1626 1627
                                          bool* pHasData) {
  // no data in the sql string anymore.
  if (0 == pTbName->n) {
    if (0 != pTbName->type && '\0' != pStmt->pSql[0]) {
      return buildSyntaxErrMsg(&pCxt->msg, "invalid charactor in SQL", pTbName->z);
1628 1629
    }

X
Xiaoyu Wang 已提交
1630 1631
    if (0 == pStmt->totalRowsNum && (!TSDB_QUERY_HAS_TYPE(pStmt->insertType, TSDB_QUERY_TYPE_STMT_INSERT))) {
      return buildInvalidOperationMsg(&pCxt->msg, "no data in sql");
D
stmt  
dapan1121 已提交
1632 1633
    }

X
Xiaoyu Wang 已提交
1634 1635 1636
    *pHasData = false;
    return TSDB_CODE_SUCCESS;
  }
X
Xiaoyu Wang 已提交
1637

X
Xiaoyu Wang 已提交
1638 1639 1640
  if (TSDB_QUERY_HAS_TYPE(pStmt->insertType, TSDB_QUERY_TYPE_STMT_INSERT) && pStmt->totalTbNum > 0) {
    return buildInvalidOperationMsg(&pCxt->msg, "single table allowed in one stmt");
  }
1641

X
Xiaoyu Wang 已提交
1642 1643 1644
  if (TK_NK_QUESTION == pTbName->type) {
    if (NULL == pCxt->pComCxt->pStmtCb) {
      return buildSyntaxErrMsg(&pCxt->msg, "? only used in stmt", pTbName->z);
X
Xiaoyu Wang 已提交
1645
    }
X
Xiaoyu Wang 已提交
1646

X
Xiaoyu Wang 已提交
1647 1648 1649 1650 1651 1652 1653
    char*   tbName = NULL;
    int32_t code = (*pCxt->pComCxt->pStmtCb->getTbNameFn)(pCxt->pComCxt->pStmtCb->pStmt, &tbName);
    if (TSDB_CODE_SUCCESS == code) {
      pTbName->z = tbName;
      pTbName->n = strlen(tbName);
    } else {
      return code;
1654
    }
X
Xiaoyu Wang 已提交
1655
  }
1656

X
Xiaoyu Wang 已提交
1657 1658 1659
  *pHasData = true;
  return TSDB_CODE_SUCCESS;
}
1660

X
Xiaoyu Wang 已提交
1661
static int32_t setStmtInfo(SInsertParseContext* pCxt, SVnodeModifyOpStmt* pStmt) {
X
Xiaoyu Wang 已提交
1662
  SBoundColInfo* tags = taosMemoryMalloc(sizeof(pCxt->tags));
X
Xiaoyu Wang 已提交
1663
  if (NULL == tags) {
S
Shengliang Guan 已提交
1664
    return TSDB_CODE_OUT_OF_MEMORY;
X
Xiaoyu Wang 已提交
1665 1666
  }
  memcpy(tags, &pCxt->tags, sizeof(pCxt->tags));
1667

X
Xiaoyu Wang 已提交
1668
  SStmtCallback* pStmtCb = pCxt->pComCxt->pStmtCb;
X
Xiaoyu Wang 已提交
1669 1670 1671
  int32_t        code = (*pStmtCb->setInfoFn)(pStmtCb->pStmt, pStmt->pTableMeta, tags, &pStmt->targetTableName,
                                       pStmt->usingTableProcessing, pStmt->pVgroupsHashObj, pStmt->pTableBlockHashObj,
                                       pStmt->usingTableName.tname);
1672

X
Xiaoyu Wang 已提交
1673 1674 1675 1676 1677
  memset(&pCxt->tags, 0, sizeof(pCxt->tags));
  pStmt->pVgroupsHashObj = NULL;
  pStmt->pTableBlockHashObj = NULL;
  return code;
}
1678

X
Xiaoyu Wang 已提交
1679
static int32_t parseInsertBodyBottom(SInsertParseContext* pCxt, SVnodeModifyOpStmt* pStmt) {
X
Xiaoyu Wang 已提交
1680 1681 1682
  if (TSDB_QUERY_HAS_TYPE(pStmt->insertType, TSDB_QUERY_TYPE_STMT_INSERT)) {
    return setStmtInfo(pCxt, pStmt);
  }
D
stmt  
dapan1121 已提交
1683

X
Xiaoyu Wang 已提交
1684
  // merge according to vgId
X
Xiaoyu Wang 已提交
1685
  int32_t code = insMergeTableDataCxt(pStmt->pTableBlockHashObj, &pStmt->pVgDataBlocks);
X
Xiaoyu Wang 已提交
1686
  if (TSDB_CODE_SUCCESS == code) {
X
Xiaoyu Wang 已提交
1687
    code = insBuildVgDataBlocks(pStmt->pVgroupsHashObj, pStmt->pVgDataBlocks, &pStmt->pDataBlocks);
X
Xiaoyu Wang 已提交
1688
  }
X
Xiaoyu Wang 已提交
1689

X
Xiaoyu Wang 已提交
1690 1691
  return code;
}
1692

X
Xiaoyu Wang 已提交
1693 1694 1695 1696 1697
// tb_name
//     [USING stb_name [(tag1_name, ...)] TAGS (tag1_value, ...)]
//     [(field1_name, ...)]
//     VALUES (field1_value, ...) [(field1_value2, ...) ...] | FILE csv_file_path
// [...];
X
Xiaoyu Wang 已提交
1698
static int32_t parseInsertBody(SInsertParseContext* pCxt, SVnodeModifyOpStmt* pStmt) {
X
Xiaoyu Wang 已提交
1699 1700 1701 1702
  SToken  token;
  int32_t code = TSDB_CODE_SUCCESS;
  bool    hasData = true;
  // for each table
X
Xiaoyu Wang 已提交
1703
  while (TSDB_CODE_SUCCESS == code && hasData && !pCxt->missCache && !pStmt->fileProcessing) {
X
Xiaoyu Wang 已提交
1704 1705 1706 1707 1708
    // pStmt->pSql -> tb_name ...
    NEXT_TOKEN(pStmt->pSql, token);
    code = checkTableClauseFirstToken(pCxt, pStmt, &token, &hasData);
    if (TSDB_CODE_SUCCESS == code && hasData) {
      code = parseInsertTableClause(pCxt, pStmt, &token);
1709 1710
    }
  }
X
Xiaoyu Wang 已提交
1711

X
Xiaoyu Wang 已提交
1712 1713 1714 1715 1716
  if (TSDB_CODE_SUCCESS == code && !pCxt->missCache) {
    code = parseInsertBodyBottom(pCxt, pStmt);
  }
  return code;
}
D
stmt  
dapan1121 已提交
1717

X
Xiaoyu Wang 已提交
1718
static void destroySubTableHashElem(void* p) { taosMemoryFree(*(STableMeta**)p); }
X
Xiaoyu Wang 已提交
1719

X
Xiaoyu Wang 已提交
1720
static int32_t createVnodeModifOpStmt(SInsertParseContext* pCxt, bool reentry, SNode** pOutput) {
X
Xiaoyu Wang 已提交
1721
  SVnodeModifyOpStmt* pStmt = (SVnodeModifyOpStmt*)nodesMakeNode(QUERY_NODE_VNODE_MODIFY_STMT);
X
Xiaoyu Wang 已提交
1722 1723
  if (NULL == pStmt) {
    return TSDB_CODE_OUT_OF_MEMORY;
D
stmt  
dapan1121 已提交
1724
  }
X
Xiaoyu Wang 已提交
1725

X
Xiaoyu Wang 已提交
1726
  if (pCxt->pComCxt->pStmtCb) {
X
Xiaoyu Wang 已提交
1727
    TSDB_QUERY_SET_TYPE(pStmt->insertType, TSDB_QUERY_TYPE_STMT_INSERT);
1728
  }
X
Xiaoyu Wang 已提交
1729
  pStmt->pSql = pCxt->pComCxt->pSql;
X
Xiaoyu Wang 已提交
1730 1731
  pStmt->freeHashFunc = insDestroyTableDataCxtHashMap;
  pStmt->freeArrayFunc = insDestroyVgroupDataCxtList;
X
Xiaoyu Wang 已提交
1732

X
Xiaoyu Wang 已提交
1733 1734 1735 1736 1737
  if (!reentry) {
    pStmt->pVgroupsHashObj = taosHashInit(128, taosGetDefaultHashFunction(TSDB_DATA_TYPE_INT), true, HASH_NO_LOCK);
    pStmt->pTableBlockHashObj =
        taosHashInit(128, taosGetDefaultHashFunction(TSDB_DATA_TYPE_BIGINT), true, HASH_NO_LOCK);
  }
X
Xiaoyu Wang 已提交
1738 1739 1740
  pStmt->pSubTableHashObj = taosHashInit(128, taosGetDefaultHashFunction(TSDB_DATA_TYPE_VARCHAR), true, HASH_NO_LOCK);
  pStmt->pTableNameHashObj = taosHashInit(128, taosGetDefaultHashFunction(TSDB_DATA_TYPE_VARCHAR), true, HASH_NO_LOCK);
  pStmt->pDbFNameHashObj = taosHashInit(64, taosGetDefaultHashFunction(TSDB_DATA_TYPE_VARCHAR), true, HASH_NO_LOCK);
X
Xiaoyu Wang 已提交
1741 1742
  if ((!reentry && (NULL == pStmt->pVgroupsHashObj || NULL == pStmt->pTableBlockHashObj)) ||
      NULL == pStmt->pSubTableHashObj || NULL == pStmt->pTableNameHashObj || NULL == pStmt->pDbFNameHashObj) {
X
Xiaoyu Wang 已提交
1743 1744
    nodesDestroyNode((SNode*)pStmt);
    return TSDB_CODE_OUT_OF_MEMORY;
1745
  }
X
Xiaoyu Wang 已提交
1746 1747 1748 1749 1750

  taosHashSetFreeFp(pStmt->pSubTableHashObj, destroySubTableHashElem);

  *pOutput = (SNode*)pStmt;
  return TSDB_CODE_SUCCESS;
1751 1752
}

X
Xiaoyu Wang 已提交
1753
static int32_t createInsertQuery(SInsertParseContext* pCxt, SQuery** pOutput) {
X
Xiaoyu Wang 已提交
1754 1755 1756
  SQuery* pQuery = (SQuery*)nodesMakeNode(QUERY_NODE_QUERY);
  if (NULL == pQuery) {
    return TSDB_CODE_OUT_OF_MEMORY;
D
stmt  
dapan1121 已提交
1757
  }
X
Xiaoyu Wang 已提交
1758

X
Xiaoyu Wang 已提交
1759 1760 1761
  pQuery->execMode = QUERY_EXEC_MODE_SCHEDULE;
  pQuery->haveResultSet = false;
  pQuery->msgType = TDMT_VND_SUBMIT;
1762

X
Xiaoyu Wang 已提交
1763
  int32_t code = createVnodeModifOpStmt(pCxt, false, &pQuery->pRoot);
X
Xiaoyu Wang 已提交
1764 1765 1766 1767
  if (TSDB_CODE_SUCCESS == code) {
    *pOutput = pQuery;
  } else {
    nodesDestroyNode((SNode*)pQuery);
D
stmt  
dapan1121 已提交
1768
  }
X
Xiaoyu Wang 已提交
1769 1770
  return code;
}
D
stmt  
dapan1121 已提交
1771

X
Xiaoyu Wang 已提交
1772 1773 1774
static int32_t checkAuthFromMetaData(const SArray* pUsers) {
  if (1 != taosArrayGetSize(pUsers)) {
    return TSDB_CODE_FAILED;
1775
  }
1776

X
Xiaoyu Wang 已提交
1777 1778 1779 1780 1781 1782
  SMetaRes* pRes = taosArrayGet(pUsers, 0);
  if (TSDB_CODE_SUCCESS == pRes->code) {
    return (*(bool*)pRes->pRes) ? TSDB_CODE_SUCCESS : TSDB_CODE_PAR_PERMISSION_DENIED;
  }
  return pRes->code;
}
X
Xiaoyu Wang 已提交
1783

X
Xiaoyu Wang 已提交
1784 1785 1786 1787
static int32_t getTableMetaFromMetaData(const SArray* pTables, STableMeta** pMeta) {
  if (1 != taosArrayGetSize(pTables)) {
    return TSDB_CODE_FAILED;
  }
X
Xiaoyu Wang 已提交
1788 1789

  taosMemoryFreeClear(*pMeta);
X
Xiaoyu Wang 已提交
1790 1791 1792 1793
  SMetaRes* pRes = taosArrayGet(pTables, 0);
  if (TSDB_CODE_SUCCESS == pRes->code) {
    *pMeta = tableMetaDup((const STableMeta*)pRes->pRes);
    if (NULL == *pMeta) {
D
dapan1121 已提交
1794 1795 1796
      return TSDB_CODE_OUT_OF_MEMORY;
    }
  }
X
Xiaoyu Wang 已提交
1797 1798
  return pRes->code;
}
1799

X
Xiaoyu Wang 已提交
1800
static int32_t getTableVgroupFromMetaData(const SArray* pTables, SVnodeModifyOpStmt* pStmt, bool isStb) {
X
Xiaoyu Wang 已提交
1801 1802
  if (1 != taosArrayGetSize(pTables)) {
    return TSDB_CODE_FAILED;
D
dapan1121 已提交
1803 1804
  }

X
Xiaoyu Wang 已提交
1805 1806 1807
  SMetaRes* pRes = taosArrayGet(pTables, 0);
  if (TSDB_CODE_SUCCESS != pRes->code) {
    return pRes->code;
1808
  }
1809

X
Xiaoyu Wang 已提交
1810 1811 1812 1813 1814 1815 1816
  SVgroupInfo* pVg = pRes->pRes;
  if (isStb) {
    pStmt->pTableMeta->vgId = pVg->vgId;
  }
  return taosHashPut(pStmt->pVgroupsHashObj, (const char*)&pVg->vgId, sizeof(pVg->vgId), (char*)pVg,
                     sizeof(SVgroupInfo));
}
D
dapan1121 已提交
1817

X
Xiaoyu Wang 已提交
1818
static int32_t getTableSchemaFromMetaData(SInsertParseContext* pCxt, const SMetaData* pMetaData,
X
Xiaoyu Wang 已提交
1819
                                          SVnodeModifyOpStmt* pStmt, bool isStb) {
X
Xiaoyu Wang 已提交
1820 1821 1822
  int32_t code = checkAuthFromMetaData(pMetaData->pUser);
  if (TSDB_CODE_SUCCESS == code) {
    code = getTableMetaFromMetaData(pMetaData->pTableMeta, &pStmt->pTableMeta);
X
Xiaoyu Wang 已提交
1823
  }
X
Xiaoyu Wang 已提交
1824 1825 1826
  if (TSDB_CODE_SUCCESS == code && !isStb && TSDB_SUPER_TABLE == pStmt->pTableMeta->tableType) {
    code = buildInvalidOperationMsg(&pCxt->msg, "insert data into super table is not supported");
  }
1827 1828 1829
  if (TSDB_CODE_SUCCESS == code && isStb) {
    code = storeTableMeta(pCxt, pStmt);
  }
X
Xiaoyu Wang 已提交
1830 1831
  if (TSDB_CODE_SUCCESS == code) {
    code = getTableVgroupFromMetaData(pMetaData->pTableHash, pStmt, isStb);
1832
  }
X
Xiaoyu Wang 已提交
1833
  return code;
1834
}
D
stmt  
dapan1121 已提交
1835

X
Xiaoyu Wang 已提交
1836 1837 1838 1839 1840 1841
static void destoryTablesReq(void* p) {
  STablesReq* pRes = (STablesReq*)p;
  taosArrayDestroy(pRes->pTables);
}

static void clearCatalogReq(SCatalogReq* pCatalogReq) {
X
Xiaoyu Wang 已提交
1842 1843 1844 1845
  if (NULL == pCatalogReq) {
    return;
  }

X
Xiaoyu Wang 已提交
1846 1847 1848 1849 1850 1851 1852 1853
  taosArrayDestroyEx(pCatalogReq->pTableMeta, destoryTablesReq);
  pCatalogReq->pTableMeta = NULL;
  taosArrayDestroyEx(pCatalogReq->pTableHash, destoryTablesReq);
  pCatalogReq->pTableHash = NULL;
  taosArrayDestroy(pCatalogReq->pUser);
  pCatalogReq->pUser = NULL;
}

X
Xiaoyu Wang 已提交
1854
static int32_t setVnodeModifOpStmt(SInsertParseContext* pCxt, SCatalogReq* pCatalogReq, const SMetaData* pMetaData,
X
Xiaoyu Wang 已提交
1855
                                   SVnodeModifyOpStmt* pStmt) {
X
Xiaoyu Wang 已提交
1856 1857
  clearCatalogReq(pCatalogReq);

X
Xiaoyu Wang 已提交
1858
  if (pStmt->usingTableProcessing) {
X
Xiaoyu Wang 已提交
1859
    return getTableSchemaFromMetaData(pCxt, pMetaData, pStmt, true);
X
Xiaoyu Wang 已提交
1860
  }
X
Xiaoyu Wang 已提交
1861
  return getTableSchemaFromMetaData(pCxt, pMetaData, pStmt, false);
X
Xiaoyu Wang 已提交
1862 1863
}

X
Xiaoyu Wang 已提交
1864
static int32_t resetVnodeModifOpStmt(SInsertParseContext* pCxt, SQuery* pQuery) {
X
Xiaoyu Wang 已提交
1865 1866 1867 1868
  nodesDestroyNode(pQuery->pRoot);

  int32_t code = createVnodeModifOpStmt(pCxt, true, &pQuery->pRoot);
  if (TSDB_CODE_SUCCESS == code) {
X
Xiaoyu Wang 已提交
1869
    SVnodeModifyOpStmt* pStmt = (SVnodeModifyOpStmt*)pQuery->pRoot;
X
Xiaoyu Wang 已提交
1870

X
Xiaoyu Wang 已提交
1871 1872
    (*pCxt->pComCxt->pStmtCb->getExecInfoFn)(pCxt->pComCxt->pStmtCb->pStmt, &pStmt->pVgroupsHashObj,
                                             &pStmt->pTableBlockHashObj);
X
Xiaoyu Wang 已提交
1873 1874 1875 1876 1877 1878
    if (NULL == pStmt->pVgroupsHashObj) {
      pStmt->pVgroupsHashObj = taosHashInit(128, taosGetDefaultHashFunction(TSDB_DATA_TYPE_INT), true, HASH_NO_LOCK);
    }
    if (NULL == pStmt->pTableBlockHashObj) {
      pStmt->pTableBlockHashObj =
          taosHashInit(128, taosGetDefaultHashFunction(TSDB_DATA_TYPE_BINARY), true, HASH_NO_LOCK);
1879
    }
X
Xiaoyu Wang 已提交
1880 1881 1882
    if (NULL == pStmt->pVgroupsHashObj || NULL == pStmt->pTableBlockHashObj) {
      code = TSDB_CODE_OUT_OF_MEMORY;
    }
1883
  }
X
Xiaoyu Wang 已提交
1884

X
Xiaoyu Wang 已提交
1885
  return code;
1886 1887
}

X
Xiaoyu Wang 已提交
1888
static int32_t initInsertQuery(SInsertParseContext* pCxt, SCatalogReq* pCatalogReq, const SMetaData* pMetaData,
X
Xiaoyu Wang 已提交
1889
                               SQuery** pQuery) {
X
Xiaoyu Wang 已提交
1890 1891 1892
  if (NULL == *pQuery) {
    return createInsertQuery(pCxt, pQuery);
  }
X
Xiaoyu Wang 已提交
1893

X
Xiaoyu Wang 已提交
1894
  if (NULL != pCxt->pComCxt->pStmtCb) {
X
Xiaoyu Wang 已提交
1895 1896 1897
    return resetVnodeModifOpStmt(pCxt, *pQuery);
  }

X
Xiaoyu Wang 已提交
1898
  SVnodeModifyOpStmt* pStmt = (SVnodeModifyOpStmt*)(*pQuery)->pRoot;
X
Xiaoyu Wang 已提交
1899 1900 1901

  if (!pStmt->fileProcessing) {
    return setVnodeModifOpStmt(pCxt, pCatalogReq, pMetaData, pStmt);
X
Xiaoyu Wang 已提交
1902 1903 1904
  }

  return TSDB_CODE_SUCCESS;
1905 1906
}

X
Xiaoyu Wang 已提交
1907
static int32_t setRefreshMate(SQuery* pQuery) {
X
Xiaoyu Wang 已提交
1908
  SVnodeModifyOpStmt* pStmt = (SVnodeModifyOpStmt*)pQuery->pRoot;
1909 1910 1911 1912 1913 1914 1915 1916 1917

  if (taosHashGetSize(pStmt->pTableNameHashObj) > 0) {
    taosArrayDestroy(pQuery->pTableList);
    pQuery->pTableList = taosArrayInit(taosHashGetSize(pStmt->pTableNameHashObj), sizeof(SName));
    SName* pTable = taosHashIterate(pStmt->pTableNameHashObj, NULL);
    while (NULL != pTable) {
      taosArrayPush(pQuery->pTableList, pTable);
      pTable = taosHashIterate(pStmt->pTableNameHashObj, pTable);
    }
1918 1919
  }

1920 1921 1922 1923 1924 1925 1926 1927
  if (taosHashGetSize(pStmt->pDbFNameHashObj) > 0) {
    taosArrayDestroy(pQuery->pDbList);
    pQuery->pDbList = taosArrayInit(taosHashGetSize(pStmt->pDbFNameHashObj), TSDB_DB_FNAME_LEN);
    char* pDb = taosHashIterate(pStmt->pDbFNameHashObj, NULL);
    while (NULL != pDb) {
      taosArrayPush(pQuery->pDbList, pDb);
      pDb = taosHashIterate(pStmt->pDbFNameHashObj, pDb);
    }
1928 1929 1930 1931 1932
  }

  return TSDB_CODE_SUCCESS;
}

X
Xiaoyu Wang 已提交
1933 1934 1935 1936 1937 1938
// INSERT INTO
//   tb_name
//       [USING stb_name [(tag1_name, ...)] TAGS (tag1_value, ...) [table_options]]
//       [(field1_name, ...)]
//       VALUES (field1_value, ...) [(field1_value2, ...) ...] | FILE csv_file_path
//   [...];
X
Xiaoyu Wang 已提交
1939
static int32_t parseInsertSqlFromStart(SInsertParseContext* pCxt, SVnodeModifyOpStmt* pStmt) {
X
Xiaoyu Wang 已提交
1940 1941 1942 1943 1944
  int32_t code = skipInsertInto(&pStmt->pSql, &pCxt->msg);
  if (TSDB_CODE_SUCCESS == code) {
    code = parseInsertBody(pCxt, pStmt);
  }
  return code;
1945 1946
}

X
Xiaoyu Wang 已提交
1947
static int32_t parseInsertSqlFromCsv(SInsertParseContext* pCxt, SVnodeModifyOpStmt* pStmt) {
X
Xiaoyu Wang 已提交
1948 1949
  STableDataCxt* pTableCxt = NULL;
  int32_t        code = getTableDataCxt(pCxt, pStmt, &pTableCxt);
X
Xiaoyu Wang 已提交
1950
  if (TSDB_CODE_SUCCESS == code) {
X
Xiaoyu Wang 已提交
1951
    code = parseDataFromFileImpl(pCxt, pStmt, pTableCxt);
1952 1953
  }

X
Xiaoyu Wang 已提交
1954 1955 1956 1957 1958 1959 1960 1961 1962
  if (TSDB_CODE_SUCCESS == code) {
    if (pStmt->fileProcessing) {
      code = parseInsertBodyBottom(pCxt, pStmt);
    } else {
      code = parseInsertBody(pCxt, pStmt);
    }
  }

  return code;
X
Xiaoyu Wang 已提交
1963 1964
}

X
Xiaoyu Wang 已提交
1965
static int32_t parseInsertSqlFromTable(SInsertParseContext* pCxt, SVnodeModifyOpStmt* pStmt) {
X
Xiaoyu Wang 已提交
1966 1967 1968 1969 1970 1971
  int32_t code = parseInsertTableClauseBottom(pCxt, pStmt);
  if (TSDB_CODE_SUCCESS == code) {
    code = parseInsertBody(pCxt, pStmt);
  }
  return code;
}
1972

X
Xiaoyu Wang 已提交
1973
static int32_t parseInsertSqlImpl(SInsertParseContext* pCxt, SVnodeModifyOpStmt* pStmt) {
X
Xiaoyu Wang 已提交
1974 1975 1976
  if (pStmt->pSql == pCxt->pComCxt->pSql || NULL != pCxt->pComCxt->pStmtCb) {
    return parseInsertSqlFromStart(pCxt, pStmt);
  }
1977

X
Xiaoyu Wang 已提交
1978 1979 1980
  if (pStmt->fileProcessing) {
    return parseInsertSqlFromCsv(pCxt, pStmt);
  }
1981

X
Xiaoyu Wang 已提交
1982 1983
  return parseInsertSqlFromTable(pCxt, pStmt);
}
1984

X
Xiaoyu Wang 已提交
1985 1986 1987 1988 1989
static int32_t buildInsertTableReq(SName* pName, SArray** pTables) {
  *pTables = taosArrayInit(1, sizeof(SName));
  if (NULL == *pTables) {
    return TSDB_CODE_OUT_OF_MEMORY;
  }
1990

X
Xiaoyu Wang 已提交
1991 1992 1993
  taosArrayPush(*pTables, pName);
  return TSDB_CODE_SUCCESS;
}
1994

X
Xiaoyu Wang 已提交
1995 1996 1997 1998 1999
static int32_t buildInsertDbReq(SName* pName, SArray** pDbs) {
  if (NULL == *pDbs) {
    *pDbs = taosArrayInit(1, sizeof(STablesReq));
    if (NULL == *pDbs) {
      return TSDB_CODE_OUT_OF_MEMORY;
2000
    }
X
Xiaoyu Wang 已提交
2001
  }
2002

X
Xiaoyu Wang 已提交
2003 2004 2005 2006
  STablesReq req = {0};
  tNameGetFullDbName(pName, req.dbFName);
  buildInsertTableReq(pName, &req.pTables);
  taosArrayPush(*pDbs, &req);
2007

X
Xiaoyu Wang 已提交
2008 2009
  return TSDB_CODE_SUCCESS;
}
2010

X
Xiaoyu Wang 已提交
2011 2012 2013 2014 2015
static int32_t buildInsertUserAuthReq(const char* pUser, SName* pName, SArray** pUserAuth) {
  *pUserAuth = taosArrayInit(1, sizeof(SUserAuthInfo));
  if (NULL == *pUserAuth) {
    return TSDB_CODE_OUT_OF_MEMORY;
  }
X
Xiaoyu Wang 已提交
2016

X
Xiaoyu Wang 已提交
2017 2018 2019 2020
  SUserAuthInfo userAuth = {.type = AUTH_TYPE_WRITE};
  snprintf(userAuth.user, sizeof(userAuth.user), "%s", pUser);
  tNameGetFullDbName(pName, userAuth.dbFName);
  taosArrayPush(*pUserAuth, &userAuth);
2021

X
Xiaoyu Wang 已提交
2022 2023 2024
  return TSDB_CODE_SUCCESS;
}

X
Xiaoyu Wang 已提交
2025
static int32_t buildInsertCatalogReq(SInsertParseContext* pCxt, SVnodeModifyOpStmt* pStmt, SCatalogReq* pCatalogReq) {
X
Xiaoyu Wang 已提交
2026 2027 2028 2029 2030 2031
  int32_t code = buildInsertUserAuthReq(pCxt->pComCxt->pUser, &pStmt->targetTableName, &pCatalogReq->pUser);
  if (TSDB_CODE_SUCCESS == code) {
    if (0 == pStmt->usingTableName.type) {
      code = buildInsertDbReq(&pStmt->targetTableName, &pCatalogReq->pTableMeta);
    } else {
      code = buildInsertDbReq(&pStmt->usingTableName, &pCatalogReq->pTableMeta);
2032
    }
X
Xiaoyu Wang 已提交
2033 2034 2035 2036 2037 2038
  }
  if (TSDB_CODE_SUCCESS == code) {
    code = buildInsertDbReq(&pStmt->targetTableName, &pCatalogReq->pTableHash);
  }
  return code;
}
2039

X
Xiaoyu Wang 已提交
2040
static int32_t setNextStageInfo(SInsertParseContext* pCxt, SQuery* pQuery, SCatalogReq* pCatalogReq) {
X
Xiaoyu Wang 已提交
2041
  SVnodeModifyOpStmt* pStmt = (SVnodeModifyOpStmt*)pQuery->pRoot;
X
Xiaoyu Wang 已提交
2042
  if (pCxt->missCache) {
2043 2044
    parserDebug("0x%" PRIx64 " %d rows of %d tables have been inserted before cache miss", pCxt->pComCxt->requestId,
                pStmt->totalRowsNum, pStmt->totalTbNum);
X
Xiaoyu Wang 已提交
2045

X
Xiaoyu Wang 已提交
2046
    pQuery->execStage = QUERY_EXEC_STAGE_PARSE;
2047
    return buildInsertCatalogReq(pCxt, pStmt, pCatalogReq);
2048 2049
  }

2050 2051
  parserDebug("0x%" PRIx64 " %d rows of %d tables have been inserted", pCxt->pComCxt->requestId, pStmt->totalRowsNum,
              pStmt->totalTbNum);
X
Xiaoyu Wang 已提交
2052

X
Xiaoyu Wang 已提交
2053
  pQuery->execStage = QUERY_EXEC_STAGE_SCHEDULE;
2054 2055 2056
  return TSDB_CODE_SUCCESS;
}

X
Xiaoyu Wang 已提交
2057
int32_t parseInsertSql(SParseContext* pCxt, SQuery** pQuery, SCatalogReq* pCatalogReq, const SMetaData* pMetaData) {
X
Xiaoyu Wang 已提交
2058 2059 2060 2061 2062
  SInsertParseContext context = {.pComCxt = pCxt,
                                 .msg = {.buf = pCxt->pMsg, .len = pCxt->msgLen},
                                 .missCache = false,
                                 .usingDuplicateTable = false,
                                 .forceUpdate = (NULL != pCatalogReq ? pCatalogReq->forceUpdate : false)};
X
Xiaoyu Wang 已提交
2063

X
Xiaoyu Wang 已提交
2064
  int32_t code = initInsertQuery(&context, pCatalogReq, pMetaData, pQuery);
2065
  if (TSDB_CODE_SUCCESS == code) {
X
Xiaoyu Wang 已提交
2066
    code = parseInsertSqlImpl(&context, (SVnodeModifyOpStmt*)(*pQuery)->pRoot);
2067 2068
  }
  if (TSDB_CODE_SUCCESS == code) {
X
Xiaoyu Wang 已提交
2069 2070 2071 2072 2073
    code = setNextStageInfo(&context, *pQuery, pCatalogReq);
  }
  if ((TSDB_CODE_SUCCESS == code || NEED_CLIENT_HANDLE_ERROR(code)) &&
      QUERY_EXEC_STAGE_SCHEDULE == (*pQuery)->execStage) {
    code = setRefreshMate(*pQuery);
2074
  }
X
Xiaoyu Wang 已提交
2075
  insDestroyBoundColInfo(&context.tags);
2076 2077
  return code;
}