parInsertSql.c 75.0 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
  bool           needTableTagVal;
X
Xiaoyu Wang 已提交
57
} SInsertParseContext;
58

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

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

X
Xiaoyu Wang 已提交
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 89
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);
90
  }
X
Xiaoyu Wang 已提交
91 92 93
  NEXT_TOKEN(*pSql, token);
  if (TK_INTO != token.type) {
    return buildSyntaxErrMsg(pMsg, "keyword INTO is expected", token.z);
94 95 96 97
  }
  return TSDB_CODE_SUCCESS;
}

X
Xiaoyu Wang 已提交
98 99 100 101 102 103 104 105 106 107 108 109 110
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);
    }
111
  }
X
Xiaoyu Wang 已提交
112 113
  return TSDB_CODE_SUCCESS;
}
D
dapan1121 已提交
114

X
Xiaoyu Wang 已提交
115 116 117 118 119 120 121 122 123 124 125 126 127
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;
128 129
}

X
Xiaoyu Wang 已提交
130 131 132 133 134 135 136 137 138 139 140 141
// 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);
    }
142
  }
X
Xiaoyu Wang 已提交
143

X
Xiaoyu Wang 已提交
144 145 146 147 148 149 150 151 152 153 154 155 156 157
  // 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);
    }
158 159
  }

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

  return code;
165
}
D
dapan 已提交
166

X
Xiaoyu Wang 已提交
167
static int32_t parseDuplicateUsingClause(SInsertParseContext* pCxt, SVnodeModifyOpStmt* pStmt, bool* pDuplicate) {
X
Xiaoyu Wang 已提交
168 169 170 171 172 173 174 175 176 177 178
  *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 已提交
179
  }
X
Xiaoyu Wang 已提交
180

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

X
Xiaoyu Wang 已提交
184
// pStmt->pSql -> field1_name, ...)
X
Xiaoyu Wang 已提交
185 186 187 188 189
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 已提交
190
  }
D
stmt  
dapan1121 已提交
191

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

D
dapan1121 已提交
194
  int16_t lastColIdx = -1;  // last column found
X
Xiaoyu Wang 已提交
195 196 197
  int32_t code = TSDB_CODE_SUCCESS;
  while (TSDB_CODE_SUCCESS == code) {
    SToken token;
X
Xiaoyu Wang 已提交
198 199 200 201 202 203 204 205 206 207 208
    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 已提交
209 210
    int16_t t = lastColIdx + 1;
    int16_t index = insFindCol(&token, t, pBoundInfo->numOfCols, pSchema);
X
Xiaoyu Wang 已提交
211 212 213 214
    if (index < 0 && t > 0) {
      index = insFindCol(&token, 0, t, pSchema);
    }
    if (index < 0) {
X
Xiaoyu Wang 已提交
215 216 217 218 219 220 221 222
      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 已提交
223 224 225
    }
  }

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

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

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

X
Xiaoyu Wang 已提交
235 236 237 238 239
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;
240 241

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

    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 已提交
259
    if (pToken->z[k] == '(' && pToken->z[k + 1] == ')') {  // for insert NOW()/TODAY()
260 261 262 263
      *end = pTokenEnd = &pToken->z[k + 2];
      k++;
      continue;
    }
264
    if (pToken->z[k] == ',') {
265 266
      *end = pTokenEnd;
      *time = ts;
267 268 269 270 271 272 273 274 275 276 277
      return 0;
    }

    break;
  }

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

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

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

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

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

301
    *end = pTokenEnd;
302 303
  }

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

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

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

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

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

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

    case TSDB_DATA_TYPE_TINYINT: {
X
Xiaoyu Wang 已提交
347
      if (TSDB_CODE_SUCCESS != toInteger(pToken->z, pToken->n, 10, &iv)) {
X
Xiaoyu Wang 已提交
348 349 350 351 352
        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 已提交
353 354
      *(int8_t*)(&val->i64) = iv;
      break;
X
Xiaoyu Wang 已提交
355 356
    }

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

    case TSDB_DATA_TYPE_SMALLINT: {
X
Xiaoyu Wang 已提交
368
      if (TSDB_CODE_SUCCESS != toInteger(pToken->z, pToken->n, 10, &iv)) {
X
Xiaoyu Wang 已提交
369 370 371 372
        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 已提交
373 374
      *(int16_t*)(&val->i64) = iv;
      break;
X
Xiaoyu Wang 已提交
375 376 377
    }

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

    case TSDB_DATA_TYPE_INT: {
X
Xiaoyu Wang 已提交
388
      if (TSDB_CODE_SUCCESS != toInteger(pToken->z, pToken->n, 10, &iv)) {
X
Xiaoyu Wang 已提交
389 390 391 392
        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 已提交
393 394
      *(int32_t*)(&val->i64) = iv;
      break;
X
Xiaoyu Wang 已提交
395 396 397
    }

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

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

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

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

    case TSDB_DATA_TYPE_DOUBLE: {
      double dv;
438
      if (TK_NK_ILLEGAL == toDouble(pToken, &dv, &endptr)) {
X
Xiaoyu Wang 已提交
439 440 441 442 443
        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 已提交
444 445 446

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

    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 已提交
452
        return generateSyntaxErrMsg(pMsgBuf, TSDB_CODE_PAR_VALUE_TOO_LONG, pSchema->name);
X
Xiaoyu Wang 已提交
453
      }
454
      val->pData = taosStrdup(pToken->z);
X
Xiaoyu Wang 已提交
455 456
      val->nData = pToken->n;
      break;
X
Xiaoyu Wang 已提交
457 458 459
    }

    case TSDB_DATA_TYPE_NCHAR: {
X
Xiaoyu Wang 已提交
460 461 462 463 464 465 466 467 468 469 470 471 472 473
      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);
474
      }
X
Xiaoyu Wang 已提交
475 476 477
      val->pData = p;
      val->nData = output;
      break;
478
    }
X
Xiaoyu Wang 已提交
479
    case TSDB_DATA_TYPE_TIMESTAMP: {
X
Xiaoyu Wang 已提交
480
      if (parseTime(end, pToken, timePrec, &iv, pMsgBuf) != TSDB_CODE_SUCCESS) {
X
Xiaoyu Wang 已提交
481 482 483
        return buildSyntaxErrMsg(pMsgBuf, "invalid timestamp", pToken->z);
      }

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

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

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

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

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

X
Xiaoyu Wang 已提交
508
static int32_t parseTagValue(SInsertParseContext* pCxt, SVnodeModifyOpStmt* pStmt, SSchema* pTagSchema, SToken* pToken,
X
Xiaoyu Wang 已提交
509 510 511 512 513 514 515 516
                             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);
517 518
    }

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

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

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);
560
    }
X
Xiaoyu Wang 已提交
561 562 563 564 565 566 567 568 569

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

  return TSDB_CODE_SUCCESS;
}

570 571 572 573 574 575 576 577 578 579 580
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;
  }
X
Xiaoyu Wang 已提交
581 582 583 584 585

  pValue->node.resType = ((SColumnNode*)*pNode)->node.resType;
  nodesDestroyNode(*pNode);
  *pNode = (SNode*)pValue;

586 587 588
  switch (pVal->type) {
    case TSDB_DATA_TYPE_BOOL:
      pValue->datum.b = *(int8_t*)(&pVal->i64);
X
Xiaoyu Wang 已提交
589
      *(bool*)&pValue->typeData = pValue->datum.b;
590 591 592
      break;
    case TSDB_DATA_TYPE_TINYINT:
      pValue->datum.i = *(int8_t*)(&pVal->i64);
X
Xiaoyu Wang 已提交
593
      *(int8_t*)&pValue->typeData = pValue->datum.i;
594 595 596
      break;
    case TSDB_DATA_TYPE_SMALLINT:
      pValue->datum.i = *(int16_t*)(&pVal->i64);
X
Xiaoyu Wang 已提交
597
      *(int16_t*)&pValue->typeData = pValue->datum.i;
598 599 600
      break;
    case TSDB_DATA_TYPE_INT:
      pValue->datum.i = *(int32_t*)(&pVal->i64);
X
Xiaoyu Wang 已提交
601
      *(int32_t*)&pValue->typeData = pValue->datum.i;
602 603 604
      break;
    case TSDB_DATA_TYPE_BIGINT:
      pValue->datum.i = pVal->i64;
X
Xiaoyu Wang 已提交
605
      pValue->typeData = pValue->datum.i;
606 607 608
      break;
    case TSDB_DATA_TYPE_FLOAT:
      pValue->datum.d = *(float*)(&pVal->i64);
X
Xiaoyu Wang 已提交
609
      *(float*)&pValue->typeData = pValue->datum.d;
610 611 612
      break;
    case TSDB_DATA_TYPE_DOUBLE:
      pValue->datum.d = *(double*)(&pVal->i64);
X
Xiaoyu Wang 已提交
613
      *(double*)&pValue->typeData = pValue->datum.d;
614 615 616 617 618 619 620 621 622 623 624 625
      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;
X
Xiaoyu Wang 已提交
626
      pValue->typeData = pValue->datum.i;
627 628 629
      break;
    case TSDB_DATA_TYPE_UTINYINT:
      pValue->datum.i = *(uint8_t*)(&pVal->i64);
X
Xiaoyu Wang 已提交
630
      *(uint8_t*)&pValue->typeData = pValue->datum.i;
631 632 633
      break;
    case TSDB_DATA_TYPE_USMALLINT:
      pValue->datum.i = *(uint16_t*)(&pVal->i64);
X
Xiaoyu Wang 已提交
634
      *(uint16_t*)&pValue->typeData = pValue->datum.i;
635 636 637
      break;
    case TSDB_DATA_TYPE_UINT:
      pValue->datum.i = *(uint32_t*)(&pVal->i64);
X
Xiaoyu Wang 已提交
638
      *(uint32_t*)&pValue->typeData = pValue->datum.i;
639 640 641
      break;
    case TSDB_DATA_TYPE_UBIGINT:
      pValue->datum.i = *(uint64_t*)(&pVal->i64);
X
Xiaoyu Wang 已提交
642
      *(uint64_t*)&pValue->typeData = pValue->datum.i;
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 683 684 685 686
      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;
}

X
Xiaoyu Wang 已提交
687 688
static int32_t checkSubtablePrivilege(SArray* pTagVals, SArray* pTagName, SNode** pCond) {
  int32_t code = setTagVal(pTagVals, pTagName, *pCond);
689
  if (TSDB_CODE_SUCCESS == code) {
X
Xiaoyu Wang 已提交
690
    code = scalarCalculateConstants(*pCond, pCond);
691 692
  }
  if (TSDB_CODE_SUCCESS == code) {
X
Xiaoyu Wang 已提交
693
    code = checkTagCondResult(*pCond);
694
  }
X
Xiaoyu Wang 已提交
695
  NODES_DESTORY_NODE(*pCond);
696 697 698
  return code;
}

X
Xiaoyu Wang 已提交
699
// pSql -> tag1_value, ...)
X
Xiaoyu Wang 已提交
700
static int32_t parseTagsClauseImpl(SInsertParseContext* pCxt, SVnodeModifyOpStmt* pStmt) {
X
Xiaoyu Wang 已提交
701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719
  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;
720
    }
X
Xiaoyu Wang 已提交
721 722 723 724

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

X
Xiaoyu Wang 已提交
727
    SSchema* pTagSchema = &pSchema[pCxt->tags.pColIndex[i]];
X
Xiaoyu Wang 已提交
728 729 730 731
    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 已提交
732
    }
733 734
  }

X
Xiaoyu Wang 已提交
735 736 737 738
  if (TSDB_CODE_SUCCESS == code && NULL != pStmt->pTagCond) {
    code = checkSubtablePrivilege(pTagVals, pTagName, &pStmt->pTagCond);
  }

X
Xiaoyu Wang 已提交
739 740 741
  if (TSDB_CODE_SUCCESS == code && !isParseBindParam && !isJson) {
    code = tTagNew(pTagVals, 1, false, &pTag);
  }
742

X
Xiaoyu Wang 已提交
743
  if (TSDB_CODE_SUCCESS == code && !isParseBindParam) {
X
Xiaoyu Wang 已提交
744
    code = buildCreateTbReq(pStmt, pTag, pTagName);
X
Xiaoyu Wang 已提交
745 746 747 748 749 750 751
    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);
752
    }
X
Xiaoyu Wang 已提交
753 754 755 756 757 758 759 760 761
  }
  taosArrayDestroy(pTagVals);
  taosArrayDestroy(pTagName);
  tTagFree(pTag);
  return code;
}

// input pStmt->pSql:  TAGS (tag1_value, ...) [table_options] ...
// output pStmt->pSql: [table_options] ...
X
Xiaoyu Wang 已提交
762
static int32_t parseTagsClause(SInsertParseContext* pCxt, SVnodeModifyOpStmt* pStmt) {
X
Xiaoyu Wang 已提交
763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780
  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);
781 782
    }
  }
X
Xiaoyu Wang 已提交
783 784
  return code;
}
785

X
Xiaoyu Wang 已提交
786
static int32_t storeTableMeta(SInsertParseContext* pCxt, SVnodeModifyOpStmt* pStmt) {
X
Xiaoyu Wang 已提交
787
  pStmt->pTableMeta->suid = pStmt->pTableMeta->uid;
X
Xiaoyu Wang 已提交
788 789 790 791 792 793
  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;
794
  }
795

X
Xiaoyu Wang 已提交
796 797 798 799 800
  char tbFName[TSDB_TABLE_FNAME_LEN];
  tNameExtractFullName(&pStmt->targetTableName, tbFName);
  return taosHashPut(pStmt->pSubTableHashObj, tbFName, strlen(tbFName), &pBackup, POINTER_BYTES);
}

X
Xiaoyu Wang 已提交
801
static int32_t parseTableOptions(SInsertParseContext* pCxt, SVnodeModifyOpStmt* pStmt) {
X
Xiaoyu Wang 已提交
802 803 804 805 806 807 808 809 810 811
  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 已提交
812 813
      pStmt->pCreateTblReq->ttl = taosStr2Int32(token.z, NULL, 10);
      if (pStmt->pCreateTblReq->ttl < 0) {
X
Xiaoyu Wang 已提交
814 815 816 817 818 819 820 821 822 823 824 825
        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 已提交
826 827
      pStmt->pCreateTblReq->comment = strndup(pCxt->tmpTokenBuf, len);
      if (NULL == pStmt->pCreateTblReq->comment) {
X
Xiaoyu Wang 已提交
828 829
        return TSDB_CODE_OUT_OF_MEMORY;
      }
X
Xiaoyu Wang 已提交
830
      pStmt->pCreateTblReq->commentLen = len;
X
Xiaoyu Wang 已提交
831 832 833 834
    } else {
      break;
    }
  } while (1);
835 836 837
  return TSDB_CODE_SUCCESS;
}

X
Xiaoyu Wang 已提交
838 839 840 841 842 843
// input pStmt->pSql:
//   1. [(tag1_name, ...)] ...
//   2. VALUES ... | FILE ...
// output pStmt->pSql:
//   1. [(field1_name, ...)]
//   2. VALUES ... | FILE ...
X
Xiaoyu Wang 已提交
844
static int32_t parseUsingClauseBottom(SInsertParseContext* pCxt, SVnodeModifyOpStmt* pStmt) {
X
Xiaoyu Wang 已提交
845
  if (!pStmt->usingTableProcessing || pCxt->usingDuplicateTable) {
X
Xiaoyu Wang 已提交
846 847
    return TSDB_CODE_SUCCESS;
  }
wmmhello's avatar
wmmhello 已提交
848

X
Xiaoyu Wang 已提交
849 850 851 852 853 854 855 856 857 858 859
  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 已提交
860 861 862 863 864 865
static void setUserAuthInfo(SParseContext* pCxt, SName* pTbName, SUserAuthInfo* pInfo) {
  snprintf(pInfo->user, sizeof(pInfo->user), "%s", pCxt->pUser);
  memcpy(&pInfo->tbName, pTbName, sizeof(SName));
  pInfo->type = AUTH_TYPE_WRITE;
}

X
Xiaoyu Wang 已提交
866
static int32_t checkAuth(SParseContext* pCxt, SName* pTbName, bool* pMissCache, SNode** pTagCond) {
X
Xiaoyu Wang 已提交
867 868 869 870 871
  int32_t       code = TSDB_CODE_SUCCESS;
  SUserAuthInfo authInfo = {0};
  setUserAuthInfo(pCxt, pTbName, &authInfo);
  SUserAuthRes authRes = {0};
  bool         exists = true;
X
Xiaoyu Wang 已提交
872
  if (pCxt->async) {
D
dapan1121 已提交
873
    code = catalogChkAuthFromCache(pCxt->pCatalog, &authInfo, &authRes, &exists);
X
Xiaoyu Wang 已提交
874
  } else {
X
Xiaoyu Wang 已提交
875 876 877 878
    SRequestConnInfo conn = {.pTrans = pCxt->pTransporter,
                             .requestId = pCxt->requestId,
                             .requestObjRefId = pCxt->requestRid,
                             .mgmtEps = pCxt->mgmtEpSet};
D
dapan1121 已提交
879
    code = catalogChkAuth(pCxt->pCatalog, &conn, &authInfo, &authRes);
X
Xiaoyu Wang 已提交
880
  }
X
Xiaoyu Wang 已提交
881 882 883
  if (TSDB_CODE_SUCCESS == code) {
    if (!exists) {
      *pMissCache = true;
X
Xiaoyu Wang 已提交
884
    } else if (!authRes.pass) {
X
Xiaoyu Wang 已提交
885
      code = TSDB_CODE_PAR_PERMISSION_DENIED;
X
Xiaoyu Wang 已提交
886 887
    } else if (NULL != authRes.pCond) {
      *pTagCond = authRes.pCond;
X
Xiaoyu Wang 已提交
888
    }
X
Xiaoyu Wang 已提交
889 890 891 892
  }
  return code;
}

X
Xiaoyu Wang 已提交
893 894 895 896 897 898 899 900 901 902 903 904 905 906 907
static int32_t checkAuthForTable(SParseContext* pCxt, SName* pTbName, bool* pMissCache, bool* pNeedTableTagVal) {
  SNode*  pTagCond = NULL;
  int32_t code = checkAuth(pCxt, pTbName, pMissCache, &pTagCond);
  if (TSDB_CODE_SUCCESS == code) {
    *pNeedTableTagVal = ((*pMissCache) || (NULL != pTagCond));
    *pMissCache = (NULL != pTagCond);
  }
  nodesDestroyNode(pTagCond);
  return code;
}

static int32_t checkAuthForStable(SParseContext* pCxt, SName* pTbName, bool* pMissCache, SNode** pTagCond) {
  return checkAuth(pCxt, pTbName, pMissCache, pTagCond);
}

X
Xiaoyu Wang 已提交
908 909
static int32_t getTableMeta(SInsertParseContext* pCxt, SName* pTbName, bool isStb, STableMeta** pTableMeta,
                            bool* pMissCache) {
X
Xiaoyu Wang 已提交
910 911
  SParseContext* pComCxt = pCxt->pComCxt;
  int32_t        code = TSDB_CODE_SUCCESS;
X
Xiaoyu Wang 已提交
912 913
  if (pComCxt->async) {
    if (isStb) {
X
Xiaoyu Wang 已提交
914
      code = catalogGetCachedSTableMeta(pComCxt->pCatalog, pTbName, pTableMeta);
X
Xiaoyu Wang 已提交
915
    } else {
X
Xiaoyu Wang 已提交
916
      code = catalogGetCachedTableMeta(pComCxt->pCatalog, pTbName, pTableMeta);
X
Xiaoyu Wang 已提交
917 918
    }
  } else {
X
Xiaoyu Wang 已提交
919 920 921 922
    SRequestConnInfo conn = {.pTrans = pComCxt->pTransporter,
                             .requestId = pComCxt->requestId,
                             .requestObjRefId = pComCxt->requestRid,
                             .mgmtEps = pComCxt->mgmtEpSet};
X
Xiaoyu Wang 已提交
923 924 925 926
    if (isStb) {
      code = catalogGetSTableMeta(pComCxt->pCatalog, &conn, pTbName, pTableMeta);
    } else {
      code = catalogGetTableMeta(pComCxt->pCatalog, &conn, pTbName, pTableMeta);
wmmhello's avatar
wmmhello 已提交
927
    }
X
Xiaoyu Wang 已提交
928 929 930 931 932 933
  }
  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 已提交
934 935
    } else if (!isStb && TSDB_SUPER_TABLE == (*pTableMeta)->tableType) {
      code = buildInvalidOperationMsg(&pCxt->msg, "insert data into super table is not supported");
X
Xiaoyu Wang 已提交
936 937 938 939 940
    }
  }
  return code;
}

X
Xiaoyu Wang 已提交
941
static int32_t getTableVgroup(SParseContext* pCxt, SVnodeModifyOpStmt* pStmt, bool isStb, bool* pMissCache) {
X
Xiaoyu Wang 已提交
942 943 944
  int32_t     code = TSDB_CODE_SUCCESS;
  SVgroupInfo vg;
  bool        exists = true;
X
Xiaoyu Wang 已提交
945
  if (pCxt->async) {
X
Xiaoyu Wang 已提交
946
    code = catalogGetCachedTableHashVgroup(pCxt->pCatalog, &pStmt->targetTableName, &vg, &exists);
X
Xiaoyu Wang 已提交
947
  } else {
X
Xiaoyu Wang 已提交
948 949 950 951
    SRequestConnInfo conn = {.pTrans = pCxt->pTransporter,
                             .requestId = pCxt->requestId,
                             .requestObjRefId = pCxt->requestRid,
                             .mgmtEps = pCxt->mgmtEpSet};
X
Xiaoyu Wang 已提交
952 953 954 955 956 957 958 959 960 961 962 963 964
    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;
}
965

X
Xiaoyu Wang 已提交
966
static int32_t getTableMetaAndVgroupImpl(SParseContext* pCxt, SVnodeModifyOpStmt* pStmt, bool* pMissCache) {
967
  SVgroupInfo vg;
968
  int32_t     code = catalogGetCachedTableVgMeta(pCxt->pCatalog, &pStmt->targetTableName, &vg, &pStmt->pTableMeta);
969
  if (TSDB_CODE_SUCCESS == code) {
970
    if (NULL != pStmt->pTableMeta) {
971 972
      code = taosHashPut(pStmt->pVgroupsHashObj, (const char*)&vg.vgId, sizeof(vg.vgId), (char*)&vg, sizeof(vg));
    }
973
    *pMissCache = (NULL == pStmt->pTableMeta);
974 975 976 977
  }
  return code;
}

X
Xiaoyu Wang 已提交
978
static int32_t getTableMetaAndVgroup(SInsertParseContext* pCxt, SVnodeModifyOpStmt* pStmt, bool* pMissCache) {
979 980 981
  SParseContext* pComCxt = pCxt->pComCxt;
  int32_t        code = TSDB_CODE_SUCCESS;
  if (pComCxt->async) {
D
dapan1121 已提交
982
    code = getTableMetaAndVgroupImpl(pComCxt, pStmt, pMissCache);
983 984 985 986 987 988 989 990 991
  } 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;
}

992 993 994 995 996 997 998 999 1000 1001 1002 1003
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 已提交
1004
static int32_t getTargetTableSchema(SInsertParseContext* pCxt, SVnodeModifyOpStmt* pStmt) {
1005 1006 1007 1008 1009
  if (pCxt->forceUpdate) {
    pCxt->missCache = true;
    return TSDB_CODE_SUCCESS;
  }

X
Xiaoyu Wang 已提交
1010
  int32_t code = checkAuthForTable(pCxt->pComCxt, &pStmt->targetTableName, &pCxt->missCache, &pCxt->needTableTagVal);
X
Xiaoyu Wang 已提交
1011
  if (TSDB_CODE_SUCCESS == code && !pCxt->missCache) {
1012
    code = getTableMetaAndVgroup(pCxt, pStmt, &pCxt->missCache);
X
Xiaoyu Wang 已提交
1013
  }
1014
  if (TSDB_CODE_SUCCESS == code && !pCxt->pComCxt->async) {
1015
    code = collectUseDatabase(&pStmt->targetTableName, pStmt->pDbFNameHashObj);
1016 1017 1018
    if (TSDB_CODE_SUCCESS == code) {
      code = collectUseTable(&pStmt->targetTableName, pStmt->pTableNameHashObj);
    }
1019
  }
X
Xiaoyu Wang 已提交
1020 1021 1022
  return code;
}

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

X
Xiaoyu Wang 已提交
1027
static int32_t getUsingTableSchema(SInsertParseContext* pCxt, SVnodeModifyOpStmt* pStmt) {
1028 1029 1030 1031 1032
  if (pCxt->forceUpdate) {
    pCxt->missCache = true;
    return TSDB_CODE_SUCCESS;
  }

X
Xiaoyu Wang 已提交
1033
  int32_t code = checkAuthForStable(pCxt->pComCxt, &pStmt->usingTableName, &pCxt->missCache, &pStmt->pTagCond);
X
Xiaoyu Wang 已提交
1034
  if (TSDB_CODE_SUCCESS == code && !pCxt->missCache) {
X
Xiaoyu Wang 已提交
1035 1036 1037 1038 1039
    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);
  }
1040 1041 1042 1043 1044 1045
  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 已提交
1046 1047 1048
  return code;
}

X
Xiaoyu Wang 已提交
1049
static int32_t parseUsingTableNameImpl(SInsertParseContext* pCxt, SVnodeModifyOpStmt* pStmt) {
X
Xiaoyu Wang 已提交
1050 1051 1052 1053 1054 1055
  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 已提交
1056
  if (TSDB_CODE_SUCCESS == code && !pCxt->missCache) {
X
Xiaoyu Wang 已提交
1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067
    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 已提交
1068
static int32_t parseUsingTableName(SInsertParseContext* pCxt, SVnodeModifyOpStmt* pStmt) {
X
Xiaoyu Wang 已提交
1069 1070 1071 1072 1073 1074 1075
  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 已提交
1076
  pStmt->usingTableProcessing = true;
X
Xiaoyu Wang 已提交
1077 1078
  // pStmt->pSql -> stb_name [(tag1_name, ...)
  pStmt->pSql += index;
X
Xiaoyu Wang 已提交
1079 1080
  int32_t code = parseDuplicateUsingClause(pCxt, pStmt, &pCxt->usingDuplicateTable);
  if (TSDB_CODE_SUCCESS == code && !pCxt->usingDuplicateTable) {
X
Xiaoyu Wang 已提交
1081 1082 1083 1084 1085
    return parseUsingTableNameImpl(pCxt, pStmt);
  }
  return code;
}

X
Xiaoyu Wang 已提交
1086
static int32_t preParseTargetTableName(SInsertParseContext* pCxt, SVnodeModifyOpStmt* pStmt, SToken* pTbName) {
X
Xiaoyu Wang 已提交
1087 1088 1089 1090 1091 1092 1093 1094 1095 1096
  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 已提交
1097
static int32_t preParseBoundColumnsClause(SInsertParseContext* pCxt, SVnodeModifyOpStmt* pStmt) {
X
Xiaoyu Wang 已提交
1098 1099 1100 1101
  SToken  token;
  int32_t index = 0;
  NEXT_TOKEN_KEEP_SQL(pStmt->pSql, token, index);
  if (TK_NK_LP != token.type) {
1102 1103 1104
    return TSDB_CODE_SUCCESS;
  }

X
Xiaoyu Wang 已提交
1105 1106 1107 1108 1109 1110
  // pStmt->pSql -> field1_name, ...)
  pStmt->pSql += index;
  pStmt->pBoundCols = pStmt->pSql;
  return skipParentheses(pCxt, &pStmt->pSql);
}

X
Xiaoyu Wang 已提交
1111
static int32_t getTableDataCxt(SInsertParseContext* pCxt, SVnodeModifyOpStmt* pStmt, STableDataCxt** pTableCxt) {
X
Xiaoyu Wang 已提交
1112
  if (pCxt->pComCxt->async) {
X
Xiaoyu Wang 已提交
1113 1114
    return insGetTableDataCxt(pStmt->pTableBlockHashObj, &pStmt->pTableMeta->uid, sizeof(pStmt->pTableMeta->uid),
                              pStmt->pTableMeta, &pStmt->pCreateTblReq, pTableCxt, false);
X
Xiaoyu Wang 已提交
1115
  }
X
Xiaoyu Wang 已提交
1116

X
Xiaoyu Wang 已提交
1117 1118
  char tbFName[TSDB_TABLE_FNAME_LEN];
  tNameExtractFullName(&pStmt->targetTableName, tbFName);
D
dapan1121 已提交
1119 1120 1121
  if (pStmt->usingTableProcessing) {
    pStmt->pTableMeta->uid = 0;
  }
X
Xiaoyu Wang 已提交
1122
  return insGetTableDataCxt(pStmt->pTableBlockHashObj, tbFName, strlen(tbFName), pStmt->pTableMeta,
D
dapan1121 已提交
1123
                            &pStmt->pCreateTblReq, pTableCxt, NULL != pCxt->pComCxt->pStmtCb);
X
Xiaoyu Wang 已提交
1124 1125
}

X
Xiaoyu Wang 已提交
1126
static int32_t parseBoundColumnsClause(SInsertParseContext* pCxt, SVnodeModifyOpStmt* pStmt, STableDataCxt* pTableCxt) {
X
Xiaoyu Wang 已提交
1127 1128 1129 1130 1131 1132 1133 1134 1135
  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 已提交
1136 1137
    return parseBoundColumns(pCxt, &pStmt->pSql, false, getTableColumnSchema(pStmt->pTableMeta),
                             &pTableCxt->boundColsInfo);
X
Xiaoyu Wang 已提交
1138 1139 1140
  }

  if (NULL != pStmt->pBoundCols) {
X
Xiaoyu Wang 已提交
1141 1142
    return parseBoundColumns(pCxt, &pStmt->pBoundCols, false, getTableColumnSchema(pStmt->pTableMeta),
                             &pTableCxt->boundColsInfo);
X
Xiaoyu Wang 已提交
1143 1144 1145 1146 1147
  }

  return TSDB_CODE_SUCCESS;
}

D
dapan1121 已提交
1148 1149 1150 1151 1152 1153
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 已提交
1154
    SSchema*  pSchema = &pTableCxt->pMeta->schema[pTableCxt->boundColsInfo.pColIndex[i]];
D
dapan1121 已提交
1155 1156 1157 1158 1159 1160 1161 1162 1163 1164
    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 已提交
1165 1166 1167 1168
// input pStmt->pSql:
//   1. [(tag1_name, ...)] ...
//   2. VALUES ... | FILE ...
// output pStmt->pSql: VALUES ... | FILE ...
X
Xiaoyu Wang 已提交
1169
static int32_t parseSchemaClauseBottom(SInsertParseContext* pCxt, SVnodeModifyOpStmt* pStmt,
X
Xiaoyu Wang 已提交
1170
                                       STableDataCxt** pTableCxt) {
X
Xiaoyu Wang 已提交
1171 1172
  int32_t code = parseUsingClauseBottom(pCxt, pStmt);
  if (TSDB_CODE_SUCCESS == code) {
X
Xiaoyu Wang 已提交
1173
    code = getTableDataCxt(pCxt, pStmt, pTableCxt);
X
Xiaoyu Wang 已提交
1174 1175
  }
  if (TSDB_CODE_SUCCESS == code) {
X
Xiaoyu Wang 已提交
1176
    code = parseBoundColumnsClause(pCxt, pStmt, *pTableCxt);
X
Xiaoyu Wang 已提交
1177
  }
D
dapan1121 已提交
1178 1179 1180
  if (TSDB_CODE_SUCCESS == code) {
    code = initTableColSubmitData(*pTableCxt);
  }
X
Xiaoyu Wang 已提交
1181 1182 1183 1184 1185 1186 1187
  return code;
}

// input pStmt->pSql: [(field1_name, ...)] [ USING ... ] VALUES ... | FILE ...
// output pStmt->pSql:
//   1. [(tag1_name, ...)] ...
//   2. VALUES ... | FILE ...
X
Xiaoyu Wang 已提交
1188
static int32_t parseSchemaClauseTop(SInsertParseContext* pCxt, SVnodeModifyOpStmt* pStmt, SToken* pTbName) {
X
Xiaoyu Wang 已提交
1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201
  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 已提交
1202
                                   int16_t timePrec, SColVal* pVal) {
wmmhello's avatar
wmmhello 已提交
1203 1204 1205 1206
  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 已提交
1207
          pVal->value.val = TRUE_VALUE;
wmmhello's avatar
wmmhello 已提交
1208
        } else if (strncmp(pToken->z, "false", pToken->n) == 0) {
X
Xiaoyu Wang 已提交
1209
          pVal->value.val = FALSE_VALUE;
wmmhello's avatar
wmmhello 已提交
1210
        } else {
X
Xiaoyu Wang 已提交
1211
          return buildSyntaxErrMsg(&pCxt->msg, "invalid bool data", pToken->z);
wmmhello's avatar
wmmhello 已提交
1212 1213
        }
      } else if (pToken->type == TK_NK_INTEGER) {
X
Xiaoyu Wang 已提交
1214
        pVal->value.val = ((taosStr2Int64(pToken->z, NULL, 10) == 0) ? FALSE_VALUE : TRUE_VALUE);
wmmhello's avatar
wmmhello 已提交
1215
      } else if (pToken->type == TK_NK_FLOAT) {
X
Xiaoyu Wang 已提交
1216
        pVal->value.val = ((taosStr2Double(pToken->z, NULL) == 0) ? FALSE_VALUE : TRUE_VALUE);
wmmhello's avatar
wmmhello 已提交
1217
      } else {
X
Xiaoyu Wang 已提交
1218
        return buildSyntaxErrMsg(&pCxt->msg, "invalid bool data", pToken->z);
D
dapan1121 已提交
1219
      }
X
Xiaoyu Wang 已提交
1220
      break;
wmmhello's avatar
wmmhello 已提交
1221 1222
    }
    case TSDB_DATA_TYPE_TINYINT: {
X
Xiaoyu Wang 已提交
1223
      if (TSDB_CODE_SUCCESS != toInteger(pToken->z, pToken->n, 10, &pVal->value.val)) {
X
Xiaoyu Wang 已提交
1224
        return buildSyntaxErrMsg(&pCxt->msg, "invalid tinyint data", pToken->z);
X
Xiaoyu Wang 已提交
1225
      } else if (!IS_VALID_TINYINT(pVal->value.val)) {
X
Xiaoyu Wang 已提交
1226
        return buildSyntaxErrMsg(&pCxt->msg, "tinyint data overflow", pToken->z);
D
dapan1121 已提交
1227
      }
X
Xiaoyu Wang 已提交
1228
      break;
1229
    }
wmmhello's avatar
wmmhello 已提交
1230
    case TSDB_DATA_TYPE_UTINYINT: {
X
Xiaoyu Wang 已提交
1231
      if (TSDB_CODE_SUCCESS != toUInteger(pToken->z, pToken->n, 10, &pVal->value.val)) {
X
Xiaoyu Wang 已提交
1232
        return buildSyntaxErrMsg(&pCxt->msg, "invalid unsigned tinyint data", pToken->z);
X
Xiaoyu Wang 已提交
1233
      } else if (pVal->value.val > UINT8_MAX) {
X
Xiaoyu Wang 已提交
1234
        return buildSyntaxErrMsg(&pCxt->msg, "unsigned tinyint data overflow", pToken->z);
wmmhello's avatar
wmmhello 已提交
1235
      }
X
Xiaoyu Wang 已提交
1236
      break;
wmmhello's avatar
wmmhello 已提交
1237 1238
    }
    case TSDB_DATA_TYPE_SMALLINT: {
X
Xiaoyu Wang 已提交
1239
      if (TSDB_CODE_SUCCESS != toInteger(pToken->z, pToken->n, 10, &pVal->value.val)) {
X
Xiaoyu Wang 已提交
1240
        return buildSyntaxErrMsg(&pCxt->msg, "invalid smallint data", pToken->z);
X
Xiaoyu Wang 已提交
1241
      } else if (!IS_VALID_SMALLINT(pVal->value.val)) {
X
Xiaoyu Wang 已提交
1242
        return buildSyntaxErrMsg(&pCxt->msg, "smallint data overflow", pToken->z);
wmmhello's avatar
wmmhello 已提交
1243
      }
X
Xiaoyu Wang 已提交
1244
      break;
wmmhello's avatar
wmmhello 已提交
1245 1246
    }
    case TSDB_DATA_TYPE_USMALLINT: {
X
Xiaoyu Wang 已提交
1247
      if (TSDB_CODE_SUCCESS != toUInteger(pToken->z, pToken->n, 10, &pVal->value.val)) {
X
Xiaoyu Wang 已提交
1248
        return buildSyntaxErrMsg(&pCxt->msg, "invalid unsigned smallint data", pToken->z);
X
Xiaoyu Wang 已提交
1249
      } else if (pVal->value.val > UINT16_MAX) {
X
Xiaoyu Wang 已提交
1250
        return buildSyntaxErrMsg(&pCxt->msg, "unsigned smallint data overflow", pToken->z);
wmmhello's avatar
wmmhello 已提交
1251
      }
X
Xiaoyu Wang 已提交
1252
      break;
wmmhello's avatar
wmmhello 已提交
1253 1254
    }
    case TSDB_DATA_TYPE_INT: {
X
Xiaoyu Wang 已提交
1255
      if (TSDB_CODE_SUCCESS != toInteger(pToken->z, pToken->n, 10, &pVal->value.val)) {
X
Xiaoyu Wang 已提交
1256
        return buildSyntaxErrMsg(&pCxt->msg, "invalid int data", pToken->z);
X
Xiaoyu Wang 已提交
1257
      } else if (!IS_VALID_INT(pVal->value.val)) {
X
Xiaoyu Wang 已提交
1258
        return buildSyntaxErrMsg(&pCxt->msg, "int data overflow", pToken->z);
wmmhello's avatar
wmmhello 已提交
1259
      }
X
Xiaoyu Wang 已提交
1260
      break;
wmmhello's avatar
wmmhello 已提交
1261 1262
    }
    case TSDB_DATA_TYPE_UINT: {
X
Xiaoyu Wang 已提交
1263
      if (TSDB_CODE_SUCCESS != toUInteger(pToken->z, pToken->n, 10, &pVal->value.val)) {
X
Xiaoyu Wang 已提交
1264
        return buildSyntaxErrMsg(&pCxt->msg, "invalid unsigned int data", pToken->z);
X
Xiaoyu Wang 已提交
1265
      } else if (pVal->value.val > UINT32_MAX) {
X
Xiaoyu Wang 已提交
1266
        return buildSyntaxErrMsg(&pCxt->msg, "unsigned int data overflow", pToken->z);
wmmhello's avatar
wmmhello 已提交
1267
      }
X
Xiaoyu Wang 已提交
1268
      break;
wmmhello's avatar
wmmhello 已提交
1269 1270
    }
    case TSDB_DATA_TYPE_BIGINT: {
X
Xiaoyu Wang 已提交
1271
      if (TSDB_CODE_SUCCESS != toInteger(pToken->z, pToken->n, 10, &pVal->value.val)) {
X
Xiaoyu Wang 已提交
1272
        return buildSyntaxErrMsg(&pCxt->msg, "invalid bigint data", pToken->z);
wmmhello's avatar
wmmhello 已提交
1273
      }
X
Xiaoyu Wang 已提交
1274
      break;
wmmhello's avatar
wmmhello 已提交
1275 1276
    }
    case TSDB_DATA_TYPE_UBIGINT: {
X
Xiaoyu Wang 已提交
1277
      if (TSDB_CODE_SUCCESS != toUInteger(pToken->z, pToken->n, 10, &pVal->value.val)) {
X
Xiaoyu Wang 已提交
1278
        return buildSyntaxErrMsg(&pCxt->msg, "invalid unsigned bigint data", pToken->z);
wmmhello's avatar
wmmhello 已提交
1279
      }
X
Xiaoyu Wang 已提交
1280
      break;
wmmhello's avatar
wmmhello 已提交
1281 1282
    }
    case TSDB_DATA_TYPE_FLOAT: {
X
Xiaoyu Wang 已提交
1283
      char*  endptr = NULL;
wmmhello's avatar
wmmhello 已提交
1284 1285
      double dv;
      if (TK_NK_ILLEGAL == toDouble(pToken, &dv, &endptr)) {
X
Xiaoyu Wang 已提交
1286
        return buildSyntaxErrMsg(&pCxt->msg, "illegal float data", pToken->z);
wmmhello's avatar
wmmhello 已提交
1287 1288 1289
      }
      if (((dv == HUGE_VAL || dv == -HUGE_VAL) && errno == ERANGE) || dv > FLT_MAX || dv < -FLT_MAX || isinf(dv) ||
          isnan(dv)) {
X
Xiaoyu Wang 已提交
1290
        return buildSyntaxErrMsg(&pCxt->msg, "illegal float data", pToken->z);
wmmhello's avatar
wmmhello 已提交
1291
      }
X
Xiaoyu Wang 已提交
1292 1293
      float f = dv;
      memcpy(&pVal->value.val, &f, sizeof(f));
X
Xiaoyu Wang 已提交
1294
      break;
wmmhello's avatar
wmmhello 已提交
1295 1296
    }
    case TSDB_DATA_TYPE_DOUBLE: {
X
Xiaoyu Wang 已提交
1297
      char*  endptr = NULL;
wmmhello's avatar
wmmhello 已提交
1298 1299
      double dv;
      if (TK_NK_ILLEGAL == toDouble(pToken, &dv, &endptr)) {
X
Xiaoyu Wang 已提交
1300
        return buildSyntaxErrMsg(&pCxt->msg, "illegal double data", pToken->z);
wmmhello's avatar
wmmhello 已提交
1301 1302
      }
      if (((dv == HUGE_VAL || dv == -HUGE_VAL) && errno == ERANGE) || isinf(dv) || isnan(dv)) {
X
Xiaoyu Wang 已提交
1303
        return buildSyntaxErrMsg(&pCxt->msg, "illegal double data", pToken->z);
wmmhello's avatar
wmmhello 已提交
1304
      }
X
Xiaoyu Wang 已提交
1305 1306
      pVal->value.val = *(int64_t*)&dv;
      break;
wmmhello's avatar
wmmhello 已提交
1307 1308 1309 1310
    }
    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 已提交
1311
        return generateSyntaxErrMsg(&pCxt->msg, TSDB_CODE_PAR_VALUE_TOO_LONG, pSchema->name);
D
stmt  
dapan1121 已提交
1312
      }
X
Xiaoyu Wang 已提交
1313 1314 1315 1316 1317
      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 已提交
1318 1319
      pVal->value.nData = pToken->n;
      break;
X
Xiaoyu Wang 已提交
1320
    }
X
Xiaoyu Wang 已提交
1321
    case TSDB_DATA_TYPE_NCHAR: {
X
Xiaoyu Wang 已提交
1322 1323 1324 1325 1326 1327 1328
      // 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)) {
1329
        taosMemoryFree(pUcs4);
X
Xiaoyu Wang 已提交
1330 1331 1332 1333 1334 1335 1336 1337 1338 1339
        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;
1340
    }
X
Xiaoyu Wang 已提交
1341 1342 1343
    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);
1344
      }
X
Xiaoyu Wang 已提交
1345 1346 1347 1348 1349
      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 已提交
1350 1351
      pVal->value.nData = pToken->n;
      break;
1352
    }
X
Xiaoyu Wang 已提交
1353
    case TSDB_DATA_TYPE_TIMESTAMP: {
X
Xiaoyu Wang 已提交
1354
      if (parseTime(pSql, pToken, timePrec, &pVal->value.val, &pCxt->msg) != TSDB_CODE_SUCCESS) {
X
Xiaoyu Wang 已提交
1355 1356
        return buildSyntaxErrMsg(&pCxt->msg, "invalid timestamp", pToken->z);
      }
X
Xiaoyu Wang 已提交
1357
      break;
X
Xiaoyu Wang 已提交
1358
    }
X
Xiaoyu Wang 已提交
1359 1360
    default:
      return TSDB_CODE_FAILED;
X
Xiaoyu Wang 已提交
1361
  }
1362

X
Xiaoyu Wang 已提交
1363
  pVal->flag = CV_FLAG_VALUE;
X
Xiaoyu Wang 已提交
1364
  return TSDB_CODE_SUCCESS;
X
Xiaoyu Wang 已提交
1365
}
D
dapan 已提交
1366

X
Xiaoyu Wang 已提交
1367
static int32_t parseValueToken(SInsertParseContext* pCxt, const char** pSql, SToken* pToken, SSchema* pSchema,
X
Xiaoyu Wang 已提交
1368
                               int16_t timePrec, SColVal* pVal) {
X
Xiaoyu Wang 已提交
1369 1370 1371 1372 1373
  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 已提交
1374 1375
    pVal->flag = CV_FLAG_NULL;
    return TSDB_CODE_SUCCESS;
1376 1377
  }

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

X
Xiaoyu Wang 已提交
1382
  if (TSDB_CODE_SUCCESS == code) {
X
Xiaoyu Wang 已提交
1383
    code = parseValueTokenImpl(pCxt, pSql, pToken, pSchema, timePrec, pVal);
X
Xiaoyu Wang 已提交
1384
  }
1385

X
Xiaoyu Wang 已提交
1386
  return code;
1387 1388
}

X
Xiaoyu Wang 已提交
1389 1390 1391 1392
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 已提交
1393
    if (IS_VAR_DATA_TYPE(pCol->type)) {
X
Xiaoyu Wang 已提交
1394 1395 1396 1397 1398
      taosMemoryFreeClear(pCol->value.pData);
    }
  }
}

X
Xiaoyu Wang 已提交
1399
static int parseOneRow(SInsertParseContext* pCxt, const char** pSql, STableDataCxt* pTableCxt, bool* pGotRow,
X
Xiaoyu Wang 已提交
1400
                       SToken* pToken) {
X
Xiaoyu Wang 已提交
1401 1402 1403 1404 1405
  SBoundColInfo* pCols = &pTableCxt->boundColsInfo;
  bool           isParseBindParam = false;
  SSchema*       pSchemas = getTableColumnSchema(pTableCxt->pMeta);

  int32_t code = TSDB_CODE_SUCCESS;
1406
  // 1. set the parsed value from sql string
X
Xiaoyu Wang 已提交
1407
  for (int i = 0; i < pCols->numOfBound && TSDB_CODE_SUCCESS == code; ++i) {
X
Xiaoyu Wang 已提交
1408 1409 1410 1411 1412
    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 已提交
1413
      break;
X
Xiaoyu Wang 已提交
1414
    }
D
stmt  
dapan1121 已提交
1415

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

X
Xiaoyu Wang 已提交
1419
    if (pToken->type == TK_NK_QUESTION) {
D
stmt  
dapan1121 已提交
1420
      isParseBindParam = true;
X
Xiaoyu Wang 已提交
1421 1422
      if (NULL == pCxt->pComCxt->pStmtCb) {
        code = buildSyntaxErrMsg(&pCxt->msg, "? only used in stmt", pToken->z);
X
Xiaoyu Wang 已提交
1423 1424 1425 1426 1427 1428
        break;
      }
    } else {
      if (TK_NK_RP == pToken->type) {
        code = generateSyntaxErrMsg(&pCxt->msg, TSDB_CODE_PAR_INVALID_COLUMNS_NUM);
        break;
D
stmt  
dapan1121 已提交
1429
      }
D
dapan1121 已提交
1430

X
Xiaoyu Wang 已提交
1431 1432 1433 1434
      if (isParseBindParam) {
        code = buildInvalidOperationMsg(&pCxt->msg, "no mix usage for ? and values");
        break;
      }
X
Xiaoyu Wang 已提交
1435

X
Xiaoyu Wang 已提交
1436 1437 1438
      if (TSDB_CODE_SUCCESS == code) {
        code = parseValueToken(pCxt, pSql, pToken, pSchema, getTableInfo(pTableCxt->pMeta).precision, pVal);
      }
X
Xiaoyu Wang 已提交
1439
    }
1440

X
Xiaoyu Wang 已提交
1441 1442 1443 1444
    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 已提交
1445 1446
      }
    }
1447 1448
  }

D
dapan1121 已提交
1449
  if (TSDB_CODE_SUCCESS == code && !isParseBindParam) {
X
Xiaoyu Wang 已提交
1450
    SRow** pRow = taosArrayReserve(pTableCxt->pData->aRowP, 1);
X
Xiaoyu Wang 已提交
1451
    code = tRowBuild(pTableCxt->pValues, pTableCxt->pSchema, pRow);
X
Xiaoyu Wang 已提交
1452 1453 1454
    if (TSDB_CODE_SUCCESS == code) {
      insCheckTableDataOrder(pTableCxt, TD_ROW_KEY(*pRow));
    }
X
Xiaoyu Wang 已提交
1455
  }
1456

X
Xiaoyu Wang 已提交
1457 1458
  if (TSDB_CODE_SUCCESS == code && !isParseBindParam) {
    *pGotRow = true;
1459 1460
  }

X
Xiaoyu Wang 已提交
1461 1462
  clearColValArray(pTableCxt->pValues);

X
Xiaoyu Wang 已提交
1463
  return code;
1464 1465 1466
}

// pSql -> (field1_value, ...) [(field1_value2, ...) ...]
X
Xiaoyu Wang 已提交
1467
static int32_t parseValues(SInsertParseContext* pCxt, SVnodeModifyOpStmt* pStmt, STableDataCxt* pTableCxt,
X
Xiaoyu Wang 已提交
1468 1469
                           int32_t* pNumOfRows, SToken* pToken) {
  int32_t code = TSDB_CODE_SUCCESS;
X
Xiaoyu Wang 已提交
1470 1471 1472

  (*pNumOfRows) = 0;
  while (TSDB_CODE_SUCCESS == code) {
1473
    int32_t index = 0;
X
Xiaoyu Wang 已提交
1474 1475
    NEXT_TOKEN_KEEP_SQL(pStmt->pSql, *pToken, index);
    if (TK_NK_LP != pToken->type) {
1476 1477
      break;
    }
X
Xiaoyu Wang 已提交
1478
    pStmt->pSql += index;
1479

D
stmt  
dapan1121 已提交
1480
    bool gotRow = false;
X
Xiaoyu Wang 已提交
1481
    if (TSDB_CODE_SUCCESS == code) {
X
Xiaoyu Wang 已提交
1482
      code = parseOneRow(pCxt, &pStmt->pSql, pTableCxt, &gotRow, pToken);
D
stmt  
dapan1121 已提交
1483
    }
1484

X
Xiaoyu Wang 已提交
1485 1486 1487 1488 1489 1490 1491
    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);
      }
1492 1493
    }

X
Xiaoyu Wang 已提交
1494 1495
    if (TSDB_CODE_SUCCESS == code && gotRow) {
      (*pNumOfRows)++;
D
stmt  
dapan1121 已提交
1496
    }
1497 1498
  }

X
Xiaoyu Wang 已提交
1499 1500 1501
  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);
1502
  }
X
Xiaoyu Wang 已提交
1503
  return code;
1504 1505
}

X
Xiaoyu Wang 已提交
1506
// VALUES (field1_value, ...) [(field1_value2, ...) ...]
X
Xiaoyu Wang 已提交
1507
static int32_t parseValuesClause(SInsertParseContext* pCxt, SVnodeModifyOpStmt* pStmt, STableDataCxt* pTableCxt,
X
Xiaoyu Wang 已提交
1508
                                 SToken* pToken) {
1509
  int32_t numOfRows = 0;
X
Xiaoyu Wang 已提交
1510
  int32_t code = parseValues(pCxt, pStmt, pTableCxt, &numOfRows, pToken);
X
Xiaoyu Wang 已提交
1511 1512 1513 1514 1515 1516
  if (TSDB_CODE_SUCCESS == code) {
    pStmt->totalRowsNum += numOfRows;
    pStmt->totalTbNum += 1;
    TSDB_QUERY_SET_TYPE(pStmt->insertType, TSDB_QUERY_TYPE_INSERT);
  }
  return code;
1517 1518
}

X
Xiaoyu Wang 已提交
1519
static int32_t parseCsvFile(SInsertParseContext* pCxt, SVnodeModifyOpStmt* pStmt, STableDataCxt* pTableCxt,
X
Xiaoyu Wang 已提交
1520 1521
                            int32_t* pNumOfRows) {
  int32_t code = TSDB_CODE_SUCCESS;
X
Xiaoyu Wang 已提交
1522
  (*pNumOfRows) = 0;
X
Xiaoyu Wang 已提交
1523 1524
  char*   pLine = NULL;
  int64_t readLen = 0;
D
dapan1121 已提交
1525
  bool    firstLine = (pStmt->fileProcessing == false);
X
Xiaoyu Wang 已提交
1526
  pStmt->fileProcessing = false;
X
Xiaoyu Wang 已提交
1527
  while (TSDB_CODE_SUCCESS == code && (readLen = taosGetLineFile(pStmt->fp, &pLine)) != -1) {
X
Xiaoyu Wang 已提交
1528 1529 1530 1531 1532
    if (('\r' == pLine[readLen - 1]) || ('\n' == pLine[readLen - 1])) {
      pLine[--readLen] = '\0';
    }

    if (readLen == 0) {
D
dapan1121 已提交
1533
      firstLine = false;
X
Xiaoyu Wang 已提交
1534 1535 1536
      continue;
    }

X
Xiaoyu Wang 已提交
1537 1538 1539 1540
    bool gotRow = false;
    if (TSDB_CODE_SUCCESS == code) {
      SToken token;
      strtolower(pLine, pLine);
X
Xiaoyu Wang 已提交
1541
      const char* pRow = pLine;
1542

H
Haojun Liao 已提交
1543
      code = parseOneRow(pCxt, (const char**)&pRow, pTableCxt, &gotRow, &token);
D
dapan1121 已提交
1544 1545 1546 1547 1548
      if (code && firstLine) {
        firstLine = false;
        code = 0;
        continue;
      }
X
Xiaoyu Wang 已提交
1549
    }
X
Xiaoyu Wang 已提交
1550 1551 1552

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

X
Xiaoyu Wang 已提交
1555
    if (TSDB_CODE_SUCCESS == code && (*pNumOfRows) > tsMaxMemUsedByInsert * 1024 * 1024) {
X
Xiaoyu Wang 已提交
1556
      pStmt->fileProcessing = true;
1557 1558
      break;
    }
D
dapan1121 已提交
1559 1560

    firstLine = false;
X
Xiaoyu Wang 已提交
1561
  }
X
Xiaoyu Wang 已提交
1562
  taosMemoryFree(pLine);
X
Xiaoyu Wang 已提交
1563

X
Xiaoyu Wang 已提交
1564
  if (TSDB_CODE_SUCCESS == code && 0 == (*pNumOfRows) &&
X
Xiaoyu Wang 已提交
1565
      (!TSDB_QUERY_HAS_TYPE(pStmt->insertType, TSDB_QUERY_TYPE_STMT_INSERT)) && !pStmt->fileProcessing) {
X
Xiaoyu Wang 已提交
1566
    code = buildSyntaxErrMsg(&pCxt->msg, "no any data points", NULL);
X
Xiaoyu Wang 已提交
1567
  }
X
Xiaoyu Wang 已提交
1568
  return code;
X
Xiaoyu Wang 已提交
1569 1570
}

X
Xiaoyu Wang 已提交
1571
static int32_t parseDataFromFileImpl(SInsertParseContext* pCxt, SVnodeModifyOpStmt* pStmt, STableDataCxt* pTableCxt) {
X
Xiaoyu Wang 已提交
1572
  int32_t numOfRows = 0;
X
Xiaoyu Wang 已提交
1573
  int32_t code = parseCsvFile(pCxt, pStmt, pTableCxt, &numOfRows);
X
Xiaoyu Wang 已提交
1574 1575 1576 1577
  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 已提交
1578
    if (!pStmt->fileProcessing) {
X
Xiaoyu Wang 已提交
1579 1580 1581 1582
      taosCloseFile(&pStmt->fp);
    } else {
      parserDebug("0x%" PRIx64 " insert from csv. File is too large, do it in batches.", pCxt->pComCxt->requestId);
    }
1583
  }
X
Xiaoyu Wang 已提交
1584
  return code;
X
Xiaoyu Wang 已提交
1585 1586
}

X
Xiaoyu Wang 已提交
1587
static int32_t parseDataFromFile(SInsertParseContext* pCxt, SVnodeModifyOpStmt* pStmt, SToken* pFilePath,
X
Xiaoyu Wang 已提交
1588
                                 STableDataCxt* pTableCxt) {
1589
  char filePathStr[TSDB_FILENAME_LEN] = {0};
X
Xiaoyu Wang 已提交
1590 1591
  if (TK_NK_STRING == pFilePath->type) {
    trimString(pFilePath->z, pFilePath->n, filePathStr, sizeof(filePathStr));
1592
  } else {
X
Xiaoyu Wang 已提交
1593
    strncpy(filePathStr, pFilePath->z, pFilePath->n);
1594
  }
X
Xiaoyu Wang 已提交
1595 1596
  pStmt->fp = taosOpenFile(filePathStr, TD_FILE_READ | TD_FILE_STREAM);
  if (NULL == pStmt->fp) {
1597 1598 1599
    return TAOS_SYSTEM_ERROR(errno);
  }

X
Xiaoyu Wang 已提交
1600
  return parseDataFromFileImpl(pCxt, pStmt, pTableCxt);
1601 1602
}

X
Xiaoyu Wang 已提交
1603
static int32_t parseFileClause(SInsertParseContext* pCxt, SVnodeModifyOpStmt* pStmt, STableDataCxt* pTableCxt,
X
Xiaoyu Wang 已提交
1604
                               SToken* pToken) {
1605 1606 1607 1608
  if (tsUseAdapter) {
    return buildInvalidOperationMsg(&pCxt->msg, "proxy mode does not support csv loading");
  }

X
Xiaoyu Wang 已提交
1609 1610 1611
  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);
1612
  }
X
Xiaoyu Wang 已提交
1613
  return parseDataFromFile(pCxt, pStmt, pToken, pTableCxt);
X
Xiaoyu Wang 已提交
1614 1615
}

X
Xiaoyu Wang 已提交
1616
// VALUES (field1_value, ...) [(field1_value2, ...) ...] | FILE csv_file_path
X
Xiaoyu Wang 已提交
1617
static int32_t parseDataClause(SInsertParseContext* pCxt, SVnodeModifyOpStmt* pStmt, STableDataCxt* pTableCxt) {
X
Xiaoyu Wang 已提交
1618 1619 1620 1621
  SToken token;
  NEXT_TOKEN(pStmt->pSql, token);
  switch (token.type) {
    case TK_VALUES:
X
Xiaoyu Wang 已提交
1622
      return parseValuesClause(pCxt, pStmt, pTableCxt, &token);
X
Xiaoyu Wang 已提交
1623
    case TK_FILE:
X
Xiaoyu Wang 已提交
1624
      return parseFileClause(pCxt, pStmt, pTableCxt, &token);
X
Xiaoyu Wang 已提交
1625 1626 1627 1628
    default:
      break;
  }
  return buildSyntaxErrMsg(&pCxt->msg, "keyword VALUES or FILE is expected", token.z);
X
Xiaoyu Wang 已提交
1629 1630
}

X
Xiaoyu Wang 已提交
1631 1632 1633
// input pStmt->pSql:
//   1. [(tag1_name, ...)] ...
//   2. VALUES ... | FILE ...
X
Xiaoyu Wang 已提交
1634
static int32_t parseInsertTableClauseBottom(SInsertParseContext* pCxt, SVnodeModifyOpStmt* pStmt) {
X
Xiaoyu Wang 已提交
1635 1636
  STableDataCxt* pTableCxt = NULL;
  int32_t        code = parseSchemaClauseBottom(pCxt, pStmt, &pTableCxt);
X
Xiaoyu Wang 已提交
1637
  if (TSDB_CODE_SUCCESS == code) {
X
Xiaoyu Wang 已提交
1638
    code = parseDataClause(pCxt, pStmt, pTableCxt);
X
Xiaoyu Wang 已提交
1639 1640 1641 1642
  }
  return code;
}

X
Xiaoyu Wang 已提交
1643
static void resetEnvPreTable(SInsertParseContext* pCxt, SVnodeModifyOpStmt* pStmt) {
X
Xiaoyu Wang 已提交
1644
  insDestroyBoundColInfo(&pCxt->tags);
X
Xiaoyu Wang 已提交
1645
  taosMemoryFreeClear(pStmt->pTableMeta);
X
Xiaoyu Wang 已提交
1646 1647
  nodesDestroyNode(pStmt->pTagCond);
  taosArrayDestroy(pStmt->pTableTag);
X
Xiaoyu Wang 已提交
1648 1649
  tdDestroySVCreateTbReq(pStmt->pCreateTblReq);
  taosMemoryFreeClear(pStmt->pCreateTblReq);
X
Xiaoyu Wang 已提交
1650 1651
  pCxt->missCache = false;
  pCxt->usingDuplicateTable = false;
X
Xiaoyu Wang 已提交
1652
  pStmt->pBoundCols = NULL;
X
Xiaoyu Wang 已提交
1653 1654
  pStmt->usingTableProcessing = false;
  pStmt->fileProcessing = false;
1655
  pStmt->usingTableName.type = 0;
X
Xiaoyu Wang 已提交
1656 1657
}

X
Xiaoyu Wang 已提交
1658
// input pStmt->pSql: [(field1_name, ...)] [ USING ... ] VALUES ... | FILE ...
X
Xiaoyu Wang 已提交
1659
static int32_t parseInsertTableClause(SInsertParseContext* pCxt, SVnodeModifyOpStmt* pStmt, SToken* pTbName) {
X
Xiaoyu Wang 已提交
1660
  resetEnvPreTable(pCxt, pStmt);
X
Xiaoyu Wang 已提交
1661 1662 1663 1664 1665 1666
  int32_t code = parseSchemaClauseTop(pCxt, pStmt, pTbName);
  if (TSDB_CODE_SUCCESS == code && !pCxt->missCache) {
    code = parseInsertTableClauseBottom(pCxt, pStmt);
  }
  return code;
}
X
Xiaoyu Wang 已提交
1667

X
Xiaoyu Wang 已提交
1668
static int32_t checkTableClauseFirstToken(SInsertParseContext* pCxt, SVnodeModifyOpStmt* pStmt, SToken* pTbName,
X
Xiaoyu Wang 已提交
1669 1670 1671 1672 1673
                                          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);
1674 1675
    }

X
Xiaoyu Wang 已提交
1676 1677
    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 已提交
1678 1679
    }

X
Xiaoyu Wang 已提交
1680 1681 1682
    *pHasData = false;
    return TSDB_CODE_SUCCESS;
  }
X
Xiaoyu Wang 已提交
1683

X
Xiaoyu Wang 已提交
1684 1685 1686
  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");
  }
1687

X
Xiaoyu Wang 已提交
1688 1689 1690
  if (TK_NK_QUESTION == pTbName->type) {
    if (NULL == pCxt->pComCxt->pStmtCb) {
      return buildSyntaxErrMsg(&pCxt->msg, "? only used in stmt", pTbName->z);
X
Xiaoyu Wang 已提交
1691
    }
X
Xiaoyu Wang 已提交
1692

X
Xiaoyu Wang 已提交
1693 1694 1695 1696 1697 1698 1699
    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;
1700
    }
X
Xiaoyu Wang 已提交
1701
  }
1702

1703
  if (TK_NK_ID != pTbName->type && TK_NK_STRING != pTbName->type && TK_NK_QUESTION != pTbName->type) {
1704 1705 1706
    return buildSyntaxErrMsg(&pCxt->msg, "table_name is expected", pTbName->z);
  }

X
Xiaoyu Wang 已提交
1707 1708 1709
  *pHasData = true;
  return TSDB_CODE_SUCCESS;
}
1710

X
Xiaoyu Wang 已提交
1711
static int32_t setStmtInfo(SInsertParseContext* pCxt, SVnodeModifyOpStmt* pStmt) {
X
Xiaoyu Wang 已提交
1712
  SBoundColInfo* tags = taosMemoryMalloc(sizeof(pCxt->tags));
X
Xiaoyu Wang 已提交
1713
  if (NULL == tags) {
S
Shengliang Guan 已提交
1714
    return TSDB_CODE_OUT_OF_MEMORY;
X
Xiaoyu Wang 已提交
1715 1716
  }
  memcpy(tags, &pCxt->tags, sizeof(pCxt->tags));
1717

X
Xiaoyu Wang 已提交
1718
  SStmtCallback* pStmtCb = pCxt->pComCxt->pStmtCb;
X
Xiaoyu Wang 已提交
1719 1720 1721
  int32_t        code = (*pStmtCb->setInfoFn)(pStmtCb->pStmt, pStmt->pTableMeta, tags, &pStmt->targetTableName,
                                       pStmt->usingTableProcessing, pStmt->pVgroupsHashObj, pStmt->pTableBlockHashObj,
                                       pStmt->usingTableName.tname);
1722

X
Xiaoyu Wang 已提交
1723 1724 1725 1726 1727
  memset(&pCxt->tags, 0, sizeof(pCxt->tags));
  pStmt->pVgroupsHashObj = NULL;
  pStmt->pTableBlockHashObj = NULL;
  return code;
}
1728

X
Xiaoyu Wang 已提交
1729
static int32_t parseInsertBodyBottom(SInsertParseContext* pCxt, SVnodeModifyOpStmt* pStmt) {
X
Xiaoyu Wang 已提交
1730 1731 1732
  if (TSDB_QUERY_HAS_TYPE(pStmt->insertType, TSDB_QUERY_TYPE_STMT_INSERT)) {
    return setStmtInfo(pCxt, pStmt);
  }
D
stmt  
dapan1121 已提交
1733

X
Xiaoyu Wang 已提交
1734
  // merge according to vgId
X
Xiaoyu Wang 已提交
1735
  int32_t code = insMergeTableDataCxt(pStmt->pTableBlockHashObj, &pStmt->pVgDataBlocks);
X
Xiaoyu Wang 已提交
1736
  if (TSDB_CODE_SUCCESS == code) {
X
Xiaoyu Wang 已提交
1737
    code = insBuildVgDataBlocks(pStmt->pVgroupsHashObj, pStmt->pVgDataBlocks, &pStmt->pDataBlocks);
X
Xiaoyu Wang 已提交
1738
  }
X
Xiaoyu Wang 已提交
1739

X
Xiaoyu Wang 已提交
1740 1741
  return code;
}
1742

X
Xiaoyu Wang 已提交
1743 1744 1745 1746 1747
// tb_name
//     [USING stb_name [(tag1_name, ...)] TAGS (tag1_value, ...)]
//     [(field1_name, ...)]
//     VALUES (field1_value, ...) [(field1_value2, ...) ...] | FILE csv_file_path
// [...];
X
Xiaoyu Wang 已提交
1748
static int32_t parseInsertBody(SInsertParseContext* pCxt, SVnodeModifyOpStmt* pStmt) {
X
Xiaoyu Wang 已提交
1749 1750 1751 1752
  SToken  token;
  int32_t code = TSDB_CODE_SUCCESS;
  bool    hasData = true;
  // for each table
X
Xiaoyu Wang 已提交
1753
  while (TSDB_CODE_SUCCESS == code && hasData && !pCxt->missCache && !pStmt->fileProcessing) {
X
Xiaoyu Wang 已提交
1754 1755 1756 1757 1758
    // 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);
1759 1760
    }
  }
X
Xiaoyu Wang 已提交
1761

X
Xiaoyu Wang 已提交
1762 1763 1764 1765 1766
  if (TSDB_CODE_SUCCESS == code && !pCxt->missCache) {
    code = parseInsertBodyBottom(pCxt, pStmt);
  }
  return code;
}
D
stmt  
dapan1121 已提交
1767

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

X
Xiaoyu Wang 已提交
1770
static int32_t createVnodeModifOpStmt(SInsertParseContext* pCxt, bool reentry, SNode** pOutput) {
X
Xiaoyu Wang 已提交
1771
  SVnodeModifyOpStmt* pStmt = (SVnodeModifyOpStmt*)nodesMakeNode(QUERY_NODE_VNODE_MODIFY_STMT);
X
Xiaoyu Wang 已提交
1772 1773
  if (NULL == pStmt) {
    return TSDB_CODE_OUT_OF_MEMORY;
D
stmt  
dapan1121 已提交
1774
  }
X
Xiaoyu Wang 已提交
1775

X
Xiaoyu Wang 已提交
1776
  if (pCxt->pComCxt->pStmtCb) {
X
Xiaoyu Wang 已提交
1777
    TSDB_QUERY_SET_TYPE(pStmt->insertType, TSDB_QUERY_TYPE_STMT_INSERT);
1778
  }
X
Xiaoyu Wang 已提交
1779
  pStmt->pSql = pCxt->pComCxt->pSql;
X
Xiaoyu Wang 已提交
1780 1781
  pStmt->freeHashFunc = insDestroyTableDataCxtHashMap;
  pStmt->freeArrayFunc = insDestroyVgroupDataCxtList;
X
Xiaoyu Wang 已提交
1782

X
Xiaoyu Wang 已提交
1783 1784 1785 1786 1787
  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 已提交
1788 1789 1790
  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 已提交
1791 1792
  if ((!reentry && (NULL == pStmt->pVgroupsHashObj || NULL == pStmt->pTableBlockHashObj)) ||
      NULL == pStmt->pSubTableHashObj || NULL == pStmt->pTableNameHashObj || NULL == pStmt->pDbFNameHashObj) {
X
Xiaoyu Wang 已提交
1793 1794
    nodesDestroyNode((SNode*)pStmt);
    return TSDB_CODE_OUT_OF_MEMORY;
1795
  }
X
Xiaoyu Wang 已提交
1796 1797 1798 1799 1800

  taosHashSetFreeFp(pStmt->pSubTableHashObj, destroySubTableHashElem);

  *pOutput = (SNode*)pStmt;
  return TSDB_CODE_SUCCESS;
1801 1802
}

X
Xiaoyu Wang 已提交
1803
static int32_t createInsertQuery(SInsertParseContext* pCxt, SQuery** pOutput) {
X
Xiaoyu Wang 已提交
1804 1805 1806
  SQuery* pQuery = (SQuery*)nodesMakeNode(QUERY_NODE_QUERY);
  if (NULL == pQuery) {
    return TSDB_CODE_OUT_OF_MEMORY;
D
stmt  
dapan1121 已提交
1807
  }
X
Xiaoyu Wang 已提交
1808

X
Xiaoyu Wang 已提交
1809 1810 1811
  pQuery->execMode = QUERY_EXEC_MODE_SCHEDULE;
  pQuery->haveResultSet = false;
  pQuery->msgType = TDMT_VND_SUBMIT;
1812

X
Xiaoyu Wang 已提交
1813
  int32_t code = createVnodeModifOpStmt(pCxt, false, &pQuery->pRoot);
X
Xiaoyu Wang 已提交
1814 1815 1816 1817
  if (TSDB_CODE_SUCCESS == code) {
    *pOutput = pQuery;
  } else {
    nodesDestroyNode((SNode*)pQuery);
D
stmt  
dapan1121 已提交
1818
  }
X
Xiaoyu Wang 已提交
1819 1820
  return code;
}
D
stmt  
dapan1121 已提交
1821

X
Xiaoyu Wang 已提交
1822
static int32_t checkAuthFromMetaData(const SArray* pUsers, SNode** pTagCond) {
X
Xiaoyu Wang 已提交
1823 1824
  if (1 != taosArrayGetSize(pUsers)) {
    return TSDB_CODE_FAILED;
1825
  }
1826

X
Xiaoyu Wang 已提交
1827 1828
  SMetaRes* pRes = taosArrayGet(pUsers, 0);
  if (TSDB_CODE_SUCCESS == pRes->code) {
X
Xiaoyu Wang 已提交
1829 1830 1831 1832 1833
    SUserAuthRes* pAuth = pRes->pRes;
    if (NULL != pAuth->pCond) {
      *pTagCond = nodesCloneNode(pAuth->pCond);
    }
    return pAuth->pass ? TSDB_CODE_SUCCESS : TSDB_CODE_PAR_PERMISSION_DENIED;
X
Xiaoyu Wang 已提交
1834 1835 1836
  }
  return pRes->code;
}
X
Xiaoyu Wang 已提交
1837

X
Xiaoyu Wang 已提交
1838 1839 1840 1841
static int32_t getTableMetaFromMetaData(const SArray* pTables, STableMeta** pMeta) {
  if (1 != taosArrayGetSize(pTables)) {
    return TSDB_CODE_FAILED;
  }
X
Xiaoyu Wang 已提交
1842 1843

  taosMemoryFreeClear(*pMeta);
X
Xiaoyu Wang 已提交
1844 1845 1846 1847
  SMetaRes* pRes = taosArrayGet(pTables, 0);
  if (TSDB_CODE_SUCCESS == pRes->code) {
    *pMeta = tableMetaDup((const STableMeta*)pRes->pRes);
    if (NULL == *pMeta) {
D
dapan1121 已提交
1848 1849 1850
      return TSDB_CODE_OUT_OF_MEMORY;
    }
  }
X
Xiaoyu Wang 已提交
1851 1852
  return pRes->code;
}
1853

X
Xiaoyu Wang 已提交
1854
static int32_t getTableVgroupFromMetaData(const SArray* pTables, SVnodeModifyOpStmt* pStmt, bool isStb) {
X
Xiaoyu Wang 已提交
1855 1856
  if (1 != taosArrayGetSize(pTables)) {
    return TSDB_CODE_FAILED;
D
dapan1121 已提交
1857 1858
  }

X
Xiaoyu Wang 已提交
1859 1860 1861
  SMetaRes* pRes = taosArrayGet(pTables, 0);
  if (TSDB_CODE_SUCCESS != pRes->code) {
    return pRes->code;
1862
  }
1863

X
Xiaoyu Wang 已提交
1864 1865 1866 1867 1868 1869 1870
  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 已提交
1871

X
Xiaoyu Wang 已提交
1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902
static int32_t buildTagNameFromMeta(STableMeta* pMeta, SArray** pTagName) {
  *pTagName = taosArrayInit(pMeta->tableInfo.numOfTags, TSDB_COL_NAME_LEN);
  if (NULL == *pTagName) {
    return TSDB_CODE_OUT_OF_MEMORY;
  }
  SSchema* pSchema = getTableTagSchema(pMeta);
  for (int32_t i = 0; i < pMeta->tableInfo.numOfTags; ++i) {
    taosArrayPush(*pTagName, pSchema[i].name);
  }
  return TSDB_CODE_SUCCESS;
}

static int32_t checkSubtablePrivilegeForTable(const SArray* pTables, SVnodeModifyOpStmt* pStmt) {
  if (1 != taosArrayGetSize(pTables)) {
    return TSDB_CODE_FAILED;
  }

  SMetaRes* pRes = taosArrayGet(pTables, 0);
  if (TSDB_CODE_SUCCESS != pRes->code) {
    return pRes->code;
  }

  SArray* pTagName = NULL;
  int32_t code = buildTagNameFromMeta(pStmt->pTableMeta, &pTagName);
  if (TSDB_CODE_SUCCESS == code) {
    code = checkSubtablePrivilege((SArray*)pRes->pRes, pTagName, &pStmt->pTagCond);
  }
  taosArrayDestroy(pTagName);
  return code;
}

X
Xiaoyu Wang 已提交
1903
static int32_t getTableSchemaFromMetaData(SInsertParseContext* pCxt, const SMetaData* pMetaData,
X
Xiaoyu Wang 已提交
1904
                                          SVnodeModifyOpStmt* pStmt, bool isStb) {
X
Xiaoyu Wang 已提交
1905
  int32_t code = checkAuthFromMetaData(pMetaData->pUser, &pStmt->pTagCond);
X
Xiaoyu Wang 已提交
1906 1907
  if (TSDB_CODE_SUCCESS == code) {
    code = getTableMetaFromMetaData(pMetaData->pTableMeta, &pStmt->pTableMeta);
X
Xiaoyu Wang 已提交
1908
  }
X
Xiaoyu Wang 已提交
1909 1910 1911
  if (TSDB_CODE_SUCCESS == code && !isStb && TSDB_SUPER_TABLE == pStmt->pTableMeta->tableType) {
    code = buildInvalidOperationMsg(&pCxt->msg, "insert data into super table is not supported");
  }
1912 1913 1914
  if (TSDB_CODE_SUCCESS == code && isStb) {
    code = storeTableMeta(pCxt, pStmt);
  }
X
Xiaoyu Wang 已提交
1915 1916
  if (TSDB_CODE_SUCCESS == code) {
    code = getTableVgroupFromMetaData(pMetaData->pTableHash, pStmt, isStb);
1917
  }
X
Xiaoyu Wang 已提交
1918 1919 1920
  if (TSDB_CODE_SUCCESS == code && !isStb && NULL != pStmt->pTagCond) {
    code = checkSubtablePrivilegeForTable(pMetaData->pTableTag, pStmt);
  }
X
Xiaoyu Wang 已提交
1921
  return code;
1922
}
D
stmt  
dapan1121 已提交
1923

X
Xiaoyu Wang 已提交
1924 1925 1926 1927 1928 1929
static void destoryTablesReq(void* p) {
  STablesReq* pRes = (STablesReq*)p;
  taosArrayDestroy(pRes->pTables);
}

static void clearCatalogReq(SCatalogReq* pCatalogReq) {
X
Xiaoyu Wang 已提交
1930 1931 1932 1933
  if (NULL == pCatalogReq) {
    return;
  }

X
Xiaoyu Wang 已提交
1934 1935 1936 1937 1938 1939
  taosArrayDestroyEx(pCatalogReq->pTableMeta, destoryTablesReq);
  pCatalogReq->pTableMeta = NULL;
  taosArrayDestroyEx(pCatalogReq->pTableHash, destoryTablesReq);
  pCatalogReq->pTableHash = NULL;
  taosArrayDestroy(pCatalogReq->pUser);
  pCatalogReq->pUser = NULL;
X
Xiaoyu Wang 已提交
1940 1941
  taosArrayDestroy(pCatalogReq->pTableTag);
  pCatalogReq->pTableTag = NULL;
X
Xiaoyu Wang 已提交
1942 1943
}

X
Xiaoyu Wang 已提交
1944
static int32_t setVnodeModifOpStmt(SInsertParseContext* pCxt, SCatalogReq* pCatalogReq, const SMetaData* pMetaData,
X
Xiaoyu Wang 已提交
1945
                                   SVnodeModifyOpStmt* pStmt) {
X
Xiaoyu Wang 已提交
1946 1947
  clearCatalogReq(pCatalogReq);

X
Xiaoyu Wang 已提交
1948
  if (pStmt->usingTableProcessing) {
X
Xiaoyu Wang 已提交
1949
    return getTableSchemaFromMetaData(pCxt, pMetaData, pStmt, true);
X
Xiaoyu Wang 已提交
1950
  }
X
Xiaoyu Wang 已提交
1951
  return getTableSchemaFromMetaData(pCxt, pMetaData, pStmt, false);
X
Xiaoyu Wang 已提交
1952 1953
}

X
Xiaoyu Wang 已提交
1954
static int32_t resetVnodeModifOpStmt(SInsertParseContext* pCxt, SQuery* pQuery) {
X
Xiaoyu Wang 已提交
1955 1956 1957 1958
  nodesDestroyNode(pQuery->pRoot);

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

X
Xiaoyu Wang 已提交
1961 1962
    (*pCxt->pComCxt->pStmtCb->getExecInfoFn)(pCxt->pComCxt->pStmtCb->pStmt, &pStmt->pVgroupsHashObj,
                                             &pStmt->pTableBlockHashObj);
X
Xiaoyu Wang 已提交
1963 1964 1965 1966 1967 1968
    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);
1969
    }
X
Xiaoyu Wang 已提交
1970 1971 1972
    if (NULL == pStmt->pVgroupsHashObj || NULL == pStmt->pTableBlockHashObj) {
      code = TSDB_CODE_OUT_OF_MEMORY;
    }
1973
  }
X
Xiaoyu Wang 已提交
1974

X
Xiaoyu Wang 已提交
1975
  return code;
1976 1977
}

X
Xiaoyu Wang 已提交
1978
static int32_t initInsertQuery(SInsertParseContext* pCxt, SCatalogReq* pCatalogReq, const SMetaData* pMetaData,
X
Xiaoyu Wang 已提交
1979
                               SQuery** pQuery) {
X
Xiaoyu Wang 已提交
1980 1981 1982
  if (NULL == *pQuery) {
    return createInsertQuery(pCxt, pQuery);
  }
X
Xiaoyu Wang 已提交
1983

X
Xiaoyu Wang 已提交
1984
  if (NULL != pCxt->pComCxt->pStmtCb) {
X
Xiaoyu Wang 已提交
1985 1986 1987
    return resetVnodeModifOpStmt(pCxt, *pQuery);
  }

X
Xiaoyu Wang 已提交
1988
  SVnodeModifyOpStmt* pStmt = (SVnodeModifyOpStmt*)(*pQuery)->pRoot;
X
Xiaoyu Wang 已提交
1989 1990 1991

  if (!pStmt->fileProcessing) {
    return setVnodeModifOpStmt(pCxt, pCatalogReq, pMetaData, pStmt);
X
Xiaoyu Wang 已提交
1992 1993 1994
  }

  return TSDB_CODE_SUCCESS;
1995 1996
}

X
Xiaoyu Wang 已提交
1997
static int32_t setRefreshMate(SQuery* pQuery) {
X
Xiaoyu Wang 已提交
1998
  SVnodeModifyOpStmt* pStmt = (SVnodeModifyOpStmt*)pQuery->pRoot;
1999 2000 2001 2002 2003 2004 2005 2006 2007

  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);
    }
2008 2009
  }

2010 2011 2012 2013 2014 2015 2016 2017
  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);
    }
2018 2019 2020 2021 2022
  }

  return TSDB_CODE_SUCCESS;
}

X
Xiaoyu Wang 已提交
2023 2024 2025 2026 2027 2028
// 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 已提交
2029
static int32_t parseInsertSqlFromStart(SInsertParseContext* pCxt, SVnodeModifyOpStmt* pStmt) {
X
Xiaoyu Wang 已提交
2030 2031 2032 2033 2034
  int32_t code = skipInsertInto(&pStmt->pSql, &pCxt->msg);
  if (TSDB_CODE_SUCCESS == code) {
    code = parseInsertBody(pCxt, pStmt);
  }
  return code;
2035 2036
}

X
Xiaoyu Wang 已提交
2037
static int32_t parseInsertSqlFromCsv(SInsertParseContext* pCxt, SVnodeModifyOpStmt* pStmt) {
X
Xiaoyu Wang 已提交
2038 2039
  STableDataCxt* pTableCxt = NULL;
  int32_t        code = getTableDataCxt(pCxt, pStmt, &pTableCxt);
X
Xiaoyu Wang 已提交
2040
  if (TSDB_CODE_SUCCESS == code) {
X
Xiaoyu Wang 已提交
2041
    code = parseDataFromFileImpl(pCxt, pStmt, pTableCxt);
2042 2043
  }

X
Xiaoyu Wang 已提交
2044 2045 2046 2047 2048 2049 2050 2051 2052
  if (TSDB_CODE_SUCCESS == code) {
    if (pStmt->fileProcessing) {
      code = parseInsertBodyBottom(pCxt, pStmt);
    } else {
      code = parseInsertBody(pCxt, pStmt);
    }
  }

  return code;
X
Xiaoyu Wang 已提交
2053 2054
}

X
Xiaoyu Wang 已提交
2055
static int32_t parseInsertSqlFromTable(SInsertParseContext* pCxt, SVnodeModifyOpStmt* pStmt) {
X
Xiaoyu Wang 已提交
2056 2057 2058 2059 2060 2061
  int32_t code = parseInsertTableClauseBottom(pCxt, pStmt);
  if (TSDB_CODE_SUCCESS == code) {
    code = parseInsertBody(pCxt, pStmt);
  }
  return code;
}
2062

X
Xiaoyu Wang 已提交
2063
static int32_t parseInsertSqlImpl(SInsertParseContext* pCxt, SVnodeModifyOpStmt* pStmt) {
X
Xiaoyu Wang 已提交
2064 2065 2066
  if (pStmt->pSql == pCxt->pComCxt->pSql || NULL != pCxt->pComCxt->pStmtCb) {
    return parseInsertSqlFromStart(pCxt, pStmt);
  }
2067

X
Xiaoyu Wang 已提交
2068 2069 2070
  if (pStmt->fileProcessing) {
    return parseInsertSqlFromCsv(pCxt, pStmt);
  }
2071

X
Xiaoyu Wang 已提交
2072 2073
  return parseInsertSqlFromTable(pCxt, pStmt);
}
2074

X
Xiaoyu Wang 已提交
2075 2076 2077 2078 2079
static int32_t buildInsertTableReq(SName* pName, SArray** pTables) {
  *pTables = taosArrayInit(1, sizeof(SName));
  if (NULL == *pTables) {
    return TSDB_CODE_OUT_OF_MEMORY;
  }
2080

X
Xiaoyu Wang 已提交
2081 2082 2083
  taosArrayPush(*pTables, pName);
  return TSDB_CODE_SUCCESS;
}
2084

X
Xiaoyu Wang 已提交
2085 2086 2087 2088 2089
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;
2090
    }
X
Xiaoyu Wang 已提交
2091
  }
2092

X
Xiaoyu Wang 已提交
2093 2094 2095 2096
  STablesReq req = {0};
  tNameGetFullDbName(pName, req.dbFName);
  buildInsertTableReq(pName, &req.pTables);
  taosArrayPush(*pDbs, &req);
2097

X
Xiaoyu Wang 已提交
2098 2099
  return TSDB_CODE_SUCCESS;
}
2100

X
Xiaoyu Wang 已提交
2101 2102 2103 2104 2105
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 已提交
2106

X
Xiaoyu Wang 已提交
2107 2108
  SUserAuthInfo userAuth = {.type = AUTH_TYPE_WRITE};
  snprintf(userAuth.user, sizeof(userAuth.user), "%s", pUser);
X
Xiaoyu Wang 已提交
2109
  memcpy(&userAuth.tbName, pName, sizeof(SName));
X
Xiaoyu Wang 已提交
2110
  taosArrayPush(*pUserAuth, &userAuth);
2111

X
Xiaoyu Wang 已提交
2112 2113 2114
  return TSDB_CODE_SUCCESS;
}

X
Xiaoyu Wang 已提交
2115 2116
static int32_t buildInsertTableTagReq(SName* pName, SArray** pTables) { return buildInsertTableReq(pName, pTables); }

X
Xiaoyu Wang 已提交
2117
static int32_t buildInsertCatalogReq(SInsertParseContext* pCxt, SVnodeModifyOpStmt* pStmt, SCatalogReq* pCatalogReq) {
X
Xiaoyu Wang 已提交
2118 2119 2120 2121 2122 2123
  int32_t code = buildInsertUserAuthReq(
      pCxt->pComCxt->pUser, (0 == pStmt->usingTableName.type ? &pStmt->targetTableName : &pStmt->usingTableName),
      &pCatalogReq->pUser);
  if (TSDB_CODE_SUCCESS == code && pCxt->needTableTagVal) {
    code = buildInsertTableTagReq(&pStmt->targetTableName, &pCatalogReq->pTableTag);
  }
X
Xiaoyu Wang 已提交
2124 2125 2126 2127 2128
  if (TSDB_CODE_SUCCESS == code) {
    if (0 == pStmt->usingTableName.type) {
      code = buildInsertDbReq(&pStmt->targetTableName, &pCatalogReq->pTableMeta);
    } else {
      code = buildInsertDbReq(&pStmt->usingTableName, &pCatalogReq->pTableMeta);
2129
    }
X
Xiaoyu Wang 已提交
2130 2131 2132 2133 2134 2135
  }
  if (TSDB_CODE_SUCCESS == code) {
    code = buildInsertDbReq(&pStmt->targetTableName, &pCatalogReq->pTableHash);
  }
  return code;
}
2136

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

X
Xiaoyu Wang 已提交
2143
    pQuery->execStage = QUERY_EXEC_STAGE_PARSE;
2144
    return buildInsertCatalogReq(pCxt, pStmt, pCatalogReq);
2145 2146
  }

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

X
Xiaoyu Wang 已提交
2150
  pQuery->execStage = QUERY_EXEC_STAGE_SCHEDULE;
2151 2152 2153
  return TSDB_CODE_SUCCESS;
}

X
Xiaoyu Wang 已提交
2154
int32_t parseInsertSql(SParseContext* pCxt, SQuery** pQuery, SCatalogReq* pCatalogReq, const SMetaData* pMetaData) {
X
Xiaoyu Wang 已提交
2155 2156 2157 2158 2159
  SInsertParseContext context = {.pComCxt = pCxt,
                                 .msg = {.buf = pCxt->pMsg, .len = pCxt->msgLen},
                                 .missCache = false,
                                 .usingDuplicateTable = false,
                                 .forceUpdate = (NULL != pCatalogReq ? pCatalogReq->forceUpdate : false)};
X
Xiaoyu Wang 已提交
2160

X
Xiaoyu Wang 已提交
2161
  int32_t code = initInsertQuery(&context, pCatalogReq, pMetaData, pQuery);
2162
  if (TSDB_CODE_SUCCESS == code) {
X
Xiaoyu Wang 已提交
2163
    code = parseInsertSqlImpl(&context, (SVnodeModifyOpStmt*)(*pQuery)->pRoot);
2164 2165
  }
  if (TSDB_CODE_SUCCESS == code) {
X
Xiaoyu Wang 已提交
2166 2167 2168 2169 2170
    code = setNextStageInfo(&context, *pQuery, pCatalogReq);
  }
  if ((TSDB_CODE_SUCCESS == code || NEED_CLIENT_HANDLE_ERROR(code)) &&
      QUERY_EXEC_STAGE_SCHEDULE == (*pQuery)->execStage) {
    code = setRefreshMate(*pQuery);
2171
  }
X
Xiaoyu Wang 已提交
2172
  insDestroyBoundColInfo(&context.tags);
2173 2174
  return code;
}