Coverage Report

Created: 2026-10-18 06:28

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/tdengine/source/libs/parser/src/parInsertSql.c
Line
Count
Source
1
/*
2
 * Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
3
 *
4
 * This program is free software: you can use, redistribute, and/or modify
5
 * it under the terms of the GNU Affero General Public License, version 3
6
 * or later ("AGPL"), as published by the Free Software Foundation.
7
 *
8
 * This program is distributed in the hope that it will be useful, but WITHOUT
9
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10
 * FITNESS FOR A PARTICULAR PURPOSE.
11
 *
12
 * You should have received a copy of the GNU Affero General Public License
13
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
14
 */
15
16
#include "crypt.h"
17
#include "decimal.h"
18
#include "geosWrapper.h"
19
#include "parInsertUtil.h"
20
#include "parToken.h"
21
#include "query.h"
22
#include "scalar.h"
23
#include "tbase64.h"
24
#include "tglobal.h"
25
#include "ttime.h"
26
27
// CSV delimiter and quote character definitions
28
0
#define CSV_DEFAULT_DELIMITER ','
29
0
#define CSV_QUOTE_SINGLE      '\''
30
0
#define CSV_QUOTE_DOUBLE      '"'
31
0
#define CSV_ESCAPE_CHAR       '\\'
32
#define CSV_QUOTE_NONE        '\0'
33
34
typedef struct SCsvParser {
35
  char      delimiter;            // Field delimiter (default: ',')
36
  char      quote;                // Quote character (default: '"')
37
  char      escape;               // Escape character (default: '\')
38
  bool      allowNewlineInField;  // Allow newlines in quoted fields
39
  char*     buffer;               // Read buffer
40
  size_t    bufferSize;           // Buffer size
41
  size_t    bufferPos;            // Current position in buffer
42
  size_t    bufferLen;            // Valid data length in buffer
43
  bool      eof;                  // End of file reached
44
  TdFilePtr pFile;                // File pointer
45
  // Line buffer for reuse to avoid frequent memory allocation
46
  char*  lineBuffer;          // Reusable line buffer
47
  size_t lineBufferCapacity;  // Line buffer capacity
48
} SCsvParser;
49
50
typedef struct SInsertParseContext {
51
  SParseContext* pComCxt;
52
  SMsgBuf        msg;
53
  char           tmpTokenBuf[TSDB_MAX_BYTES_PER_ROW];
54
  SBoundColInfo  tags;  // for stmt
55
  bool           missCache;
56
  bool           usingDuplicateTable;
57
  bool           forceUpdate;
58
  bool           needTableTagVal;
59
  bool           needRequest;  // whether or not request server
60
  // bool           isStmtBind;   // whether is stmt bind
61
  uint8_t stmtTbNameFlag;
62
  SSHashObj* pParsedValues;  // <cid, SColVal> for stmt bind col
63
} SInsertParseContext;
64
65
typedef int32_t (*_row_append_fn_t)(SMsgBuf* pMsgBuf, const void* value, int32_t len, void* param);
66
static int32_t parseBoundTagsClause(SInsertParseContext* pCxt, SVnodeModifyOpStmt* pStmt);
67
static int32_t parseTagsClause(SInsertParseContext* pCxt, SVnodeModifyOpStmt* pStmt, bool autoCreate);
68
69
// CSV parser function declarations
70
static int32_t csvParserInit(SCsvParser* parser, TdFilePtr pFile);
71
static void    csvParserDestroy(SCsvParser* parser);
72
static int32_t csvParserFillBuffer(SCsvParser* parser);
73
static int32_t csvParserReadLine(SCsvParser* parser);
74
static void    destroySavedCsvParser(SVnodeModifyOpStmt* pStmt);
75
static int32_t csvParserExpandLineBuffer(SCsvParser* parser, size_t requiredLen);
76
77
static uint8_t TRUE_VALUE = (uint8_t)TSDB_TRUE;
78
static uint8_t FALSE_VALUE = (uint8_t)TSDB_FALSE;
79
80
0
static FORCE_INLINE bool isNullValue(int8_t dataType, SToken* pToken) {
81
0
  return TK_NULL == pToken->type ||
82
0
         (TK_NK_STRING == pToken->type && !IS_STR_DATA_TYPE(dataType) && IS_NULL_STR(pToken->z, pToken->n));
83
0
}
84
85
0
static FORCE_INLINE int32_t toDouble(SToken* pToken, double* value, char** endPtr) {
86
0
  SET_ERRNO(0);
87
0
  *value = taosStr2Double(pToken->z, endPtr);
88
0
89
0
  // not a valid integer number, return error
90
0
  if ((*endPtr - pToken->z) != pToken->n) {
91
0
    return TK_NK_ILLEGAL;
92
0
  }
93
0
94
0
  return pToken->type;
95
0
}
96
97
5
static int32_t skipInsertInto(const char** pSql, SMsgBuf* pMsg) {
98
5
  SToken token;
99
5
  NEXT_TOKEN(*pSql, token);
100
5
  if (TK_INSERT != token.type && TK_IMPORT != token.type) {
101
0
    return buildSyntaxErrMsg(pMsg, "keyword INSERT is expected", token.z);
102
0
  }
103
5
  NEXT_TOKEN(*pSql, token);
104
5
  if (TK_INTO != token.type) {
105
5
    return buildSyntaxErrMsg(pMsg, "keyword INTO is expected", token.z);
106
5
  }
107
0
  return TSDB_CODE_SUCCESS;
108
5
}
109
110
0
static int32_t skipParentheses(SInsertParseContext* pCxt, const char** pSql) {
111
0
  SToken  token;
112
0
  int32_t expectRightParenthesis = 1;
113
0
  while (1) {
114
0
    NEXT_TOKEN(*pSql, token);
115
0
    if (TK_NK_LP == token.type) {
116
0
      ++expectRightParenthesis;
117
0
    } else if (TK_NK_RP == token.type && 0 == --expectRightParenthesis) {
118
0
      break;
119
0
    }
120
0
    if (0 == token.n) {
121
0
      return buildSyntaxErrMsg(&pCxt->msg, ") expected", NULL);
122
0
    }
123
0
  }
124
0
  return TSDB_CODE_SUCCESS;
125
0
}
126
127
0
static int32_t skipTableOptions(SInsertParseContext* pCxt, const char** pSql) {
128
0
  do {
129
0
    int32_t index = 0;
130
0
    SToken  token;
131
0
    NEXT_TOKEN_KEEP_SQL(*pSql, token, index);
132
0
    if (TK_TTL == token.type || TK_COMMENT == token.type) {
133
0
      *pSql += index;
134
0
      NEXT_TOKEN_WITH_PREV(*pSql, token);
135
0
    } else {
136
0
      break;
137
0
    }
138
0
  } while (1);
139
0
  return TSDB_CODE_SUCCESS;
140
0
}
141
142
// pSql -> stb_name [(tag1_name, ...)] TAGS (tag1_value, ...)
143
0
static int32_t ignoreUsingClause(SInsertParseContext* pCxt, SVnodeModifyOpStmt* pStmt) {
144
0
  const char** pSql = &pStmt->pSql;
145
0
  int32_t      code = TSDB_CODE_SUCCESS;
146
0
  SToken       token;
147
0
  NEXT_TOKEN(*pSql, token);
148
149
0
  NEXT_TOKEN(*pSql, token);
150
0
  if (TK_NK_LP == token.type) {
151
0
    code = skipParentheses(pCxt, pSql);
152
0
    if (TSDB_CODE_SUCCESS == code) {
153
0
      NEXT_TOKEN(*pSql, token);
154
0
    }
155
0
  }
156
157
  // pSql -> TAGS (tag1_value, ...)
158
0
  if (TSDB_CODE_SUCCESS == code) {
159
0
    if (TK_TAGS != token.type) {
160
0
      code = buildSyntaxErrMsg(&pCxt->msg, "TAGS is expected", token.z);
161
0
    } else {
162
0
      NEXT_TOKEN(*pSql, token);
163
0
    }
164
0
  }
165
0
  if (TSDB_CODE_SUCCESS == code) {
166
0
    if (TK_NK_LP != token.type) {
167
0
      code = buildSyntaxErrMsg(&pCxt->msg, "( is expected", token.z);
168
0
    } else {
169
0
      code = skipParentheses(pCxt, pSql);
170
0
    }
171
0
  }
172
173
0
  if (TSDB_CODE_SUCCESS == code) {
174
0
    code = skipTableOptions(pCxt, pSql);
175
0
  }
176
177
0
  return code;
178
0
}
179
180
0
static int32_t ignoreUsingClauseAndCheckTagValues(SInsertParseContext* pCxt, SVnodeModifyOpStmt* pStmt) {
181
0
  const char** pSql = &pStmt->pSql;
182
0
  int32_t      code = TSDB_CODE_SUCCESS;
183
0
  code = parseBoundTagsClause(pCxt, pStmt);
184
0
  if (TSDB_CODE_SUCCESS != code) {
185
0
    return code;
186
0
  }
187
  // pSql -> TAGS (tag1_value, ...)
188
0
  code = parseTagsClause(pCxt, pStmt, true);
189
0
  if (TSDB_CODE_SUCCESS != code) {
190
0
    return code;
191
0
  }
192
193
0
  if (TSDB_CODE_SUCCESS == code) {
194
0
    code = skipTableOptions(pCxt, pSql);
195
0
  }
196
197
0
  return code;
198
0
}
199
200
0
static int32_t parseDuplicateUsingClause(SInsertParseContext* pCxt, SVnodeModifyOpStmt* pStmt, bool* pDuplicate) {
201
0
  int32_t code = TSDB_CODE_SUCCESS;
202
0
  *pDuplicate = false;
203
204
0
  char tbFName[TSDB_TABLE_FNAME_LEN];
205
0
  code = tNameExtractFullName(&pStmt->targetTableName, tbFName);
206
0
  if (TSDB_CODE_SUCCESS != code) {
207
0
    return code;
208
0
  }
209
0
  STableMeta** pMeta = taosHashGet(pStmt->pSubTableHashObj, tbFName, strlen(tbFName));
210
0
  if (NULL != pMeta) {
211
0
    *pDuplicate = true;
212
0
    pCxt->missCache = false;
213
0
    code = cloneTableMeta(*pMeta, &pStmt->pTableMeta);
214
0
    if (TSDB_CODE_SUCCESS != code) {
215
0
      return code;
216
0
    }
217
0
    return ignoreUsingClause(pCxt, pStmt);
218
0
  }
219
220
0
  return code;
221
0
}
222
223
typedef enum { BOUND_TAGS, BOUND_COLUMNS, BOUND_ALL_AND_TBNAME } EBoundColumnsType;
224
225
0
static int32_t getTbnameSchemaIndex(STableMeta* pTableMeta) {
226
0
  return pTableMeta->tableInfo.numOfTags + pTableMeta->tableInfo.numOfColumns;
227
0
}
228
229
// pStmt->pSql -> field1_name, ...)
230
static int32_t parseBoundColumns(SInsertParseContext* pCxt, SVnodeModifyOpStmt* pStmt, const char** pSql,
231
0
                                 EBoundColumnsType boundColsType, STableMeta* pTableMeta, SBoundColInfo* pBoundInfo) {
232
0
  SSchema* pSchema = NULL;
233
0
  if (boundColsType == BOUND_TAGS) {
234
0
    pSchema = getTableTagSchema(pTableMeta);
235
0
  } else if (boundColsType == BOUND_COLUMNS) {
236
0
    pSchema = getTableColumnSchema(pTableMeta);
237
0
  } else {
238
0
    pSchema = pTableMeta->schema;
239
0
    if (pBoundInfo->numOfCols != getTbnameSchemaIndex(pTableMeta) + 1) {
240
0
      parserError("%s failed, invalid columns num:%d, tbname index:%d", __func__, pBoundInfo->numOfCols, getTbnameSchemaIndex(pTableMeta));
241
0
      return TSDB_CODE_PAR_INVALID_COLUMNS_NUM;
242
0
    }
243
0
  }
244
0
  int32_t tbnameSchemaIndex = getTbnameSchemaIndex(pTableMeta);
245
246
0
  bool* pUseCols = taosMemoryCalloc(pBoundInfo->numOfCols, sizeof(bool));
247
0
  if (NULL == pUseCols) {
248
0
    return terrno;
249
0
  }
250
251
0
  pBoundInfo->numOfBound = 0;
252
0
  pBoundInfo->hasBoundCols = true;
253
254
0
  bool    hasPK = pTableMeta->tableInfo.numOfPKs;
255
0
  int16_t numOfBoundPKs = 0;
256
0
  int16_t lastColIdx = -1;  // last column found
257
0
  SArray* pPrivCols = pStmt->pPrivCols;
258
0
  int32_t lastPrivColIdx = 0, nPrivCols = taosArrayGetSize(pPrivCols);
259
0
  int32_t code = TSDB_CODE_SUCCESS;
260
0
  while (TSDB_CODE_SUCCESS == code) {
261
0
    SToken token;
262
0
    NEXT_TOKEN(*pSql, token);
263
264
0
    if (TK_NK_RP == token.type) {
265
0
      break;
266
0
    }
267
268
0
    char tmpTokenBuf[TSDB_COL_NAME_LEN + 2] = {0};  // used for deleting Escape character backstick(`)
269
0
    if (token.n >= TSDB_COL_NAME_LEN + 2) {
270
0
      taosMemoryFree(pUseCols);
271
0
      return generateSyntaxErrMsg(&pCxt->msg, TSDB_CODE_PAR_INVALID_COLUMN, token.z);
272
0
    }
273
0
    tstrncpy(tmpTokenBuf, token.z, token.n < sizeof(tmpTokenBuf) ? token.n + 1 : sizeof(tmpTokenBuf));
274
0
    token.z = tmpTokenBuf;
275
0
    token.n = strdequote(token.z);
276
277
0
    if (boundColsType == BOUND_ALL_AND_TBNAME && token.n == strlen("tbname") && (strcasecmp(token.z, "tbname") == 0)) {
278
0
      pBoundInfo->pColIndex[pBoundInfo->numOfBound] = tbnameSchemaIndex;
279
0
      pUseCols[tbnameSchemaIndex] = true;
280
0
      ++pBoundInfo->numOfBound;
281
0
      continue;
282
0
    }
283
284
0
    int16_t t = lastColIdx + 1;
285
0
    int16_t end = (boundColsType == BOUND_ALL_AND_TBNAME) ? (pBoundInfo->numOfCols - 1) : pBoundInfo->numOfCols;
286
0
    int16_t index = insFindCol(&token, t, end, pSchema);
287
0
    if (index < 0 && t > 0) {
288
0
      index = insFindCol(&token, 0, t, pSchema);
289
0
    }
290
0
    if (index < 0) {
291
0
      code = generateSyntaxErrMsg(&pCxt->msg, TSDB_CODE_PAR_INVALID_COLUMN, token.z);
292
0
    } else if (pUseCols[index]) {
293
0
      code = buildSyntaxErrMsg(&pCxt->msg, "duplicated column name", token.z);
294
0
    } else {
295
0
      lastColIdx = index;
296
0
      pUseCols[index] = true;
297
0
      pBoundInfo->pColIndex[pBoundInfo->numOfBound] = index;
298
0
      ++pBoundInfo->numOfBound;
299
0
      if (hasPK && (pSchema[index].flags & COL_IS_KEY)) ++numOfBoundPKs;
300
301
0
      if (pPrivCols) {  // check column-level privileges
302
0
        int32_t j = lastPrivColIdx;
303
0
        bool    found = false;
304
0
        for (; lastPrivColIdx < nPrivCols; ++lastPrivColIdx) {
305
0
          SColNameFlag* pColNameFlag = (SColNameFlag*)TARRAY_GET_ELEM(pPrivCols, lastPrivColIdx);
306
0
          if (pSchema[index].colId == pColNameFlag->colId) {
307
0
            found = true;
308
0
            break;
309
0
          }
310
0
        }
311
0
        if (!found) {
312
0
          for (int32_t k = 0; k < j; ++k) {
313
0
            SColNameFlag* pColNameFlag = (SColNameFlag*)TARRAY_GET_ELEM(pPrivCols, k);
314
0
            if (pSchema[index].colId == pColNameFlag->colId) {
315
0
              found = true;
316
0
              break;
317
0
            }
318
0
          }
319
0
        }
320
0
        if (!found) {
321
0
          taosMemoryFree(pUseCols);
322
0
          return generateSyntaxErrMsg(&pCxt->msg, TSDB_CODE_PAR_COL_PERMISSION_DENIED, token.z);
323
0
        }
324
0
      }
325
0
    }
326
0
  }
327
328
0
  if (TSDB_CODE_SUCCESS == code && (BOUND_TAGS != boundColsType)) {
329
0
    if (!pUseCols[0]) {
330
0
      code = buildInvalidOperationMsg(&pCxt->msg, "Primary timestamp column should not be null");
331
0
    }
332
0
    if (numOfBoundPKs != pTableMeta->tableInfo.numOfPKs) {
333
0
      code = buildInvalidOperationMsg(&pCxt->msg, "Primary key column should not be none");
334
0
    }
335
0
  }
336
0
  if (TSDB_CODE_SUCCESS == code && (BOUND_ALL_AND_TBNAME == boundColsType) && !pUseCols[tbnameSchemaIndex]) {
337
0
    code = buildInvalidOperationMsg(&pCxt->msg, "tbname column should not be null");
338
0
  }
339
0
  taosMemoryFree(pUseCols);
340
341
0
  return code;
342
0
}
343
344
static int32_t parseTimestampOrInterval(const char** end, SToken* pToken, int16_t timePrec, int64_t* ts,
345
0
                                        int64_t* interval, SMsgBuf* pMsgBuf, bool* isTs, timezone_t tz) {
346
0
  if (pToken->type == TK_NOW) {
347
0
    *isTs = true;
348
0
    *ts = taosGetTimestamp(timePrec);
349
0
  } else if (pToken->type == TK_TODAY) {
350
0
    *isTs = true;
351
0
    *ts = taosGetTimestampToday(timePrec, tz);
352
0
  } else if (pToken->type == TK_NK_INTEGER) {
353
0
    *isTs = true;
354
0
    if (TSDB_CODE_SUCCESS != toInteger(pToken->z, pToken->n, 10, ts)) {
355
0
      return buildSyntaxErrMsg(pMsgBuf, "invalid timestamp format", pToken->z);
356
0
    }
357
0
  } else if (pToken->type == TK_NK_VARIABLE) {
358
0
    char unit = 0;
359
0
    *isTs = false;
360
0
    if (parseAbsoluteDuration(pToken->z, pToken->n, interval, &unit, timePrec) != TSDB_CODE_SUCCESS) {
361
0
      return TSDB_CODE_TSC_INVALID_OPERATION;
362
0
    }
363
0
  } else {  // parse the RFC-3339/ISO-8601 timestamp format string
364
0
    *isTs = true;
365
0
    if (taosParseTime(pToken->z, ts, pToken->n, timePrec, tz) != TSDB_CODE_SUCCESS) {
366
0
      if ((pToken->n == 0) ||
367
0
          (pToken->type != TK_NK_STRING && pToken->type != TK_NK_HEX && pToken->type != TK_NK_BIN)) {
368
0
        return buildSyntaxErrMsg(pMsgBuf, "invalid timestamp format", pToken->z);
369
0
      }
370
0
      if (IS_NOW_STR(pToken->z, pToken->n)) {
371
0
        *isTs = true;
372
0
        *ts = taosGetTimestamp(timePrec);
373
0
      } else if (IS_TODAY_STR(pToken->z, pToken->n)) {
374
0
        *isTs = true;
375
0
        *ts = taosGetTimestampToday(timePrec, tz);
376
0
      } else if (TSDB_CODE_SUCCESS == toIntegerPure(pToken->z, pToken->n, 10, ts)) {
377
0
        *isTs = true;
378
0
      } else {
379
0
        return buildSyntaxErrMsg(pMsgBuf, "invalid timestamp format", pToken->z);
380
0
      }
381
0
    }
382
0
  }
383
384
0
  return TSDB_CODE_SUCCESS;
385
0
}
386
387
static int parseTime(const char** end, SToken* pToken, int16_t timePrec, int64_t* time, SMsgBuf* pMsgBuf,
388
0
                     timezone_t tz) {
389
0
  int32_t     index = 0, i = 0;
390
0
  int64_t     interval = 0, tempInterval = 0;
391
0
  int64_t     ts = 0, tempTs = 0;
392
0
  bool        firstIsTS = false, secondIsTs = false;
393
0
  const char* pTokenEnd = *end;
394
395
0
  if (TSDB_CODE_SUCCESS !=
396
0
      parseTimestampOrInterval(&pTokenEnd, pToken, timePrec, &ts, &interval, pMsgBuf, &firstIsTS, tz)) {
397
0
    return buildSyntaxErrMsg(pMsgBuf, "invalid timestamp format", pToken->z);
398
0
  }
399
400
0
  if (firstIsTS) {
401
0
    *time = ts;
402
0
  }
403
404
0
  for (int k = pToken->n; pToken->z[k] != '\0'; k++) {
405
0
    if (pToken->z[k] == ' ' || pToken->z[k] == '\t') continue;
406
0
    if (pToken->z[k] == '(') {  // for insert NOW()/TODAY()
407
0
      if (pToken->z[k + 1] == ')') {
408
0
        *end = pTokenEnd = &pToken->z[k + 2];
409
0
        ++k;
410
0
        continue;
411
0
      } else {
412
0
        char nc = pToken->z[k + 1];
413
0
        while (nc == ' ' || nc == '\t' || nc == '\n' || nc == '\r' || nc == '\f') {
414
0
          nc = pToken->z[(++k) + 1];
415
0
        }
416
0
        if (nc == ')') {
417
0
          *end = pTokenEnd = &pToken->z[k + 2];
418
0
          ++k;
419
0
          continue;
420
0
        }
421
0
      }
422
0
    }
423
0
    if (pToken->z[k] == ',') {
424
0
      *end = pTokenEnd;
425
0
      if (!firstIsTS) {
426
0
        return buildSyntaxErrMsg(pMsgBuf, "invalid timestamp format", pToken->z);
427
0
      }
428
0
      *time = ts;
429
0
      return TSDB_CODE_SUCCESS;
430
0
    }
431
0
    break;
432
0
  }
433
434
0
  while (pTokenEnd[i] != '\0') {
435
0
    if (pTokenEnd[i] == ' ' || pTokenEnd[i] == '\t') {
436
0
      i++;
437
0
      continue;
438
0
    } else if (pTokenEnd[i] == ',' || pTokenEnd[i] == ')') {
439
0
      *end = pTokenEnd + i;
440
0
      if (!firstIsTS) {
441
0
        return buildSyntaxErrMsg(pMsgBuf, "invalid timestamp format", pToken->z);
442
0
      }
443
0
      *time = ts;
444
0
      return TSDB_CODE_SUCCESS;
445
0
    } else {
446
0
      break;
447
0
    }
448
0
  }
449
0
  pTokenEnd = pTokenEnd + i;
450
451
0
  index = 0;
452
0
  SToken token = tStrGetToken(pTokenEnd, &index, false, NULL);
453
454
0
  if (token.type == TK_NK_MINUS || token.type == TK_NK_PLUS) {
455
0
    pTokenEnd += index;
456
0
    index = 0;
457
0
    SToken valueToken = tStrGetToken(pTokenEnd, &index, false, NULL);
458
0
    pTokenEnd += index;
459
0
    char tmpTokenBuf[TSDB_MAX_BYTES_PER_ROW];
460
0
    if (TK_NK_STRING == valueToken.type) {
461
0
      if (valueToken.n >= TSDB_MAX_BYTES_PER_ROW) {
462
0
        return buildSyntaxErrMsg(pMsgBuf, "invalid timestamp format", valueToken.z);
463
0
      }
464
0
      int32_t len = trimString(valueToken.z, valueToken.n, tmpTokenBuf, TSDB_MAX_BYTES_PER_ROW);
465
0
      valueToken.z = tmpTokenBuf;
466
0
      valueToken.n = len;
467
0
    }
468
469
0
    if (TSDB_CODE_SUCCESS !=
470
0
        parseTimestampOrInterval(&pTokenEnd, &valueToken, timePrec, &tempTs, &tempInterval, pMsgBuf, &secondIsTs, tz)) {
471
0
      return buildSyntaxErrMsg(pMsgBuf, "invalid timestamp format", pToken->z);
472
0
    }
473
474
0
    if (valueToken.n < 2) {
475
0
      return buildSyntaxErrMsg(pMsgBuf, "value expected in timestamp", token.z);
476
0
    }
477
478
0
    if (secondIsTs) {
479
      // not support operator between tow timestamp, such as today() + now()
480
0
      if (firstIsTS) {
481
0
        return buildSyntaxErrMsg(pMsgBuf, "invalid timestamp format", pToken->z);
482
0
      }
483
0
      ts = tempTs;
484
0
    } else {
485
      // not support operator between tow interval, such as 2h + 3s
486
0
      if (!firstIsTS) {
487
0
        return buildSyntaxErrMsg(pMsgBuf, "invalid timestamp format", pToken->z);
488
0
      }
489
0
      interval = tempInterval;
490
0
    }
491
0
    if (token.type == TK_NK_MINUS) {
492
      // not support interval - ts,such as 2h - today()
493
0
      if (secondIsTs) {
494
0
        return buildSyntaxErrMsg(pMsgBuf, "invalid timestamp format", pToken->z);
495
0
      }
496
0
      *time = ts - interval;
497
0
    } else {
498
0
      *time = ts + interval;
499
0
    }
500
501
0
    for (int k = valueToken.n; valueToken.z[k] != '\0'; k++) {
502
0
      if (valueToken.z[k] == ' ' || valueToken.z[k] == '\t') continue;
503
0
      if (valueToken.z[k] == '(' && valueToken.z[k + 1] == ')') {  // for insert NOW()/TODAY()
504
0
        *end = pTokenEnd = &valueToken.z[k + 2];
505
0
        k++;
506
0
        continue;
507
0
      }
508
0
      if (valueToken.z[k] == ',' || valueToken.z[k] == ')') {
509
0
        *end = pTokenEnd;
510
0
        return TSDB_CODE_SUCCESS;
511
0
      }
512
0
      return buildSyntaxErrMsg(pMsgBuf, "invalid timestamp format", pToken->z);
513
0
    }
514
0
  }
515
516
0
  *end = pTokenEnd;
517
0
  return TSDB_CODE_SUCCESS;
518
0
}
519
520
// need to call geosFreeBuffer(*output) later
521
0
static int parseGeometry(SToken* pToken, unsigned char** output, size_t* size) {
522
0
#ifdef USE_GEOS
523
0
  int32_t code = TSDB_CODE_FAILED;
524
525
  //[ToDo] support to parse WKB as well as WKT
526
0
  if (pToken->type == TK_NK_STRING) {
527
0
    code = initCtxGeomFromText();
528
0
    if (code != TSDB_CODE_SUCCESS) {
529
0
      return code;
530
0
    }
531
532
0
    code = doGeomFromText(pToken->z, output, size);
533
0
    if (code != TSDB_CODE_SUCCESS) {
534
0
      return code;
535
0
    }
536
0
  }
537
538
0
  return code;
539
#else
540
  TAOS_RETURN(TSDB_CODE_OPS_NOT_SUPPORT);
541
#endif
542
0
}
543
544
static int32_t parseSingleStrParam(SInsertParseContext* pCxt, const char** ppSql, SToken* pToken, SColVal* pVal,
545
0
                                   char* tokenBuf, int32_t* inputBytes, bool* final) {
546
0
  NEXT_VALID_TOKEN(*ppSql, *pToken);
547
0
  if (TK_NK_LP != pToken->type) {
548
0
    return buildSyntaxErrMsg(&pCxt->msg, "( expected", pToken->z);
549
0
  }
550
551
0
  NEXT_VALID_TOKEN(*ppSql, *pToken);
552
0
  if (TK_NULL == pToken->type) {
553
0
    NEXT_VALID_TOKEN(*ppSql, *pToken);
554
0
    if (TK_NK_RP == pToken->type) {
555
0
      pVal->flag = CV_FLAG_NULL;
556
557
0
      *final = true;
558
0
      return TSDB_CODE_SUCCESS;
559
0
    } else {
560
0
      return buildSyntaxErrMsg(&pCxt->msg, ") expected", pToken->z);
561
0
    }
562
0
  } else if (TK_NK_STRING != pToken->type) {
563
0
    return buildSyntaxErrMsg(&pCxt->msg, "string expected", pToken->z);
564
0
  }
565
566
0
  *inputBytes = trimString(pToken->z, pToken->n, tokenBuf, TSDB_MAX_BYTES_PER_ROW);
567
568
0
  NEXT_VALID_TOKEN(*ppSql, *pToken);
569
0
  if (TK_NK_RP != pToken->type) {
570
0
    return buildSyntaxErrMsg(&pCxt->msg, ") expected", pToken->z);
571
0
  }
572
573
0
  return TSDB_CODE_SUCCESS;
574
0
}
575
576
static int32_t parseBinary(SInsertParseContext* pCxt, const char** ppSql, SToken* pToken, SColVal* pVal,
577
0
                           SSchema* pSchema) {
578
0
  int32_t   code = 0;
579
0
  int32_t   bytes = pSchema->bytes;
580
0
  uint8_t** pData = &pVal->value.pData;
581
0
  uint32_t* nData = &pVal->value.nData;
582
583
0
  if (pToken->type == TK_FROM_BASE64 || pToken->type == TK_TO_BASE64 || pToken->type == TK_MD5 ||
584
0
      pToken->type == TK_SHA || pToken->type == TK_SHA1 || pToken->type == TK_SHA2 || pToken->type == TK_AES_ENCRYPT ||
585
0
      pToken->type == TK_AES_DECRYPT || pToken->type == TK_SM4_ENCRYPT || pToken->type == TK_SM4_DECRYPT) {
586
0
    char*   input = NULL;
587
0
    int32_t inputBytes = 0;
588
0
    int32_t outputBytes = 0;
589
0
    bool    final = false;
590
591
0
    char* tmpTokenBuf = taosMemoryMalloc(TSDB_MAX_BYTES_PER_ROW);
592
0
    if (NULL == tmpTokenBuf) {
593
0
      return terrno;
594
0
    }
595
596
0
    if (pToken->type == TK_FROM_BASE64) {
597
0
      code = parseSingleStrParam(pCxt, ppSql, pToken, pVal, tmpTokenBuf, &inputBytes, &final);
598
0
      if (TSDB_CODE_SUCCESS != code || final) {
599
0
        taosMemoryFree(tmpTokenBuf);
600
601
0
        return code;
602
0
      }
603
604
0
      input = tmpTokenBuf;
605
606
0
      outputBytes = tbase64_decode_len(inputBytes);
607
0
      if (outputBytes + VARSTR_HEADER_SIZE > bytes) {
608
0
        taosMemoryFree(tmpTokenBuf);
609
610
0
        return generateSyntaxErrMsg(&pCxt->msg, TSDB_CODE_PAR_VALUE_TOO_LONG, pSchema->name);
611
0
      }
612
613
0
      *pData = taosMemoryMalloc(outputBytes);
614
0
      if (NULL == *pData) {
615
0
        taosMemoryFree(tmpTokenBuf);
616
617
0
        return terrno;
618
0
      }
619
620
0
      if (TSDB_CODE_SUCCESS != tbase64_decode(*pData, (const uint8_t*)input, inputBytes, (VarDataLenT*)&outputBytes)) {
621
0
        pVal->flag = CV_FLAG_NULL;
622
623
0
        taosMemoryFree(tmpTokenBuf);
624
625
0
        return TSDB_CODE_SUCCESS;
626
0
      }
627
0
      *nData = outputBytes;
628
0
    } else if (pToken->type == TK_TO_BASE64) {
629
0
      code = parseSingleStrParam(pCxt, ppSql, pToken, pVal, tmpTokenBuf, &inputBytes, &final);
630
0
      if (TSDB_CODE_SUCCESS != code || final) {
631
0
        taosMemoryFree(tmpTokenBuf);
632
633
0
        return code;
634
0
      }
635
636
0
      input = tmpTokenBuf;
637
638
0
      outputBytes = tbase64_encode_len(inputBytes);
639
0
      if (outputBytes + VARSTR_HEADER_SIZE > bytes) {
640
0
        taosMemoryFree(tmpTokenBuf);
641
642
0
        return generateSyntaxErrMsg(&pCxt->msg, TSDB_CODE_PAR_VALUE_TOO_LONG, pSchema->name);
643
0
      }
644
645
0
      *pData = taosMemoryMalloc(outputBytes);
646
0
      if (NULL == *pData) {
647
0
        taosMemoryFree(tmpTokenBuf);
648
649
0
        return terrno;
650
0
      }
651
652
0
      tbase64_encode(*pData, input, inputBytes, outputBytes);
653
0
      *nData = outputBytes;
654
0
    } else if (pToken->type == TK_MD5) {
655
0
      code = parseSingleStrParam(pCxt, ppSql, pToken, pVal, tmpTokenBuf, &inputBytes, &final);
656
0
      if (TSDB_CODE_SUCCESS != code || final) {
657
0
        taosMemoryFree(tmpTokenBuf);
658
659
0
        return code;
660
0
      }
661
662
0
      input = tmpTokenBuf;
663
664
0
      if (MD5_OUTPUT_LEN + VARSTR_HEADER_SIZE > bytes) {
665
0
        taosMemoryFree(tmpTokenBuf);
666
667
0
        return generateSyntaxErrMsg(&pCxt->msg, TSDB_CODE_PAR_VALUE_TOO_LONG, pSchema->name);
668
0
      }
669
670
0
      int32_t bufLen = TMAX(MD5_OUTPUT_LEN + VARSTR_HEADER_SIZE + 1, inputBytes);
671
0
      *pData = taosMemoryMalloc(bufLen);
672
0
      if (NULL == *pData) {
673
0
        taosMemoryFree(tmpTokenBuf);
674
675
0
        return terrno;
676
0
      }
677
678
0
      (void)memcpy(*pData, input, inputBytes);
679
0
      int32_t len = taosCreateMD5Hash(*pData, inputBytes, bufLen);
680
0
      *nData = len;
681
0
    } else if (pToken->type == TK_SHA2) {
682
0
      NEXT_VALID_TOKEN(*ppSql, *pToken);
683
0
      if (TK_NK_LP != pToken->type) {
684
0
        taosMemoryFree(tmpTokenBuf);
685
686
0
        return buildSyntaxErrMsg(&pCxt->msg, "( expected", pToken->z);
687
0
      }
688
689
0
      NEXT_VALID_TOKEN(*ppSql, *pToken);
690
0
      if (TK_NULL == pToken->type) {
691
0
        NEXT_VALID_TOKEN(*ppSql, *pToken);
692
0
        if (TK_NK_COMMA != pToken->type) {
693
0
          taosMemoryFree(tmpTokenBuf);
694
695
0
          return buildSyntaxErrMsg(&pCxt->msg, ", expected", pToken->z);
696
0
        }
697
698
0
        NEXT_VALID_TOKEN(*ppSql, *pToken);
699
0
        if (TK_NK_INTEGER != pToken->type) {
700
0
          taosMemoryFree(tmpTokenBuf);
701
702
0
          return buildSyntaxErrMsg(&pCxt->msg, "integer [224, 256, 384, 512] expected", pToken->z);
703
0
        }
704
705
0
        NEXT_VALID_TOKEN(*ppSql, *pToken);
706
0
        if (TK_NK_RP == pToken->type) {
707
0
          pVal->flag = CV_FLAG_NULL;
708
709
0
          taosMemoryFree(tmpTokenBuf);
710
711
0
          return TSDB_CODE_SUCCESS;
712
0
        }
713
0
      } else if (TK_NK_STRING != pToken->type) {
714
0
        taosMemoryFree(tmpTokenBuf);
715
716
0
        return buildSyntaxErrMsg(&pCxt->msg, "string expected", pToken->z);
717
0
      }
718
719
0
      inputBytes = trimString(pToken->z, pToken->n, tmpTokenBuf, TSDB_MAX_BYTES_PER_ROW);
720
0
      input = tmpTokenBuf;
721
722
0
      NEXT_VALID_TOKEN(*ppSql, *pToken);
723
0
      if (TK_NK_COMMA != pToken->type) {
724
0
        taosMemoryFree(tmpTokenBuf);
725
726
0
        return buildSyntaxErrMsg(&pCxt->msg, ", expected", pToken->z);
727
0
      }
728
729
0
      int64_t digestLen = 224;
730
0
      NEXT_VALID_TOKEN(*ppSql, *pToken);
731
0
      if (TK_NK_INTEGER != pToken->type) {
732
0
        taosMemoryFree(tmpTokenBuf);
733
734
0
        return buildSyntaxErrMsg(&pCxt->msg, "integer [224, 256, 384, 512] expected", pToken->z);
735
0
      } else {
736
0
        if (TSDB_CODE_SUCCESS != toInteger(pToken->z, pToken->n, 10, &digestLen)) {
737
0
          taosMemoryFree(tmpTokenBuf);
738
739
0
          return buildSyntaxErrMsg(&pCxt->msg, "invalid integer format", pToken->z);
740
0
        }
741
742
0
        if (224 != digestLen && 256 != digestLen && 384 != digestLen && 512 != digestLen) {
743
0
          taosMemoryFree(tmpTokenBuf);
744
745
0
          return buildSyntaxErrMsg(&pCxt->msg, "sha2 digest length must be one of 224, 256, 384, 512", pToken->z);
746
0
        }
747
0
      }
748
749
0
      NEXT_VALID_TOKEN(*ppSql, *pToken);
750
0
      if (TK_NK_RP != pToken->type) {
751
0
        taosMemoryFree(tmpTokenBuf);
752
753
0
        return buildSyntaxErrMsg(&pCxt->msg, ") expected", pToken->z);
754
0
      }
755
756
0
      if (SHA2_OUTPUT_LEN + VARSTR_HEADER_SIZE > bytes) {
757
0
        taosMemoryFree(tmpTokenBuf);
758
759
0
        return generateSyntaxErrMsg(&pCxt->msg, TSDB_CODE_PAR_VALUE_TOO_LONG, pSchema->name);
760
0
      }
761
762
0
      int32_t bufLen = TMAX(SHA2_OUTPUT_LEN + VARSTR_HEADER_SIZE + 1, inputBytes);
763
0
      *pData = taosMemoryMalloc(bufLen);
764
0
      if (NULL == *pData) {
765
0
        taosMemoryFree(tmpTokenBuf);
766
767
0
        return terrno;
768
0
      }
769
770
0
      (void)memcpy(*pData, input, inputBytes);
771
0
      int32_t len = taosCreateSHA2Hash((char *)*pData, inputBytes, digestLen, bufLen);
772
0
      *nData = len;
773
0
    } else if (pToken->type == TK_SHA || pToken->type == TK_SHA1) {
774
0
      NEXT_VALID_TOKEN(*ppSql, *pToken);
775
0
      if (TK_NK_LP != pToken->type) {
776
0
        taosMemoryFree(tmpTokenBuf);
777
778
0
        return buildSyntaxErrMsg(&pCxt->msg, "( expected", pToken->z);
779
0
      }
780
781
0
      NEXT_VALID_TOKEN(*ppSql, *pToken);
782
0
      if (TK_NULL == pToken->type) {
783
0
        NEXT_VALID_TOKEN(*ppSql, *pToken);
784
0
        if (TK_NK_RP == pToken->type) {
785
0
          pVal->flag = CV_FLAG_NULL;
786
787
0
          taosMemoryFree(tmpTokenBuf);
788
789
0
          return TSDB_CODE_SUCCESS;
790
0
        }
791
0
      } else if (TK_NK_STRING != pToken->type) {
792
0
        taosMemoryFree(tmpTokenBuf);
793
794
0
        return buildSyntaxErrMsg(&pCxt->msg, "string expected", pToken->z);
795
0
      }
796
797
0
      inputBytes = trimString(pToken->z, pToken->n, tmpTokenBuf, TSDB_MAX_BYTES_PER_ROW);
798
0
      input = tmpTokenBuf;
799
800
0
      NEXT_VALID_TOKEN(*ppSql, *pToken);
801
0
      if (TK_NK_RP != pToken->type) {
802
0
        taosMemoryFree(tmpTokenBuf);
803
804
0
        return buildSyntaxErrMsg(&pCxt->msg, ") expected", pToken->z);
805
0
      }
806
807
0
      if (SHA1_OUTPUT_LEN + VARSTR_HEADER_SIZE > bytes) {
808
0
        taosMemoryFree(tmpTokenBuf);
809
810
0
        return generateSyntaxErrMsg(&pCxt->msg, TSDB_CODE_PAR_VALUE_TOO_LONG, pSchema->name);
811
0
      }
812
813
0
      int32_t bufLen = TMAX(SHA1_OUTPUT_LEN + VARSTR_HEADER_SIZE + 1, inputBytes);
814
0
      *pData = taosMemoryMalloc(bufLen);
815
0
      if (NULL == *pData) {
816
0
        taosMemoryFree(tmpTokenBuf);
817
818
0
        return terrno;
819
0
      }
820
821
0
      (void)memcpy(*pData, input, inputBytes);
822
0
      int32_t len = taosCreateSHA1Hash((char *)(*pData), inputBytes, bufLen) ;
823
0
      *nData = len;
824
0
    } else if (pToken->type == TK_AES_ENCRYPT) {
825
0
      NEXT_VALID_TOKEN(*ppSql, *pToken);
826
0
      if (TK_NK_LP != pToken->type) {
827
0
        taosMemoryFree(tmpTokenBuf);
828
829
0
        return buildSyntaxErrMsg(&pCxt->msg, "( expected", pToken->z);
830
0
      }
831
832
0
      NEXT_VALID_TOKEN(*ppSql, *pToken);
833
0
      if (TK_NK_STRING != pToken->type && TK_NULL != pToken->type) {
834
0
        taosMemoryFree(tmpTokenBuf);
835
836
0
        return buildSyntaxErrMsg(&pCxt->msg, "string or null expected", pToken->z);
837
0
      } else if (TK_NULL == pToken->type) {
838
0
        NEXT_VALID_TOKEN(*ppSql, *pToken);
839
0
        if (TK_NK_COMMA != pToken->type) {
840
0
          taosMemoryFree(tmpTokenBuf);
841
842
0
          return buildSyntaxErrMsg(&pCxt->msg, ", expected", pToken->z);
843
0
        }
844
845
0
        NEXT_VALID_TOKEN(*ppSql, *pToken);
846
0
        if (TK_NK_STRING != pToken->type) {
847
0
          taosMemoryFree(tmpTokenBuf);
848
849
0
          return buildSyntaxErrMsg(&pCxt->msg, "key string expected", pToken->z);
850
0
        }
851
852
0
        NEXT_VALID_TOKEN(*ppSql, *pToken);
853
0
        if (TK_NK_RP == pToken->type) {
854
0
          pVal->flag = CV_FLAG_NULL;
855
856
0
          taosMemoryFree(tmpTokenBuf);
857
858
0
          return TSDB_CODE_SUCCESS;
859
0
        } else if (TK_NK_STRING == pToken->type) {
860
0
          NEXT_VALID_TOKEN(*ppSql, *pToken);
861
0
          if (TK_NK_RP == pToken->type) {
862
0
            pVal->flag = CV_FLAG_NULL;
863
864
0
            taosMemoryFree(tmpTokenBuf);
865
866
0
            return TSDB_CODE_SUCCESS;
867
0
          }
868
0
        } else {
869
0
          taosMemoryFree(tmpTokenBuf);
870
871
0
          return buildSyntaxErrMsg(&pCxt->msg, "iv string expected", pToken->z);
872
0
        }
873
0
      } else {
874
0
        inputBytes = trimString(pToken->z, pToken->n, tmpTokenBuf, TSDB_MAX_BYTES_PER_ROW);
875
0
        input = tmpTokenBuf;
876
0
      }
877
878
0
      NEXT_VALID_TOKEN(*ppSql, *pToken);
879
0
      if (TK_NK_COMMA != pToken->type) {
880
0
        taosMemoryFree(tmpTokenBuf);
881
882
0
        return buildSyntaxErrMsg(&pCxt->msg, ", expected", pToken->z);
883
0
      }
884
885
0
      char*   key = NULL;
886
0
      int32_t keyBytes = 0;
887
0
      char    tmpKeyBuf[TSDB_MAX_BYTES_PER_ROW];
888
889
0
      NEXT_VALID_TOKEN(*ppSql, *pToken);
890
0
      if (TK_NK_STRING != pToken->type) {
891
0
        taosMemoryFree(tmpTokenBuf);
892
893
0
        return buildSyntaxErrMsg(&pCxt->msg, "key expected", pToken->z);
894
0
      } else {
895
0
        keyBytes = trimString(pToken->z, pToken->n, tmpKeyBuf, TSDB_MAX_BYTES_PER_ROW);
896
0
        key = tmpKeyBuf;
897
0
      }
898
899
0
      char*   iv = NULL;
900
0
      int32_t ivBytes = 0;
901
0
      char    tmpIvBuf[TSDB_MAX_BYTES_PER_ROW];
902
903
0
      NEXT_VALID_TOKEN(*ppSql, *pToken);
904
0
      if (TK_NK_RP != pToken->type && TK_NK_STRING != pToken->type) {
905
0
        taosMemoryFree(tmpTokenBuf);
906
907
0
        return buildSyntaxErrMsg(&pCxt->msg, ") or iv expected", pToken->z);
908
0
      } else if (TK_NK_STRING == pToken->type) {
909
0
        ivBytes = trimString(pToken->z, pToken->n, tmpIvBuf, TSDB_MAX_BYTES_PER_ROW);
910
0
        iv = tmpIvBuf;
911
912
0
        NEXT_VALID_TOKEN(*ppSql, *pToken);
913
0
        if (TK_NK_RP != pToken->type) {
914
0
          taosMemoryFree(tmpTokenBuf);
915
916
0
          return buildSyntaxErrMsg(&pCxt->msg, ") expected", pToken->z);
917
0
        }
918
0
      }
919
920
0
      int32_t outputBytes = taes_encrypt_len(inputBytes);
921
0
      if (outputBytes + VARSTR_HEADER_SIZE > bytes) {
922
0
        taosMemoryFree(tmpTokenBuf);
923
924
0
        return generateSyntaxErrMsg(&pCxt->msg, TSDB_CODE_PAR_VALUE_TOO_LONG, pSchema->name);
925
0
      }
926
927
0
      int32_t bufLen = outputBytes + VARSTR_HEADER_SIZE + 1;
928
0
      *pData = taosMemoryCalloc(1, bufLen);
929
0
      if (NULL == *pData) {
930
0
        taosMemoryFree(tmpTokenBuf);
931
932
0
        return terrno;
933
0
      }
934
935
0
      (void)memcpy(*pData, input, inputBytes);
936
937
0
      int32_t keypaddedlen = taes_encrypt_len(keyBytes);
938
0
      char*   pKeyPaddingBuf = taosMemoryMalloc(keypaddedlen);
939
0
      if (!pKeyPaddingBuf) {
940
0
        taosMemoryFree(tmpTokenBuf);
941
942
0
        return terrno;
943
0
      }
944
0
      (void)memcpy(pKeyPaddingBuf, key, keyBytes);
945
946
0
      int32_t len = taosAesEncrypt(pKeyPaddingBuf, keyBytes, *pData, inputBytes, iv);
947
0
      *nData = len;
948
949
0
      taosMemoryFree(pKeyPaddingBuf);
950
0
    } else if (pToken->type == TK_AES_DECRYPT) {
951
0
      NEXT_VALID_TOKEN(*ppSql, *pToken);
952
0
      if (TK_NK_LP != pToken->type) {
953
0
        taosMemoryFree(tmpTokenBuf);
954
955
0
        return buildSyntaxErrMsg(&pCxt->msg, "( expected", pToken->z);
956
0
      }
957
958
0
      NEXT_VALID_TOKEN(*ppSql, *pToken);
959
0
      if (TK_NK_STRING != pToken->type && TK_NULL != pToken->type) {
960
0
        taosMemoryFree(tmpTokenBuf);
961
962
0
        return buildSyntaxErrMsg(&pCxt->msg, "string or null expected", pToken->z);
963
0
      } else if (TK_NULL == pToken->type) {
964
0
        NEXT_VALID_TOKEN(*ppSql, *pToken);
965
0
        if (TK_NK_COMMA != pToken->type) {
966
0
          taosMemoryFree(tmpTokenBuf);
967
968
0
          return buildSyntaxErrMsg(&pCxt->msg, ", expected", pToken->z);
969
0
        }
970
971
0
        NEXT_VALID_TOKEN(*ppSql, *pToken);
972
0
        if (TK_NK_STRING != pToken->type) {
973
0
          taosMemoryFree(tmpTokenBuf);
974
975
0
          return buildSyntaxErrMsg(&pCxt->msg, "key string expected", pToken->z);
976
0
        }
977
978
0
        NEXT_VALID_TOKEN(*ppSql, *pToken);
979
0
        if (TK_NK_RP == pToken->type) {
980
0
          pVal->flag = CV_FLAG_NULL;
981
982
0
          taosMemoryFree(tmpTokenBuf);
983
984
0
          return TSDB_CODE_SUCCESS;
985
0
        } else if (TK_NK_STRING == pToken->type) {
986
0
          NEXT_VALID_TOKEN(*ppSql, *pToken);
987
0
          if (TK_NK_RP == pToken->type) {
988
0
            pVal->flag = CV_FLAG_NULL;
989
990
0
            taosMemoryFree(tmpTokenBuf);
991
992
0
            return TSDB_CODE_SUCCESS;
993
0
          }
994
0
        } else {
995
0
          taosMemoryFree(tmpTokenBuf);
996
997
0
          return buildSyntaxErrMsg(&pCxt->msg, "iv string expected", pToken->z);
998
0
        }
999
0
      } else {
1000
0
        inputBytes = trimString(pToken->z, pToken->n, tmpTokenBuf, TSDB_MAX_BYTES_PER_ROW);
1001
0
        input = tmpTokenBuf;
1002
0
      }
1003
1004
0
      NEXT_VALID_TOKEN(*ppSql, *pToken);
1005
0
      if (TK_NK_COMMA != pToken->type) {
1006
0
        taosMemoryFree(tmpTokenBuf);
1007
1008
0
        return buildSyntaxErrMsg(&pCxt->msg, ", expected", pToken->z);
1009
0
      }
1010
1011
0
      char*   key = NULL;
1012
0
      int32_t keyBytes = 0;
1013
0
      char    tmpKeyBuf[TSDB_MAX_BYTES_PER_ROW];
1014
1015
0
      NEXT_VALID_TOKEN(*ppSql, *pToken);
1016
0
      if (TK_NK_STRING != pToken->type) {
1017
0
        taosMemoryFree(tmpTokenBuf);
1018
1019
0
        return buildSyntaxErrMsg(&pCxt->msg, "key expected", pToken->z);
1020
0
      } else {
1021
0
        keyBytes = trimString(pToken->z, pToken->n, tmpKeyBuf, TSDB_MAX_BYTES_PER_ROW);
1022
0
        key = tmpKeyBuf;
1023
0
      }
1024
1025
0
      char*   iv = NULL;
1026
0
      int32_t ivBytes = 0;
1027
0
      char    tmpIvBuf[TSDB_MAX_BYTES_PER_ROW];
1028
1029
0
      NEXT_VALID_TOKEN(*ppSql, *pToken);
1030
0
      if (TK_NK_RP != pToken->type && TK_NK_STRING != pToken->type) {
1031
0
        taosMemoryFree(tmpTokenBuf);
1032
1033
0
        return buildSyntaxErrMsg(&pCxt->msg, ") or iv expected", pToken->z);
1034
0
      } else if (TK_NK_STRING == pToken->type) {
1035
0
        ivBytes = trimString(pToken->z, pToken->n, tmpIvBuf, TSDB_MAX_BYTES_PER_ROW);
1036
0
        iv = tmpIvBuf;
1037
1038
0
        NEXT_VALID_TOKEN(*ppSql, *pToken);
1039
0
        if (TK_NK_RP != pToken->type) {
1040
0
          taosMemoryFree(tmpTokenBuf);
1041
1042
0
          return buildSyntaxErrMsg(&pCxt->msg, ") expected", pToken->z);
1043
0
        }
1044
0
      }
1045
1046
0
      int32_t outputBytes = taes_encrypt_len(inputBytes);
1047
0
      if (outputBytes + VARSTR_HEADER_SIZE > bytes) {
1048
0
        taosMemoryFree(tmpTokenBuf);
1049
1050
0
        return generateSyntaxErrMsg(&pCxt->msg, TSDB_CODE_PAR_VALUE_TOO_LONG, pSchema->name);
1051
0
      }
1052
1053
0
      int32_t bufLen = outputBytes + VARSTR_HEADER_SIZE + 1;
1054
0
      *pData = taosMemoryMalloc(bufLen);
1055
0
      if (NULL == *pData) {
1056
0
        taosMemoryFree(tmpTokenBuf);
1057
1058
0
        return terrno;
1059
0
      }
1060
1061
0
      (void)memcpy(*pData, input, inputBytes);
1062
1063
0
      int32_t keypaddedlen = taes_encrypt_len(keyBytes);
1064
0
      char*   pKeyPaddingBuf = taosMemoryMalloc(keypaddedlen);
1065
0
      if (!pKeyPaddingBuf) {
1066
0
        taosMemoryFree(tmpTokenBuf);
1067
1068
0
        return terrno;
1069
0
      }
1070
0
      (void)memcpy(pKeyPaddingBuf, key, keyBytes);
1071
1072
0
      int32_t len = taosAesDecrypt(pKeyPaddingBuf, keyBytes, *pData, inputBytes, iv);
1073
0
      *nData = len;
1074
1075
0
      taosMemoryFree(pKeyPaddingBuf);
1076
0
    } else if (pToken->type == TK_SM4_ENCRYPT) {
1077
0
      NEXT_VALID_TOKEN(*ppSql, *pToken);
1078
0
      if (TK_NK_LP != pToken->type) {
1079
0
        taosMemoryFree(tmpTokenBuf);
1080
1081
0
        return buildSyntaxErrMsg(&pCxt->msg, "( expected", pToken->z);
1082
0
      }
1083
1084
0
      NEXT_VALID_TOKEN(*ppSql, *pToken);
1085
0
      if (TK_NK_STRING != pToken->type && TK_NULL != pToken->type) {
1086
0
        taosMemoryFree(tmpTokenBuf);
1087
1088
0
        return buildSyntaxErrMsg(&pCxt->msg, "string or null expected", pToken->z);
1089
0
      } else if (TK_NULL == pToken->type) {
1090
0
        NEXT_VALID_TOKEN(*ppSql, *pToken);
1091
0
        if (TK_NK_COMMA != pToken->type) {
1092
0
          taosMemoryFree(tmpTokenBuf);
1093
1094
0
          return buildSyntaxErrMsg(&pCxt->msg, ", expected", pToken->z);
1095
0
        }
1096
1097
0
        NEXT_VALID_TOKEN(*ppSql, *pToken);
1098
0
        if (TK_NK_STRING != pToken->type) {
1099
0
          taosMemoryFree(tmpTokenBuf);
1100
1101
0
          return buildSyntaxErrMsg(&pCxt->msg, "key string expected", pToken->z);
1102
0
        }
1103
1104
0
        NEXT_VALID_TOKEN(*ppSql, *pToken);
1105
0
        if (TK_NK_RP == pToken->type) {
1106
0
          pVal->flag = CV_FLAG_NULL;
1107
1108
0
          taosMemoryFree(tmpTokenBuf);
1109
1110
0
          return TSDB_CODE_SUCCESS;
1111
0
        } else {
1112
0
          taosMemoryFree(tmpTokenBuf);
1113
1114
0
          return buildSyntaxErrMsg(&pCxt->msg, ") expected", pToken->z);
1115
0
        }
1116
0
      } else {
1117
0
        inputBytes = trimString(pToken->z, pToken->n, tmpTokenBuf, TSDB_MAX_BYTES_PER_ROW);
1118
0
        input = tmpTokenBuf;
1119
0
      }
1120
1121
0
      NEXT_VALID_TOKEN(*ppSql, *pToken);
1122
0
      if (TK_NK_COMMA != pToken->type) {
1123
0
        taosMemoryFree(tmpTokenBuf);
1124
1125
0
        return buildSyntaxErrMsg(&pCxt->msg, ", expected", pToken->z);
1126
0
      }
1127
1128
0
      char*   key = NULL;
1129
0
      int32_t keyBytes = 0;
1130
0
      char    tmpKeyBuf[TSDB_MAX_BYTES_PER_ROW];
1131
1132
0
      NEXT_VALID_TOKEN(*ppSql, *pToken);
1133
0
      if (TK_NK_STRING != pToken->type) {
1134
0
        taosMemoryFree(tmpTokenBuf);
1135
1136
0
        return buildSyntaxErrMsg(&pCxt->msg, "key expected", pToken->z);
1137
0
      } else {
1138
0
        keyBytes = trimString(pToken->z, pToken->n, tmpKeyBuf, TSDB_MAX_BYTES_PER_ROW);
1139
0
        key = tmpKeyBuf;
1140
0
      }
1141
1142
0
      NEXT_VALID_TOKEN(*ppSql, *pToken);
1143
0
      if (TK_NK_RP != pToken->type) {
1144
0
        taosMemoryFree(tmpTokenBuf);
1145
1146
0
        return buildSyntaxErrMsg(&pCxt->msg, ") expected", pToken->z);
1147
0
      }
1148
1149
0
      int32_t outputBytes = tsm4_encrypt_len(inputBytes);
1150
0
      if (outputBytes + VARSTR_HEADER_SIZE > bytes) {
1151
0
        taosMemoryFree(tmpTokenBuf);
1152
1153
0
        return generateSyntaxErrMsg(&pCxt->msg, TSDB_CODE_PAR_VALUE_TOO_LONG, pSchema->name);
1154
0
      }
1155
1156
0
      int32_t bufLen = outputBytes + VARSTR_HEADER_SIZE + 1;
1157
0
      *pData = taosMemoryMalloc(bufLen);
1158
0
      if (NULL == *pData) {
1159
0
        taosMemoryFree(tmpTokenBuf);
1160
1161
0
        return terrno;
1162
0
      }
1163
1164
0
      (void)memcpy(*pData, input, inputBytes);
1165
1166
0
      int32_t keypaddedlen = tsm4_encrypt_len(keyBytes);
1167
0
      char*   pKeyPaddingBuf = taosMemoryMalloc(keypaddedlen);
1168
0
      if (!pKeyPaddingBuf) {
1169
0
        taosMemoryFree(tmpTokenBuf);
1170
1171
0
        return terrno;
1172
0
      }
1173
0
      (void)memcpy(pKeyPaddingBuf, key, keyBytes);
1174
1175
0
      int32_t len = taosSm4Encrypt(pKeyPaddingBuf, keyBytes, *pData, inputBytes);
1176
0
      *nData = len;
1177
1178
0
      taosMemoryFree(pKeyPaddingBuf);
1179
0
    } else if (pToken->type == TK_SM4_DECRYPT) {
1180
0
      NEXT_VALID_TOKEN(*ppSql, *pToken);
1181
0
      if (TK_NK_LP != pToken->type) {
1182
0
        taosMemoryFree(tmpTokenBuf);
1183
1184
0
        return buildSyntaxErrMsg(&pCxt->msg, "( expected", pToken->z);
1185
0
      }
1186
1187
0
      NEXT_VALID_TOKEN(*ppSql, *pToken);
1188
0
      if (TK_NK_STRING != pToken->type && TK_NULL != pToken->type) {
1189
0
        taosMemoryFree(tmpTokenBuf);
1190
1191
0
        return buildSyntaxErrMsg(&pCxt->msg, "string or null expected", pToken->z);
1192
0
      } else if (TK_NULL == pToken->type) {
1193
0
        NEXT_VALID_TOKEN(*ppSql, *pToken);
1194
0
        if (TK_NK_COMMA != pToken->type) {
1195
0
          taosMemoryFree(tmpTokenBuf);
1196
1197
0
          return buildSyntaxErrMsg(&pCxt->msg, ", expected", pToken->z);
1198
0
        }
1199
1200
0
        NEXT_VALID_TOKEN(*ppSql, *pToken);
1201
0
        if (TK_NK_STRING != pToken->type) {
1202
0
          taosMemoryFree(tmpTokenBuf);
1203
1204
0
          return buildSyntaxErrMsg(&pCxt->msg, "key string expected", pToken->z);
1205
0
        }
1206
1207
0
        NEXT_VALID_TOKEN(*ppSql, *pToken);
1208
0
        if (TK_NK_RP == pToken->type) {
1209
0
          pVal->flag = CV_FLAG_NULL;
1210
1211
0
          taosMemoryFree(tmpTokenBuf);
1212
1213
0
          return TSDB_CODE_SUCCESS;
1214
0
        } else {
1215
0
          taosMemoryFree(tmpTokenBuf);
1216
1217
0
          return buildSyntaxErrMsg(&pCxt->msg, ") expected", pToken->z);
1218
0
        }
1219
0
      } else {
1220
0
        inputBytes = trimString(pToken->z, pToken->n, tmpTokenBuf, TSDB_MAX_BYTES_PER_ROW);
1221
0
        input = tmpTokenBuf;
1222
0
      }
1223
1224
0
      NEXT_VALID_TOKEN(*ppSql, *pToken);
1225
0
      if (TK_NK_COMMA != pToken->type) {
1226
0
        taosMemoryFree(tmpTokenBuf);
1227
1228
0
        return buildSyntaxErrMsg(&pCxt->msg, ", expected", pToken->z);
1229
0
      }
1230
1231
0
      char*   key = NULL;
1232
0
      int32_t keyBytes = 0;
1233
0
      char    tmpKeyBuf[TSDB_MAX_BYTES_PER_ROW];
1234
1235
0
      NEXT_VALID_TOKEN(*ppSql, *pToken);
1236
0
      if (TK_NK_STRING != pToken->type) {
1237
0
        taosMemoryFree(tmpTokenBuf);
1238
1239
0
        return buildSyntaxErrMsg(&pCxt->msg, "key expected", pToken->z);
1240
0
      } else {
1241
0
        keyBytes = trimString(pToken->z, pToken->n, tmpKeyBuf, TSDB_MAX_BYTES_PER_ROW);
1242
0
        key = tmpKeyBuf;
1243
0
      }
1244
1245
0
      NEXT_VALID_TOKEN(*ppSql, *pToken);
1246
0
      if (TK_NK_RP != pToken->type) {
1247
0
        taosMemoryFree(tmpTokenBuf);
1248
1249
0
        return buildSyntaxErrMsg(&pCxt->msg, ") expected", pToken->z);
1250
0
      }
1251
1252
0
      int32_t outputBytes = tsm4_encrypt_len(inputBytes);
1253
0
      if (outputBytes + VARSTR_HEADER_SIZE > bytes) {
1254
0
        taosMemoryFree(tmpTokenBuf);
1255
1256
0
        return generateSyntaxErrMsg(&pCxt->msg, TSDB_CODE_PAR_VALUE_TOO_LONG, pSchema->name);
1257
0
      }
1258
1259
0
      int32_t bufLen = outputBytes + VARSTR_HEADER_SIZE + 1;
1260
0
      *pData = taosMemoryMalloc(bufLen);
1261
0
      if (NULL == *pData) {
1262
0
        taosMemoryFree(tmpTokenBuf);
1263
1264
0
        return terrno;
1265
0
      }
1266
1267
0
      (void)memcpy(*pData, input, inputBytes);
1268
1269
0
      int32_t keypaddedlen = tsm4_encrypt_len(keyBytes);
1270
0
      char*   pKeyPaddingBuf = taosMemoryMalloc(keypaddedlen);
1271
0
      if (!pKeyPaddingBuf) {
1272
0
        taosMemoryFree(tmpTokenBuf);
1273
1274
0
        return terrno;
1275
0
      }
1276
0
      (void)memcpy(pKeyPaddingBuf, key, keyBytes);
1277
1278
0
      int32_t len = taosSm4Decrypt(pKeyPaddingBuf, keyBytes, *pData, inputBytes);
1279
0
      *nData = len;
1280
1281
0
      taosMemoryFree(pKeyPaddingBuf);
1282
0
    } else {
1283
0
      taosMemoryFree(tmpTokenBuf);
1284
1285
0
      return buildSyntaxErrMsg(&pCxt->msg, "invalid identifier", pToken->z);
1286
0
    }
1287
1288
0
    taosMemoryFree(tmpTokenBuf);
1289
0
  } else {
1290
0
    if (pToken->n + VARSTR_HEADER_SIZE > bytes) {
1291
0
      return generateSyntaxErrMsg(&pCxt->msg, TSDB_CODE_PAR_VALUE_TOO_LONG, pSchema->name);
1292
0
    }
1293
1294
0
    *pData = taosMemoryMalloc(pToken->n);
1295
0
    if (NULL == *pData) {
1296
0
      return terrno;
1297
0
    }
1298
0
    memcpy(*pData, pToken->z, pToken->n);
1299
0
    *nData = pToken->n;
1300
0
  }
1301
1302
0
  pVal->flag = CV_FLAG_VALUE;
1303
0
  return TSDB_CODE_SUCCESS;
1304
0
}
1305
1306
0
static int32_t parseVarbinary(SToken* pToken, uint8_t** pData, uint32_t* nData, int32_t bytes) {
1307
0
  if (pToken->type != TK_NK_STRING) {
1308
0
    return TSDB_CODE_PAR_INVALID_VARBINARY;
1309
0
  }
1310
1311
0
  if (isHex(pToken->z + 1, pToken->n - 2)) {
1312
0
    if (!isValidateHex(pToken->z + 1, pToken->n - 2)) {
1313
0
      return TSDB_CODE_PAR_INVALID_VARBINARY;
1314
0
    }
1315
1316
0
    void*    data = NULL;
1317
0
    uint32_t size = 0;
1318
0
    if (taosHex2Ascii(pToken->z + 1, pToken->n - 2, &data, &size) < 0) {
1319
0
      return TSDB_CODE_OUT_OF_MEMORY;
1320
0
    }
1321
1322
0
    if (size + VARSTR_HEADER_SIZE > bytes) {
1323
0
      taosMemoryFree(data);
1324
0
      return TSDB_CODE_PAR_VALUE_TOO_LONG;
1325
0
    }
1326
0
    *pData = data;
1327
0
    *nData = size;
1328
0
  } else {
1329
0
    *pData = taosMemoryCalloc(1, pToken->n);
1330
0
    if (!pData) return terrno;
1331
0
    int32_t len = trimString(pToken->z, pToken->n, *pData, pToken->n);
1332
0
    *nData = len;
1333
1334
0
    if (*nData + VARSTR_HEADER_SIZE > bytes) {
1335
0
      return TSDB_CODE_PAR_VALUE_TOO_LONG;
1336
0
    }
1337
0
  }
1338
0
  return TSDB_CODE_SUCCESS;
1339
0
}
1340
0
static int32_t parseBlob(SToken* pToken, uint8_t** pData, uint32_t* nData, int32_t bytes) {
1341
0
  if (pToken->type != TK_NK_STRING) {
1342
0
    return TSDB_CODE_PAR_INVALID_VARBINARY;
1343
0
  }
1344
0
  int32_t  code = 0;
1345
0
  int32_t  lino = 0;
1346
0
  uint32_t size = 0;
1347
0
  *pData = NULL;
1348
1349
0
  if (isHex(pToken->z + 1, pToken->n - 2)) {
1350
0
    if (!isValidateHex(pToken->z + 1, pToken->n - 2)) {
1351
0
      return TSDB_CODE_PAR_INVALID_VARBINARY;
1352
0
    }
1353
0
    void* data = NULL;
1354
1355
0
    if (taosHex2Ascii(pToken->z + 1, pToken->n - 2, &data, &size) < 0) {
1356
0
      TSDB_CHECK_CODE(code, lino, _error);
1357
0
    }
1358
0
    *pData = data;
1359
0
    *nData = size;
1360
0
  } else {
1361
0
    *pData = taosMemoryCalloc(1, pToken->n);
1362
0
    if (!pData) return terrno;
1363
0
    size = trimString(pToken->z, pToken->n, (char*)*pData, pToken->n);
1364
0
    *nData = size;
1365
0
  }
1366
1367
0
  if (size + BLOBSTR_HEADER_SIZE > TSDB_MAX_BLOB_LEN) {
1368
0
    TSDB_CHECK_CODE(code = TSDB_CODE_BLOB_VALUE_TOO_LONG, lino, _error);
1369
0
  }
1370
1371
0
_error:
1372
0
  if (code != 0) {
1373
0
    taosMemoryFree(pData);
1374
0
    uError("parseBlob failed at lino %d code: %s", lino, tstrerror(code));
1375
0
    return code;
1376
0
  }
1377
0
  *nData = size;
1378
0
  return TSDB_CODE_SUCCESS;
1379
0
}
1380
1381
static int32_t parseTagToken(const char** end, SToken* pToken, SSchema* pSchema, int16_t timePrec, STagVal* val,
1382
0
                             SMsgBuf* pMsgBuf, timezone_t tz, void* charsetCxt) {
1383
0
  int64_t  iv;
1384
0
  uint64_t uv;
1385
0
  char*    endptr = NULL;
1386
0
  int32_t  code = TSDB_CODE_SUCCESS;
1387
1388
#if 0
1389
  if (isNullValue(pSchema->type, pToken)) {
1390
    if (TSDB_DATA_TYPE_TIMESTAMP == pSchema->type && PRIMARYKEY_TIMESTAMP_COL_ID == pSchema->colId) {
1391
      return buildSyntaxErrMsg(pMsgBuf, "Primary timestamp column can not be null", pToken->z);
1392
    }
1393
1394
    return TSDB_CODE_SUCCESS;
1395
  }
1396
#endif
1397
1398
0
  val->cid = pSchema->colId;
1399
0
  val->type = pSchema->type;
1400
1401
0
  switch (pSchema->type) {
1402
0
    case TSDB_DATA_TYPE_BOOL: {
1403
0
      if ((pToken->type == TK_NK_BOOL || pToken->type == TK_NK_STRING) && (pToken->n != 0)) {
1404
0
        if (IS_TRUE_STR(pToken->z, pToken->n)) {
1405
0
          *(int8_t*)(&val->i64) = TRUE_VALUE;
1406
0
        } else if (IS_FALSE_STR(pToken->z, pToken->n)) {
1407
0
          *(int8_t*)(&val->i64) = FALSE_VALUE;
1408
0
        } else if (TSDB_CODE_SUCCESS == toDoubleEx(pToken->z, pToken->n, pToken->type, (double*)&iv)) {
1409
0
          *(int8_t*)(&val->i64) = (*(double*)&iv == 0 ? FALSE_VALUE : TRUE_VALUE);
1410
0
        } else {
1411
0
          return buildSyntaxErrMsg(pMsgBuf, "invalid bool data", pToken->z);
1412
0
        }
1413
0
      } else if (pToken->type == TK_NK_INTEGER) {
1414
0
        *(int8_t*)(&val->i64) = ((taosStr2Int64(pToken->z, NULL, 10) == 0) ? FALSE_VALUE : TRUE_VALUE);
1415
0
      } else if (pToken->type == TK_NK_FLOAT) {
1416
0
        *(int8_t*)(&val->i64) = ((taosStr2Double(pToken->z, NULL) == 0) ? FALSE_VALUE : TRUE_VALUE);
1417
0
      } else if ((pToken->type == TK_NK_HEX || pToken->type == TK_NK_BIN) &&
1418
0
                 (TSDB_CODE_SUCCESS == toDoubleEx(pToken->z, pToken->n, pToken->type, (double*)&iv))) {
1419
0
        *(int8_t*)(&val->i64) = (*(double*)&iv == 0 ? FALSE_VALUE : TRUE_VALUE);
1420
0
      } else {
1421
0
        return buildSyntaxErrMsg(pMsgBuf, "invalid bool data", pToken->z);
1422
0
      }
1423
0
      break;
1424
0
    }
1425
1426
0
    case TSDB_DATA_TYPE_TINYINT: {
1427
0
      code = toIntegerEx(pToken->z, pToken->n, pToken->type, &iv);
1428
0
      if (TSDB_CODE_SUCCESS != code) {
1429
0
        return buildSyntaxErrMsg(pMsgBuf, "invalid tinyint data", pToken->z);
1430
0
      } else if (!IS_VALID_TINYINT(iv)) {
1431
0
        return buildSyntaxErrMsg(pMsgBuf, "tinyint data overflow", pToken->z);
1432
0
      }
1433
1434
0
      *(int8_t*)(&val->i64) = iv;
1435
0
      break;
1436
0
    }
1437
1438
0
    case TSDB_DATA_TYPE_UTINYINT: {
1439
0
      code = toUIntegerEx(pToken->z, pToken->n, pToken->type, &uv);
1440
0
      if (TSDB_CODE_SUCCESS != code) {
1441
0
        return buildSyntaxErrMsg(pMsgBuf, "invalid unsigned tinyint data", pToken->z);
1442
0
      } else if (uv > UINT8_MAX) {
1443
0
        return buildSyntaxErrMsg(pMsgBuf, "unsigned tinyint data overflow", pToken->z);
1444
0
      }
1445
0
      *(uint8_t*)(&val->i64) = uv;
1446
0
      break;
1447
0
    }
1448
1449
0
    case TSDB_DATA_TYPE_SMALLINT: {
1450
0
      code = toIntegerEx(pToken->z, pToken->n, pToken->type, &iv);
1451
0
      if (TSDB_CODE_SUCCESS != code) {
1452
0
        return buildSyntaxErrMsg(pMsgBuf, "invalid smallint data", pToken->z);
1453
0
      } else if (!IS_VALID_SMALLINT(iv)) {
1454
0
        return buildSyntaxErrMsg(pMsgBuf, "smallint data overflow", pToken->z);
1455
0
      }
1456
0
      *(int16_t*)(&val->i64) = iv;
1457
0
      break;
1458
0
    }
1459
1460
0
    case TSDB_DATA_TYPE_USMALLINT: {
1461
0
      code = toUIntegerEx(pToken->z, pToken->n, pToken->type, &uv);
1462
0
      if (TSDB_CODE_SUCCESS != code) {
1463
0
        return buildSyntaxErrMsg(pMsgBuf, "invalid unsigned smallint data", pToken->z);
1464
0
      } else if (uv > UINT16_MAX) {
1465
0
        return buildSyntaxErrMsg(pMsgBuf, "unsigned smallint data overflow", pToken->z);
1466
0
      }
1467
0
      *(uint16_t*)(&val->i64) = uv;
1468
0
      break;
1469
0
    }
1470
1471
0
    case TSDB_DATA_TYPE_INT: {
1472
0
      code = toIntegerEx(pToken->z, pToken->n, pToken->type, &iv);
1473
0
      if (TSDB_CODE_SUCCESS != code) {
1474
0
        return buildSyntaxErrMsg(pMsgBuf, "invalid int data", pToken->z);
1475
0
      } else if (!IS_VALID_INT(iv)) {
1476
0
        return buildSyntaxErrMsg(pMsgBuf, "int data overflow", pToken->z);
1477
0
      }
1478
0
      *(int32_t*)(&val->i64) = iv;
1479
0
      break;
1480
0
    }
1481
1482
0
    case TSDB_DATA_TYPE_UINT: {
1483
0
      code = toUIntegerEx(pToken->z, pToken->n, pToken->type, &uv);
1484
0
      if (TSDB_CODE_SUCCESS != code) {
1485
0
        return buildSyntaxErrMsg(pMsgBuf, "invalid unsigned int data", pToken->z);
1486
0
      } else if (uv > UINT32_MAX) {
1487
0
        return buildSyntaxErrMsg(pMsgBuf, "unsigned int data overflow", pToken->z);
1488
0
      }
1489
0
      *(uint32_t*)(&val->i64) = uv;
1490
0
      break;
1491
0
    }
1492
1493
0
    case TSDB_DATA_TYPE_BIGINT: {
1494
0
      code = toIntegerEx(pToken->z, pToken->n, pToken->type, &iv);
1495
0
      if (TSDB_CODE_SUCCESS != code) {
1496
0
        return buildSyntaxErrMsg(pMsgBuf, "invalid bigint data", pToken->z);
1497
0
      }
1498
0
      val->i64 = iv;
1499
0
      break;
1500
0
    }
1501
1502
0
    case TSDB_DATA_TYPE_UBIGINT: {
1503
0
      code = toUIntegerEx(pToken->z, pToken->n, pToken->type, &uv);
1504
0
      if (TSDB_CODE_SUCCESS != code) {
1505
0
        return buildSyntaxErrMsg(pMsgBuf, "invalid unsigned bigint data", pToken->z);
1506
0
      }
1507
0
      *(uint64_t*)(&val->i64) = uv;
1508
0
      break;
1509
0
    }
1510
1511
0
    case TSDB_DATA_TYPE_FLOAT: {
1512
0
      double dv;
1513
0
      code = toDoubleEx(pToken->z, pToken->n, pToken->type, &dv);
1514
0
      if (TSDB_CODE_SUCCESS != code) {
1515
0
        return buildSyntaxErrMsg(pMsgBuf, "illegal float data", pToken->z);
1516
0
      }
1517
0
      if (dv > FLT_MAX || dv < -FLT_MAX || isinf(dv) || isnan(dv)) {
1518
0
        return buildSyntaxErrMsg(pMsgBuf, "illegal float data", pToken->z);
1519
0
      }
1520
0
      *(float*)(&val->i64) = dv;
1521
0
      break;
1522
0
    }
1523
1524
0
    case TSDB_DATA_TYPE_DOUBLE: {
1525
0
      double dv;
1526
0
      code = toDoubleEx(pToken->z, pToken->n, pToken->type, &dv);
1527
0
      if (TSDB_CODE_SUCCESS != code) {
1528
0
        return buildSyntaxErrMsg(pMsgBuf, "illegal float data", pToken->z);
1529
0
      }
1530
0
      if (((dv == HUGE_VAL || dv == -HUGE_VAL) && ERRNO == ERANGE) || isinf(dv) || isnan(dv)) {
1531
0
        return buildSyntaxErrMsg(pMsgBuf, "illegal double data", pToken->z);
1532
0
      }
1533
1534
0
      *(double*)(&val->i64) = dv;
1535
0
      break;
1536
0
    }
1537
1538
0
    case TSDB_DATA_TYPE_BINARY: {
1539
      // Too long values will raise the invalid sql error message
1540
0
      if (pToken->n + VARSTR_HEADER_SIZE > pSchema->bytes) {
1541
0
        return generateSyntaxErrMsg(pMsgBuf, TSDB_CODE_PAR_VALUE_TOO_LONG, pSchema->name);
1542
0
      }
1543
0
      val->pData = taosStrdup(pToken->z);
1544
0
      if (!val->pData) {
1545
0
        return terrno;
1546
0
      }
1547
0
      val->nData = pToken->n;
1548
0
      break;
1549
0
    }
1550
0
    case TSDB_DATA_TYPE_VARBINARY: {
1551
0
      code = parseVarbinary(pToken, &val->pData, &val->nData, pSchema->bytes);
1552
0
      if (code != TSDB_CODE_SUCCESS) {
1553
0
        return generateSyntaxErrMsg(pMsgBuf, code, pSchema->name);
1554
0
      }
1555
0
      break;
1556
0
    }
1557
0
    case TSDB_DATA_TYPE_GEOMETRY: {
1558
0
      unsigned char* output = NULL;
1559
0
      size_t         size = 0;
1560
1561
0
      code = parseGeometry(pToken, &output, &size);
1562
0
      if (code != TSDB_CODE_SUCCESS) {
1563
0
        code = buildSyntaxErrMsg(pMsgBuf, getGeosErrMsg(code), pToken->z);
1564
0
      } else if (size + VARSTR_HEADER_SIZE > pSchema->bytes) {
1565
        // Too long values will raise the invalid sql error message
1566
0
        code = generateSyntaxErrMsg(pMsgBuf, TSDB_CODE_PAR_VALUE_TOO_LONG, pSchema->name);
1567
0
      } else {
1568
0
        val->pData = taosMemoryMalloc(size);
1569
0
        if (NULL == val->pData) {
1570
0
          code = terrno;
1571
0
        } else {
1572
0
          memcpy(val->pData, output, size);
1573
0
          val->nData = size;
1574
0
        }
1575
0
      }
1576
1577
0
      geosFreeBuffer(output);
1578
0
      break;
1579
0
    }
1580
1581
0
    case TSDB_DATA_TYPE_NCHAR: {
1582
0
      int32_t output = 0;
1583
0
      int64_t realLen = pToken->n << 2;
1584
0
      if (realLen > pSchema->bytes - VARSTR_HEADER_SIZE) realLen = pSchema->bytes - VARSTR_HEADER_SIZE;
1585
0
      void* p = taosMemoryMalloc(realLen);
1586
0
      if (p == NULL) {
1587
0
        return terrno;
1588
0
      }
1589
0
      if (!taosMbsToUcs4(pToken->z, pToken->n, (TdUcs4*)(p), realLen, &output, charsetCxt)) {
1590
0
        if (terrno == TAOS_SYSTEM_ERROR(E2BIG)) {
1591
0
          taosMemoryFree(p);
1592
0
          return generateSyntaxErrMsg(pMsgBuf, TSDB_CODE_PAR_VALUE_TOO_LONG, pSchema->name);
1593
0
        }
1594
0
        char buf[512] = {0};
1595
0
        snprintf(buf, tListLen(buf), " taosMbsToUcs4 error:%s %d %d", strerror(terrno), ERRNO, EILSEQ);
1596
0
        taosMemoryFree(p);
1597
0
        return buildSyntaxErrMsg(pMsgBuf, buf, pToken->z);
1598
0
      }
1599
0
      val->pData = p;
1600
0
      val->nData = output;
1601
0
      break;
1602
0
    }
1603
0
    case TSDB_DATA_TYPE_TIMESTAMP: {
1604
0
      if (parseTime(end, pToken, timePrec, &iv, pMsgBuf, tz) != TSDB_CODE_SUCCESS) {
1605
0
        return buildSyntaxErrMsg(pMsgBuf, "invalid timestamp", pToken->z);
1606
0
      }
1607
1608
0
      val->i64 = iv;
1609
0
      break;
1610
0
    }
1611
0
    case TSDB_DATA_TYPE_MEDIUMBLOB:
1612
0
    case TSDB_DATA_TYPE_BLOB: {
1613
0
      code = generateSyntaxErrMsg(pMsgBuf, TSDB_CODE_BLOB_NOT_SUPPORT_TAG, pSchema->name);
1614
0
      break;
1615
0
    }
1616
0
  }
1617
1618
0
  return code;
1619
0
}
1620
1621
// input pStmt->pSql:  [(tag1_name, ...)] TAGS (tag1_value, ...) ...
1622
// output pStmt->pSql: TAGS (tag1_value, ...) ...
1623
0
static int32_t parseBoundTagsClause(SInsertParseContext* pCxt, SVnodeModifyOpStmt* pStmt) {
1624
0
  int32_t code = insInitBoundColsInfo(getNumOfTags(pStmt->pTableMeta), &pCxt->tags);
1625
0
  if (TSDB_CODE_SUCCESS != code) {
1626
0
    return code;
1627
0
  }
1628
1629
0
  SToken  token;
1630
0
  int32_t index = 0;
1631
0
  NEXT_TOKEN_KEEP_SQL(pStmt->pSql, token, index);
1632
0
  if (TK_NK_LP != token.type) {
1633
0
    return TSDB_CODE_SUCCESS;
1634
0
  }
1635
1636
0
  pStmt->pSql += index;
1637
0
  return parseBoundColumns(pCxt, pStmt, &pStmt->pSql, BOUND_TAGS, pStmt->pTableMeta, &pCxt->tags);
1638
0
}
1639
1640
int32_t parseTagValue(SMsgBuf* pMsgBuf, const char** pSql, uint8_t precision, SSchema* pTagSchema, SToken* pToken,
1641
0
                      SArray* pTagName, SArray* pTagVals, STag** pTag, timezone_t tz, void* charsetCxt) {
1642
0
  bool isNull = isNullValue(pTagSchema->type, pToken);
1643
0
  if (!isNull && pTagName) {
1644
0
    int32_t code = insTagNameAppend(pTagName, pTagSchema->name, pTagSchema->colId);
1645
0
    if (TSDB_CODE_SUCCESS != code) return code;
1646
0
  }
1647
1648
0
  if (pTagSchema->type == TSDB_DATA_TYPE_JSON) {
1649
0
    if (pToken->n > (TSDB_MAX_JSON_TAG_LEN - VARSTR_HEADER_SIZE) / TSDB_NCHAR_SIZE) {
1650
0
      return buildSyntaxErrMsg(pMsgBuf, "json string too long than 4095", pToken->z);
1651
0
    }
1652
1653
0
    if (isNull) {
1654
0
      return tTagNew(pTagVals, 1, true, pTag);
1655
0
    } else {
1656
0
      return parseJsontoTagData(pToken->z, pTagVals, pTag, pMsgBuf, charsetCxt);
1657
0
    }
1658
0
  }
1659
1660
0
  if (isNull) return 0;
1661
1662
0
  STagVal val = {0};
1663
0
  int32_t code = parseTagToken(pSql, pToken, pTagSchema, precision, &val, pMsgBuf, tz, charsetCxt);
1664
0
  if (TSDB_CODE_SUCCESS == code) {
1665
0
    if (NULL == taosArrayPush(pTagVals, &val)) {
1666
0
      code = terrno;
1667
0
    }
1668
0
  }
1669
1670
0
  if (TSDB_CODE_SUCCESS != code && IS_VAR_DATA_TYPE(val.type)) {
1671
0
    taosMemoryFree(val.pData);
1672
0
  }
1673
1674
0
  return code;
1675
0
}
1676
1677
0
static int32_t buildCreateTbReq(SVnodeModifyOpStmt* pStmt, STag* pTag, SArray* pTagName) {
1678
0
  if (pStmt->pCreateTblReq) {
1679
0
    tdDestroySVCreateTbReq(pStmt->pCreateTblReq);
1680
0
    taosMemoryFreeClear(pStmt->pCreateTblReq);
1681
0
  }
1682
0
  pStmt->pCreateTblReq = taosMemoryCalloc(1, sizeof(SVCreateTbReq));
1683
0
  if (NULL == pStmt->pCreateTblReq) {
1684
0
    return terrno;
1685
0
  }
1686
0
  return insBuildCreateTbReq(pStmt->pCreateTblReq, pStmt->targetTableName.tname, pTag, pStmt->pTableMeta->suid,
1687
0
                             pStmt->usingTableName.tname, pTagName, pStmt->pTableMeta->tableInfo.numOfTags,
1688
0
                             TSDB_DEFAULT_TABLE_TTL);
1689
0
}
1690
1691
0
int32_t checkAndTrimValue(SToken* pToken, char* tmpTokenBuf, SMsgBuf* pMsgBuf, int8_t type) {
1692
0
  if (pToken->type == TK_NK_QUESTION) {
1693
0
    return buildInvalidOperationMsg(pMsgBuf, "insert into super table syntax is not supported for stmt");
1694
0
  }
1695
0
  if ((pToken->type != TK_NOW && pToken->type != TK_TODAY && pToken->type != TK_NK_INTEGER &&
1696
0
       pToken->type != TK_NK_STRING && pToken->type != TK_NK_FLOAT && pToken->type != TK_NK_BOOL &&
1697
0
       pToken->type != TK_NULL && pToken->type != TK_NK_HEX && pToken->type != TK_NK_OCT && pToken->type != TK_NK_BIN &&
1698
0
       pToken->type != TK_NK_VARIABLE &&
1699
0
       pToken->type != TK_FROM_BASE64 && pToken->type != TK_TO_BASE64 &&
1700
0
       pToken->type != TK_MD5 && pToken->type != TK_SHA && pToken->type != TK_SHA1 && pToken->type != TK_SHA2 &&
1701
0
       pToken->type != TK_AES_ENCRYPT && pToken->type != TK_AES_DECRYPT &&
1702
0
       pToken->type != TK_SM4_ENCRYPT && pToken->type != TK_SM4_DECRYPT) ||
1703
0
      (pToken->n == 0) || (pToken->type == TK_NK_RP)) {
1704
0
    return buildSyntaxErrMsg(pMsgBuf, "invalid data or symbol", pToken->z);
1705
0
  }
1706
1707
  // Remove quotation marks
1708
0
  if (TK_NK_STRING == pToken->type && type != TSDB_DATA_TYPE_VARBINARY && !IS_STR_DATA_BLOB(type)) {
1709
0
    if (!IS_STR_DATA_BLOB(type)) {
1710
0
      if (pToken->n >= TSDB_MAX_BYTES_PER_ROW) {
1711
0
        return buildSyntaxErrMsg(pMsgBuf, "too long string", pToken->z);
1712
0
      }
1713
1714
0
      int32_t len = trimString(pToken->z, pToken->n, tmpTokenBuf, TSDB_MAX_BYTES_PER_ROW);
1715
0
      pToken->z = tmpTokenBuf;
1716
0
      pToken->n = len;
1717
0
    } else {
1718
0
      if (pToken->n >= TSDB_MAX_BLOB_LEN) {
1719
0
        return buildSyntaxErrMsg(pMsgBuf, "too long blob", pToken->z);
1720
0
      }
1721
1722
0
      int32_t len = trimString(pToken->z, pToken->n, tmpTokenBuf, TSDB_MAX_BLOB_LEN);
1723
0
      pToken->z = tmpTokenBuf;
1724
0
      pToken->n = len;
1725
0
    }
1726
0
  }
1727
1728
0
  return TSDB_CODE_SUCCESS;
1729
0
}
1730
1731
typedef struct SRewriteTagCondCxt {
1732
  SArray* pTagVals;
1733
  SArray* pTagName;
1734
  int32_t code;
1735
} SRewriteTagCondCxt;
1736
1737
0
static int32_t rewriteTagCondColumnImpl(STagVal* pVal, SNode** pNode) {
1738
0
  SValueNode* pValue = NULL;
1739
0
  int32_t     code = nodesMakeNode(QUERY_NODE_VALUE, (SNode**)&pValue);
1740
0
  if (NULL == pValue) {
1741
0
    return code;
1742
0
  }
1743
1744
0
  pValue->node.resType = ((SColumnNode*)*pNode)->node.resType;
1745
0
  nodesDestroyNode(*pNode);
1746
0
  *pNode = (SNode*)pValue;
1747
1748
0
  switch (pVal->type) {
1749
0
    case TSDB_DATA_TYPE_BOOL:
1750
0
      pValue->datum.b = *(int8_t*)(&pVal->i64);
1751
0
      *(bool*)&pValue->typeData = pValue->datum.b;
1752
0
      break;
1753
0
    case TSDB_DATA_TYPE_TINYINT:
1754
0
      pValue->datum.i = *(int8_t*)(&pVal->i64);
1755
0
      *(int8_t*)&pValue->typeData = pValue->datum.i;
1756
0
      break;
1757
0
    case TSDB_DATA_TYPE_SMALLINT:
1758
0
      pValue->datum.i = *(int16_t*)(&pVal->i64);
1759
0
      *(int16_t*)&pValue->typeData = pValue->datum.i;
1760
0
      break;
1761
0
    case TSDB_DATA_TYPE_INT:
1762
0
      pValue->datum.i = *(int32_t*)(&pVal->i64);
1763
0
      *(int32_t*)&pValue->typeData = pValue->datum.i;
1764
0
      break;
1765
0
    case TSDB_DATA_TYPE_BIGINT:
1766
0
      pValue->datum.i = pVal->i64;
1767
0
      pValue->typeData = pValue->datum.i;
1768
0
      break;
1769
0
    case TSDB_DATA_TYPE_FLOAT:
1770
0
      pValue->datum.d = *(float*)(&pVal->i64);
1771
0
      *(float*)&pValue->typeData = pValue->datum.d;
1772
0
      break;
1773
0
    case TSDB_DATA_TYPE_DOUBLE:
1774
0
      pValue->datum.d = *(double*)(&pVal->i64);
1775
0
      *(double*)&pValue->typeData = pValue->datum.d;
1776
0
      break;
1777
0
    case TSDB_DATA_TYPE_VARCHAR:
1778
0
    case TSDB_DATA_TYPE_VARBINARY:
1779
0
    case TSDB_DATA_TYPE_NCHAR:
1780
0
      pValue->datum.p = taosMemoryCalloc(1, pVal->nData + VARSTR_HEADER_SIZE);
1781
0
      if (NULL == pValue->datum.p) {
1782
0
        return terrno;
1783
0
      }
1784
0
      varDataSetLen(pValue->datum.p, pVal->nData);
1785
0
      memcpy(varDataVal(pValue->datum.p), pVal->pData, pVal->nData);
1786
0
      break;
1787
0
    case TSDB_DATA_TYPE_TIMESTAMP:
1788
0
      pValue->datum.i = pVal->i64;
1789
0
      pValue->typeData = pValue->datum.i;
1790
0
      break;
1791
0
    case TSDB_DATA_TYPE_UTINYINT:
1792
0
      pValue->datum.i = *(uint8_t*)(&pVal->i64);
1793
0
      *(uint8_t*)&pValue->typeData = pValue->datum.i;
1794
0
      break;
1795
0
    case TSDB_DATA_TYPE_USMALLINT:
1796
0
      pValue->datum.i = *(uint16_t*)(&pVal->i64);
1797
0
      *(uint16_t*)&pValue->typeData = pValue->datum.i;
1798
0
      break;
1799
0
    case TSDB_DATA_TYPE_UINT:
1800
0
      pValue->datum.i = *(uint32_t*)(&pVal->i64);
1801
0
      *(uint32_t*)&pValue->typeData = pValue->datum.i;
1802
0
      break;
1803
0
    case TSDB_DATA_TYPE_UBIGINT:
1804
0
      pValue->datum.i = *(uint64_t*)(&pVal->i64);
1805
0
      *(uint64_t*)&pValue->typeData = pValue->datum.i;
1806
0
      break;
1807
0
    case TSDB_DATA_TYPE_JSON:
1808
0
    case TSDB_DATA_TYPE_DECIMAL:
1809
0
    case TSDB_DATA_TYPE_BLOB:
1810
0
    case TSDB_DATA_TYPE_MEDIUMBLOB:
1811
0
    default:
1812
0
      return TSDB_CODE_FAILED;
1813
0
  }
1814
0
  return TSDB_CODE_SUCCESS;
1815
0
}
1816
1817
0
static int32_t rewriteTagCondColumn(SArray* pTagVals, SArray* pTagName, SNode** pNode) {
1818
0
  SColumnNode* pCol = (SColumnNode*)*pNode;
1819
0
  int32_t      ntags = taosArrayGetSize(pTagName);
1820
0
  for (int32_t i = 0; i < ntags; ++i) {
1821
0
    char* pTagColName = taosArrayGet(pTagName, i);
1822
0
    if (0 == strcmp(pTagColName, pCol->colName)) {
1823
0
      return rewriteTagCondColumnImpl(taosArrayGet(pTagVals, i), pNode);
1824
0
    }
1825
0
  }
1826
0
  return TSDB_CODE_PAR_PERMISSION_DENIED;
1827
0
}
1828
1829
0
static EDealRes rewriteTagCond(SNode** pNode, void* pContext) {
1830
0
  if (QUERY_NODE_COLUMN == nodeType(*pNode)) {
1831
0
    SRewriteTagCondCxt* pCxt = pContext;
1832
0
    pCxt->code = rewriteTagCondColumn(pCxt->pTagVals, pCxt->pTagName, pNode);
1833
0
    return (TSDB_CODE_SUCCESS == pCxt->code ? DEAL_RES_IGNORE_CHILD : DEAL_RES_ERROR);
1834
0
  }
1835
0
  return DEAL_RES_CONTINUE;
1836
0
}
1837
1838
0
static int32_t setTagVal(SArray* pTagVals, SArray* pTagName, SNode* pCond) {
1839
0
  SRewriteTagCondCxt cxt = {.code = TSDB_CODE_SUCCESS, .pTagVals = pTagVals, .pTagName = pTagName};
1840
0
  nodesRewriteExpr(&pCond, rewriteTagCond, &cxt);
1841
0
  return cxt.code;
1842
0
}
1843
1844
0
static int32_t checkTagCondResult(SNode* pResult) {
1845
0
  return (QUERY_NODE_VALUE == nodeType(pResult) && ((SValueNode*)pResult)->datum.b) ? TSDB_CODE_SUCCESS
1846
0
                                                                                    : TSDB_CODE_PAR_PERMISSION_DENIED;
1847
0
}
1848
1849
0
static int32_t checkSubtablePrivilege(SArray* pTagVals, SArray* pTagName, SNode** pCond) {
1850
0
  int32_t code = setTagVal(pTagVals, pTagName, *pCond);
1851
0
  if (TSDB_CODE_SUCCESS == code) {
1852
0
    code = scalarCalculateConstants(*pCond, pCond);
1853
0
  }
1854
0
  if (TSDB_CODE_SUCCESS == code) {
1855
0
    code = checkTagCondResult(*pCond);
1856
0
  }
1857
0
  NODES_DESTORY_NODE(*pCond);
1858
0
  return code;
1859
0
}
1860
1861
// pSql -> tag1_value, ...)
1862
0
static int32_t parseTagsClauseImpl(SInsertParseContext* pCxt, SVnodeModifyOpStmt* pStmt, bool autoCreate) {
1863
0
  int32_t  code = TSDB_CODE_SUCCESS;
1864
0
  SSchema* pSchema = getTableTagSchema(pStmt->pTableMeta);
1865
0
  SArray*  pTagVals = NULL;
1866
0
  SArray*  pTagName = NULL;
1867
0
  uint8_t  precision = pStmt->pTableMeta->tableInfo.precision;
1868
0
  SToken   token;
1869
0
  bool     isJson = false;
1870
0
  STag*    pTag = NULL;
1871
0
  uint8_t* pTagsIndex;
1872
0
  int32_t  numOfTags = 0;
1873
1874
0
  if (pCxt->pComCxt->stmtBindVersion == 2) {  // only support stmt2
1875
0
    pTagsIndex = taosMemoryCalloc(pCxt->tags.numOfBound, sizeof(uint8_t));
1876
0
  }
1877
1878
0
  if (!(pTagVals = taosArrayInit(pCxt->tags.numOfBound, sizeof(STagVal))) ||
1879
0
      !(pTagName = taosArrayInit(pCxt->tags.numOfBound, TSDB_COL_NAME_LEN + sizeof(col_id_t)))) {
1880
0
    code = terrno;
1881
0
    goto _exit;
1882
0
  }
1883
1884
0
  for (int i = 0; TSDB_CODE_SUCCESS == code && i < pCxt->tags.numOfBound; ++i) {
1885
0
    NEXT_TOKEN_WITH_PREV(pStmt->pSql, token);
1886
1887
0
    if (token.type == TK_NK_QUESTION) {
1888
0
      if (pCxt->pComCxt->stmtBindVersion == 0) {
1889
0
        code = buildSyntaxErrMsg(&pCxt->msg, "? only used in stmt", token.z);
1890
0
        break;
1891
0
      }
1892
1893
0
      continue;
1894
0
    }
1895
1896
0
    SSchema* pTagSchema = &pSchema[pCxt->tags.pColIndex[i]];
1897
0
    isJson = pTagSchema->type == TSDB_DATA_TYPE_JSON;
1898
0
    code = checkAndTrimValue(&token, pCxt->tmpTokenBuf, &pCxt->msg, pTagSchema->type);
1899
0
    if (TSDB_CODE_SUCCESS == code && TK_NK_VARIABLE == token.type) {
1900
0
      code = buildSyntaxErrMsg(&pCxt->msg, "not expected tags values ", token.z);
1901
0
    }
1902
0
    if (TSDB_CODE_SUCCESS == code) {
1903
0
      code = parseTagValue(&pCxt->msg, &pStmt->pSql, precision, pTagSchema, &token, pTagName, pTagVals, &pTag,
1904
0
                           pCxt->pComCxt->timezone, pCxt->pComCxt->charsetCxt);
1905
0
    }
1906
0
    if (pCxt->pComCxt->stmtBindVersion == 2) {
1907
0
      pTagsIndex[numOfTags++] = pCxt->tags.pColIndex[i];
1908
0
    }
1909
0
  }
1910
1911
0
  if (TSDB_CODE_SUCCESS == code && NULL != pStmt->pTagCond) {
1912
0
    code = checkSubtablePrivilege(pTagVals, pTagName, &pStmt->pTagCond);
1913
0
  }
1914
1915
0
  if (TSDB_CODE_SUCCESS == code && pCxt->pComCxt->stmtBindVersion == 2) {
1916
0
    if (numOfTags > 0) {
1917
0
      if (pTagVals->size == pCxt->tags.numOfBound) {
1918
0
        pCxt->stmtTbNameFlag |= IS_FIXED_TAG;
1919
0
      } else {
1920
0
        pCxt->stmtTbNameFlag &= ~IS_FIXED_TAG;
1921
0
        pCxt->tags.parseredTags = taosMemoryMalloc(sizeof(STagsInfo));
1922
0
        if (pCxt->tags.parseredTags == NULL) {
1923
0
          code = terrno;
1924
0
          goto _exit;
1925
0
        }
1926
0
        pCxt->tags.parseredTags->numOfTags = numOfTags;
1927
0
        pCxt->tags.parseredTags->pTagIndex = pTagsIndex;
1928
0
        pCxt->tags.parseredTags->pTagVals = pTagVals;
1929
0
        pCxt->tags.parseredTags->STagNames = pTagName;
1930
0
      }
1931
0
    } else {
1932
0
      goto _exit;
1933
0
    }
1934
0
  }
1935
1936
0
  if (TSDB_CODE_SUCCESS == code && !isJson) {
1937
0
    taosArraySort(pTagName, tTagNameCompare);
1938
0
    code = tTagNew(pTagVals, 1, false, &pTag);
1939
0
  }
1940
1941
0
  if (TSDB_CODE_SUCCESS == code && !autoCreate) {
1942
0
    code = buildCreateTbReq(pStmt, pTag, pTagName);
1943
0
    pTag = NULL;
1944
0
  }
1945
1946
0
_exit:
1947
0
  if (pCxt->tags.parseredTags == NULL) {
1948
0
    for (int32_t i = 0; i < taosArrayGetSize(pTagVals); ++i) {
1949
0
      STagVal* p = (STagVal*)TARRAY_GET_ELEM(pTagVals, i);
1950
0
      if (IS_VAR_DATA_TYPE(p->type)) {
1951
0
        taosMemoryFreeClear(p->pData);
1952
0
      }
1953
0
    }
1954
0
    taosArrayDestroy(pTagVals);
1955
0
    taosArrayDestroy(pTagName);
1956
0
    if (pCxt->pComCxt->stmtBindVersion == 2) {
1957
0
      taosMemoryFreeClear(pTagsIndex);
1958
0
    }
1959
0
  }
1960
1961
0
  tTagFree(pTag);
1962
0
  return code;
1963
0
}
1964
1965
// input pStmt->pSql:  TAGS (tag1_value, ...) [table_options] ...
1966
// output pStmt->pSql: [table_options] ...
1967
0
static int32_t parseTagsClause(SInsertParseContext* pCxt, SVnodeModifyOpStmt* pStmt, bool autoCreate) {
1968
0
  SToken token;
1969
0
  NEXT_TOKEN(pStmt->pSql, token);
1970
0
  if (TK_TAGS != token.type) {
1971
0
    return buildSyntaxErrMsg(&pCxt->msg, "TAGS is expected", token.z);
1972
0
  }
1973
1974
0
  NEXT_TOKEN(pStmt->pSql, token);
1975
0
  if (TK_NK_LP != token.type) {
1976
0
    return buildSyntaxErrMsg(&pCxt->msg, "( is expected", token.z);
1977
0
  }
1978
1979
0
  int32_t code = parseTagsClauseImpl(pCxt, pStmt, autoCreate);
1980
0
  if (TSDB_CODE_SUCCESS == code) {
1981
0
    NEXT_VALID_TOKEN(pStmt->pSql, token);
1982
0
    if (TK_NK_COMMA == token.type) {
1983
0
      code = generateSyntaxErrMsg(&pCxt->msg, TSDB_CODE_PAR_TAGS_NOT_MATCHED);
1984
0
    } else if (TK_NK_RP != token.type) {
1985
0
      code = buildSyntaxErrMsg(&pCxt->msg, ") is expected", token.z);
1986
0
    }
1987
0
  }
1988
0
  return code;
1989
0
}
1990
1991
0
static int32_t storeChildTableMeta(SInsertParseContext* pCxt, SVnodeModifyOpStmt* pStmt) {
1992
0
  pStmt->pTableMeta->suid = pStmt->pTableMeta->uid;
1993
0
  pStmt->pTableMeta->uid = pStmt->totalTbNum;
1994
0
  pStmt->pTableMeta->tableType = TSDB_CHILD_TABLE;
1995
1996
0
  STableMeta* pBackup = NULL;
1997
0
  if (TSDB_CODE_SUCCESS != cloneTableMeta(pStmt->pTableMeta, &pBackup)) {
1998
0
    return TSDB_CODE_OUT_OF_MEMORY;
1999
0
  }
2000
2001
0
  char    tbFName[TSDB_TABLE_FNAME_LEN];
2002
0
  int32_t code = tNameExtractFullName(&pStmt->targetTableName, tbFName);
2003
0
  if (TSDB_CODE_SUCCESS != code) {
2004
0
    taosMemoryFree(pBackup);
2005
0
    return code;
2006
0
  }
2007
0
  code = taosHashPut(pStmt->pSubTableHashObj, tbFName, strlen(tbFName), &pBackup, POINTER_BYTES);
2008
0
  if (TSDB_CODE_SUCCESS != code) {
2009
0
    taosMemoryFree(pBackup);
2010
0
  }
2011
0
  return code;
2012
0
}
2013
2014
0
static int32_t parseTableOptions(SInsertParseContext* pCxt, SVnodeModifyOpStmt* pStmt) {
2015
0
  do {
2016
0
    int32_t index = 0;
2017
0
    SToken  token;
2018
0
    NEXT_TOKEN_KEEP_SQL(pStmt->pSql, token, index);
2019
0
    if (TK_TTL == token.type) {
2020
0
      pStmt->pSql += index;
2021
0
      NEXT_TOKEN_WITH_PREV(pStmt->pSql, token);
2022
0
      if (TK_NK_INTEGER != token.type) {
2023
0
        return buildSyntaxErrMsg(&pCxt->msg, "Invalid option ttl", token.z);
2024
0
      }
2025
0
      pStmt->pCreateTblReq->ttl = taosStr2Int32(token.z, NULL, 10);
2026
0
      if (pStmt->pCreateTblReq->ttl < 0) {
2027
0
        return buildSyntaxErrMsg(&pCxt->msg, "Invalid option ttl", token.z);
2028
0
      }
2029
0
    } else if (TK_COMMENT == token.type) {
2030
0
      pStmt->pSql += index;
2031
0
      NEXT_TOKEN(pStmt->pSql, token);
2032
0
      if (TK_NK_STRING != token.type) {
2033
0
        return buildSyntaxErrMsg(&pCxt->msg, "Invalid option comment", token.z);
2034
0
      }
2035
0
      if (token.n >= TSDB_TB_COMMENT_LEN) {
2036
0
        return buildSyntaxErrMsg(&pCxt->msg, "comment too long", token.z);
2037
0
      }
2038
0
      int32_t len = trimString(token.z, token.n, pCxt->tmpTokenBuf, TSDB_TB_COMMENT_LEN);
2039
0
      pStmt->pCreateTblReq->comment = taosStrndup(pCxt->tmpTokenBuf, len);
2040
0
      if (NULL == pStmt->pCreateTblReq->comment) {
2041
0
        return terrno;
2042
0
      }
2043
0
      pStmt->pCreateTblReq->commentLen = len;
2044
0
    } else {
2045
0
      break;
2046
0
    }
2047
0
  } while (1);
2048
0
  return TSDB_CODE_SUCCESS;
2049
0
}
2050
2051
// input pStmt->pSql:
2052
//   1. [(tag1_name, ...)] ...
2053
//   2. VALUES ... | FILE ...
2054
// output pStmt->pSql:
2055
//   1. [(field1_name, ...)]
2056
//   2. VALUES ... | FILE ...
2057
0
static int32_t parseUsingClauseBottom(SInsertParseContext* pCxt, SVnodeModifyOpStmt* pStmt) {
2058
0
  if (!pStmt->usingTableProcessing || pCxt->usingDuplicateTable) {
2059
0
    return TSDB_CODE_SUCCESS;
2060
0
  }
2061
2062
0
  int32_t code = parseBoundTagsClause(pCxt, pStmt);
2063
0
  if (TSDB_CODE_SUCCESS == code) {
2064
0
    code = parseTagsClause(pCxt, pStmt, false);
2065
0
  }
2066
0
  if (TSDB_CODE_SUCCESS == code) {
2067
0
    code = parseTableOptions(pCxt, pStmt);
2068
0
  }
2069
2070
0
  return code;
2071
0
}
2072
2073
0
static void setUserAuthInfo(SParseContext* pCxt, SName* pTbName, SUserAuthInfo* pInfo) {
2074
0
  snprintf(pInfo->user, sizeof(pInfo->user), "%s", pCxt->pUser);
2075
0
  memcpy(&pInfo->tbName, pTbName, sizeof(SName));
2076
0
  pInfo->userId = pCxt->userId;
2077
0
  pInfo->privType = PRIV_TBL_INSERT;
2078
0
  pInfo->objType = PRIV_OBJ_TBL;
2079
0
}
2080
2081
// Check CREATE TABLE privilege on the database of pTbName.
2082
// Uses the same sync/async/cache-miss logic as checkAuth().
2083
0
static int32_t checkCreateTableAuth(SParseContext* pCxt, SName* pTbName, bool* pMissCache) {
2084
0
  SUserAuthInfo authInfo = {.userId = pCxt->userId,
2085
0
                            .tbName = {.acctId = pTbName->acctId, .type = TSDB_DB_NAME_T},
2086
0
                            .privType = PRIV_TBL_CREATE,
2087
0
                            .objType = PRIV_OBJ_DB};
2088
0
  (void)snprintf(authInfo.user, sizeof(authInfo.user), "%s", pCxt->pUser);
2089
0
  (void)snprintf(authInfo.tbName.dbname, sizeof(authInfo.tbName.dbname), "%s", pTbName->dbname);
2090
2091
0
  SUserAuthRes authRes = {0};
2092
0
  SUserAuthRsp authRsp = {.exists = 1};
2093
0
  int32_t      code = 0;
2094
0
  if (pCxt->async) {
2095
0
    code = catalogChkAuthFromCache(pCxt->pCatalog, &authInfo, &authRes, &authRsp);
2096
0
    if (TSDB_CODE_SUCCESS == code && 0 == authRsp.exists) {
2097
0
      if(pMissCache) *pMissCache = true;
2098
0
      return TSDB_CODE_SUCCESS;
2099
0
    }
2100
0
  } else {
2101
0
    SRequestConnInfo conn = {.pTrans = pCxt->pTransporter,
2102
0
                             .requestId = pCxt->requestId,
2103
0
                             .requestObjRefId = pCxt->requestRid,
2104
0
                             .mgmtEps = pCxt->mgmtEpSet};
2105
0
    code = catalogChkAuth(pCxt->pCatalog, &conn, &authInfo, &authRes);
2106
0
  }
2107
0
  if (TSDB_CODE_SUCCESS == code && !authRes.pass[AUTH_RES_BASIC]) {
2108
0
    code = TSDB_CODE_PAR_PERMISSION_DENIED;
2109
0
  }
2110
0
  return code;
2111
0
}
2112
2113
static int32_t checkAuth(SParseContext* pCxt, SName* pTbName, bool isAudit, bool* pMissCache, bool* pWithInsertCond, SNode** pTagCond,
2114
0
                         SArray** pPrivCols) {
2115
0
  int32_t       code = TSDB_CODE_SUCCESS;
2116
0
  SUserAuthInfo authInfo = {0};
2117
0
  setUserAuthInfo(pCxt, pTbName, &authInfo);
2118
0
  if (isAudit) {
2119
0
    authInfo.privType = PRIV_AUDIT_TBL_INSERT;
2120
0
    authInfo.objType = PRIV_OBJ_CLUSTER;
2121
0
  }
2122
0
  SUserAuthRes authRes = {0};
2123
0
  SUserAuthRsp authRsp = {.exists = 1};
2124
0
  if (pCxt->async) {
2125
0
    code = catalogChkAuthFromCache(pCxt->pCatalog, &authInfo, &authRes, &authRsp);
2126
0
  } else {
2127
0
    SRequestConnInfo conn = {.pTrans = pCxt->pTransporter,
2128
0
                             .requestId = pCxt->requestId,
2129
0
                             .requestObjRefId = pCxt->requestRid,
2130
0
                             .mgmtEps = pCxt->mgmtEpSet};
2131
0
    code = catalogChkAuth(pCxt->pCatalog, &conn, &authInfo, &authRes);
2132
0
  }
2133
0
  if (TSDB_CODE_SUCCESS == code) {
2134
0
    if (0 == authRsp.exists) {
2135
0
      *pMissCache = true;
2136
0
    } else if (!authRes.pass[AUTH_RES_BASIC]) {
2137
0
      code = TSDB_CODE_PAR_PERMISSION_DENIED;
2138
0
    } else {
2139
0
      if (pTagCond && authRes.pCond[AUTH_RES_BASIC]) {
2140
0
        *pTagCond = authRes.pCond[AUTH_RES_BASIC];
2141
0
      }
2142
0
      if (pPrivCols && authRes.pCols) {
2143
0
        *pPrivCols = authRes.pCols;
2144
0
      }
2145
0
      *pMissCache = false;
2146
0
    }
2147
0
    if (pWithInsertCond) {
2148
0
      *pWithInsertCond = (authRsp.withInsertCond == 1);
2149
0
    }
2150
0
  }
2151
0
  return code;
2152
0
}
2153
2154
static int32_t getTableMeta(SInsertParseContext* pCxt, SName* pTbName, STableMeta** pTableMeta, bool* pMissCache,
2155
0
                            bool bUsingTable) {
2156
0
  SParseContext* pComCxt = pCxt->pComCxt;
2157
0
  int32_t        code = TSDB_CODE_SUCCESS;
2158
0
  if (pComCxt->async) {
2159
0
    if (bUsingTable) {
2160
0
      code = catalogGetCachedSTableMeta(pComCxt->pCatalog, pTbName, pTableMeta);
2161
0
    } else {
2162
0
      code = catalogGetCachedTableMeta(pComCxt->pCatalog, pTbName, pTableMeta);
2163
0
    }
2164
0
  } else {
2165
0
    SRequestConnInfo conn = {.pTrans = pComCxt->pTransporter,
2166
0
                             .requestId = pComCxt->requestId,
2167
0
                             .requestObjRefId = pComCxt->requestRid,
2168
0
                             .mgmtEps = pComCxt->mgmtEpSet};
2169
0
    if (bUsingTable) {
2170
0
      code = catalogGetSTableMeta(pComCxt->pCatalog, &conn, pTbName, pTableMeta);
2171
0
    } else {
2172
0
      code = catalogGetTableMeta(pComCxt->pCatalog, &conn, pTbName, pTableMeta);
2173
0
    }
2174
0
  }
2175
0
  if (TSDB_CODE_SUCCESS == code) {
2176
0
    if (NULL == *pTableMeta) {
2177
0
      *pMissCache = true;
2178
0
    } else if (bUsingTable && TSDB_SUPER_TABLE != (*pTableMeta)->tableType) {
2179
0
      code = buildInvalidOperationMsg(&pCxt->msg, "create table only from super table is allowed");
2180
0
    } else if (((*pTableMeta)->virtualStb) || TSDB_VIRTUAL_CHILD_TABLE == (*pTableMeta)->tableType ||
2181
0
               TSDB_VIRTUAL_NORMAL_TABLE == (*pTableMeta)->tableType) {
2182
0
      code = TSDB_CODE_VTABLE_NOT_SUPPORT_STMT;
2183
0
    }
2184
0
  }
2185
0
  return code;
2186
0
}
2187
2188
0
static int32_t getTargetTableVgroup(SParseContext* pCxt, SVnodeModifyOpStmt* pStmt, bool isStb, bool* pMissCache) {
2189
0
  int32_t     code = TSDB_CODE_SUCCESS;
2190
0
  SVgroupInfo vg;
2191
0
  bool        exists = true;
2192
0
  if (pCxt->async) {
2193
0
    code = catalogGetCachedTableHashVgroup(pCxt->pCatalog, &pStmt->targetTableName, &vg, &exists);
2194
0
  } else {
2195
0
    SRequestConnInfo conn = {.pTrans = pCxt->pTransporter,
2196
0
                             .requestId = pCxt->requestId,
2197
0
                             .requestObjRefId = pCxt->requestRid,
2198
0
                             .mgmtEps = pCxt->mgmtEpSet};
2199
0
    code = catalogGetTableHashVgroup(pCxt->pCatalog, &conn, &pStmt->targetTableName, &vg);
2200
0
  }
2201
0
  if (TSDB_CODE_SUCCESS == code) {
2202
0
    if (exists) {
2203
0
      if (isStb) {
2204
0
        pStmt->pTableMeta->vgId = vg.vgId;
2205
0
      }
2206
0
      code = taosHashPut(pStmt->pVgroupsHashObj, (const char*)&vg.vgId, sizeof(vg.vgId), (char*)&vg, sizeof(vg));
2207
0
    }
2208
0
    *pMissCache = !exists;
2209
0
  }
2210
0
  return code;
2211
0
}
2212
2213
0
static int32_t getTargetTableMetaAndVgroup(SInsertParseContext* pCxt, SVnodeModifyOpStmt* pStmt, bool* pMissCache) {
2214
0
  SParseContext* pComCxt = pCxt->pComCxt;
2215
0
  int32_t        code = TSDB_CODE_SUCCESS;
2216
0
  if (pComCxt->async) {
2217
0
    {
2218
0
      SVgroupInfo vg;
2219
0
      code = catalogGetCachedTableVgMeta(pComCxt->pCatalog, &pStmt->targetTableName, &vg, &pStmt->pTableMeta);
2220
0
      if (TSDB_CODE_SUCCESS == code) {
2221
0
        if (NULL != pStmt->pTableMeta) {
2222
0
          if (pStmt->pTableMeta->tableType == TSDB_SUPER_TABLE) {
2223
0
            pStmt->stbSyntax = true;
2224
0
          } else {
2225
0
            code = taosHashPut(pStmt->pVgroupsHashObj, (const char*)&vg.vgId, sizeof(vg.vgId), (char*)&vg, sizeof(vg));
2226
0
          }
2227
0
        }
2228
0
        *pMissCache = (NULL == pStmt->pTableMeta);
2229
0
      }
2230
0
    }
2231
0
  } else {
2232
0
    bool bUsingTable = false;
2233
0
    code = getTableMeta(pCxt, &pStmt->targetTableName, &pStmt->pTableMeta, pMissCache, bUsingTable);
2234
0
    if (TSDB_CODE_SUCCESS == code && !pCxt->missCache) {
2235
0
      if (TSDB_SUPER_TABLE == pStmt->pTableMeta->tableType) {
2236
0
        pStmt->stbSyntax = true;
2237
0
      }
2238
0
      if (!pStmt->stbSyntax) {
2239
0
        code = getTargetTableVgroup(pCxt->pComCxt, pStmt, false, &pCxt->missCache);
2240
0
      }
2241
0
    }
2242
0
  }
2243
0
  return code;
2244
0
}
2245
2246
0
static int32_t collectUseTable(const SName* pName, SHashObj* pTable) {
2247
0
  char    fullName[TSDB_TABLE_FNAME_LEN];
2248
0
  int32_t code = tNameExtractFullName(pName, fullName);
2249
0
  if (TSDB_CODE_SUCCESS != code) {
2250
0
    return code;
2251
0
  }
2252
0
  return taosHashPut(pTable, fullName, strlen(fullName), pName, sizeof(SName));
2253
0
}
2254
2255
0
static int32_t collectUseDatabase(const SName* pName, SHashObj* pDbs) {
2256
0
  char dbFName[TSDB_DB_FNAME_LEN] = {0};
2257
0
  (void)tNameGetFullDbName(pName, dbFName);
2258
0
  return taosHashPut(pDbs, dbFName, strlen(dbFName), dbFName, sizeof(dbFName));
2259
0
}
2260
2261
0
static int32_t getTargetTableSchema(SInsertParseContext* pCxt, SVnodeModifyOpStmt* pStmt) {
2262
0
  if (pCxt->forceUpdate) {
2263
0
    pCxt->missCache = true;
2264
0
    return TSDB_CODE_SUCCESS;
2265
0
  }
2266
0
  SNode*  pTagCond = NULL;
2267
0
  SArray* pPrivCols = NULL;
2268
0
  bool    withInsertCond = false;
2269
0
  int32_t code = checkAuth(pCxt->pComCxt, &pStmt->targetTableName, false, &pCxt->missCache, &withInsertCond, &pTagCond,
2270
0
                           &pPrivCols);
2271
0
  if (TSDB_CODE_SUCCESS == code && !pCxt->missCache) {
2272
0
    code = getTargetTableMetaAndVgroup(pCxt, pStmt, &pCxt->missCache);
2273
0
  }
2274
#ifdef TD_ENTERPRISE
2275
  // MAC NWD+NRU: for INSERT, user.minSecLevel <= table.secLvl <= user.maxSecLevel
2276
  // Only enforced when MAC is explicitly activated cluster-wide.
2277
  // Logic mirrors macCheckBySecLvl() in parAuthenticator.c (inline here because SInsertParseContext
2278
  // does not carry an SAuthCxt).
2279
  if (pCxt->pComCxt->macMode && TSDB_CODE_SUCCESS == code && !pCxt->missCache && pStmt->pTableMeta != NULL) {
2280
    int8_t secLvl = pStmt->pTableMeta->secLvl;
2281
    if (secLvl >= 0) {
2282
      if (pCxt->pComCxt->minSecLevel > secLvl) {
2283
        code = TSDB_CODE_MAC_NO_WRITE_DOWN;  // NWD violation
2284
      } else if (pCxt->pComCxt->maxSecLevel < secLvl) {
2285
        code = TSDB_CODE_MAC_INSUFFICIENT_LEVEL;  // NRU violation
2286
      }
2287
    }
2288
  }
2289
#endif
2290
2291
0
  if (TSDB_CODE_SUCCESS == code) {
2292
0
    if (pPrivCols) pStmt->pPrivCols = pPrivCols;
2293
#ifdef TD_ENTERPRISE
2294
#if 0
2295
    if (pStmt->pTableMeta && pStmt->pTableMeta->isAudit) {
2296
      // recheck for audit table
2297
      code = checkAuth(pCxt->pComCxt, &pStmt->targetTableName, true, &pCxt->missCache, NULL, NULL, NULL);
2298
      if (TSDB_CODE_SUCCESS != code) {
2299
        nodesDestroyNode(pTagCond);
2300
        return code;
2301
      }
2302
    }
2303
#endif
2304
    if (!pCxt->missCache) {
2305
      if (TSDB_SUPER_TABLE != pStmt->pTableMeta->tableType) {
2306
        pCxt->needTableTagVal = (NULL != pTagCond);
2307
        pCxt->missCache = (NULL != pTagCond);
2308
      } else {
2309
        pStmt->pTagCond = pTagCond;
2310
        pTagCond = NULL;
2311
      }
2312
    } else if (withInsertCond && !pCxt->pComCxt->isSuperUser) {
2313
      // If miss cache, always request tag value and reserved for permission check later if pTagCond exists. This may
2314
      // lead to redundant request but ensure correctness, and this only happens when cache is invalid or first time
2315
      // insert.
2316
      pCxt->needTableTagVal = true;
2317
    }
2318
#else
2319
0
    pStmt->pTagCond = NULL;
2320
0
#endif
2321
0
  }
2322
0
  if (pTagCond) nodesDestroyNode(pTagCond);
2323
2324
0
  if (TSDB_CODE_SUCCESS == code && !pCxt->pComCxt->async) {
2325
0
    code = collectUseDatabase(&pStmt->targetTableName, pStmt->pDbFNameHashObj);
2326
0
    if (TSDB_CODE_SUCCESS == code) {
2327
0
      code = collectUseTable(&pStmt->targetTableName, pStmt->pTableNameHashObj);
2328
0
    }
2329
0
  }
2330
0
  return code;
2331
0
}
2332
2333
0
static int32_t preParseUsingTableName(SInsertParseContext* pCxt, SVnodeModifyOpStmt* pStmt, SToken* pTbName) {
2334
0
  return insCreateSName(&pStmt->usingTableName, pTbName, pCxt->pComCxt->acctId, pCxt->pComCxt->db, &pCxt->msg);
2335
0
}
2336
2337
0
static int32_t getUsingTableSchema(SInsertParseContext* pCxt, SVnodeModifyOpStmt* pStmt, bool* ctbCacheHit) {
2338
0
  int32_t     code = TSDB_CODE_SUCCESS;
2339
0
  STableMeta* pStableMeta = NULL;
2340
0
  STableMeta* pCtableMeta = NULL;
2341
0
  if (pCxt->forceUpdate) {
2342
0
    pCxt->missCache = true;
2343
0
    return TSDB_CODE_SUCCESS;
2344
0
  }
2345
0
  char stableFName[TSDB_TABLE_FNAME_LEN];
2346
0
  code = tNameExtractFullName(&pStmt->usingTableName, stableFName);
2347
0
  if (TSDB_CODE_SUCCESS != code) {
2348
0
    return code;
2349
0
  }
2350
2351
0
  char ctableFName[TSDB_TABLE_FNAME_LEN];
2352
0
  code = tNameExtractFullName(&pStmt->targetTableName, ctableFName);
2353
0
  if (TSDB_CODE_SUCCESS != code) {
2354
0
    return code;
2355
0
  }
2356
2357
0
  if (strcmp(stableFName, ctableFName) == 0) {
2358
0
    return TSDB_CODE_TDB_TABLE_IN_OTHER_STABLE;
2359
0
  }
2360
0
  if (!pCxt->missCache) {
2361
0
    char tbFName[TSDB_TABLE_FNAME_LEN];
2362
0
    code = tNameExtractFullName(&pStmt->usingTableName, tbFName);
2363
0
    if (TSDB_CODE_SUCCESS != code) {
2364
0
      return code;
2365
0
    }
2366
0
    STableMeta** ppStableMeta = taosHashGet(pStmt->pSuperTableHashObj, tbFName, strlen(tbFName));
2367
0
    if (NULL != ppStableMeta) {
2368
0
      pStableMeta = *ppStableMeta;
2369
0
    }
2370
0
    if (NULL == pStableMeta) {
2371
0
      bool bUsingTable = true;
2372
0
      code = getTableMeta(pCxt, &pStmt->usingTableName, &pStableMeta, &pCxt->missCache, bUsingTable);
2373
0
      if (TSDB_CODE_SUCCESS == code) {
2374
0
        code = taosHashPut(pStmt->pSuperTableHashObj, tbFName, strlen(tbFName), &pStableMeta, POINTER_BYTES);
2375
0
      } else {
2376
0
        taosMemoryFreeClear(pStableMeta);
2377
0
      }
2378
0
    }
2379
0
  }
2380
0
  if (pCxt->pComCxt->stmtBindVersion > 0) {
2381
0
    goto _no_ctb_cache;
2382
0
  }
2383
2384
0
  if (TSDB_CODE_SUCCESS == code && !pCxt->missCache) {
2385
0
    bool bUsingTable = false;
2386
0
    code = getTableMeta(pCxt, &pStmt->targetTableName, &pCtableMeta, &pCxt->missCache, bUsingTable);
2387
0
  }
2388
2389
0
  if (TSDB_CODE_SUCCESS == code && !pCxt->missCache) {
2390
0
    code = (pStableMeta->suid == pCtableMeta->suid) ? TSDB_CODE_SUCCESS : TSDB_CODE_TDB_TABLE_IN_OTHER_STABLE;
2391
0
    *ctbCacheHit = true;
2392
0
  }
2393
0
_no_ctb_cache:
2394
  // Check INSERT privilege on the super table.
2395
  // For the non-USING path this is done in getTargetTableSchema() → checkAuth(). We mirror it here.
2396
  // async second-round coverage: checkAuthFromMetaData() only runs when *pQuery != NULL (second round);
2397
  // the first-round sync path (createInsertQuery) performs no auth, so this call is always needed.
2398
0
  if (TSDB_CODE_SUCCESS == code && !pCxt->missCache) {
2399
0
    bool    missCache = false;
2400
0
    SNode*  pTagCond = NULL;
2401
0
    SArray* pPrivCols = NULL;
2402
0
    bool    withInsertCond = false;
2403
0
    code = checkAuth(pCxt->pComCxt, &pStmt->usingTableName, false, &missCache, &withInsertCond, &pTagCond, &pPrivCols);
2404
0
    if (TSDB_CODE_SUCCESS == code) {
2405
0
      if (!missCache) {
2406
        // Propagate row-condition and column-privilege to pStmt, exactly as getTargetTableSchema() does,
2407
        // so that tag-value privilege checks (checkSubtablePrivilege) and column-level INSERT
2408
        // restrictions are enforced for the super table on the USING write path.
2409
0
        if (pPrivCols) pStmt->pPrivCols = pPrivCols;
2410
0
        pStmt->pTagCond = pTagCond;
2411
0
        if (withInsertCond && !pCxt->pComCxt->isSuperUser && pTagCond == NULL) {
2412
0
          pCxt->needTableTagVal = true;
2413
0
        }
2414
0
      } else {
2415
0
        pCxt->missCache = true;
2416
0
        nodesDestroyNode(pTagCond);
2417
0
        taosArrayDestroy(pPrivCols);
2418
0
      }
2419
0
    }
2420
0
  }
2421
  // ctb does not exist: will be auto-created. Check CREATE TABLE privilege on the db.
2422
  // !missCache guard: async cache-miss defers to the second round (processTableSchemaFromMetaData).
2423
0
  if (TSDB_CODE_SUCCESS == code && !pCxt->missCache && !(*ctbCacheHit)) {
2424
0
    code = checkCreateTableAuth(pCxt->pComCxt, &pStmt->targetTableName, &pCxt->missCache);
2425
0
  }
2426
0
  if (TSDB_CODE_SUCCESS == code) {
2427
0
    if (*ctbCacheHit) {
2428
0
      code = cloneTableMeta(pCtableMeta, &pStmt->pTableMeta);
2429
0
    } else {
2430
0
      code = cloneTableMeta(pStableMeta, &pStmt->pTableMeta);
2431
0
    }
2432
0
  }
2433
0
  taosMemoryFree(pCtableMeta);
2434
0
  if (TSDB_CODE_SUCCESS == code && !pCxt->missCache) {
2435
0
    code = getTargetTableVgroup(pCxt->pComCxt, pStmt, true, &pCxt->missCache);
2436
0
  }
2437
0
  if (TSDB_CODE_SUCCESS == code && !pCxt->pComCxt->async) {
2438
0
    code = collectUseDatabase(&pStmt->usingTableName, pStmt->pDbFNameHashObj);
2439
0
    if (TSDB_CODE_SUCCESS == code) {
2440
0
      code = collectUseTable(&pStmt->usingTableName, pStmt->pTableNameHashObj);
2441
0
    }
2442
0
  }
2443
0
  return code;
2444
0
}
2445
2446
0
static int32_t parseUsingTableNameImpl(SInsertParseContext* pCxt, SVnodeModifyOpStmt* pStmt) {
2447
0
  SToken token;
2448
0
  NEXT_TOKEN(pStmt->pSql, token);
2449
0
  bool    ctbCacheHit = false;
2450
0
  int32_t code = preParseUsingTableName(pCxt, pStmt, &token);
2451
0
  if (TSDB_CODE_SUCCESS == code) {
2452
0
    code = getUsingTableSchema(pCxt, pStmt, &ctbCacheHit);
2453
0
    if (TSDB_CODE_SUCCESS == code && ctbCacheHit && !pCxt->missCache) {
2454
0
      pStmt->usingTableProcessing = false;
2455
0
      return ignoreUsingClauseAndCheckTagValues(pCxt, pStmt);
2456
0
    }
2457
0
  }
2458
0
  if (TSDB_CODE_SUCCESS == code && !pCxt->missCache) {
2459
0
    code = storeChildTableMeta(pCxt, pStmt);
2460
0
  }
2461
0
  return code;
2462
0
}
2463
2464
// input pStmt->pSql:
2465
//   1(care). [USING stb_name [(tag1_name, ...)] TAGS (tag1_value, ...) [table_options]] ...
2466
//   2. VALUES ... | FILE ...
2467
// output pStmt->pSql:
2468
//   1. [(tag1_name, ...)] TAGS (tag1_value, ...) [table_options]] ...
2469
//   2. VALUES ... | FILE ...
2470
0
static int32_t parseUsingTableName(SInsertParseContext* pCxt, SVnodeModifyOpStmt* pStmt) {
2471
0
  SToken  token;
2472
0
  int32_t index = 0;
2473
0
  NEXT_TOKEN_KEEP_SQL(pStmt->pSql, token, index);
2474
0
  if (TK_USING != token.type) {
2475
0
    return getTargetTableSchema(pCxt, pStmt);
2476
0
  }
2477
0
  pStmt->usingTableProcessing = true;
2478
0
  pCxt->stmtTbNameFlag |= USING_CLAUSE;
2479
  // pStmt->pSql -> stb_name [(tag1_name, ...)
2480
0
  pStmt->pSql += index;
2481
0
  int32_t code = parseDuplicateUsingClause(pCxt, pStmt, &pCxt->usingDuplicateTable);
2482
0
  if (TSDB_CODE_SUCCESS == code && !pCxt->usingDuplicateTable) {
2483
0
    return parseUsingTableNameImpl(pCxt, pStmt);
2484
0
  }
2485
0
  return code;
2486
0
}
2487
2488
0
static int32_t preParseTargetTableName(SInsertParseContext* pCxt, SVnodeModifyOpStmt* pStmt, SToken* pTbName) {
2489
0
  int32_t code = insCreateSName(&pStmt->targetTableName, pTbName, pCxt->pComCxt->acctId, pCxt->pComCxt->db, &pCxt->msg);
2490
0
  if (TSDB_CODE_SUCCESS == code) {
2491
0
    if (IS_SYS_DBNAME(pStmt->targetTableName.dbname)) {
2492
0
      return TSDB_CODE_PAR_SYSTABLE_NOT_ALLOWED;
2493
0
    }
2494
#ifdef TD_ENTERPRISE
2495
    // Fast-path: if ext source cache is already populated (warm connection),
2496
    // reject immediately without needing Phase 2 catalog fetch.
2497
    if (tsFederatedQueryEnable && pStmt->targetTableName.dbname[0] != '\0' && pCxt->pComCxt->pCatalog) {
2498
      bool isExtSrc = false;
2499
      int32_t rc = catalogIsExtSource(pCxt->pComCxt->pCatalog, pStmt->targetTableName.dbname, &isExtSrc);
2500
      if (TSDB_CODE_SUCCESS == rc && isExtSrc) {
2501
        return TSDB_CODE_EXT_SOURCE_WRITE_NOT_SUPPORTED;
2502
      }
2503
    }
2504
#endif
2505
0
  }
2506
2507
0
  return code;
2508
0
}
2509
2510
// input pStmt->pSql:
2511
//   1(care). [(field1_name, ...)] ...
2512
//   2. [ USING ... ] ...
2513
//   3. VALUES ... | FILE ...
2514
// output pStmt->pSql:
2515
//   1. [ USING ... ] ...
2516
//   2. VALUES ... | FILE ...
2517
0
static int32_t preParseBoundColumnsClause(SInsertParseContext* pCxt, SVnodeModifyOpStmt* pStmt) {
2518
0
  SToken  token;
2519
0
  int32_t index = 0;
2520
0
  NEXT_TOKEN_KEEP_SQL(pStmt->pSql, token, index);
2521
0
  if (TK_NK_LP != token.type) {
2522
0
    return TSDB_CODE_SUCCESS;
2523
0
  }
2524
2525
  // pStmt->pSql -> field1_name, ...)
2526
0
  pStmt->pSql += index;
2527
0
  pStmt->pBoundCols = pStmt->pSql;
2528
0
  return skipParentheses(pCxt, &pStmt->pSql);
2529
0
}
2530
2531
0
static int32_t getTableDataCxt(SInsertParseContext* pCxt, SVnodeModifyOpStmt* pStmt, STableDataCxt** pTableCxt) {
2532
0
  if (pCxt->pComCxt->async) {
2533
0
    return insGetTableDataCxt(pStmt->pTableBlockHashObj, &pStmt->pTableMeta->uid, sizeof(pStmt->pTableMeta->uid),
2534
0
                              pStmt->pTableMeta, &pStmt->pCreateTblReq, pTableCxt, false, false);
2535
0
  }
2536
2537
0
  char    tbFName[TSDB_TABLE_FNAME_LEN];
2538
0
  int32_t code = 0;
2539
0
  if ((pCxt->stmtTbNameFlag & NO_DATA_USING_CLAUSE) == USING_CLAUSE) {
2540
0
    tstrncpy(pStmt->targetTableName.tname, pStmt->usingTableName.tname, sizeof(pStmt->targetTableName.tname));
2541
0
    tstrncpy(pStmt->targetTableName.dbname, pStmt->usingTableName.dbname, sizeof(pStmt->targetTableName.dbname));
2542
0
    pStmt->targetTableName.type = TSDB_SUPER_TABLE;
2543
0
    pStmt->pTableMeta->tableType = TSDB_SUPER_TABLE;
2544
0
  }
2545
2546
0
  code = tNameExtractFullName(&pStmt->targetTableName, tbFName);
2547
2548
0
  if (TSDB_CODE_SUCCESS != code) {
2549
0
    return code;
2550
0
  }
2551
0
  if (pStmt->usingTableProcessing) {
2552
0
    pStmt->pTableMeta->uid = 0;
2553
0
  }
2554
0
  return insGetTableDataCxt(pStmt->pTableBlockHashObj, tbFName, strlen(tbFName), pStmt->pTableMeta,
2555
0
                            &pStmt->pCreateTblReq, pTableCxt, NULL != pCxt->pComCxt->pStmtCb, false);
2556
0
}
2557
#ifdef TD_ENTERPRISE
2558
static int32_t parseCheckNoBoundColPriv(SInsertParseContext* pCxt, SVnodeModifyOpStmt* pStmt) {
2559
  int32_t nPrivs = taosArrayGetSize(pStmt->pPrivCols);
2560
  if (nPrivs <= 0) {
2561
    return TSDB_CODE_SUCCESS;
2562
  }
2563
  int32_t nCols = pStmt->pTableMeta->tableInfo.numOfColumns;
2564
  /**
2565
   * It cann't provide the specific missing column info although with better performance. For better UE, we check each
2566
   * column one by one.
2567
   */
2568
  // if (nPrivs < nCols) return TSDB_CODE_PAR_COL_PERMISSION_DENIED;
2569
2570
  // both the schema and privCols are ordered by colId asc
2571
  SSchema* pSchemas = pStmt->pTableMeta->schema;
2572
  int32_t  j = 0;
2573
  for (int32_t i = 0; i < nCols; ++i) {
2574
    SSchema* pSchema = &pSchemas[i];
2575
    bool     found = false;
2576
    for (; j < nPrivs; ++j) {
2577
      SColNameFlag* pColFlag = (SColNameFlag*)TARRAY_GET_ELEM(pStmt->pPrivCols, j);
2578
      if (pColFlag->colId == pSchema->colId) {
2579
        found = true;
2580
        ++j;
2581
        break;
2582
      } else if (pColFlag->colId > pSchema->colId) {
2583
        break;
2584
      }
2585
    }
2586
2587
    if (!found) {
2588
      return generateSyntaxErrMsg(&pCxt->msg, TSDB_CODE_PAR_COL_PERMISSION_DENIED, pSchema->name);
2589
    }
2590
  }
2591
2592
  return TSDB_CODE_SUCCESS;
2593
}
2594
#endif
2595
2596
0
static int32_t parseBoundColumnsClause(SInsertParseContext* pCxt, SVnodeModifyOpStmt* pStmt, STableDataCxt* pTableCxt) {
2597
0
  SToken  token;
2598
0
  int32_t index = 0;
2599
0
  NEXT_TOKEN_KEEP_SQL(pStmt->pSql, token, index);
2600
0
  if (TK_NK_LP == token.type) {
2601
0
    pStmt->pSql += index;
2602
0
    if (NULL != pStmt->pBoundCols) {
2603
0
      return buildSyntaxErrMsg(&pCxt->msg, "keyword VALUES or FILE is expected", token.z);
2604
0
    }
2605
    // pStmt->pSql -> field1_name, ...)
2606
0
    return parseBoundColumns(pCxt, pStmt, &pStmt->pSql, BOUND_COLUMNS, pStmt->pTableMeta, &pTableCxt->boundColsInfo);
2607
0
  }
2608
2609
0
  if (NULL != pStmt->pBoundCols) {
2610
0
    return parseBoundColumns(pCxt, pStmt, &pStmt->pBoundCols, BOUND_COLUMNS, pStmt->pTableMeta,
2611
0
                             &pTableCxt->boundColsInfo);
2612
0
  } else if (pTableCxt->boundColsInfo.hasBoundCols) {
2613
0
    insResetBoundColsInfo(&pTableCxt->boundColsInfo);
2614
0
  } else if (NULL != pStmt->pPrivCols) {
2615
#ifdef TD_ENTERPRISE
2616
    PAR_ERR_RET(parseCheckNoBoundColPriv(pCxt, pStmt));
2617
#endif
2618
0
  }
2619
2620
2621
0
  return TSDB_CODE_SUCCESS;
2622
0
}
2623
2624
0
int32_t initTableColSubmitData(STableDataCxt* pTableCxt) {
2625
0
  if (0 == (pTableCxt->pData->flags & SUBMIT_REQ_COLUMN_DATA_FORMAT)) {
2626
0
    return TSDB_CODE_SUCCESS;
2627
0
  }
2628
2629
  /* Clear any existing aCol entries before adding new ones.
2630
   * The entry may have been retained across exec cycles (keepTable
2631
   * path) and still hold deep-cleared SColData entries whose nVal
2632
   * was zeroed by qResetStmtDataBlock.  Without this clear,
2633
   * taosArrayReserve appends to the existing entries, doubling
2634
   * nColData and producing a corrupt submit request. */
2635
0
  if (pTableCxt->pData->aCol) {
2636
0
    taosArrayClear(pTableCxt->pData->aCol);
2637
0
  }
2638
2639
0
  for (int32_t i = 0; i < pTableCxt->boundColsInfo.numOfBound; ++i) {
2640
0
    SSchema*  pSchema = &pTableCxt->pMeta->schema[pTableCxt->boundColsInfo.pColIndex[i]];
2641
0
    SColData* pCol = taosArrayReserve(pTableCxt->pData->aCol, 1);
2642
0
    if (NULL == pCol) {
2643
0
      return terrno;
2644
0
    }
2645
0
    tColDataInit(pCol, pSchema->colId, pSchema->type, pSchema->flags);
2646
0
  }
2647
2648
0
  return TSDB_CODE_SUCCESS;
2649
0
}
2650
2651
0
int32_t initTableColSubmitDataWithBoundInfo(STableDataCxt* pTableCxt, SBoundColInfo pBoundColsInfo) {
2652
0
  qDestroyBoundColInfo(&(pTableCxt->boundColsInfo));
2653
0
  pTableCxt->boundColsInfo = pBoundColsInfo;
2654
0
  if (pTableCxt->pData->aCol) {
2655
0
    taosArrayClear(pTableCxt->pData->aCol);
2656
0
  }
2657
0
  for (int32_t i = 0; i < pBoundColsInfo.numOfBound; ++i) {
2658
0
    SSchema*  pSchema = &pTableCxt->pMeta->schema[pTableCxt->boundColsInfo.pColIndex[i]];
2659
0
    SColData* pCol = taosArrayReserve(pTableCxt->pData->aCol, 1);
2660
0
    if (NULL == pCol) {
2661
0
      return terrno;
2662
0
    }
2663
0
    tColDataInit(pCol, pSchema->colId, pSchema->type, pSchema->flags);
2664
0
  }
2665
2666
0
  return TSDB_CODE_SUCCESS;
2667
0
}
2668
2669
// input pStmt->pSql:
2670
//   1. [(tag1_name, ...)] ...
2671
//   2. VALUES ... | FILE ...
2672
// output pStmt->pSql: VALUES ... | FILE ...
2673
static int32_t parseSchemaClauseBottom(SInsertParseContext* pCxt, SVnodeModifyOpStmt* pStmt,
2674
0
                                       STableDataCxt** pTableCxt) {
2675
0
  int32_t code = parseUsingClauseBottom(pCxt, pStmt);
2676
0
  if (TSDB_CODE_SUCCESS == code) {
2677
0
    code = getTableDataCxt(pCxt, pStmt, pTableCxt);
2678
0
  }
2679
0
  if (TSDB_CODE_SUCCESS == code) {
2680
0
    code = parseBoundColumnsClause(pCxt, pStmt, *pTableCxt);
2681
0
  }
2682
0
  if (TSDB_CODE_SUCCESS == code) {
2683
0
    code = initTableColSubmitData(*pTableCxt);
2684
0
  }
2685
0
  return code;
2686
0
}
2687
2688
// input pStmt->pSql: [(field1_name, ...)] [ USING ... ] VALUES ... | FILE ...
2689
// output pStmt->pSql:
2690
//   1. [(tag1_name, ...)] ...
2691
//   2. VALUES ... | FILE ...
2692
0
static int32_t parseSchemaClauseTop(SInsertParseContext* pCxt, SVnodeModifyOpStmt* pStmt, SToken* pTbName) {
2693
0
  int32_t code = preParseTargetTableName(pCxt, pStmt, pTbName);
2694
0
  if (TSDB_CODE_SUCCESS == code) {
2695
    // option: [(field1_name, ...)]
2696
0
    code = preParseBoundColumnsClause(pCxt, pStmt);
2697
0
  }
2698
0
  if (TSDB_CODE_SUCCESS == code) {
2699
    // option: [USING stb_name]
2700
0
    code = parseUsingTableName(pCxt, pStmt);
2701
0
  }
2702
0
  return code;
2703
0
}
2704
2705
static int32_t parseValueTokenImpl(SInsertParseContext* pCxt, const char** pSql, SToken* pToken, SSchema* pSchema,
2706
0
                                   const SSchemaExt* pExtSchema, int16_t timePrec, SColVal* pVal) {
2707
0
  switch (pSchema->type) {
2708
0
    case TSDB_DATA_TYPE_BOOL: {
2709
0
      if ((pToken->type == TK_NK_BOOL || pToken->type == TK_NK_STRING) && (pToken->n != 0)) {
2710
0
        if (IS_TRUE_STR(pToken->z, pToken->n)) {
2711
0
          VALUE_SET_TRIVIAL_DATUM(&pVal->value, TRUE_VALUE);
2712
0
        } else if (IS_FALSE_STR(pToken->z, pToken->n)) {
2713
0
          VALUE_SET_TRIVIAL_DATUM(&pVal->value, FALSE_VALUE);
2714
0
        } else if (TSDB_CODE_SUCCESS ==
2715
0
                   toDoubleEx(pToken->z, pToken->n, pToken->type, (double*)&VALUE_GET_TRIVIAL_DATUM(&pVal->value))) {
2716
0
          int8_t v = (*(double*)&VALUE_GET_TRIVIAL_DATUM(&pVal->value) == 0 ? FALSE_VALUE : TRUE_VALUE);
2717
0
          valueSetDatum(&pVal->value, TSDB_DATA_TYPE_BOOL, &v, tDataTypes[TSDB_DATA_TYPE_BOOL].bytes);
2718
0
        } else {
2719
0
          return buildSyntaxErrMsg(&pCxt->msg, "invalid bool data", pToken->z);
2720
0
        }
2721
0
      } else if (pToken->type == TK_NK_INTEGER) {
2722
0
        int8_t v = ((taosStr2Int64(pToken->z, NULL, 10) == 0) ? FALSE_VALUE : TRUE_VALUE);
2723
0
        VALUE_SET_TRIVIAL_DATUM(&pVal->value, v);
2724
0
      } else if (pToken->type == TK_NK_FLOAT) {
2725
0
        int8_t v = ((taosStr2Double(pToken->z, NULL) == 0) ? FALSE_VALUE : TRUE_VALUE);
2726
0
        VALUE_SET_TRIVIAL_DATUM(&pVal->value, v);
2727
0
      } else if ((pToken->type == TK_NK_HEX || pToken->type == TK_NK_BIN) &&
2728
0
                 (TSDB_CODE_SUCCESS ==
2729
0
                  toDoubleEx(pToken->z, pToken->n, pToken->type, (double*)&VALUE_GET_TRIVIAL_DATUM(&pVal->value)))) {
2730
0
        int8_t v = *(double*)&VALUE_GET_TRIVIAL_DATUM(&pVal->value) == 0 ? FALSE_VALUE : TRUE_VALUE;
2731
0
        valueSetDatum(&pVal->value, TSDB_DATA_TYPE_BOOL, &v, tDataTypes[TSDB_DATA_TYPE_BOOL].bytes);
2732
0
      } else {
2733
0
        return buildSyntaxErrMsg(&pCxt->msg, "invalid bool data", pToken->z);
2734
0
      }
2735
0
      break;
2736
0
    }
2737
0
    case TSDB_DATA_TYPE_TINYINT: {
2738
0
      int32_t code = toIntegerEx(pToken->z, pToken->n, pToken->type, &VALUE_GET_TRIVIAL_DATUM(&pVal->value));
2739
0
      if (TSDB_CODE_SUCCESS != code) {
2740
0
        return buildSyntaxErrMsg(&pCxt->msg, "invalid tinyint data", pToken->z);
2741
0
      } else if (!IS_VALID_TINYINT(VALUE_GET_TRIVIAL_DATUM(&pVal->value))) {
2742
0
        return buildSyntaxErrMsg(&pCxt->msg, "tinyint data overflow", pToken->z);
2743
0
      }
2744
0
      break;
2745
0
    }
2746
0
    case TSDB_DATA_TYPE_UTINYINT: {
2747
0
      int32_t code =
2748
0
          toUIntegerEx(pToken->z, pToken->n, pToken->type, (uint64_t*)&VALUE_GET_TRIVIAL_DATUM(&pVal->value));
2749
0
      if (TSDB_CODE_SUCCESS != code) {
2750
0
        return buildSyntaxErrMsg(&pCxt->msg, "invalid unsigned tinyint data", pToken->z);
2751
0
      } else if (VALUE_GET_TRIVIAL_DATUM(&pVal->value) > UINT8_MAX) {
2752
0
        return buildSyntaxErrMsg(&pCxt->msg, "unsigned tinyint data overflow", pToken->z);
2753
0
      }
2754
0
      break;
2755
0
    }
2756
0
    case TSDB_DATA_TYPE_SMALLINT: {
2757
0
      int32_t code = toIntegerEx(pToken->z, pToken->n, pToken->type, &VALUE_GET_TRIVIAL_DATUM(&pVal->value));
2758
0
      if (TSDB_CODE_SUCCESS != code) {
2759
0
        return buildSyntaxErrMsg(&pCxt->msg, "invalid smallint data", pToken->z);
2760
0
      } else if (!IS_VALID_SMALLINT(VALUE_GET_TRIVIAL_DATUM(&pVal->value))) {
2761
0
        return buildSyntaxErrMsg(&pCxt->msg, "smallint data overflow", pToken->z);
2762
0
      }
2763
0
      break;
2764
0
    }
2765
0
    case TSDB_DATA_TYPE_USMALLINT: {
2766
0
      int32_t code = toUIntegerEx(pToken->z, pToken->n, pToken->type, &VALUE_GET_TRIVIAL_DATUM(&pVal->value));
2767
0
      if (TSDB_CODE_SUCCESS != code) {
2768
0
        return buildSyntaxErrMsg(&pCxt->msg, "invalid unsigned smallint data", pToken->z);
2769
0
      } else if (VALUE_GET_TRIVIAL_DATUM(&pVal->value) > UINT16_MAX) {
2770
0
        return buildSyntaxErrMsg(&pCxt->msg, "unsigned smallint data overflow", pToken->z);
2771
0
      }
2772
0
      break;
2773
0
    }
2774
0
    case TSDB_DATA_TYPE_INT: {
2775
0
      int32_t code = toIntegerEx(pToken->z, pToken->n, pToken->type, &VALUE_GET_TRIVIAL_DATUM(&pVal->value));
2776
0
      if (TSDB_CODE_SUCCESS != code) {
2777
0
        return buildSyntaxErrMsg(&pCxt->msg, "invalid int data", pToken->z);
2778
0
      } else if (!IS_VALID_INT(VALUE_GET_TRIVIAL_DATUM(&pVal->value))) {
2779
0
        return buildSyntaxErrMsg(&pCxt->msg, "int data overflow", pToken->z);
2780
0
      }
2781
0
      break;
2782
0
    }
2783
0
    case TSDB_DATA_TYPE_UINT: {
2784
0
      int32_t code = toUIntegerEx(pToken->z, pToken->n, pToken->type, &VALUE_GET_TRIVIAL_DATUM(&pVal->value));
2785
0
      if (TSDB_CODE_SUCCESS != code) {
2786
0
        return buildSyntaxErrMsg(&pCxt->msg, "invalid unsigned int data", pToken->z);
2787
0
      } else if (VALUE_GET_TRIVIAL_DATUM(&pVal->value) > UINT32_MAX) {
2788
0
        return buildSyntaxErrMsg(&pCxt->msg, "unsigned int data overflow", pToken->z);
2789
0
      }
2790
0
      break;
2791
0
    }
2792
0
    case TSDB_DATA_TYPE_BIGINT: {
2793
0
      int32_t code = toIntegerEx(pToken->z, pToken->n, pToken->type, &VALUE_GET_TRIVIAL_DATUM(&pVal->value));
2794
0
      if (TSDB_CODE_SUCCESS != code) {
2795
0
        return buildSyntaxErrMsg(&pCxt->msg, "invalid bigint data", pToken->z);
2796
0
      }
2797
0
      break;
2798
0
    }
2799
0
    case TSDB_DATA_TYPE_UBIGINT: {
2800
0
      int32_t code = toUIntegerEx(pToken->z, pToken->n, pToken->type, &VALUE_GET_TRIVIAL_DATUM(&pVal->value));
2801
0
      if (TSDB_CODE_SUCCESS != code) {
2802
0
        return buildSyntaxErrMsg(&pCxt->msg, "invalid unsigned bigint data", pToken->z);
2803
0
      }
2804
0
      break;
2805
0
    }
2806
0
    case TSDB_DATA_TYPE_FLOAT: {
2807
0
      double  dv;
2808
0
      int32_t code = toDoubleEx(pToken->z, pToken->n, pToken->type, &dv);
2809
0
      if (TSDB_CODE_SUCCESS != code) {
2810
0
        return buildSyntaxErrMsg(&pCxt->msg, "illegal float data", pToken->z);
2811
0
      }
2812
0
      if (dv > FLT_MAX || dv < -FLT_MAX || isinf(dv) || isnan(dv)) {
2813
0
        return buildSyntaxErrMsg(&pCxt->msg, "illegal float data", pToken->z);
2814
0
      }
2815
0
      float f = dv;
2816
0
      valueSetDatum(&pVal->value, TSDB_DATA_TYPE_FLOAT, &f, sizeof(f));
2817
0
      break;
2818
0
    }
2819
0
    case TSDB_DATA_TYPE_DOUBLE: {
2820
0
      double  dv;
2821
0
      int32_t code = toDoubleEx(pToken->z, pToken->n, pToken->type, &dv);
2822
0
      if (TSDB_CODE_SUCCESS != code) {
2823
0
        return buildSyntaxErrMsg(&pCxt->msg, "illegal float data", pToken->z);
2824
0
      }
2825
0
      if (isinf(dv) || isnan(dv)) {
2826
0
        return buildSyntaxErrMsg(&pCxt->msg, "illegal double data", pToken->z);
2827
0
      }
2828
0
      VALUE_SET_TRIVIAL_DATUM(&pVal->value, (*(int64_t*)&dv));
2829
0
      break;
2830
0
    }
2831
0
    case TSDB_DATA_TYPE_BINARY: {
2832
0
      return parseBinary(pCxt, pSql, pToken, pVal, pSchema);
2833
0
    }
2834
0
    case TSDB_DATA_TYPE_VARBINARY: {
2835
0
      int32_t code = parseVarbinary(pToken, &pVal->value.pData, &pVal->value.nData, pSchema->bytes);
2836
0
      if (code != TSDB_CODE_SUCCESS) {
2837
0
        return generateSyntaxErrMsg(&pCxt->msg, code, pSchema->name);
2838
0
      }
2839
0
      break;
2840
0
    }
2841
0
    case TSDB_DATA_TYPE_NCHAR: {
2842
      // if the converted output len is over than pColumnModel->bytes, return error: 'Argument list too long'
2843
0
      int32_t len = 0;
2844
0
      int64_t realLen = pToken->n << 2;
2845
0
      if (realLen > pSchema->bytes - VARSTR_HEADER_SIZE) realLen = pSchema->bytes - VARSTR_HEADER_SIZE;
2846
0
      char* pUcs4 = taosMemoryMalloc(realLen);
2847
0
      if (NULL == pUcs4) {
2848
0
        return terrno;
2849
0
      }
2850
0
      if (!taosMbsToUcs4(pToken->z, pToken->n, (TdUcs4*)pUcs4, realLen, &len, pCxt->pComCxt->charsetCxt)) {
2851
0
        taosMemoryFree(pUcs4);
2852
0
        if (terrno == TAOS_SYSTEM_ERROR(E2BIG)) {
2853
0
          return generateSyntaxErrMsg(&pCxt->msg, TSDB_CODE_PAR_VALUE_TOO_LONG, pSchema->name);
2854
0
        }
2855
0
        char buf[512] = {0};
2856
0
        snprintf(buf, tListLen(buf), "%s", strerror(terrno));
2857
0
        return buildSyntaxErrMsg(&pCxt->msg, buf, pToken->z);
2858
0
      }
2859
0
      pVal->value.pData = pUcs4;
2860
0
      pVal->value.nData = len;
2861
0
      break;
2862
0
    }
2863
0
    case TSDB_DATA_TYPE_JSON: {
2864
0
      if (pToken->n > (TSDB_MAX_JSON_TAG_LEN - VARSTR_HEADER_SIZE) / TSDB_NCHAR_SIZE) {
2865
0
        return buildSyntaxErrMsg(&pCxt->msg, "json string too long than 4095", pToken->z);
2866
0
      }
2867
0
      pVal->value.pData = taosMemoryMalloc(pToken->n);
2868
0
      if (NULL == pVal->value.pData) {
2869
0
        return terrno;
2870
0
      }
2871
0
      memcpy(pVal->value.pData, pToken->z, pToken->n);
2872
0
      pVal->value.nData = pToken->n;
2873
0
      break;
2874
0
    }
2875
0
    case TSDB_DATA_TYPE_GEOMETRY: {
2876
0
      int32_t        code = TSDB_CODE_FAILED;
2877
0
      unsigned char* output = NULL;
2878
0
      size_t         size = 0;
2879
2880
0
      code = parseGeometry(pToken, &output, &size);
2881
0
      if (code != TSDB_CODE_SUCCESS) {
2882
0
        code = buildSyntaxErrMsg(&pCxt->msg, getGeosErrMsg(code), pToken->z);
2883
0
      }
2884
      // Too long values will raise the invalid sql error message
2885
0
      else if (size + VARSTR_HEADER_SIZE > pSchema->bytes) {
2886
0
        code = generateSyntaxErrMsg(&pCxt->msg, TSDB_CODE_PAR_VALUE_TOO_LONG, pSchema->name);
2887
0
      } else {
2888
0
        pVal->value.pData = taosMemoryMalloc(size);
2889
0
        if (NULL == pVal->value.pData) {
2890
0
          code = terrno;
2891
0
        } else {
2892
0
          memcpy(pVal->value.pData, output, size);
2893
0
          pVal->value.nData = size;
2894
0
        }
2895
0
      }
2896
2897
0
      geosFreeBuffer(output);
2898
0
      if (code != TSDB_CODE_SUCCESS) {
2899
0
        return code;
2900
0
      }
2901
2902
0
      break;
2903
0
    }
2904
0
    case TSDB_DATA_TYPE_TIMESTAMP: {
2905
0
      if (parseTime(pSql, pToken, timePrec, &VALUE_GET_TRIVIAL_DATUM(&pVal->value), &pCxt->msg,
2906
0
                    pCxt->pComCxt->timezone) != TSDB_CODE_SUCCESS) {
2907
0
        return buildSyntaxErrMsg(&pCxt->msg, "invalid timestamp", pToken->z);
2908
0
      }
2909
0
      break;
2910
0
    }
2911
0
    case TSDB_DATA_TYPE_BLOB:
2912
0
    case TSDB_DATA_TYPE_MEDIUMBLOB: {
2913
0
      int32_t code = parseBlob(pToken, &pVal->value.pData, &pVal->value.nData, pSchema->bytes);
2914
0
      if (code != TSDB_CODE_SUCCESS) {
2915
0
        return generateSyntaxErrMsg(&pCxt->msg, code, pSchema->name);
2916
0
      }
2917
0
    } break;
2918
0
    case TSDB_DATA_TYPE_DECIMAL: {
2919
0
      if (!pExtSchema) {
2920
0
        qError("Decimal type without ext schema info, cannot parse decimal values");
2921
0
        return TSDB_CODE_DECIMAL_PARSE_ERROR;
2922
0
      }
2923
0
      uint8_t precision = 0, scale = 0;
2924
0
      decimalFromTypeMod(pExtSchema->typeMod, &precision, &scale);
2925
0
      Decimal128 dec = {0};
2926
0
      int32_t    code = decimal128FromStr(pToken->z, pToken->n, precision, scale, &dec);
2927
0
      if (TSDB_CODE_SUCCESS != code) {
2928
0
        return code;
2929
0
      }
2930
2931
      // precision check
2932
      // scale auto fit
2933
2934
0
      code = decimal128ToDataVal(&dec, &pVal->value);
2935
0
      if (TSDB_CODE_SUCCESS != code) {
2936
0
        return code;
2937
0
      }
2938
0
      break;
2939
0
    }
2940
0
    case TSDB_DATA_TYPE_DECIMAL64: {
2941
0
      if (!pExtSchema) {
2942
0
        qError("Decimal type without ext schema info, cannot parse decimal values");
2943
0
        return TSDB_CODE_DECIMAL_PARSE_ERROR;
2944
0
      }
2945
0
      uint8_t precision = 0, scale = 0;
2946
0
      decimalFromTypeMod(pExtSchema->typeMod, &precision, &scale);
2947
0
      Decimal64 dec = {0};
2948
0
      int32_t   code = decimal64FromStr(pToken->z, pToken->n, precision, scale, &dec);
2949
0
      if (TSDB_CODE_SUCCESS != code) {
2950
0
        return code;
2951
0
      }
2952
0
      code = decimal64ToDataVal(&dec, &pVal->value);
2953
0
      if (TSDB_CODE_SUCCESS != code) {
2954
0
        return code;
2955
0
      }
2956
0
      break;
2957
0
    }
2958
0
    default:
2959
2960
0
      return TSDB_CODE_FAILED;
2961
0
  }
2962
2963
0
  pVal->flag = CV_FLAG_VALUE;
2964
0
  return TSDB_CODE_SUCCESS;
2965
0
}
2966
2967
static int32_t parseValueToken(SInsertParseContext* pCxt, const char** pSql, SToken* pToken, SSchema* pSchema,
2968
0
                               const SSchemaExt* pExtSchema, int16_t timePrec, SColVal* pVal) {
2969
0
  int32_t code = checkAndTrimValue(pToken, pCxt->tmpTokenBuf, &pCxt->msg, pSchema->type);
2970
0
  if (TSDB_CODE_SUCCESS == code && isNullValue(pSchema->type, pToken)) {
2971
0
    if (TSDB_DATA_TYPE_TIMESTAMP == pSchema->type && PRIMARYKEY_TIMESTAMP_COL_ID == pSchema->colId) {
2972
0
      return buildSyntaxErrMsg(&pCxt->msg, "Primary timestamp column should not be null", pToken->z);
2973
0
    }
2974
2975
0
    pVal->flag = CV_FLAG_NULL;
2976
0
    return TSDB_CODE_SUCCESS;
2977
0
  }
2978
2979
0
  if (TSDB_CODE_SUCCESS == code) {
2980
0
    if (pToken->n == 0 && IS_NUMERIC_TYPE(pSchema->type)) {
2981
0
      return buildSyntaxErrMsg(&pCxt->msg, "invalid numeric data", pToken->z);
2982
0
    }
2983
0
    code = parseValueTokenImpl(pCxt, pSql, pToken, pSchema, pExtSchema, timePrec, pVal);
2984
0
  }
2985
2986
0
  return code;
2987
0
}
2988
2989
0
static void clearColValArray(SArray* pCols) {
2990
0
  int32_t num = taosArrayGetSize(pCols);
2991
0
  for (int32_t i = 0; i < num; ++i) {
2992
0
    SColVal* pCol = taosArrayGet(pCols, i);
2993
0
    if (IS_VAR_DATA_TYPE(pCol->value.type) || pCol->value.type == TSDB_DATA_TYPE_DECIMAL) {
2994
0
      taosMemoryFreeClear(pCol->value.pData);
2995
0
    }
2996
0
  }
2997
0
}
2998
2999
typedef struct SStbRowsDataContext {
3000
  SName stbName;
3001
3002
  STableMeta*   pStbMeta;
3003
  SNode*        pTagCond;
3004
  SBoundColInfo boundColsInfo;
3005
3006
  // the following fields are for each stb row
3007
  SArray*        aTagVals;
3008
  SArray*        aColVals;
3009
  SArray*        aTagNames;
3010
  SName          ctbName;
3011
  STag*          pTag;
3012
  STableMeta*    pCtbMeta;
3013
  SVCreateTbReq* pCreateCtbReq;
3014
  bool           hasTimestampTag;
3015
  bool           isJsonTag;
3016
} SStbRowsDataContext;
3017
3018
typedef union SRowsDataContext {
3019
  STableDataCxt*       pTableDataCxt;
3020
  SStbRowsDataContext* pStbRowsCxt;
3021
} SRowsDataContext;
3022
3023
0
int32_t parseTbnameToken(SMsgBuf* pMsgBuf, char* tname, SToken* pToken, bool* pFoundCtbName) {
3024
0
  *pFoundCtbName = false;
3025
3026
0
  if (isNullValue(TSDB_DATA_TYPE_BINARY, pToken)) {
3027
0
    return buildInvalidOperationMsg(pMsgBuf, "tbname can not be null value");
3028
0
  }
3029
3030
0
  if (pToken->n > 0) {
3031
0
    if (pToken->n <= TSDB_TABLE_NAME_LEN - 1) {
3032
0
      for (int i = 0; i < pToken->n; ++i) {
3033
0
        if (pToken->z[i] == '.') {
3034
0
          return buildInvalidOperationMsg(pMsgBuf, "tbname can not contain '.'");
3035
0
        } else {
3036
0
          tname[i] = pToken->z[i];
3037
0
        }
3038
0
      }
3039
0
      tname[pToken->n] = '\0';
3040
0
      *pFoundCtbName = true;
3041
0
    } else {
3042
0
      return buildInvalidOperationMsg(pMsgBuf, "tbname is too long");
3043
0
    }
3044
0
  } else {
3045
0
    return buildInvalidOperationMsg(pMsgBuf, "tbname can not be empty");
3046
0
  }
3047
0
  return TSDB_CODE_SUCCESS;
3048
0
}
3049
3050
static int32_t processCtbTagsAfterCtbName(SInsertParseContext* pCxt, SVnodeModifyOpStmt* pStmt,
3051
                                          SStbRowsDataContext* pStbRowsCxt, bool ctbFirst, const SToken* tagTokens,
3052
0
                                          SSchema* const* tagSchemas, int numOfTagTokens) {
3053
0
  int32_t code = TSDB_CODE_SUCCESS;
3054
0
  uint8_t precision = pStmt->pTableMeta->tableInfo.precision;
3055
3056
0
  if (code == TSDB_CODE_SUCCESS && ctbFirst) {
3057
0
    for (int32_t i = 0; code == TSDB_CODE_SUCCESS && i < numOfTagTokens; ++i) {
3058
0
      SToken*  pTagToken = (SToken*)(tagTokens + i);
3059
0
      SSchema* pTagSchema = tagSchemas[i];
3060
0
      code = checkAndTrimValue(pTagToken, pCxt->tmpTokenBuf, &pCxt->msg, pTagSchema->type);
3061
0
      if (code == TSDB_CODE_SUCCESS && TK_NK_VARIABLE == pTagToken->type) {
3062
0
        code = buildInvalidOperationMsg(&pCxt->msg, "not expected tag");
3063
0
      }
3064
3065
0
      if (code == TSDB_CODE_SUCCESS) {
3066
0
        code = parseTagValue(&pCxt->msg, NULL, precision, pTagSchema, pTagToken, pStbRowsCxt->aTagNames,
3067
0
                             pStbRowsCxt->aTagVals, &pStbRowsCxt->pTag, pCxt->pComCxt->timezone,
3068
0
                             pCxt->pComCxt->charsetCxt);
3069
0
      }
3070
0
    }
3071
0
    if (code == TSDB_CODE_SUCCESS && !pStbRowsCxt->isJsonTag) {
3072
0
      taosArraySort(pStbRowsCxt->aTagNames, tTagNameCompare);
3073
0
      code = tTagNew(pStbRowsCxt->aTagVals, 1, false, &pStbRowsCxt->pTag);
3074
0
    }
3075
0
  }
3076
0
  if (code == TSDB_CODE_SUCCESS && pStbRowsCxt->pTagCond) {
3077
0
    code = checkSubtablePrivilege(pStbRowsCxt->aTagVals, pStbRowsCxt->aTagNames, &pStbRowsCxt->pTagCond);
3078
0
  }
3079
0
  return code;
3080
0
}
3081
3082
static int32_t doGetStbRowValues(SInsertParseContext* pCxt, SVnodeModifyOpStmt* pStmt, const char** ppSql,
3083
                                 SStbRowsDataContext* pStbRowsCxt, SToken* pToken, const SBoundColInfo* pCols,
3084
                                 const SSchema* pSchemas, const SSchemaExt* pExtSchemas, SToken* tagTokens,
3085
                                 SSchema** tagSchemas, int* pNumOfTagTokens, bool* bFoundTbName, bool* setCtbName,
3086
0
                                 SBoundColInfo* ctbCols) {
3087
0
  int32_t code = TSDB_CODE_SUCCESS;
3088
0
  SArray* pTagNames = pStbRowsCxt->aTagNames;
3089
0
  SArray* pTagVals = pStbRowsCxt->aTagVals;
3090
0
  bool    canParseTagsAfter = !pStbRowsCxt->pTagCond && !pStbRowsCxt->hasTimestampTag;
3091
0
  int32_t numOfCols = getNumOfColumns(pStbRowsCxt->pStbMeta);
3092
0
  int32_t numOfTags = getNumOfTags(pStbRowsCxt->pStbMeta);
3093
0
  int32_t tbnameIdx = getTbnameSchemaIndex(pStbRowsCxt->pStbMeta);
3094
0
  uint8_t precision = getTableInfo(pStbRowsCxt->pStbMeta).precision;
3095
0
  int     tag_index = 0;
3096
0
  int     col_index = 0;
3097
0
  for (int i = 0; i < pCols->numOfBound && (code) == TSDB_CODE_SUCCESS; ++i) {
3098
0
    const char* pTmpSql = *ppSql;
3099
0
    bool        ignoreComma = false;
3100
0
    NEXT_TOKEN_WITH_PREV_EXT(*ppSql, *pToken, &ignoreComma);
3101
3102
0
    if (ignoreComma) {
3103
0
      code = buildSyntaxErrMsg(&pCxt->msg, "invalid data or symbol", pTmpSql);
3104
0
      break;
3105
0
    }
3106
3107
0
    if (TK_NK_RP == pToken->type) {
3108
0
      code = generateSyntaxErrMsg(&pCxt->msg, TSDB_CODE_PAR_INVALID_COLUMNS_NUM);
3109
0
      break;
3110
0
    }
3111
3112
    // cols tags tbname
3113
0
    if (TK_NK_QUESTION == pToken->type) {
3114
0
      if (pCxt->pComCxt->stmtBindVersion != 2) {
3115
0
        return buildInvalidOperationMsg(&pCxt->msg,
3116
0
                                        "insert into stb(...tbname...)values(...,?,...) only support in stmt2");
3117
0
      }
3118
0
      if (pCols->pColIndex[i] == tbnameIdx) {
3119
0
        *bFoundTbName = true;
3120
0
        char* tbName = NULL;
3121
0
        if ((*pCxt->pComCxt->pStmtCb->getTbNameFn)(pCxt->pComCxt->pStmtCb->pStmt, &tbName) == TSDB_CODE_SUCCESS) {
3122
0
          tstrncpy(pStbRowsCxt->ctbName.tname, tbName, sizeof(pStbRowsCxt->ctbName.tname));
3123
0
          tstrncpy(pStmt->usingTableName.tname, pStmt->targetTableName.tname, sizeof(pStmt->usingTableName.tname));
3124
0
          tstrncpy(pStmt->targetTableName.tname, tbName, sizeof(pStmt->targetTableName.tname));
3125
0
          tstrncpy(pStmt->usingTableName.dbname, pStmt->targetTableName.dbname, sizeof(pStmt->usingTableName.dbname));
3126
0
          pStmt->usingTableName.type = 1;
3127
0
          pStmt->pTableMeta->tableType = TSDB_CHILD_TABLE;  // set the table type to child table for parse cache
3128
0
          *setCtbName = true;
3129
0
        }
3130
0
      } else if (pCols->pColIndex[i] < numOfCols) {
3131
        // bind column
3132
0
        if (ctbCols->pColIndex == NULL) {
3133
0
          ctbCols->pColIndex = taosMemoryCalloc(numOfCols, sizeof(int16_t));
3134
0
          if (NULL == ctbCols->pColIndex) {
3135
0
            return terrno;
3136
0
          }
3137
0
        }
3138
0
        ctbCols->pColIndex[col_index++] = pCols->pColIndex[i];
3139
0
        ctbCols->numOfBound++;
3140
0
        ctbCols->numOfCols++;
3141
3142
0
      } else if (pCols->pColIndex[i] < tbnameIdx) {
3143
0
        if (pCxt->tags.pColIndex == NULL) {
3144
0
          pCxt->tags.pColIndex = taosMemoryCalloc(numOfTags, sizeof(int16_t));
3145
0
          if (NULL == pCxt->tags.pColIndex) {
3146
0
            return terrno;
3147
0
          }
3148
0
        }
3149
0
        if (!(tag_index < numOfTags)) {
3150
0
          return buildInvalidOperationMsg(&pCxt->msg, "not expected numOfTags");
3151
0
        }
3152
0
        pStmt->usingTableProcessing = true;
3153
0
        pCxt->tags.pColIndex[tag_index++] = pCols->pColIndex[i] - numOfCols;
3154
0
        pCxt->tags.mixTagsCols = true;
3155
0
        pCxt->tags.numOfBound++;
3156
0
        pCxt->tags.numOfCols++;
3157
0
      } else {
3158
0
        return buildInvalidOperationMsg(&pCxt->msg, "not expected numOfBound");
3159
0
      }
3160
0
    } else {
3161
0
      if (pCxt->pComCxt->stmtBindVersion == 2 && pCxt->pComCxt->pStmtCb != NULL) {
3162
0
        if (pCols->pColIndex[i] < numOfCols) {
3163
0
          const SSchema*    pSchema = &pSchemas[pCols->pColIndex[i]];
3164
0
          const SSchemaExt* pExtSchema = pExtSchemas + pCols->pColIndex[i];
3165
0
          SColVal*          pVal = taosArrayGet(pStbRowsCxt->aColVals, pCols->pColIndex[i]);
3166
0
          code = parseValueToken(pCxt, ppSql, pToken, (SSchema*)pSchema, pExtSchema, precision, pVal);
3167
0
          if (TK_NK_VARIABLE == pToken->type) {
3168
0
            code = buildInvalidOperationMsg(&pCxt->msg, "not expected row value");
3169
0
          }
3170
3171
0
          if (ctbCols->pColIndex == NULL) {
3172
0
            ctbCols->pColIndex = taosMemoryCalloc(numOfCols, sizeof(int16_t));
3173
0
            if (NULL == ctbCols->pColIndex) {
3174
0
              return terrno;
3175
0
            }
3176
0
          }
3177
0
          ctbCols->pColIndex[col_index++] = pCols->pColIndex[i];
3178
0
          ctbCols->numOfBound++;
3179
0
          ctbCols->numOfCols++;
3180
3181
0
          if (code == TSDB_CODE_SUCCESS && pCxt->pParsedValues == NULL) {
3182
0
            pCxt->pParsedValues =
3183
0
                tSimpleHashInit(pCols->numOfBound, taosGetDefaultHashFunction(TSDB_DATA_TYPE_SMALLINT));
3184
0
            if (pCxt->pParsedValues == NULL) {
3185
0
              return terrno;
3186
0
            }
3187
0
            tSimpleHashSetFreeFp(pCxt->pParsedValues, destroyColVal);
3188
0
          }
3189
3190
0
          if (code == TSDB_CODE_SUCCESS) {
3191
0
            SColVal clonedVal = *pVal;
3192
0
            if (COL_VAL_IS_VALUE(&clonedVal) && IS_VAR_DATA_TYPE(clonedVal.value.type)) {
3193
0
              clonedVal.value.pData = taosMemoryMalloc(clonedVal.value.nData);
3194
0
              if (NULL == clonedVal.value.pData) {
3195
0
                code = terrno;
3196
0
                break;
3197
0
              }
3198
0
              memcpy(clonedVal.value.pData, pVal->value.pData, clonedVal.value.nData);
3199
0
            }
3200
3201
0
            clonedVal.cid = pSchema->colId;
3202
0
            code = tSimpleHashPut(pCxt->pParsedValues, &pSchema->colId, sizeof(int16_t), &clonedVal, sizeof(SColVal));
3203
0
            if (code != TSDB_CODE_SUCCESS) {
3204
0
              if (COL_VAL_IS_VALUE(&clonedVal) && IS_VAR_DATA_TYPE(clonedVal.value.type)) {
3205
0
                taosMemoryFree(clonedVal.value.pData);
3206
0
                clonedVal.value.pData = NULL;
3207
0
              }
3208
0
              return code;
3209
0
            }
3210
0
          }
3211
0
        } else if (pCols->pColIndex[i] < tbnameIdx) {
3212
0
          if (pCxt->tags.parseredTags == NULL) {
3213
0
            pCxt->tags.parseredTags = taosMemoryCalloc(1, sizeof(STagsInfo));
3214
0
            if (pCxt->tags.parseredTags == NULL) {
3215
0
              code = terrno;
3216
0
            } else {
3217
0
              pCxt->tags.parseredTags->STagNames = taosArrayInit(numOfTags, TSDB_COL_NAME_LEN + sizeof(col_id_t));
3218
0
              pCxt->tags.parseredTags->pTagVals = taosArrayInit(numOfTags, sizeof(STagVal));
3219
0
              pCxt->tags.parseredTags->pTagIndex = taosMemoryCalloc(numOfTags, sizeof(uint8_t));
3220
0
              pCxt->tags.parseredTags->numOfTags = 0;
3221
3222
0
              if (pCxt->tags.parseredTags->STagNames == NULL || pCxt->tags.parseredTags->pTagVals == NULL ||
3223
0
                  pCxt->tags.parseredTags->pTagIndex == NULL) {
3224
0
                return terrno;
3225
0
              }
3226
0
            }
3227
0
          }
3228
3229
0
          const SSchema* pTagSchema = &pSchemas[pCols->pColIndex[i]];
3230
          // if (canParseTagsAfter) {
3231
          //   tagTokens[(*pNumOfTagTokens)] = *pToken;
3232
          //   tagSchemas[(*pNumOfTagTokens)] = (SSchema*)pTagSchema;
3233
          //   ++(*pNumOfTagTokens);
3234
          // } else {
3235
0
          code = checkAndTrimValue(pToken, pCxt->tmpTokenBuf, &pCxt->msg, pTagSchema->type);
3236
0
          if (code == TSDB_CODE_SUCCESS && TK_NK_VARIABLE == pToken->type) {
3237
0
            code = buildInvalidOperationMsg(&pCxt->msg, "not expected row value");
3238
0
          }
3239
0
          if (code == TSDB_CODE_SUCCESS) {
3240
0
            code = parseTagValue(&pCxt->msg, ppSql, precision, (SSchema*)pTagSchema, pToken,
3241
0
                                 pCxt->tags.parseredTags->STagNames, pCxt->tags.parseredTags->pTagVals,
3242
0
                                 &pStbRowsCxt->pTag, pCxt->pComCxt->timezone, pCxt->pComCxt->charsetCxt);
3243
0
          }
3244
3245
0
          pCxt->tags.parseredTags->pTagIndex[pCxt->tags.parseredTags->numOfTags++] = pCols->pColIndex[i] - numOfCols;
3246
3247
0
          if (pCxt->tags.pColIndex == NULL) {
3248
0
            pCxt->tags.pColIndex = taosMemoryCalloc(numOfTags, sizeof(int16_t));
3249
0
            if (NULL == pCxt->tags.pColIndex) {
3250
0
              return terrno;
3251
0
            }
3252
0
          }
3253
0
          if (!(tag_index < numOfTags)) {
3254
0
            return buildInvalidOperationMsg(&pCxt->msg, "not expected numOfTags");
3255
0
          }
3256
0
          pStmt->usingTableProcessing = true;
3257
0
          pCxt->tags.pColIndex[tag_index++] = pCols->pColIndex[i] - numOfCols;
3258
0
          pCxt->tags.mixTagsCols = true;
3259
0
          pCxt->tags.numOfBound++;
3260
0
          pCxt->tags.numOfCols++;
3261
          // }
3262
0
        } else if (pCols->pColIndex[i] == tbnameIdx) {
3263
0
          return buildInvalidOperationMsg(&pCxt->msg, "STMT tbname in bound cols should not be a fixed value");
3264
0
        }
3265
0
      } else {
3266
0
        if (pCols->pColIndex[i] < numOfCols) {
3267
0
          const SSchema*    pSchema = &pSchemas[pCols->pColIndex[i]];
3268
0
          const SSchemaExt* pExtSchema = pExtSchemas + pCols->pColIndex[i];
3269
0
          SColVal*          pVal = taosArrayGet(pStbRowsCxt->aColVals, pCols->pColIndex[i]);
3270
0
          code = parseValueToken(pCxt, ppSql, pToken, (SSchema*)pSchema, pExtSchema, precision, pVal);
3271
0
          if (TK_NK_VARIABLE == pToken->type) {
3272
0
            code = buildInvalidOperationMsg(&pCxt->msg, "not expected row value");
3273
0
          }
3274
0
        } else if (pCols->pColIndex[i] < tbnameIdx) {
3275
0
          const SSchema* pTagSchema = &pSchemas[pCols->pColIndex[i]];
3276
0
          if (canParseTagsAfter) {
3277
0
            tagTokens[(*pNumOfTagTokens)] = *pToken;
3278
0
            tagSchemas[(*pNumOfTagTokens)] = (SSchema*)pTagSchema;
3279
0
            ++(*pNumOfTagTokens);
3280
0
          } else {
3281
0
            code = checkAndTrimValue(pToken, pCxt->tmpTokenBuf, &pCxt->msg, pTagSchema->type);
3282
0
            if (code == TSDB_CODE_SUCCESS && TK_NK_VARIABLE == pToken->type) {
3283
0
              code = buildInvalidOperationMsg(&pCxt->msg, "not expected row value");
3284
0
            }
3285
0
            if (code == TSDB_CODE_SUCCESS) {
3286
0
              code = parseTagValue(&pCxt->msg, ppSql, precision, (SSchema*)pTagSchema, pToken, pTagNames, pTagVals,
3287
0
                                   &pStbRowsCxt->pTag, pCxt->pComCxt->timezone, pCxt->pComCxt->charsetCxt);
3288
0
            }
3289
0
          }
3290
0
        } else if (pCols->pColIndex[i] == tbnameIdx) {
3291
0
          code = checkAndTrimValue(pToken, pCxt->tmpTokenBuf, &pCxt->msg, TSDB_DATA_TYPE_BINARY);
3292
0
          if (TK_NK_VARIABLE == pToken->type) {
3293
0
            code = buildInvalidOperationMsg(&pCxt->msg, "not expected tbname");
3294
0
          }
3295
3296
0
          if (code == TSDB_CODE_SUCCESS) {
3297
0
            code = parseTbnameToken(&pCxt->msg, pStbRowsCxt->ctbName.tname, pToken, bFoundTbName);
3298
0
          }
3299
0
        }
3300
0
      }
3301
0
    }
3302
3303
0
    if (code == TSDB_CODE_SUCCESS && i < pCols->numOfBound - 1) {
3304
0
      NEXT_VALID_TOKEN(*ppSql, *pToken);
3305
0
      if (TK_NK_COMMA != pToken->type) {
3306
0
        code = buildSyntaxErrMsg(&pCxt->msg, ", expected", pToken->z);
3307
0
      }
3308
0
    }
3309
0
  }
3310
3311
0
  return code;
3312
0
}
3313
3314
static int32_t getStbRowValues(SInsertParseContext* pCxt, SVnodeModifyOpStmt* pStmt, const char** ppSql,
3315
                               SStbRowsDataContext* pStbRowsCxt, bool* pGotRow, SToken* pToken, bool* pCtbFirst,
3316
0
                               bool* setCtbName, SBoundColInfo* ctbCols) {
3317
0
  SBoundColInfo* pCols = &pStbRowsCxt->boundColsInfo;
3318
0
  SSchema*       pSchemas = getTableColumnSchema(pStbRowsCxt->pStbMeta);
3319
0
  SSchemaExt*    pExtSchemas = getTableColumnExtSchema(pStbRowsCxt->pStbMeta);
3320
3321
0
  bool        bFoundTbName = false;
3322
0
  const char* pOrigSql = *ppSql;
3323
3324
0
  int32_t  code = TSDB_CODE_SUCCESS;
3325
0
  SToken   tagTokens[TSDB_MAX_TAGS] = {0};
3326
0
  SSchema* tagSchemas[TSDB_MAX_TAGS] = {0};
3327
0
  int      numOfTagTokens = 0;
3328
3329
0
  code = doGetStbRowValues(pCxt, pStmt, ppSql, pStbRowsCxt, pToken, pCols, pSchemas, pExtSchemas, tagTokens, tagSchemas,
3330
0
                           &numOfTagTokens, &bFoundTbName, setCtbName, ctbCols);
3331
3332
0
  if (code != TSDB_CODE_SUCCESS) {
3333
0
    return code;
3334
0
  }
3335
3336
0
  if (!bFoundTbName) {
3337
0
    code = buildSyntaxErrMsg(&pCxt->msg, "tbname value expected", pOrigSql);
3338
0
  }
3339
3340
0
  bool ctbFirst = true;
3341
0
  char ctbFName[TSDB_TABLE_FNAME_LEN];
3342
0
  if (code == TSDB_CODE_SUCCESS) {
3343
0
    code = tNameExtractFullName(&pStbRowsCxt->ctbName, ctbFName);
3344
0
  }
3345
0
  if (TSDB_CODE_SUCCESS == code) {
3346
0
    STableMeta** pCtbMeta = taosHashGet(pStmt->pSubTableHashObj, ctbFName, strlen(ctbFName));
3347
0
    ctbFirst = (pCtbMeta == NULL);
3348
0
    if (!ctbFirst) {
3349
0
      pStbRowsCxt->pCtbMeta->uid = (*pCtbMeta)->uid;
3350
0
      pStbRowsCxt->pCtbMeta->vgId = (*pCtbMeta)->vgId;
3351
0
    }
3352
0
    *pCtbFirst = ctbFirst;
3353
0
  }
3354
3355
0
  if (code == TSDB_CODE_SUCCESS) {
3356
0
    code = processCtbTagsAfterCtbName(pCxt, pStmt, pStbRowsCxt, ctbFirst, tagTokens, tagSchemas, numOfTagTokens);
3357
0
  }
3358
3359
0
  if (code == TSDB_CODE_SUCCESS) {
3360
0
    *pGotRow = true;
3361
0
  }
3362
0
  return code;
3363
0
}
3364
3365
static int32_t processCtbAutoCreationAndCtbMeta(SInsertParseContext* pCxt, SVnodeModifyOpStmt* pStmt,
3366
0
                                                SStbRowsDataContext* pStbRowsCxt) {
3367
0
  int32_t code = TSDB_CODE_SUCCESS;
3368
0
  bool    stmtNoCreateTbReq = (pCxt->pComCxt->stmtBindVersion == 2 && pCxt->tags.numOfBound == 0);
3369
3370
0
  if (!stmtNoCreateTbReq) {
3371
0
    pStbRowsCxt->pCreateCtbReq = taosMemoryCalloc(1, sizeof(SVCreateTbReq));
3372
0
    if (pStbRowsCxt->pCreateCtbReq == NULL) {
3373
0
      code = terrno;
3374
0
    }
3375
0
    if (code == TSDB_CODE_SUCCESS) {
3376
0
      code = insBuildCreateTbReq(pStbRowsCxt->pCreateCtbReq, pStbRowsCxt->ctbName.tname, pStbRowsCxt->pTag,
3377
0
                                 pStbRowsCxt->pStbMeta->uid, pStbRowsCxt->stbName.tname, pStbRowsCxt->aTagNames,
3378
0
                                 getNumOfTags(pStbRowsCxt->pStbMeta), TSDB_DEFAULT_TABLE_TTL);
3379
0
      pStbRowsCxt->pTag = NULL;
3380
0
    }
3381
0
  }
3382
3383
0
  if (code == TSDB_CODE_SUCCESS) {
3384
0
    char ctbFName[TSDB_TABLE_FNAME_LEN];
3385
0
    code = tNameExtractFullName(&pStbRowsCxt->ctbName, ctbFName);
3386
0
    SVgroupInfo      vg;
3387
0
    SRequestConnInfo conn = {.pTrans = pCxt->pComCxt->pTransporter,
3388
0
                             .requestId = pCxt->pComCxt->requestId,
3389
0
                             .requestObjRefId = pCxt->pComCxt->requestRid,
3390
0
                             .mgmtEps = pCxt->pComCxt->mgmtEpSet};
3391
0
    if (TSDB_CODE_SUCCESS == code) {
3392
0
      code = catalogGetTableHashVgroup(pCxt->pComCxt->pCatalog, &conn, &pStbRowsCxt->ctbName, &vg);
3393
0
    }
3394
0
    if (code == TSDB_CODE_SUCCESS) {
3395
0
      code = taosHashPut(pStmt->pVgroupsHashObj, (const char*)(&vg.vgId), sizeof(vg.vgId), &vg, sizeof(vg));
3396
0
    }
3397
0
    STableMeta* pBackup = NULL;
3398
0
    if (TSDB_CODE_SUCCESS == code) {
3399
0
      if (stmtNoCreateTbReq) {
3400
        /* Resolve child uid by db+tbname; must belong to the super table in this INSERT (same suid). */
3401
0
        STableMeta* pMeta = NULL;
3402
0
        code = catalogGetTableMeta(pCxt->pComCxt->pCatalog, &conn, &pStbRowsCxt->ctbName, &pMeta);
3403
0
        if (TSDB_CODE_SUCCESS == code) {
3404
0
          if (pMeta == NULL) {
3405
0
            code = TSDB_CODE_PAR_TABLE_NOT_EXIST;
3406
0
          } else if (TSDB_CHILD_TABLE != pMeta->tableType || pMeta->suid != pStbRowsCxt->pStbMeta->uid) {
3407
0
            taosMemoryFreeClear(pMeta);
3408
0
            code = generateSyntaxErrMsg(&pCxt->msg, TSDB_CODE_TDB_TABLE_IN_OTHER_STABLE);
3409
0
          } else {
3410
0
            pStbRowsCxt->pCtbMeta->uid = pMeta->uid;
3411
0
            pStbRowsCxt->pCtbMeta->sversion = pMeta->sversion;
3412
0
            pStbRowsCxt->pCtbMeta->tversion = pMeta->tversion;
3413
0
            taosMemoryFreeClear(pMeta);
3414
0
          }
3415
0
        }
3416
0
      } else {
3417
0
        pStbRowsCxt->pCtbMeta->uid = taosHashGetSize(pStmt->pSubTableHashObj) + 1;
3418
0
      }
3419
0
      if (TSDB_CODE_SUCCESS == code) {
3420
0
        pStbRowsCxt->pCtbMeta->vgId = vg.vgId;
3421
0
        code = cloneTableMeta(pStbRowsCxt->pCtbMeta, &pBackup);
3422
0
      }
3423
0
    }
3424
0
    if (TSDB_CODE_SUCCESS == code) {
3425
0
      code = taosHashPut(pStmt->pSubTableHashObj, ctbFName, strlen(ctbFName), &pBackup, POINTER_BYTES);
3426
0
    }
3427
0
    if (TSDB_CODE_SUCCESS == code) {
3428
0
      code = collectUseTable(&pStbRowsCxt->ctbName, pStmt->pTableNameHashObj);
3429
0
    }
3430
0
  }
3431
0
  return code;
3432
0
}
3433
3434
0
static void clearStbRowsDataContext(SStbRowsDataContext* pStbRowsCxt) {
3435
0
  if (pStbRowsCxt == NULL) return;
3436
3437
0
  taosArrayClear(pStbRowsCxt->aTagNames);
3438
0
  for (int i = 0; i < taosArrayGetSize(pStbRowsCxt->aTagVals); ++i) {
3439
0
    STagVal* p = (STagVal*)taosArrayGet(pStbRowsCxt->aTagVals, i);
3440
0
    if (IS_VAR_DATA_TYPE(p->type)) {
3441
0
      taosMemoryFreeClear(p->pData);
3442
0
    }
3443
0
  }
3444
0
  taosArrayClear(pStbRowsCxt->aTagVals);
3445
3446
0
  clearColValArray(pStbRowsCxt->aColVals);
3447
3448
0
  tTagFree(pStbRowsCxt->pTag);
3449
0
  pStbRowsCxt->pTag = NULL;
3450
0
  tdDestroySVCreateTbReq(pStbRowsCxt->pCreateCtbReq);
3451
0
  taosMemoryFreeClear(pStbRowsCxt->pCreateCtbReq);
3452
3453
0
  if (pStbRowsCxt->boundColsInfo.parseredTags != NULL) {
3454
0
    if (pStbRowsCxt->boundColsInfo.parseredTags->STagNames != NULL) {
3455
0
      taosArrayDestroy(pStbRowsCxt->boundColsInfo.parseredTags->STagNames);
3456
0
    }
3457
0
    if (pStbRowsCxt->boundColsInfo.parseredTags->pTagVals != NULL) {
3458
0
      taosArrayDestroy(pStbRowsCxt->boundColsInfo.parseredTags->pTagVals);
3459
0
    }
3460
0
    taosMemoryFreeClear(pStbRowsCxt->boundColsInfo.parseredTags);
3461
0
  }
3462
0
}
3463
3464
5
static void clearInsertParseContext(SInsertParseContext* pCxt) {
3465
5
  if (pCxt == NULL) return;
3466
3467
5
  if (pCxt->pParsedValues != NULL) {
3468
0
    tSimpleHashCleanup(pCxt->pParsedValues);
3469
0
    pCxt->pParsedValues = NULL;
3470
0
  }
3471
5
}
3472
3473
static int32_t parseStbBoundInfo(SVnodeModifyOpStmt* pStmt, SStbRowsDataContext* pStbRowsCxt,
3474
0
                                 STableDataCxt** ppTableDataCxt) {
3475
0
  char    tbFName[TSDB_TABLE_FNAME_LEN];
3476
0
  int32_t code = tNameExtractFullName(&pStmt->targetTableName, tbFName);
3477
0
  if (TSDB_CODE_SUCCESS != code) {
3478
0
    return code;
3479
0
  }
3480
0
  if (pStmt->usingTableProcessing) {
3481
0
    pStmt->pTableMeta->uid = 0;
3482
0
  }
3483
3484
0
  code = insGetTableDataCxt(pStmt->pTableBlockHashObj, tbFName, strlen(tbFName), pStmt->pTableMeta,
3485
0
                            &pStmt->pCreateTblReq, ppTableDataCxt, false, true);
3486
0
  if (code != TSDB_CODE_SUCCESS) {
3487
0
    return code;
3488
0
  }
3489
3490
0
  qDestroyBoundColInfo(&((*ppTableDataCxt)->boundColsInfo));
3491
0
  (*ppTableDataCxt)->boundColsInfo = pStbRowsCxt->boundColsInfo;
3492
3493
0
  (*ppTableDataCxt)->boundColsInfo.pColIndex = taosMemoryCalloc(pStbRowsCxt->boundColsInfo.numOfBound, sizeof(int16_t));
3494
0
  if (NULL == (*ppTableDataCxt)->boundColsInfo.pColIndex) {
3495
0
    return terrno;
3496
0
  }
3497
0
  (void)memcpy((*ppTableDataCxt)->boundColsInfo.pColIndex, pStbRowsCxt->boundColsInfo.pColIndex,
3498
0
               sizeof(int16_t) * pStmt->pStbRowsCxt->boundColsInfo.numOfBound);
3499
3500
0
  int32_t ret = initTableColSubmitData(*ppTableDataCxt);
3501
0
  if (ret != TSDB_CODE_SUCCESS) {
3502
0
    return ret;
3503
0
  }
3504
3505
0
  return TSDB_CODE_SUCCESS;
3506
0
}
3507
3508
static int32_t parseOneStbRow(SInsertParseContext* pCxt, SVnodeModifyOpStmt* pStmt, const char** ppSql,
3509
                              SStbRowsDataContext* pStbRowsCxt, bool* pGotRow, SToken* pToken,
3510
0
                              STableDataCxt** ppTableDataCxt) {
3511
0
  bool          bFirstTable = false;
3512
0
  bool          setCtbName = false;
3513
0
  bool          ctbColsTransferred = false;
3514
0
  SBoundColInfo ctbCols = {0};
3515
0
  int32_t code = getStbRowValues(pCxt, pStmt, ppSql, pStbRowsCxt, pGotRow, pToken, &bFirstTable, &setCtbName, &ctbCols);
3516
3517
0
  if (!setCtbName && pCxt->pComCxt->stmtBindVersion == 2) {
3518
0
    taosMemoryFreeClear(ctbCols.pColIndex);
3519
0
    return parseStbBoundInfo(pStmt, pStbRowsCxt, ppTableDataCxt);
3520
0
  }
3521
3522
0
  if (code != TSDB_CODE_SUCCESS || !*pGotRow) {
3523
0
    goto _return;
3524
0
  }
3525
3526
0
  if (code == TSDB_CODE_SUCCESS && bFirstTable) {
3527
0
    code = processCtbAutoCreationAndCtbMeta(pCxt, pStmt, pStbRowsCxt);
3528
0
  }
3529
0
  if (code == TSDB_CODE_SUCCESS) {
3530
0
    if (pCxt->pComCxt->stmtBindVersion == 2) {
3531
0
      char ctbFName[TSDB_TABLE_FNAME_LEN];
3532
0
      code = tNameExtractFullName(&pStbRowsCxt->ctbName, ctbFName);
3533
0
      if (code != TSDB_CODE_SUCCESS) {
3534
0
        goto _return;
3535
0
      }
3536
0
      code = insGetTableDataCxt(pStmt->pTableBlockHashObj, ctbFName, strlen(ctbFName), pStbRowsCxt->pCtbMeta,
3537
0
                                &pStbRowsCxt->pCreateCtbReq, ppTableDataCxt, true, true);
3538
0
    } else {
3539
0
      code =
3540
0
          insGetTableDataCxt(pStmt->pTableBlockHashObj, &pStbRowsCxt->pCtbMeta->uid, sizeof(pStbRowsCxt->pCtbMeta->uid),
3541
0
                             pStbRowsCxt->pCtbMeta, &pStbRowsCxt->pCreateCtbReq, ppTableDataCxt, false, true);
3542
0
    }
3543
0
  }
3544
0
  if (code == TSDB_CODE_SUCCESS) {
3545
0
    if (pCxt->pComCxt->stmtBindVersion == 2) {
3546
0
      int32_t tbnameIdx = getTbnameSchemaIndex(pStbRowsCxt->pStbMeta);
3547
0
      code = initTableColSubmitDataWithBoundInfo(*ppTableDataCxt, ctbCols);
3548
0
      if (code == TSDB_CODE_SUCCESS) {
3549
0
        ctbColsTransferred = true;
3550
0
      }
3551
0
    } else {
3552
0
      code = initTableColSubmitData(*ppTableDataCxt);
3553
0
    }
3554
0
  }
3555
0
  if (code == TSDB_CODE_SUCCESS && pCxt->pComCxt->stmtBindVersion == 0) {
3556
0
    SRow** pRow = taosArrayReserve((*ppTableDataCxt)->pData->aRowP, 1);
3557
0
    if ((*ppTableDataCxt)->hasBlob) {
3558
0
      SRowBuildScanInfo sinfo = {.hasBlob = 1, .scanType = ROW_BUILD_UPDATE};
3559
0
      if ((*ppTableDataCxt)->pData->pBlobSet == NULL) {
3560
0
        code = tBlobSetCreate(1024, 0, &(*ppTableDataCxt)->pData->pBlobSet);
3561
0
        TAOS_CHECK_GOTO(code, NULL, _return);
3562
0
      }
3563
0
      code = tRowBuildWithBlob(pStbRowsCxt->aColVals, (*ppTableDataCxt)->pSchema, pRow,
3564
0
                               (*ppTableDataCxt)->pData->pBlobSet, &sinfo);
3565
0
    } else {
3566
0
      SRowBuildScanInfo sinfo = {0};
3567
0
      code = tRowBuild(pStbRowsCxt->aColVals, (*ppTableDataCxt)->pSchema, pRow, &sinfo);
3568
0
    }
3569
0
    if (TSDB_CODE_SUCCESS == code) {
3570
0
      SRowKey key;
3571
0
      tRowGetKey(*pRow, &key);
3572
0
      insCheckTableDataOrder(*ppTableDataCxt, &key);
3573
0
    }
3574
0
  }
3575
3576
0
  if (code == TSDB_CODE_SUCCESS) {
3577
0
    *pGotRow = true;
3578
0
  }
3579
3580
0
_return:
3581
0
  if (!ctbColsTransferred && ctbCols.pColIndex != NULL) {
3582
0
    qDestroyBoundColInfo(&ctbCols);
3583
0
  }
3584
0
  clearStbRowsDataContext(pStbRowsCxt);
3585
3586
0
  return code;
3587
0
}
3588
3589
static int parseOneRow(SInsertParseContext* pCxt, const char** pSql, STableDataCxt* pTableCxt, bool* pGotRow,
3590
0
                       SToken* pToken) {
3591
0
  SBoundColInfo*    pCols = &pTableCxt->boundColsInfo;
3592
0
  SSchema*          pSchemas = getTableColumnSchema(pTableCxt->pMeta);
3593
0
  const SSchemaExt* pExtSchemas = getTableColumnExtSchema(pTableCxt->pMeta);
3594
3595
0
  int32_t code = TSDB_CODE_SUCCESS;
3596
  // 1. set the parsed value from sql string
3597
0
  for (int i = 0; i < pCols->numOfBound && TSDB_CODE_SUCCESS == code; ++i) {
3598
0
    const char* pOrigSql = *pSql;
3599
0
    bool        ignoreComma = false;
3600
0
    NEXT_TOKEN_WITH_PREV_EXT(*pSql, *pToken, &ignoreComma);
3601
0
    if (ignoreComma) {
3602
0
      code = buildSyntaxErrMsg(&pCxt->msg, "invalid data or symbol", pOrigSql);
3603
0
      break;
3604
0
    }
3605
3606
0
    SSchema*          pSchema = &pSchemas[pCols->pColIndex[i]];
3607
0
    const SSchemaExt* pExtSchema = pExtSchemas + pCols->pColIndex[i];
3608
0
    SColVal*          pVal = taosArrayGet(pTableCxt->pValues, pCols->pColIndex[i]);
3609
3610
0
    if (pToken->type == TK_NK_QUESTION) {
3611
0
      if (pCxt->pComCxt->stmtBindVersion == 0) {
3612
0
        code = buildSyntaxErrMsg(&pCxt->msg, "? only used in stmt", pToken->z);
3613
0
        break;
3614
0
      }
3615
0
    } else {
3616
0
      if (TK_NK_RP == pToken->type) {
3617
0
        code = generateSyntaxErrMsg(&pCxt->msg, TSDB_CODE_PAR_INVALID_COLUMNS_NUM);
3618
0
        break;
3619
0
      }
3620
3621
0
      if (TSDB_CODE_SUCCESS == code) {
3622
0
        code = parseValueToken(pCxt, pSql, pToken, pSchema, pExtSchema, getTableInfo(pTableCxt->pMeta).precision, pVal);
3623
3624
0
        if (TSDB_CODE_SUCCESS == code && pCxt->pComCxt->stmtBindVersion!=0) {
3625
0
          if (NULL == pCxt->pParsedValues) {
3626
0
            pCxt->pParsedValues =
3627
0
                tSimpleHashInit(pCols->numOfBound, taosGetDefaultHashFunction(TSDB_DATA_TYPE_SMALLINT));
3628
0
            if (NULL == pCxt->pParsedValues) {
3629
0
              code = terrno;
3630
0
              break;
3631
0
            }
3632
0
            tSimpleHashSetFreeFp(pCxt->pParsedValues, destroyColVal);
3633
0
          }
3634
3635
0
          SColVal clonedVal = *pVal;
3636
0
          if (COL_VAL_IS_VALUE(&clonedVal) && IS_VAR_DATA_TYPE(clonedVal.value.type)) {
3637
0
            clonedVal.value.pData = taosMemoryMalloc(clonedVal.value.nData);
3638
0
            if (NULL == clonedVal.value.pData) {
3639
0
              code = terrno;
3640
0
              break;
3641
0
            }
3642
0
            memcpy(clonedVal.value.pData, pVal->value.pData, clonedVal.value.nData);
3643
0
          }
3644
3645
0
          code = tSimpleHashPut(pCxt->pParsedValues, &pSchema->colId, sizeof(int16_t), &clonedVal, sizeof(SColVal));
3646
0
          if (code != TSDB_CODE_SUCCESS) {
3647
0
            if (COL_VAL_IS_VALUE(&clonedVal) && IS_VAR_DATA_TYPE(clonedVal.value.type)) {
3648
0
              taosMemoryFree(clonedVal.value.pData);
3649
0
              clonedVal.value.pData = NULL;
3650
0
            }
3651
0
            break;
3652
0
          }
3653
0
        }
3654
0
      }
3655
0
    }
3656
3657
0
    if (TSDB_CODE_SUCCESS == code && i < pCols->numOfBound - 1) {
3658
0
      NEXT_VALID_TOKEN(*pSql, *pToken);
3659
0
      if (TK_NK_COMMA != pToken->type) {
3660
        // ')' before all columns are consumed means the client has a stale schema with
3661
        // more columns than the server (e.g. after DROP COLUMN from another connection).
3662
        // Any other unexpected token is a genuine syntax error in the SQL.
3663
0
        if (!pCxt->forceUpdate && TK_NK_RP == pToken->type) {
3664
0
          code = TSDB_CODE_TDB_INVALID_TABLE_SCHEMA_VER;
3665
0
          parserWarn("QID:0x%" PRIx64 ", column number is smaller than %d, need retry", pCxt->pComCxt->requestId,
3666
0
                     pCols->numOfBound);
3667
0
        } else {
3668
0
          code = buildSyntaxErrMsg(&pCxt->msg, ", expected", pToken->z);
3669
0
        }
3670
0
      }
3671
0
    }
3672
0
  }
3673
3674
0
  if (TSDB_CODE_SUCCESS == code && pCxt->pComCxt->stmtBindVersion == 0) {
3675
0
    SRow** pRow = taosArrayReserve(pTableCxt->pData->aRowP, 1);
3676
0
    if (pTableCxt->hasBlob) {
3677
0
      SRowBuildScanInfo sinfo = {.hasBlob = 1, .scanType = ROW_BUILD_UPDATE};
3678
0
      if (pTableCxt->pData->pBlobSet == NULL) {
3679
0
        code = tBlobSetCreate(1024, 0, &pTableCxt->pData->pBlobSet);
3680
0
        TAOS_CHECK_RETURN(code);
3681
0
      }
3682
0
      code = tRowBuildWithBlob(pTableCxt->pValues, pTableCxt->pSchema, pRow, pTableCxt->pData->pBlobSet, &sinfo);
3683
0
    } else {
3684
0
      SRowBuildScanInfo sinfo = {0};
3685
0
      code = tRowBuild(pTableCxt->pValues, pTableCxt->pSchema, pRow, &sinfo);
3686
0
    }
3687
0
    if (TSDB_CODE_SUCCESS == code) {
3688
0
      SRowKey key;
3689
0
      tRowGetKey(*pRow, &key);
3690
0
      insCheckTableDataOrder(pTableCxt, &key);
3691
0
    }
3692
0
  }
3693
3694
0
  if (TSDB_CODE_SUCCESS == code && pCxt->pComCxt->stmtBindVersion == 0) {
3695
0
    *pGotRow = true;
3696
0
  }
3697
3698
0
  clearColValArray(pTableCxt->pValues);
3699
3700
0
  return code;
3701
0
}
3702
3703
// pSql -> (field1_value, ...) [(field1_value2, ...) ...]
3704
static int32_t parseValues(SInsertParseContext* pCxt, SVnodeModifyOpStmt* pStmt, SRowsDataContext rowsDataCxt,
3705
0
                           int32_t* pNumOfRows, SToken* pToken) {
3706
0
  int32_t code = TSDB_CODE_SUCCESS;
3707
3708
0
  (*pNumOfRows) = 0;
3709
0
  while (TSDB_CODE_SUCCESS == code) {
3710
0
    int32_t index = 0;
3711
0
    NEXT_TOKEN_KEEP_SQL(pStmt->pSql, *pToken, index);
3712
0
    if (TK_NK_LP != pToken->type) {
3713
0
      break;
3714
0
    }
3715
0
    pStmt->pSql += index;
3716
3717
0
    bool gotRow = false;
3718
0
    if (TSDB_CODE_SUCCESS == code) {
3719
0
      if (!pStmt->stbSyntax) {
3720
0
        code = parseOneRow(pCxt, &pStmt->pSql, rowsDataCxt.pTableDataCxt, &gotRow, pToken);
3721
0
      } else {
3722
        // foreach subtable
3723
0
        STableDataCxt* pTableDataCxt = NULL;
3724
0
        code = parseOneStbRow(pCxt, pStmt, &pStmt->pSql, rowsDataCxt.pStbRowsCxt, &gotRow, pToken, &pTableDataCxt);
3725
0
      }
3726
0
    }
3727
3728
0
    if (TSDB_CODE_SUCCESS == code) {
3729
0
      NEXT_VALID_TOKEN(pStmt->pSql, *pToken);
3730
0
      if (TK_NK_COMMA == pToken->type) {
3731
0
        code = generateSyntaxErrMsg(&pCxt->msg, TSDB_CODE_PAR_INVALID_COLUMNS_NUM);
3732
0
      } else if (TK_NK_RP != pToken->type) {
3733
0
        code = buildSyntaxErrMsg(&pCxt->msg, ") expected", pToken->z);
3734
0
      }
3735
0
    }
3736
3737
0
    if (TSDB_CODE_SUCCESS == code && gotRow) {
3738
0
      (*pNumOfRows)++;
3739
0
    }
3740
0
  }
3741
3742
0
  if (TSDB_CODE_SUCCESS == code && 0 == (*pNumOfRows) &&
3743
0
      (!TSDB_QUERY_HAS_TYPE(pStmt->insertType, TSDB_QUERY_TYPE_STMT_INSERT))) {
3744
0
    code = buildSyntaxErrMsg(&pCxt->msg, "no any data points", NULL);
3745
0
  }
3746
0
  return code;
3747
0
}
3748
3749
// VALUES (field1_value, ...) [(field1_value2, ...) ...]
3750
static int32_t parseValuesClause(SInsertParseContext* pCxt, SVnodeModifyOpStmt* pStmt, SRowsDataContext rowsDataContext,
3751
0
                                 SToken* pToken) {
3752
0
  int32_t numOfRows = 0;
3753
0
  int32_t code = parseValues(pCxt, pStmt, rowsDataContext, &numOfRows, pToken);
3754
0
  if (TSDB_CODE_SUCCESS == code) {
3755
0
    pStmt->totalRowsNum += numOfRows;
3756
0
    pStmt->totalTbNum += 1;
3757
0
    TSDB_QUERY_SET_TYPE(pStmt->insertType, TSDB_QUERY_TYPE_INSERT);
3758
0
  }
3759
0
  return code;
3760
0
}
3761
3762
// Simplified CSV parser - only handles newlines within quotes
3763
0
static int32_t csvParserReadLine(SCsvParser* parser) {
3764
0
  if (!parser) {
3765
0
    return TSDB_CODE_INVALID_PARA;
3766
0
  }
3767
3768
0
  size_t  lineLen = 0;
3769
0
  bool    inQuotes = false;
3770
0
  char    currentQuote = '\0';  // Track which quote character we're inside
3771
0
  bool    fieldStart = true;    // Track if we're at the start of a field
3772
0
  bool    afterQuote = false;   // Track if we just closed a quoted field
3773
0
  int32_t code = TSDB_CODE_SUCCESS;
3774
3775
0
  while (true) {
3776
    // Fill buffer if needed
3777
0
    if (parser->bufferPos >= parser->bufferLen) {
3778
0
      code = csvParserFillBuffer(parser);
3779
0
      if (code != TSDB_CODE_SUCCESS) {
3780
0
        break;
3781
0
      }
3782
0
      if (parser->bufferPos >= parser->bufferLen && parser->eof) {
3783
        // End of file
3784
0
        if (lineLen == 0) {
3785
0
          code = TSDB_CODE_TSC_QUERY_CANCELLED;  // Use this to indicate EOF
3786
0
        } else if (inQuotes) {
3787
          // Unclosed quote at end of file
3788
0
          code = TSDB_CODE_TSC_INVALID_INPUT;
3789
0
        }
3790
0
        break;
3791
0
      }
3792
0
    }
3793
3794
0
    char ch = parser->buffer[parser->bufferPos++];
3795
3796
    // Handle quotes - support both single and double quotes
3797
0
    if (!inQuotes && (ch == CSV_QUOTE_SINGLE || ch == CSV_QUOTE_DOUBLE)) {
3798
      // Quote can only start a field at the beginning of a field
3799
0
      if (!fieldStart) {
3800
        // Invalid: quote appears in the middle of an unquoted field
3801
0
        code = TSDB_CODE_TSC_INVALID_INPUT;
3802
0
        break;
3803
0
      }
3804
      // Starting a quoted section
3805
0
      inQuotes = true;
3806
0
      currentQuote = ch;
3807
0
      fieldStart = false;
3808
0
      afterQuote = false;
3809
0
    } else if (inQuotes && ch == currentQuote) {
3810
      // Check for escaped quote (double quote)
3811
0
      if (parser->bufferPos < parser->bufferLen && parser->buffer[parser->bufferPos] == currentQuote) {
3812
        // Escaped quote - keep both quotes in line for subsequent processing
3813
        // Ensure enough space for both quote characters
3814
0
        code = csvParserExpandLineBuffer(parser, lineLen + 2);
3815
0
        if (code != TSDB_CODE_SUCCESS) {
3816
0
          break;
3817
0
        }
3818
3819
        // Add the first quote character to the line
3820
0
        parser->lineBuffer[lineLen++] = ch;
3821
3822
        // Consume and add the second quote character
3823
0
        parser->bufferPos++;
3824
0
        ch = parser->buffer[parser->bufferPos - 1];  // The second quote
3825
0
        parser->lineBuffer[lineLen++] = ch;
3826
0
        continue;
3827
0
      } else {
3828
        // End of quoted section
3829
0
        inQuotes = false;
3830
0
        currentQuote = '\0';
3831
0
        afterQuote = true;  // Mark that we just closed a quote
3832
0
      }
3833
0
    } else if (ch == CSV_DEFAULT_DELIMITER && !inQuotes) {
3834
      // Comma marks the start of a new field
3835
0
      fieldStart = true;
3836
0
      afterQuote = false;
3837
0
    } else if (ch != '\r' && ch != '\n' && ch != ' ') {
3838
      // Non-space, non-newline character processing
3839
      // Check if we have invalid characters after closing quote
3840
0
      if (afterQuote) {
3841
        // Invalid: non-whitespace character after closing quote
3842
        // RFC 4180: after closing quote, only comma, space, or line end is allowed
3843
0
        code = TSDB_CODE_TSC_INVALID_INPUT;
3844
0
        break;
3845
0
      }
3846
      // Non-space character means we're no longer at field start
3847
0
      fieldStart = false;
3848
0
      afterQuote = false;
3849
0
    }
3850
3851
    // Handle newlines
3852
0
    if (ch == '\n' && !inQuotes) {
3853
      // End of line (not inside quotes)
3854
0
      break;
3855
0
    }
3856
3857
    // Skip \r characters only when outside quotes
3858
0
    if (ch == '\r' && !inQuotes) {
3859
0
      continue;
3860
0
    }
3861
3862
    // Expand buffer if needed
3863
0
    code = csvParserExpandLineBuffer(parser, lineLen + 1);
3864
0
    if (code != TSDB_CODE_SUCCESS) {
3865
0
      break;
3866
0
    }
3867
3868
    // Add character to line
3869
0
    parser->lineBuffer[lineLen++] = ch;
3870
0
  }
3871
3872
0
  if (code == TSDB_CODE_SUCCESS) {
3873
0
    parser->lineBuffer[lineLen] = '\0';
3874
0
  } else if (code == TSDB_CODE_TSC_INVALID_INPUT) {
3875
    // Set a more descriptive error for invalid CSV format
3876
0
    parser->lineBuffer[lineLen] = '\0';  // Null-terminate for error reporting
3877
0
  }
3878
3879
0
  return code;
3880
0
}
3881
3882
static int32_t parseCsvFile(SInsertParseContext* pCxt, SVnodeModifyOpStmt* pStmt, SRowsDataContext rowsDataCxt,
3883
0
                            int32_t* pNumOfRows) {
3884
0
  int32_t code = TSDB_CODE_SUCCESS;
3885
0
  (*pNumOfRows) = 0;
3886
3887
  // Initialize or use existing CSV parser in pStmt
3888
0
  if (pStmt->pCsvParser == NULL) {
3889
    // First time - allocate and initialize CSV parser
3890
0
    pStmt->pCsvParser = taosMemoryMalloc(sizeof(SCsvParser));
3891
0
    if (!pStmt->pCsvParser) {
3892
0
      return terrno;
3893
0
    }
3894
0
    code = csvParserInit(pStmt->pCsvParser, pStmt->fp);
3895
0
    if (code != TSDB_CODE_SUCCESS) {
3896
0
      taosMemoryFree(pStmt->pCsvParser);
3897
0
      pStmt->pCsvParser = NULL;
3898
0
      return code;
3899
0
    }
3900
0
  }
3901
  // If pStmt->pCsvParser exists, we continue from where we left off
3902
3903
0
  bool firstLine = (pStmt->fileProcessing == false);
3904
0
  pStmt->fileProcessing = false;
3905
3906
0
  while (TSDB_CODE_SUCCESS == code) {
3907
    // Read one line from CSV using the parser in pStmt
3908
0
    code = csvParserReadLine(pStmt->pCsvParser);
3909
0
    if (code == TSDB_CODE_TSC_QUERY_CANCELLED) {
3910
      // End of file
3911
0
      code = TSDB_CODE_SUCCESS;
3912
0
      break;
3913
0
    }
3914
0
    if (code == TSDB_CODE_TSC_INVALID_INPUT) {
3915
      // Invalid CSV format detected
3916
0
      code = buildSyntaxErrMsg(&pCxt->msg, "Invalid CSV format", pStmt->pCsvParser->lineBuffer);
3917
0
      break;
3918
0
    }
3919
0
    if (code != TSDB_CODE_SUCCESS) {
3920
0
      break;
3921
0
    }
3922
3923
    // Skip empty lines
3924
0
    if (!pStmt->pCsvParser->lineBuffer || strlen(pStmt->pCsvParser->lineBuffer) == 0) {
3925
0
      firstLine = false;
3926
0
      continue;
3927
0
    }
3928
3929
0
    bool   gotRow = false;
3930
0
    SToken token;
3931
0
    (void)strtolower(pStmt->pCsvParser->lineBuffer, pStmt->pCsvParser->lineBuffer);
3932
0
    const char* pRow = pStmt->pCsvParser->lineBuffer;
3933
3934
0
    if (!pStmt->stbSyntax) {
3935
0
      code = parseOneRow(pCxt, (const char**)&pRow, rowsDataCxt.pTableDataCxt, &gotRow, &token);
3936
0
    } else {
3937
0
      STableDataCxt* pTableDataCxt = NULL;
3938
0
      code = parseOneStbRow(pCxt, pStmt, (const char**)&pRow, rowsDataCxt.pStbRowsCxt, &gotRow, &token, &pTableDataCxt);
3939
0
      if (code == TSDB_CODE_SUCCESS) {
3940
0
        SStbRowsDataContext* pStbRowsCxt = rowsDataCxt.pStbRowsCxt;
3941
0
        void*                pData = pTableDataCxt;
3942
0
        code = taosHashPut(pStmt->pTableCxtHashObj, &pStbRowsCxt->pCtbMeta->uid, sizeof(pStbRowsCxt->pCtbMeta->uid),
3943
0
                           &pData, POINTER_BYTES);
3944
0
        if (TSDB_CODE_SUCCESS != code) {
3945
0
          break;
3946
0
        }
3947
0
      }
3948
0
    }
3949
3950
0
    if (code && firstLine) {
3951
0
      firstLine = false;
3952
0
      code = 0;
3953
0
      continue;
3954
0
    }
3955
3956
0
    if (TSDB_CODE_SUCCESS == code && gotRow) {
3957
0
      (*pNumOfRows)++;
3958
0
    }
3959
3960
0
    if (TSDB_CODE_SUCCESS == code && (*pNumOfRows) >= tsMaxInsertBatchRows) {
3961
      // Reached batch limit - keep the parser in pStmt for next batch
3962
0
      pStmt->fileProcessing = true;
3963
0
      break;
3964
0
    }
3965
0
    firstLine = false;
3966
0
  }
3967
3968
  // Don't destroy the parser here - it will be cleaned up when file processing is complete
3969
3970
0
  parserDebug("QID:0x%" PRIx64 ", %d rows have been parsed", pCxt->pComCxt->requestId, *pNumOfRows);
3971
3972
0
  if (TSDB_CODE_SUCCESS == code && 0 == (*pNumOfRows) && 0 == pStmt->totalRowsNum &&
3973
0
      (!TSDB_QUERY_HAS_TYPE(pStmt->insertType, TSDB_QUERY_TYPE_STMT_INSERT)) && !pStmt->fileProcessing) {
3974
0
    code = buildSyntaxErrMsg(&pCxt->msg, "no any data points", NULL);
3975
0
  }
3976
0
  return code;
3977
0
}
3978
3979
static int32_t parseDataFromFileImpl(SInsertParseContext* pCxt, SVnodeModifyOpStmt* pStmt,
3980
0
                                     SRowsDataContext rowsDataCxt) {
3981
  // init only for file
3982
0
  if (NULL == pStmt->pTableCxtHashObj) {
3983
0
    pStmt->pTableCxtHashObj = taosHashInit(128, taosGetDefaultHashFunction(TSDB_DATA_TYPE_BINARY), true, HASH_NO_LOCK);
3984
0
    if (!pStmt->pTableCxtHashObj) {
3985
0
      return terrno;
3986
0
    }
3987
0
  }
3988
0
  int32_t numOfRows = 0;
3989
0
  int32_t code = parseCsvFile(pCxt, pStmt, rowsDataCxt, &numOfRows);
3990
0
  if (TSDB_CODE_SUCCESS == code) {
3991
0
    pStmt->totalRowsNum += numOfRows;
3992
0
    pStmt->totalTbNum += 1;
3993
0
    TSDB_QUERY_SET_TYPE(pStmt->insertType, TSDB_QUERY_TYPE_FILE_INSERT);
3994
0
    if (rowsDataCxt.pTableDataCxt && rowsDataCxt.pTableDataCxt->pData) {
3995
0
      rowsDataCxt.pTableDataCxt->pData->flags |= SUBMIT_REQ_FROM_FILE;
3996
0
    }
3997
0
    if (!pStmt->fileProcessing) {
3998
      // File processing is complete, clean up saved CSV parser
3999
0
      destroySavedCsvParser(pStmt);
4000
0
      code = taosCloseFile(&pStmt->fp);
4001
0
      if (TSDB_CODE_SUCCESS != code) {
4002
0
        parserWarn("QID:0x%" PRIx64 ", failed to close file.", pCxt->pComCxt->requestId);
4003
0
      }
4004
0
    } else {
4005
0
      parserDebug("QID:0x%" PRIx64 ", insert from csv. File is too large, do it in batches.", pCxt->pComCxt->requestId);
4006
0
    }
4007
0
    if (pStmt->insertType != TSDB_QUERY_TYPE_FILE_INSERT) {
4008
0
      destroySavedCsvParser(pStmt);
4009
0
      return buildSyntaxErrMsg(&pCxt->msg, "keyword VALUES or FILE is exclusive", NULL);
4010
0
    }
4011
0
  } else {
4012
    // On error, also clean up saved CSV parser
4013
0
    destroySavedCsvParser(pStmt);
4014
0
    if (code == TSDB_CODE_TSC_SQL_SYNTAX_ERROR) {
4015
0
      return code;
4016
0
    }
4017
0
    return buildInvalidOperationMsg(&pCxt->msg, tstrerror(code));
4018
0
  }
4019
4020
  // just record pTableCxt whose data come from file
4021
0
  if (!pStmt->stbSyntax && numOfRows > 0) {
4022
0
    void* pData = rowsDataCxt.pTableDataCxt;
4023
0
    code = taosHashPut(pStmt->pTableCxtHashObj, &pStmt->pTableMeta->uid, sizeof(pStmt->pTableMeta->uid), &pData,
4024
0
                       POINTER_BYTES);
4025
0
  }
4026
4027
0
  return code;
4028
0
}
4029
4030
static int32_t parseDataFromFile(SInsertParseContext* pCxt, SVnodeModifyOpStmt* pStmt, SToken* pFilePath,
4031
0
                                 SRowsDataContext rowsDataCxt) {
4032
0
  char filePathStr[PATH_MAX + 16] = {0};
4033
0
  if (TK_NK_STRING == pFilePath->type) {
4034
0
    (void)trimString(pFilePath->z, pFilePath->n, filePathStr, sizeof(filePathStr));
4035
0
    if (strlen(filePathStr) >= PATH_MAX) {
4036
0
      return buildSyntaxErrMsg(&pCxt->msg, "file path is too long, max length is 4096", pFilePath->z);
4037
0
    }
4038
0
  } else {
4039
0
    if (pFilePath->n >= PATH_MAX) {
4040
0
      return buildSyntaxErrMsg(&pCxt->msg, "file path is too long, max length is 4096", pFilePath->z);
4041
0
    }
4042
0
    tstrncpy(filePathStr, pFilePath->z, pFilePath->n < sizeof(filePathStr) ? pFilePath->n + 1 : sizeof(filePathStr));
4043
0
  }
4044
0
  pStmt->fp = taosOpenFile(filePathStr, TD_FILE_READ);
4045
0
  if (NULL == pStmt->fp) {
4046
0
    return terrno;
4047
0
  }
4048
4049
0
  return parseDataFromFileImpl(pCxt, pStmt, rowsDataCxt);
4050
0
}
4051
4052
static int32_t parseFileClause(SInsertParseContext* pCxt, SVnodeModifyOpStmt* pStmt, SRowsDataContext rowsDataCxt,
4053
0
                               SToken* pToken) {
4054
0
  if (tsUseAdapter) {
4055
0
    return buildInvalidOperationMsg(&pCxt->msg, "proxy mode does not support csv loading");
4056
0
  }
4057
4058
0
  NEXT_TOKEN(pStmt->pSql, *pToken);
4059
0
  if (0 == pToken->n || (TK_NK_STRING != pToken->type && TK_NK_ID != pToken->type)) {
4060
0
    return buildSyntaxErrMsg(&pCxt->msg, "file path is required following keyword FILE", pToken->z);
4061
0
  }
4062
0
  return parseDataFromFile(pCxt, pStmt, pToken, rowsDataCxt);
4063
0
}
4064
4065
// VALUES (field1_value, ...) [(field1_value2, ...) ...] | FILE csv_file_path
4066
0
static int32_t parseDataClause(SInsertParseContext* pCxt, SVnodeModifyOpStmt* pStmt, SRowsDataContext rowsDataCxt) {
4067
0
  SToken token;
4068
0
  NEXT_TOKEN(pStmt->pSql, token);
4069
0
  switch (token.type) {
4070
0
    case TK_VALUES:
4071
0
      if (TSDB_QUERY_HAS_TYPE(pStmt->insertType, TSDB_QUERY_TYPE_FILE_INSERT)) {
4072
0
        return buildSyntaxErrMsg(&pCxt->msg, "keyword VALUES or FILE is exclusive", token.z);
4073
0
      }
4074
0
      return parseValuesClause(pCxt, pStmt, rowsDataCxt, &token);
4075
0
    case TK_FILE:
4076
0
      return parseFileClause(pCxt, pStmt, rowsDataCxt, &token);
4077
0
    default:
4078
0
      break;
4079
0
  }
4080
0
  return buildSyntaxErrMsg(&pCxt->msg, "keyword VALUES or FILE is expected", token.z);
4081
0
}
4082
4083
5
static void destroyStbRowsDataContext(SStbRowsDataContext* pStbRowsCxt) {
4084
5
  if (pStbRowsCxt == NULL) return;
4085
0
  clearStbRowsDataContext(pStbRowsCxt);
4086
0
  taosArrayDestroy(pStbRowsCxt->aColVals);
4087
0
  pStbRowsCxt->aColVals = NULL;
4088
0
  taosArrayDestroy(pStbRowsCxt->aTagVals);
4089
0
  pStbRowsCxt->aTagVals = NULL;
4090
0
  taosArrayDestroy(pStbRowsCxt->aTagNames);
4091
0
  pStbRowsCxt->aTagNames = NULL;
4092
0
  qDestroyBoundColInfo(&pStbRowsCxt->boundColsInfo);
4093
0
  tTagFree(pStbRowsCxt->pTag);
4094
0
  pStbRowsCxt->pTag = NULL;
4095
0
  taosMemoryFreeClear(pStbRowsCxt->pCtbMeta);
4096
0
  tdDestroySVCreateTbReq(pStbRowsCxt->pCreateCtbReq);
4097
0
  taosMemoryFreeClear(pStbRowsCxt->pCreateCtbReq);
4098
0
}
4099
4100
0
static int32_t constructStbRowsDataContext(SVnodeModifyOpStmt* pStmt, SStbRowsDataContext** ppStbRowsCxt) {
4101
0
  SStbRowsDataContext* pStbRowsCxt = taosMemoryCalloc(1, sizeof(SStbRowsDataContext));
4102
0
  if (!pStbRowsCxt) {
4103
0
    return terrno;
4104
0
  }
4105
0
  tNameAssign(&pStbRowsCxt->stbName, &pStmt->targetTableName);
4106
0
  int32_t code = collectUseTable(&pStbRowsCxt->stbName, pStmt->pTableNameHashObj);
4107
0
  if (TSDB_CODE_SUCCESS == code) {
4108
0
    code = collectUseDatabase(&pStbRowsCxt->stbName, pStmt->pDbFNameHashObj);
4109
0
  }
4110
0
  if (TSDB_CODE_SUCCESS == code) {
4111
0
    pStbRowsCxt->ctbName.type = TSDB_TABLE_NAME_T;
4112
0
    pStbRowsCxt->ctbName.acctId = pStbRowsCxt->stbName.acctId;
4113
0
    memcpy(pStbRowsCxt->ctbName.dbname, pStbRowsCxt->stbName.dbname, sizeof(pStbRowsCxt->stbName.dbname));
4114
4115
0
    pStbRowsCxt->pTagCond = pStmt->pTagCond;
4116
0
    pStbRowsCxt->pStbMeta = pStmt->pTableMeta;
4117
4118
0
    code = cloneTableMeta(pStbRowsCxt->pStbMeta, &pStbRowsCxt->pCtbMeta);
4119
0
  }
4120
0
  if (TSDB_CODE_SUCCESS == code) {
4121
0
    pStbRowsCxt->pCtbMeta->tableType = TSDB_CHILD_TABLE;
4122
0
    pStbRowsCxt->pCtbMeta->suid = pStbRowsCxt->pStbMeta->uid;
4123
4124
0
    pStbRowsCxt->aTagNames = taosArrayInit(8, TSDB_COL_NAME_LEN + sizeof(col_id_t));
4125
0
    if (!pStbRowsCxt->aTagNames) {
4126
0
      code = terrno;
4127
0
    }
4128
0
  }
4129
0
  if (TSDB_CODE_SUCCESS == code) {
4130
0
    pStbRowsCxt->aTagVals = taosArrayInit(8, sizeof(STagVal));
4131
0
    if (!pStbRowsCxt->aTagVals) {
4132
0
      code = terrno;
4133
0
    }
4134
0
  }
4135
0
  if (TSDB_CODE_SUCCESS == code) {
4136
    // col values and bound cols info of STableDataContext is not used
4137
0
    pStbRowsCxt->aColVals = taosArrayInit(getNumOfColumns(pStbRowsCxt->pStbMeta), sizeof(SColVal));
4138
0
    if (!pStbRowsCxt->aColVals) code = terrno;
4139
0
  }
4140
0
  if (TSDB_CODE_SUCCESS == code) {
4141
0
    code = insInitColValues(pStbRowsCxt->pStbMeta, pStbRowsCxt->aColVals);
4142
0
  }
4143
0
  if (TSDB_CODE_SUCCESS == code) {
4144
0
    STableComInfo tblInfo = getTableInfo(pStmt->pTableMeta);
4145
0
    code = insInitBoundColsInfo(tblInfo.numOfColumns + tblInfo.numOfTags + 1, &pStbRowsCxt->boundColsInfo);
4146
0
  }
4147
0
  if (TSDB_CODE_SUCCESS == code) {
4148
0
    *ppStbRowsCxt = pStbRowsCxt;
4149
0
  } else {
4150
0
    clearStbRowsDataContext(pStbRowsCxt);
4151
0
  }
4152
0
  return code;
4153
0
}
4154
4155
0
static int32_t parseInsertStbClauseBottom(SInsertParseContext* pCxt, SVnodeModifyOpStmt* pStmt) {
4156
0
  int32_t code = TSDB_CODE_SUCCESS;
4157
0
  if (!pStmt->pBoundCols) {
4158
0
    return buildSyntaxErrMsg(&pCxt->msg, "(...tbname, ts...) bounded cols is expected for supertable insertion",
4159
0
                             pStmt->pSql);
4160
0
  }
4161
4162
0
  SStbRowsDataContext* pStbRowsCxt = NULL;
4163
0
  code = constructStbRowsDataContext(pStmt, &pStbRowsCxt);
4164
4165
0
  if (code == TSDB_CODE_SUCCESS) {
4166
0
    code = parseBoundColumns(pCxt, pStmt, &pStmt->pBoundCols, BOUND_ALL_AND_TBNAME, pStmt->pTableMeta,
4167
0
                             &pStbRowsCxt->boundColsInfo);
4168
0
    pStbRowsCxt->hasTimestampTag = false;
4169
0
    for (int32_t i = 0; i < pStbRowsCxt->boundColsInfo.numOfBound; ++i) {
4170
0
      int16_t schemaIndex = pStbRowsCxt->boundColsInfo.pColIndex[i];
4171
0
      if (schemaIndex != getTbnameSchemaIndex(pStmt->pTableMeta) && schemaIndex >= getNumOfColumns(pStmt->pTableMeta)) {
4172
0
        if (pStmt->pTableMeta->schema[schemaIndex].type == TSDB_DATA_TYPE_TIMESTAMP) {
4173
0
          pStbRowsCxt->hasTimestampTag = true;
4174
0
        }
4175
0
        if (pStmt->pTableMeta->schema[schemaIndex].type == TSDB_DATA_TYPE_JSON) {
4176
0
          pStbRowsCxt->isJsonTag = true;
4177
0
        }
4178
0
      }
4179
0
    }
4180
0
    pStmt->pStbRowsCxt = pStbRowsCxt;
4181
0
  }
4182
4183
0
  if (code == TSDB_CODE_SUCCESS) {
4184
0
    SRowsDataContext rowsDataCxt;
4185
0
    rowsDataCxt.pStbRowsCxt = pStbRowsCxt;
4186
0
    code = parseDataClause(pCxt, pStmt, rowsDataCxt);
4187
0
  }
4188
4189
0
  return code;
4190
0
}
4191
4192
// input pStmt->pSql:
4193
//   1. [(tag1_name, ...)] ...
4194
//   2. VALUES ... | FILE ...
4195
0
static int32_t parseInsertTableClauseBottom(SInsertParseContext* pCxt, SVnodeModifyOpStmt* pStmt) {
4196
0
  if (!pStmt->stbSyntax) {
4197
0
    STableDataCxt*   pTableCxt = NULL;
4198
0
    int32_t          code = parseSchemaClauseBottom(pCxt, pStmt, &pTableCxt);
4199
0
    SRowsDataContext rowsDataCxt;
4200
0
    rowsDataCxt.pTableDataCxt = pTableCxt;
4201
0
    if (TSDB_CODE_SUCCESS == code) {
4202
0
      code = parseDataClause(pCxt, pStmt, rowsDataCxt);
4203
0
    }
4204
0
    return code;
4205
0
  } else {
4206
0
    int32_t code = parseInsertStbClauseBottom(pCxt, pStmt);
4207
0
    return code;
4208
0
  }
4209
0
}
4210
4211
0
static void resetEnvPreTable(SInsertParseContext* pCxt, SVnodeModifyOpStmt* pStmt) {
4212
0
  qDestroyBoundColInfo(&pCxt->tags);
4213
0
  clearInsertParseContext(pCxt);
4214
0
  taosMemoryFreeClear(pStmt->pTableMeta);
4215
0
  if (pStmt->pTagCond) nodesDestroyNode(pStmt->pTagCond);
4216
0
  if (pStmt->pPrivCols) taosArrayDestroy(pStmt->pPrivCols);
4217
0
  if (pStmt->pTableTag) taosArrayDestroy(pStmt->pTableTag);
4218
0
  tdDestroySVCreateTbReq(pStmt->pCreateTblReq);
4219
0
  taosMemoryFreeClear(pStmt->pCreateTblReq);
4220
0
  pCxt->missCache = false;
4221
0
  pCxt->usingDuplicateTable = false;
4222
0
  pStmt->pBoundCols = NULL;
4223
0
  pStmt->pPrivCols = NULL;
4224
0
  pStmt->pTagCond = NULL;
4225
0
  pStmt->usingTableProcessing = false;
4226
0
  pStmt->fileProcessing = false;
4227
0
  pStmt->usingTableName.type = 0;
4228
4229
0
  destroyStbRowsDataContext(pStmt->pStbRowsCxt);
4230
0
  taosMemoryFreeClear(pStmt->pStbRowsCxt);
4231
0
  pStmt->stbSyntax = false;
4232
0
}
4233
4234
// input pStmt->pSql: [(field1_name, ...)] [ USING ... ] VALUES ... | FILE ...
4235
0
static int32_t parseInsertTableClause(SInsertParseContext* pCxt, SVnodeModifyOpStmt* pStmt, SToken* pTbName) {
4236
0
  resetEnvPreTable(pCxt, pStmt);
4237
0
  int32_t code = parseSchemaClauseTop(pCxt, pStmt, pTbName);
4238
0
  if (TSDB_CODE_SUCCESS == code && !pCxt->missCache) {
4239
0
    code = parseInsertTableClauseBottom(pCxt, pStmt);
4240
0
  }
4241
4242
0
  return code;
4243
0
}
4244
4245
static int32_t checkTableClauseFirstToken(SInsertParseContext* pCxt, SVnodeModifyOpStmt* pStmt, SToken* pTbName,
4246
0
                                          bool* pHasData) {
4247
  // no data in the sql string anymore.
4248
0
  if (0 == pTbName->n) {
4249
0
    if (0 != pTbName->type && '\0' != pStmt->pSql[0]) {
4250
0
      return buildSyntaxErrMsg(&pCxt->msg, "invalid table name", pTbName->z);
4251
0
    }
4252
4253
0
    if (0 == pStmt->totalRowsNum && (!TSDB_QUERY_HAS_TYPE(pStmt->insertType, TSDB_QUERY_TYPE_STMT_INSERT))) {
4254
0
      return buildInvalidOperationMsg(&pCxt->msg, "no data in sql");
4255
0
    }
4256
4257
0
    *pHasData = false;
4258
0
    return TSDB_CODE_SUCCESS;
4259
0
  }
4260
4261
0
  if (TSDB_QUERY_HAS_TYPE(pStmt->insertType, TSDB_QUERY_TYPE_STMT_INSERT) && pStmt->totalTbNum > 0) {
4262
0
    return buildInvalidOperationMsg(&pCxt->msg, "single table allowed in one stmt");
4263
0
  }
4264
4265
0
  if (TK_NK_QUESTION == pTbName->type) {
4266
0
    pCxt->stmtTbNameFlag &= ~IS_FIXED_VALUE;
4267
0
    if (pCxt->pComCxt->stmtBindVersion == 0) {
4268
0
      return buildSyntaxErrMsg(&pCxt->msg, "? only used in stmt", pTbName->z);
4269
0
    }
4270
4271
0
    char*   tbName = NULL;
4272
0
    int32_t code = (*pCxt->pComCxt->pStmtCb->getTbNameFn)(pCxt->pComCxt->pStmtCb->pStmt, &tbName);
4273
0
    if (TSDB_CODE_SUCCESS == code) {
4274
0
      pCxt->stmtTbNameFlag |= HAS_BIND_VALUE;
4275
0
      pTbName->z = tbName;
4276
0
      pTbName->n = strlen(tbName);
4277
0
    }
4278
0
    if (code == TSDB_CODE_TSC_STMT_TBNAME_ERROR) {
4279
0
      pCxt->stmtTbNameFlag &= ~HAS_BIND_VALUE;
4280
0
      code = TSDB_CODE_SUCCESS;
4281
0
    }
4282
0
    return code;
4283
0
  }
4284
4285
0
  if (TK_NK_ID != pTbName->type && TK_NK_STRING != pTbName->type && TK_NK_QUESTION != pTbName->type) {
4286
0
    return buildSyntaxErrMsg(&pCxt->msg, "table_name is expected", pTbName->z);
4287
0
  }
4288
4289
  // db.? situation,ensure that the only thing following the '.' mark is '?'
4290
0
  char* tbNameAfterDbName = strnchr(pTbName->z, '.', pTbName->n, true);
4291
0
  if (tbNameAfterDbName != NULL) {
4292
0
    if (*(tbNameAfterDbName + 1) == '?') {
4293
0
      pCxt->stmtTbNameFlag &= ~IS_FIXED_VALUE;
4294
0
      char* tbName = NULL;
4295
0
      if (NULL == pCxt->pComCxt->pStmtCb) {
4296
0
        return buildSyntaxErrMsg(&pCxt->msg, "? only used in stmt", pTbName->z);
4297
0
      }
4298
0
      int32_t code = (*pCxt->pComCxt->pStmtCb->getTbNameFn)(pCxt->pComCxt->pStmtCb->pStmt, &tbName);
4299
0
      if (TSDB_CODE_SUCCESS == code) {
4300
0
        pCxt->stmtTbNameFlag |= HAS_BIND_VALUE;
4301
0
        pTbName->z = tbName;
4302
0
        pTbName->n = strlen(tbName);
4303
0
      }
4304
0
      if (code == TSDB_CODE_TSC_STMT_TBNAME_ERROR) {
4305
0
        pCxt->stmtTbNameFlag &= ~HAS_BIND_VALUE;
4306
0
        code = TSDB_CODE_SUCCESS;
4307
0
      }
4308
0
    } else {
4309
0
      pCxt->stmtTbNameFlag |= IS_FIXED_VALUE;
4310
0
      parserTrace("QID:0x%" PRIx64 ", stmt tbname:%s is specified in sql", pCxt->pComCxt->requestId, pTbName->z);
4311
0
      *pHasData = true;
4312
0
    }
4313
0
    return TSDB_CODE_SUCCESS;
4314
0
  }
4315
4316
0
  if (TK_NK_ID == pTbName->type) {
4317
0
    pCxt->stmtTbNameFlag |= IS_FIXED_VALUE;
4318
0
  }
4319
4320
0
  *pHasData = true;
4321
0
  return TSDB_CODE_SUCCESS;
4322
0
}
4323
4324
0
static int32_t setStmtInfo(SInsertParseContext* pCxt, SVnodeModifyOpStmt* pStmt) {
4325
0
  SBoundColInfo* tags = taosMemoryMalloc(sizeof(pCxt->tags));
4326
0
  if (NULL == tags) {
4327
0
    return terrno;
4328
0
  }
4329
0
  memcpy(tags, &pCxt->tags, sizeof(pCxt->tags));
4330
4331
0
  SStmtCallback* pStmtCb = pCxt->pComCxt->pStmtCb;
4332
0
  int32_t        code = (*pStmtCb->setInfoFn)(pStmtCb->pStmt, pStmt->pTableMeta, tags, &pCxt->pParsedValues,
4333
0
                                       &pStmt->targetTableName, pStmt->usingTableProcessing, pStmt->pVgroupsHashObj,
4334
0
                                       pStmt->pTableBlockHashObj, pStmt->usingTableName.tname, pCxt->stmtTbNameFlag);
4335
4336
0
  memset(&pCxt->tags, 0, sizeof(pCxt->tags));
4337
0
  pStmt->pVgroupsHashObj = NULL;
4338
0
  pStmt->pTableBlockHashObj = NULL;
4339
0
  return code;
4340
0
}
4341
4342
0
static int32_t parseInsertBodyBottom(SInsertParseContext* pCxt, SVnodeModifyOpStmt* pStmt) {
4343
0
  if (TSDB_QUERY_HAS_TYPE(pStmt->insertType, TSDB_QUERY_TYPE_STMT_INSERT)) {
4344
0
    return setStmtInfo(pCxt, pStmt);
4345
0
  }
4346
4347
  // release old array alloced by merge
4348
0
  pStmt->freeArrayFunc(pStmt->pVgDataBlocks);
4349
0
  pStmt->pVgDataBlocks = NULL;
4350
4351
0
  bool fileOnly = (pStmt->insertType == TSDB_QUERY_TYPE_FILE_INSERT);
4352
0
  if (fileOnly) {
4353
    // none data, skip merge & buildvgdata
4354
0
    if (0 == taosHashGetSize(pStmt->pTableCxtHashObj)) {
4355
0
      pCxt->needRequest = false;
4356
0
      return TSDB_CODE_SUCCESS;
4357
0
    }
4358
0
  }
4359
4360
  // merge according to vgId
4361
0
  int32_t code = insMergeTableDataCxt(fileOnly ? pStmt->pTableCxtHashObj : pStmt->pTableBlockHashObj,
4362
0
                                      &pStmt->pVgDataBlocks, pStmt->fileProcessing);
4363
  // clear tmp hashobj only
4364
0
  taosHashClear(pStmt->pTableCxtHashObj);
4365
4366
0
  if (TSDB_CODE_SUCCESS == code) {
4367
0
    code = insBuildVgDataBlocks(pStmt->pVgroupsHashObj, pStmt->pVgDataBlocks, &pStmt->pDataBlocks, false);
4368
0
  }
4369
4370
0
  return code;
4371
0
}
4372
4373
// tb_name
4374
//     [USING stb_name [(tag1_name, ...)] TAGS (tag1_value, ...)]
4375
//     [(field1_name, ...)]
4376
//     VALUES (field1_value, ...) [(field1_value2, ...) ...] | FILE csv_file_path
4377
// [...];
4378
0
static int32_t parseInsertBody(SInsertParseContext* pCxt, SVnodeModifyOpStmt* pStmt) {
4379
0
  SToken  token;
4380
0
  int32_t code = TSDB_CODE_SUCCESS;
4381
0
  bool    hasData = true;
4382
  // for each table
4383
0
  while (TSDB_CODE_SUCCESS == code && hasData && !pCxt->missCache && !pStmt->fileProcessing) {
4384
    // pStmt->pSql -> tb_name ...
4385
0
    NEXT_TOKEN(pStmt->pSql, token);
4386
0
    code = checkTableClauseFirstToken(pCxt, pStmt, &token, &hasData);
4387
0
    if (TSDB_CODE_SUCCESS == code && hasData) {
4388
0
      code = parseInsertTableClause(pCxt, pStmt, &token);
4389
0
    }
4390
4391
0
    if (TSDB_CODE_SUCCESS == code && pStmt->pTableMeta &&
4392
0
        (((pStmt->pTableMeta->virtualStb == 1) && (pStmt->pTableMeta->tableType == TSDB_SUPER_TABLE)) ||
4393
0
         (pStmt->pTableMeta->tableType == TSDB_VIRTUAL_NORMAL_TABLE ||
4394
0
          pStmt->pTableMeta->tableType == TSDB_VIRTUAL_CHILD_TABLE))) {
4395
0
      code = buildInvalidOperationMsg(&pCxt->msg, "Virtual table can not be written");
4396
0
    }
4397
0
  }
4398
4399
0
  if (TSDB_CODE_SUCCESS == code && !pCxt->missCache) {
4400
0
    code = parseInsertBodyBottom(pCxt, pStmt);
4401
0
  }
4402
0
  return code;
4403
0
}
4404
4405
0
static void destroySubTableHashElem(void* p) { taosMemoryFree(*(STableMeta**)p); }
4406
4407
5
static int32_t createVnodeModifOpStmt(SInsertParseContext* pCxt, bool reentry, SNode** pOutput) {
4408
5
  SVnodeModifyOpStmt* pStmt = NULL;
4409
5
  int32_t             code = nodesMakeNode(QUERY_NODE_VNODE_MODIFY_STMT, (SNode**)&pStmt);
4410
5
  if (NULL == pStmt) {
4411
0
    return code;
4412
0
  }
4413
4414
5
  if (pCxt->pComCxt->pStmtCb) {
4415
0
    TSDB_QUERY_SET_TYPE(pStmt->insertType, TSDB_QUERY_TYPE_STMT_INSERT);
4416
0
  }
4417
5
  pStmt->pSql = pCxt->pComCxt->pSql;
4418
4419
5
  pStmt->freeHashFunc = insDestroyTableDataCxtHashMap;
4420
5
  pStmt->freeArrayFunc = insDestroyVgroupDataCxtList;
4421
5
  pStmt->freeStbRowsCxtFunc = destroyStbRowsDataContext;
4422
5
  pStmt->pCsvParser = NULL;
4423
4424
5
  if (!reentry) {
4425
5
    pStmt->pVgroupsHashObj = taosHashInit(128, taosGetDefaultHashFunction(TSDB_DATA_TYPE_INT), true, HASH_ENTRY_LOCK);
4426
5
    if (pCxt->pComCxt->pStmtCb) {
4427
0
      pStmt->pTableBlockHashObj =
4428
0
          taosHashInit(128, taosGetDefaultHashFunction(TSDB_DATA_TYPE_BINARY), true, HASH_NO_LOCK);
4429
5
    } else {
4430
5
      pStmt->pTableBlockHashObj =
4431
5
          taosHashInit(128, taosGetDefaultHashFunction(TSDB_DATA_TYPE_BIGINT), true, HASH_NO_LOCK);
4432
5
    }
4433
5
  }
4434
5
  pStmt->pSubTableHashObj = taosHashInit(128, taosGetDefaultHashFunction(TSDB_DATA_TYPE_VARCHAR), true, HASH_NO_LOCK);
4435
5
  pStmt->pSuperTableHashObj = taosHashInit(128, taosGetDefaultHashFunction(TSDB_DATA_TYPE_VARCHAR), true, HASH_NO_LOCK);
4436
5
  pStmt->pTableNameHashObj = taosHashInit(128, taosGetDefaultHashFunction(TSDB_DATA_TYPE_VARCHAR), true, HASH_NO_LOCK);
4437
5
  pStmt->pDbFNameHashObj = taosHashInit(64, taosGetDefaultHashFunction(TSDB_DATA_TYPE_VARCHAR), true, HASH_NO_LOCK);
4438
5
  if ((!reentry && (NULL == pStmt->pVgroupsHashObj || NULL == pStmt->pTableBlockHashObj)) ||
4439
5
      NULL == pStmt->pSubTableHashObj || NULL == pStmt->pTableNameHashObj || NULL == pStmt->pDbFNameHashObj) {
4440
0
    nodesDestroyNode((SNode*)pStmt);
4441
0
    return TSDB_CODE_OUT_OF_MEMORY;
4442
0
  }
4443
4444
5
  taosHashSetFreeFp(pStmt->pSubTableHashObj, destroySubTableHashElem);
4445
5
  taosHashSetFreeFp(pStmt->pSuperTableHashObj, destroySubTableHashElem);
4446
4447
5
  *pOutput = (SNode*)pStmt;
4448
5
  return TSDB_CODE_SUCCESS;
4449
5
}
4450
4451
5
static int32_t createInsertQuery(SInsertParseContext* pCxt, SQuery** pOutput) {
4452
5
  SQuery* pQuery = NULL;
4453
5
  int32_t code = nodesMakeNode(QUERY_NODE_QUERY, (SNode**)&pQuery);
4454
5
  if (NULL == pQuery) {
4455
0
    return code;
4456
0
  }
4457
4458
5
  pQuery->execMode = QUERY_EXEC_MODE_SCHEDULE;
4459
5
  pQuery->haveResultSet = false;
4460
5
  pQuery->msgType = TDMT_VND_SUBMIT;
4461
4462
5
  code = createVnodeModifOpStmt(pCxt, false, &pQuery->pRoot);
4463
5
  if (TSDB_CODE_SUCCESS == code) {
4464
5
    *pOutput = pQuery;
4465
5
  } else {
4466
0
    nodesDestroyNode((SNode*)pQuery);
4467
0
  }
4468
5
  return code;
4469
5
}
4470
4471
0
static int32_t checkAuthFromMetaData(SInsertParseContext* pCxt, const SMetaData* pMetaData, SVnodeModifyOpStmt* pStmt) {
4472
0
  int32_t code = TSDB_CODE_SUCCESS;
4473
0
  if (1 != taosArrayGetSize(pMetaData->pUser)) {
4474
0
    code = TSDB_CODE_INTERNAL_ERROR;
4475
0
    uError("unexpected meta data size: %d since %s", (int32_t)taosArrayGetSize(pMetaData->pUser), tstrerror(code));
4476
0
    return code;
4477
0
  }
4478
4479
0
  SMetaRes* pRes = TARRAY_GET_ELEM(pMetaData->pUser, 0);
4480
0
  if (TSDB_CODE_SUCCESS == pRes->code) {
4481
0
    SUserAuthRes* pAuth = pRes->pRes;
4482
0
    pRes->code = nodesCloneNode(pAuth->pCond[AUTH_RES_BASIC], &pStmt->pTagCond);
4483
0
    if (pAuth->pCols && (TSDB_CODE_SUCCESS == pRes->code)) {
4484
0
      if (!(pStmt->pPrivCols = taosArrayDup(pAuth->pCols, NULL))) {
4485
0
        pRes->code = terrno;
4486
0
      }
4487
0
    }
4488
0
    if (TSDB_CODE_SUCCESS == pRes->code) {
4489
0
      return pAuth->pass[AUTH_RES_BASIC] ? TSDB_CODE_SUCCESS : TSDB_CODE_PAR_PERMISSION_DENIED;
4490
0
    }
4491
0
  }
4492
0
  return pRes->code;
4493
0
}
4494
4495
0
static int32_t getTableMetaFromMetaData(const SArray* pTables, STableMeta** pMeta) {
4496
0
  if (1 != taosArrayGetSize(pTables) && 2 != taosArrayGetSize(pTables)) {
4497
0
    return TSDB_CODE_FAILED;
4498
0
  }
4499
4500
0
  taosMemoryFreeClear(*pMeta);
4501
0
  SMetaRes* pRes = taosArrayGet(pTables, 0);
4502
0
  if (TSDB_CODE_SUCCESS == pRes->code) {
4503
0
    *pMeta = tableMetaDup((const STableMeta*)pRes->pRes);
4504
0
    if (NULL == *pMeta) {
4505
0
      return TSDB_CODE_OUT_OF_MEMORY;
4506
0
    }
4507
0
  }
4508
0
  return pRes->code;
4509
0
}
4510
4511
0
static int32_t checkAuthUseDb(SParseContext* pCxt, SName* pTbName, bool isAudit) {
4512
0
  int32_t       code = TSDB_CODE_SUCCESS;
4513
0
  SUserAuthInfo authInfo = {.userId = pCxt->userId, .privType = PRIV_DB_USE, .objType = PRIV_OBJ_DB};
4514
0
  (void)snprintf(authInfo.user, sizeof(authInfo.user), "%s", pCxt->pUser);
4515
0
  (void)snprintf(authInfo.tbName.dbname, sizeof(authInfo.tbName.dbname), "%s", pTbName->dbname);
4516
0
  authInfo.tbName.acctId = pTbName->acctId;
4517
0
  authInfo.tbName.type = TSDB_DB_NAME_T;
4518
0
  authInfo.useDb = isAudit ? AUTH_OWNED_MASK : (AUTH_AUTHORIZED_MASK | AUTH_OWNED_MASK);
4519
4520
0
  if (isAudit) {
4521
    // for audit db, recheck insert privilege
4522
0
    authInfo.privType = PRIV_AUDIT_TBL_INSERT;
4523
0
    authInfo.objType = PRIV_OBJ_TBL;
4524
0
  }
4525
4526
0
  SUserAuthRes     authRes = {0};
4527
0
  SRequestConnInfo conn = {.pTrans = pCxt->pTransporter,
4528
0
                           .requestId = pCxt->requestId,
4529
0
                           .requestObjRefId = pCxt->requestRid,
4530
0
                           .mgmtEps = pCxt->mgmtEpSet};
4531
0
  code = catalogChkAuth(pCxt->pCatalog, &conn, &authInfo, &authRes);  // cache used firstly inside the function
4532
0
  if (TSDB_CODE_SUCCESS == code && !authRes.pass[AUTH_RES_BASIC]) {
4533
0
    code = TSDB_CODE_PAR_DB_USE_PERMISSION_DENIED;
4534
0
  }
4535
0
  return code;
4536
0
}
4537
4538
0
static int32_t addTableVgroupFromMetaData(const SArray* pTables, SVnodeModifyOpStmt* pStmt, bool isStb) {
4539
0
  if (1 != taosArrayGetSize(pTables)) {
4540
0
    return TSDB_CODE_FAILED;
4541
0
  }
4542
4543
0
  SMetaRes* pRes = taosArrayGet(pTables, 0);
4544
0
  if (TSDB_CODE_SUCCESS != pRes->code) {
4545
0
    return pRes->code;
4546
0
  }
4547
4548
0
  SVgroupInfo* pVg = pRes->pRes;
4549
0
  if (isStb) {
4550
0
    pStmt->pTableMeta->vgId = pVg->vgId;
4551
0
  }
4552
0
  return taosHashPut(pStmt->pVgroupsHashObj, (const char*)&pVg->vgId, sizeof(pVg->vgId), (char*)pVg,
4553
0
                     sizeof(SVgroupInfo));
4554
0
}
4555
4556
0
static int32_t buildTagNameFromMeta(STableMeta* pMeta, SArray** pTagName) {
4557
0
  *pTagName = taosArrayInit(pMeta->tableInfo.numOfTags, TSDB_COL_NAME_LEN);
4558
0
  if (NULL == *pTagName) {
4559
0
    return terrno;
4560
0
  }
4561
0
  SSchema* pSchema = getTableTagSchema(pMeta);
4562
0
  int32_t  code = 0;
4563
0
  for (int32_t i = 0; i < pMeta->tableInfo.numOfTags; ++i) {
4564
0
    if (NULL == taosArrayPush(*pTagName, pSchema[i].name)) {
4565
0
      code = terrno;
4566
0
      taosArrayDestroy(*pTagName);
4567
0
      *pTagName = NULL;
4568
0
      break;
4569
0
    }
4570
0
  }
4571
0
  return code;
4572
0
}
4573
4574
0
static int32_t checkSubtablePrivilegeForTable(const SArray* pTables, SVnodeModifyOpStmt* pStmt) {
4575
#ifdef TD_ENTERPRISE
4576
  if (1 != taosArrayGetSize(pTables)) {
4577
    return TSDB_CODE_FAILED;
4578
  }
4579
4580
  SMetaRes* pRes = taosArrayGet(pTables, 0);
4581
  if (TSDB_CODE_SUCCESS != pRes->code) {
4582
    return pRes->code;
4583
  }
4584
4585
  SArray* pTagName = NULL;
4586
  int32_t code = buildTagNameFromMeta(pStmt->pTableMeta, &pTagName);
4587
  if (TSDB_CODE_SUCCESS == code) {
4588
    code = checkSubtablePrivilege((SArray*)pRes->pRes, pTagName, &pStmt->pTagCond);
4589
  }
4590
  taosArrayDestroy(pTagName);
4591
  return code;
4592
#else
4593
0
  return TSDB_CODE_SUCCESS;
4594
0
#endif
4595
0
}
4596
4597
static int32_t processTableSchemaFromMetaData(SInsertParseContext* pCxt, const SMetaData* pMetaData,
4598
0
                                              SVnodeModifyOpStmt* pStmt, bool isStb) {
4599
0
  int32_t code = TSDB_CODE_SUCCESS;
4600
0
  if (!isStb && TSDB_SUPER_TABLE == pStmt->pTableMeta->tableType) {
4601
0
    code = buildInvalidOperationMsg(&pCxt->msg, "insert data into super table is not supported");
4602
0
  }
4603
4604
  // Async second-round: pTableMeta[1] is ctb meta; absent/error means ctb does not exist yet.
4605
0
  if (TSDB_CODE_SUCCESS == code && isStb && taosArrayGetSize(pMetaData->pTableMeta) >= 2) {
4606
0
    SMetaRes* pCtbRes = TARRAY_GET_ELEM(pMetaData->pTableMeta, 1);
4607
0
    if (pCtbRes->code != TSDB_CODE_SUCCESS || pCtbRes->pRes == NULL) {
4608
0
      code = checkCreateTableAuth(pCxt->pComCxt, &pStmt->targetTableName, NULL);
4609
0
    }
4610
0
  }
4611
4612
0
  if (TSDB_CODE_SUCCESS == code && isStb) {
4613
0
    code = storeChildTableMeta(pCxt, pStmt);
4614
0
  }
4615
0
  if (TSDB_CODE_SUCCESS == code) {
4616
0
    code = addTableVgroupFromMetaData(pMetaData->pTableHash, pStmt, isStb);
4617
0
  }
4618
0
  if (TSDB_CODE_SUCCESS == code && !isStb && NULL != pStmt->pTagCond) {
4619
0
    code = checkSubtablePrivilegeForTable(pMetaData->pTableTag, pStmt);
4620
0
  }
4621
0
  return code;
4622
0
}
4623
4624
0
static void destoryTablesReq(void* p) {
4625
0
  STablesReq* pRes = (STablesReq*)p;
4626
0
  taosArrayDestroy(pRes->pTables);
4627
0
}
4628
4629
0
static void clearCatalogReq(SCatalogReq* pCatalogReq) {
4630
0
  if (NULL == pCatalogReq) {
4631
0
    return;
4632
0
  }
4633
4634
0
  taosArrayDestroyEx(pCatalogReq->pTableMeta, destoryTablesReq);
4635
0
  pCatalogReq->pTableMeta = NULL;
4636
0
  taosArrayDestroyEx(pCatalogReq->pTableHash, destoryTablesReq);
4637
0
  pCatalogReq->pTableHash = NULL;
4638
0
  taosArrayDestroy(pCatalogReq->pUser);
4639
0
  pCatalogReq->pUser = NULL;
4640
0
  taosArrayDestroy(pCatalogReq->pTableTag);
4641
0
  pCatalogReq->pTableTag = NULL;
4642
0
}
4643
4644
static int32_t setVnodeModifOpStmt(SInsertParseContext* pCxt, SCatalogReq* pCatalogReq, const SMetaData* pMetaData,
4645
0
                                   SVnodeModifyOpStmt* pStmt) {
4646
0
  clearCatalogReq(pCatalogReq);
4647
0
  if (pStmt->pPrivCols) {
4648
0
    taosArrayDestroy(pStmt->pPrivCols);
4649
0
    pStmt->pPrivCols = NULL;
4650
0
  }
4651
0
  if (pStmt->pTagCond) {
4652
0
    nodesDestroyNode(pStmt->pTagCond);
4653
0
    pStmt->pTagCond = NULL;
4654
0
  }
4655
4656
#ifdef TD_ENTERPRISE
4657
  // Federated query: reject INSERT into external source tables (Phase 2 check).
4658
  // In Phase 1, the dbname was registered in pCatalogReq->pExtSourceCheck.
4659
  // If the catalog resolved it as a valid ext source, reject the write here.
4660
  if (tsFederatedQueryEnable && pMetaData != NULL && pMetaData->pExtSourceInfo != NULL) {
4661
    int32_t nSrc = (int32_t)taosArrayGetSize(pMetaData->pExtSourceInfo);
4662
    for (int32_t i = 0; i < nSrc; ++i) {
4663
      SMetaRes* pRes = taosArrayGet(pMetaData->pExtSourceInfo, i);
4664
      if (pRes && pRes->code == TSDB_CODE_SUCCESS && pRes->pRes != NULL) {
4665
        return TSDB_CODE_EXT_SOURCE_WRITE_NOT_SUPPORTED;
4666
      }
4667
    }
4668
  }
4669
#endif
4670
4671
0
  int32_t code = checkAuthFromMetaData(pCxt, pMetaData, pStmt);
4672
4673
0
  if (code == TSDB_CODE_SUCCESS) {
4674
0
    code = getTableMetaFromMetaData(pMetaData->pTableMeta, &pStmt->pTableMeta);
4675
0
  }
4676
#ifdef TD_ENTERPRISE
4677
  // MAC NWD+NRU: retry path — metadata was just fetched from server, check must be enforced here too.
4678
  // (The primary NWD check in getTargetTableSchema is guarded by !missCache and therefore does not run
4679
  // when the first parse attempt hits a cache miss, e.g. fresh connections used by "taos -s".)
4680
  if (pCxt->pComCxt->macMode && code == TSDB_CODE_SUCCESS && pStmt->pTableMeta != NULL) {
4681
    int8_t secLvl = pStmt->pTableMeta->secLvl;
4682
    if (secLvl >= 0) {
4683
      if (pCxt->pComCxt->minSecLevel > secLvl) {
4684
        code = TSDB_CODE_MAC_NO_WRITE_DOWN;  // NWD violation
4685
      } else if (pCxt->pComCxt->maxSecLevel < secLvl) {
4686
        code = TSDB_CODE_MAC_INSUFFICIENT_LEVEL;  // NRU violation
4687
      }
4688
    }
4689
  }
4690
#endif
4691
0
  if (code == TSDB_CODE_SUCCESS) {
4692
0
    code = checkAuthUseDb(pCxt->pComCxt, &pStmt->targetTableName, pStmt->pTableMeta->isAudit);
4693
0
  }
4694
0
  if (code == TSDB_CODE_SUCCESS) {
4695
0
    if (pStmt->pTableMeta->tableType == TSDB_SUPER_TABLE && !pStmt->usingTableProcessing) {
4696
0
      pStmt->stbSyntax = true;
4697
0
    }
4698
0
    if (!pStmt->stbSyntax) {
4699
0
      if (pStmt->usingTableProcessing) {
4700
0
        return processTableSchemaFromMetaData(pCxt, pMetaData, pStmt, true);
4701
0
      }
4702
0
      return processTableSchemaFromMetaData(pCxt, pMetaData, pStmt, false);
4703
0
    }
4704
0
  }
4705
0
  return code;
4706
0
}
4707
4708
0
static int32_t resetVnodeModifOpStmt(SInsertParseContext* pCxt, SQuery* pQuery) {
4709
0
  nodesDestroyNode(pQuery->pRoot);
4710
4711
0
  int32_t code = createVnodeModifOpStmt(pCxt, true, &pQuery->pRoot);
4712
0
  if (TSDB_CODE_SUCCESS == code) {
4713
0
    SVnodeModifyOpStmt* pStmt = (SVnodeModifyOpStmt*)pQuery->pRoot;
4714
4715
0
    code = (*pCxt->pComCxt->pStmtCb->getExecInfoFn)(pCxt->pComCxt->pStmtCb->pStmt, &pStmt->pVgroupsHashObj,
4716
0
                                                    &pStmt->pTableBlockHashObj);
4717
0
    if (TSDB_CODE_SUCCESS == code) {
4718
0
      if (NULL == pStmt->pVgroupsHashObj) {
4719
0
        pStmt->pVgroupsHashObj = taosHashInit(128, taosGetDefaultHashFunction(TSDB_DATA_TYPE_INT), true, HASH_NO_LOCK);
4720
0
      }
4721
0
      if (NULL == pStmt->pTableBlockHashObj) {
4722
0
        pStmt->pTableBlockHashObj =
4723
0
            taosHashInit(128, taosGetDefaultHashFunction(TSDB_DATA_TYPE_BINARY), true, HASH_NO_LOCK);
4724
0
      }
4725
0
      if (NULL == pStmt->pVgroupsHashObj || NULL == pStmt->pTableBlockHashObj) {
4726
0
        code = TSDB_CODE_OUT_OF_MEMORY;
4727
0
      }
4728
0
    }
4729
0
  }
4730
4731
0
  return code;
4732
0
}
4733
4734
static int32_t initInsertQuery(SInsertParseContext* pCxt, SCatalogReq* pCatalogReq, const SMetaData* pMetaData,
4735
5
                               SQuery** pQuery) {
4736
5
  if (NULL == *pQuery) {
4737
5
    return createInsertQuery(pCxt, pQuery);
4738
5
  }
4739
4740
0
  if (NULL != pCxt->pComCxt->pStmtCb) {
4741
0
    return resetVnodeModifOpStmt(pCxt, *pQuery);
4742
0
  }
4743
4744
0
  SVnodeModifyOpStmt* pStmt = (SVnodeModifyOpStmt*)(*pQuery)->pRoot;
4745
4746
0
  if (!pStmt->fileProcessing) {
4747
0
    return setVnodeModifOpStmt(pCxt, pCatalogReq, pMetaData, pStmt);
4748
0
  }
4749
4750
0
  return TSDB_CODE_SUCCESS;
4751
0
}
4752
4753
0
static int32_t setRefreshMeta(SQuery* pQuery) {
4754
0
  SVnodeModifyOpStmt* pStmt = (SVnodeModifyOpStmt*)pQuery->pRoot;
4755
0
  int32_t             code = 0;
4756
4757
0
  if (taosHashGetSize(pStmt->pTableNameHashObj) > 0) {
4758
0
    taosArrayDestroy(pQuery->pTableList);
4759
0
    pQuery->pTableList = taosArrayInit(taosHashGetSize(pStmt->pTableNameHashObj), sizeof(SName));
4760
0
    if (!pQuery->pTableList) {
4761
0
      code = terrno;
4762
0
    } else {
4763
0
      SName* pTable = taosHashIterate(pStmt->pTableNameHashObj, NULL);
4764
0
      while (NULL != pTable) {
4765
0
        if (NULL == taosArrayPush(pQuery->pTableList, pTable)) {
4766
0
          code = terrno;
4767
0
          taosHashCancelIterate(pStmt->pTableNameHashObj, pTable);
4768
0
          break;
4769
0
        }
4770
0
        pTable = taosHashIterate(pStmt->pTableNameHashObj, pTable);
4771
0
      }
4772
0
    }
4773
0
  }
4774
4775
0
  if (TSDB_CODE_SUCCESS == code && taosHashGetSize(pStmt->pDbFNameHashObj) > 0) {
4776
0
    taosArrayDestroy(pQuery->pDbList);
4777
0
    pQuery->pDbList = taosArrayInit(taosHashGetSize(pStmt->pDbFNameHashObj), TSDB_DB_FNAME_LEN);
4778
0
    if (!pQuery->pDbList) {
4779
0
      code = terrno;
4780
0
    } else {
4781
0
      char* pDb = taosHashIterate(pStmt->pDbFNameHashObj, NULL);
4782
0
      while (NULL != pDb) {
4783
0
        if (NULL == taosArrayPush(pQuery->pDbList, pDb)) {
4784
0
          code = terrno;
4785
0
          taosHashCancelIterate(pStmt->pDbFNameHashObj, pDb);
4786
0
          break;
4787
0
        }
4788
0
        pDb = taosHashIterate(pStmt->pDbFNameHashObj, pDb);
4789
0
      }
4790
0
    }
4791
0
  }
4792
4793
0
  return code;
4794
0
}
4795
4796
// INSERT INTO
4797
//   tb_name
4798
//       [USING stb_name [(tag1_name, ...)] TAGS (tag1_value, ...) [table_options]]
4799
//       [(field1_name, ...)]
4800
//       VALUES (field1_value, ...) [(field1_value2, ...) ...] | FILE csv_file_path
4801
//   [...];
4802
5
static int32_t parseInsertSqlFromStart(SInsertParseContext* pCxt, SVnodeModifyOpStmt* pStmt) {
4803
5
  int32_t code = skipInsertInto(&pStmt->pSql, &pCxt->msg);
4804
5
  if (TSDB_CODE_SUCCESS == code) {
4805
0
    code = parseInsertBody(pCxt, pStmt);
4806
0
  }
4807
5
  return code;
4808
5
}
4809
4810
0
static int32_t parseInsertSqlFromCsv(SInsertParseContext* pCxt, SVnodeModifyOpStmt* pStmt) {
4811
0
  int32_t          code = TSDB_CODE_SUCCESS;
4812
0
  SRowsDataContext rowsDataCxt;
4813
4814
0
  if (!pStmt->stbSyntax) {
4815
0
    STableDataCxt* pTableCxt = NULL;
4816
0
    code = getTableDataCxt(pCxt, pStmt, &pTableCxt);
4817
0
    rowsDataCxt.pTableDataCxt = pTableCxt;
4818
0
  } else {
4819
0
    rowsDataCxt.pStbRowsCxt = pStmt->pStbRowsCxt;
4820
0
  }
4821
0
  if (TSDB_CODE_SUCCESS == code) {
4822
0
    code = parseDataFromFileImpl(pCxt, pStmt, rowsDataCxt);
4823
0
  }
4824
4825
0
  if (TSDB_CODE_SUCCESS == code) {
4826
0
    if (pStmt->fileProcessing) {
4827
0
      code = parseInsertBodyBottom(pCxt, pStmt);
4828
0
    } else {
4829
0
      code = parseInsertBody(pCxt, pStmt);
4830
0
    }
4831
0
  }
4832
4833
0
  return code;
4834
0
}
4835
4836
0
static int32_t parseInsertSqlFromTable(SInsertParseContext* pCxt, SVnodeModifyOpStmt* pStmt) {
4837
0
  int32_t code = parseInsertTableClauseBottom(pCxt, pStmt);
4838
0
  if (TSDB_CODE_SUCCESS == code) {
4839
0
    code = parseInsertBody(pCxt, pStmt);
4840
0
  }
4841
0
  return code;
4842
0
}
4843
4844
5
static int32_t parseInsertSqlImpl(SInsertParseContext* pCxt, SVnodeModifyOpStmt* pStmt) {
4845
5
  if (pStmt->pSql == pCxt->pComCxt->pSql || NULL != pCxt->pComCxt->pStmtCb) {
4846
5
    return parseInsertSqlFromStart(pCxt, pStmt);
4847
5
  }
4848
4849
0
  if (pStmt->fileProcessing) {
4850
0
    return parseInsertSqlFromCsv(pCxt, pStmt);
4851
0
  }
4852
4853
0
  return parseInsertSqlFromTable(pCxt, pStmt);
4854
0
}
4855
4856
0
static int32_t buildUsingInsertTableReq(SName* pSName, SName* pCName, SArray** pTables) {
4857
0
  if (NULL == *pTables) {
4858
0
    *pTables = taosArrayInit(2, sizeof(SName));
4859
0
    if (NULL == *pTables) {
4860
0
      goto _err;
4861
0
    }
4862
0
  }
4863
0
  if (NULL == taosArrayPush(*pTables, pSName)) {
4864
0
    goto _err;
4865
0
  }
4866
0
  if (NULL == taosArrayPush(*pTables, pCName)) {
4867
0
    goto _err;
4868
0
  }
4869
0
  return TSDB_CODE_SUCCESS;
4870
4871
0
_err:
4872
0
  if (NULL != *pTables) {
4873
0
    taosArrayDestroy(*pTables);
4874
0
    *pTables = NULL;
4875
0
  }
4876
0
  return terrno;
4877
0
}
4878
4879
0
static int32_t buildInsertTableReq(SName* pName, SArray** pTables) {
4880
0
  *pTables = taosArrayInit(1, sizeof(SName));
4881
0
  if (NULL == *pTables) {
4882
0
    return terrno;
4883
0
  }
4884
4885
0
  if (NULL == taosArrayPush(*pTables, pName)) {
4886
0
    taosArrayDestroy(*pTables);
4887
0
    *pTables = NULL;
4888
0
    return terrno;
4889
0
  }
4890
0
  return TSDB_CODE_SUCCESS;
4891
0
}
4892
4893
0
static int32_t buildInsertUsingDbReq(SName* pSName, SName* pCName, SArray** pDbs) {
4894
0
  if (NULL == *pDbs) {
4895
0
    *pDbs = taosArrayInit(1, sizeof(STablesReq));
4896
0
    if (NULL == *pDbs) {
4897
0
      return terrno;
4898
0
    }
4899
0
  }
4900
4901
0
  STablesReq req = {0};
4902
0
  req.autoCreate = 1;
4903
0
  (void)tNameGetFullDbName(pSName, req.dbFName);
4904
0
  (void)tNameGetFullDbName(pCName, req.dbFName);
4905
4906
0
  int32_t code = buildUsingInsertTableReq(pSName, pCName, &req.pTables);
4907
0
  if (TSDB_CODE_SUCCESS == code && NULL == taosArrayPush(*pDbs, &req)) {
4908
0
    code = TSDB_CODE_OUT_OF_MEMORY;
4909
0
  }
4910
0
  return code;
4911
0
}
4912
4913
0
static int32_t buildInsertDbReq(SName* pName, SArray** pDbs) {
4914
0
  if (NULL == *pDbs) {
4915
0
    *pDbs = taosArrayInit(1, sizeof(STablesReq));
4916
0
    if (NULL == *pDbs) {
4917
0
      return terrno;
4918
0
    }
4919
0
  }
4920
4921
0
  STablesReq req = {0};
4922
0
  (void)tNameGetFullDbName(pName, req.dbFName);
4923
0
  int32_t code = buildInsertTableReq(pName, &req.pTables);
4924
0
  if (TSDB_CODE_SUCCESS == code && NULL == taosArrayPush(*pDbs, &req)) {
4925
0
    code = TSDB_CODE_OUT_OF_MEMORY;
4926
0
  }
4927
4928
0
  return code;
4929
0
}
4930
4931
0
static int32_t buildInsertUserAuthReq(SParseContext* pCxt, SName* pName, SArray** pUserAuth) {
4932
0
  *pUserAuth = taosArrayInit(1, sizeof(SUserAuthInfo));
4933
0
  if (NULL == *pUserAuth) {
4934
0
    return terrno;
4935
0
  }
4936
4937
0
  SUserAuthInfo userAuth = {.privType = PRIV_TBL_INSERT, .objType = PRIV_OBJ_TBL, .userId = pCxt->userId};
4938
0
  snprintf(userAuth.user, sizeof(userAuth.user), "%s", pCxt->pUser);
4939
0
  memcpy(&userAuth.tbName, pName, sizeof(SName));
4940
0
  if (NULL == taosArrayPush(*pUserAuth, &userAuth)) {
4941
0
    taosArrayDestroy(*pUserAuth);
4942
0
    *pUserAuth = NULL;
4943
0
    return terrno;
4944
0
  }
4945
4946
0
  return TSDB_CODE_SUCCESS;
4947
0
}
4948
4949
0
static int32_t buildInsertTableTagReq(SName* pName, SArray** pTables) { return buildInsertTableReq(pName, pTables); }
4950
4951
0
static int32_t buildInsertCatalogReq(SInsertParseContext* pCxt, SVnodeModifyOpStmt* pStmt, SCatalogReq* pCatalogReq) {
4952
0
  int32_t code = buildInsertUserAuthReq(
4953
0
      pCxt->pComCxt, (0 == pStmt->usingTableName.type ? &pStmt->targetTableName : &pStmt->usingTableName),
4954
0
      &pCatalogReq->pUser);
4955
0
  if (TSDB_CODE_SUCCESS == code && pCxt->needTableTagVal) {
4956
0
    code = buildInsertTableTagReq(&pStmt->targetTableName, &pCatalogReq->pTableTag);
4957
0
  }
4958
0
  if (TSDB_CODE_SUCCESS == code) {
4959
0
    if (0 == pStmt->usingTableName.type) {
4960
0
      code = buildInsertDbReq(&pStmt->targetTableName, &pCatalogReq->pTableMeta);
4961
0
    } else {
4962
0
      code = buildInsertUsingDbReq(&pStmt->usingTableName, &pStmt->targetTableName, &pCatalogReq->pTableMeta);
4963
0
    }
4964
0
  }
4965
0
  if (TSDB_CODE_SUCCESS == code) {
4966
0
    code = buildInsertDbReq(&pStmt->targetTableName, &pCatalogReq->pTableHash);
4967
0
  }
4968
#ifdef TD_ENTERPRISE
4969
  if (TSDB_CODE_SUCCESS == code && tsFederatedQueryEnable && pStmt->targetTableName.dbname[0] != '\0') {
4970
    if (NULL == pCatalogReq->pExtSourceCheck) {
4971
      pCatalogReq->pExtSourceCheck = taosArrayInit(1, TSDB_TABLE_NAME_LEN);
4972
    }
4973
    if (NULL != pCatalogReq->pExtSourceCheck) {
4974
      char nameBuf[TSDB_TABLE_NAME_LEN] = {0};
4975
      tstrncpy(nameBuf, pStmt->targetTableName.dbname, TSDB_TABLE_NAME_LEN);
4976
      taosArrayPush(pCatalogReq->pExtSourceCheck, nameBuf);
4977
    }
4978
  }
4979
#endif
4980
0
  return code;
4981
0
}
4982
4983
0
static int32_t setNextStageInfo(SInsertParseContext* pCxt, SQuery* pQuery, SCatalogReq* pCatalogReq) {
4984
0
  SVnodeModifyOpStmt* pStmt = (SVnodeModifyOpStmt*)pQuery->pRoot;
4985
0
  if (pCxt->missCache) {
4986
0
    parserDebug("QID:0x%" PRIx64 ", %d rows of %d tables will be inserted before obtain the cache",
4987
0
                pCxt->pComCxt->requestId, pStmt->totalRowsNum, pStmt->totalTbNum);
4988
4989
0
    pQuery->execStage = QUERY_EXEC_STAGE_PARSE;
4990
0
    return buildInsertCatalogReq(pCxt, pStmt, pCatalogReq);
4991
0
  }
4992
4993
0
  parserDebug("QID:0x%" PRIx64 ", %d rows of %d tables will be inserted", pCxt->pComCxt->requestId, pStmt->totalRowsNum,
4994
0
              pStmt->totalTbNum);
4995
4996
0
  pQuery->execStage = QUERY_EXEC_STAGE_SCHEDULE;
4997
0
  return TSDB_CODE_SUCCESS;
4998
0
}
4999
5000
5
int32_t parseInsertSql(SParseContext* pCxt, SQuery** pQuery, SCatalogReq* pCatalogReq, const SMetaData* pMetaData) {
5001
5
  SInsertParseContext context = {.pComCxt = pCxt,
5002
5
                                 .msg = {.buf = pCxt->pMsg, .len = pCxt->msgLen},
5003
5
                                 .missCache = false,
5004
5
                                 .usingDuplicateTable = false,
5005
5
                                 .needRequest = true,
5006
5
                                 .forceUpdate = (NULL != pCatalogReq ? pCatalogReq->forceUpdate : false)};
5007
5008
5
  int32_t code = initInsertQuery(&context, pCatalogReq, pMetaData, pQuery);
5009
5
  if (TSDB_CODE_SUCCESS == code) {
5010
5
    code = parseInsertSqlImpl(&context, (SVnodeModifyOpStmt*)((*pQuery)->pRoot));
5011
5
  }
5012
5013
5
  if (TSDB_CODE_SUCCESS == code) {
5014
0
    code = setNextStageInfo(&context, *pQuery, pCatalogReq);
5015
0
  }
5016
5
  if ((TSDB_CODE_SUCCESS == code || NEED_CLIENT_HANDLE_ERROR(code)) &&
5017
0
      QUERY_EXEC_STAGE_SCHEDULE == (*pQuery)->execStage) {
5018
0
    code = setRefreshMeta(*pQuery);
5019
0
  }
5020
5021
5
  qDestroyBoundColInfo(&context.tags);
5022
5
  clearInsertParseContext(&context);
5023
  // if no data to insert, set emptyMode to avoid request server
5024
5
  if (!context.needRequest) {
5025
0
    (*pQuery)->execMode = QUERY_EXEC_MODE_EMPTY_RESULT;
5026
0
  }
5027
5
  return code;
5028
5
}
5029
5030
// CSV Parser Implementation
5031
0
static int32_t csvParserInit(SCsvParser* parser, TdFilePtr pFile) {
5032
0
  if (!parser || !pFile) {
5033
0
    return TSDB_CODE_INVALID_PARA;
5034
0
  }
5035
5036
0
  memset(parser, 0, sizeof(SCsvParser));
5037
5038
  // Set default CSV format
5039
0
  parser->delimiter = CSV_DEFAULT_DELIMITER;
5040
0
  parser->quote = CSV_QUOTE_SINGLE;  // Default to single quote for TDengine compatibility
5041
0
  parser->escape = CSV_ESCAPE_CHAR;
5042
0
  parser->allowNewlineInField = true;
5043
5044
  // Initialize buffer
5045
0
  parser->bufferSize = 64 * 1024;  // 64KB buffer
5046
0
  parser->buffer = taosMemoryMalloc(parser->bufferSize);
5047
0
  if (!parser->buffer) {
5048
0
    return terrno;
5049
0
  }
5050
5051
  // Initialize line buffer for reuse
5052
0
  parser->lineBufferCapacity = 64 * 1024;  // Initial 64KB line buffer
5053
0
  parser->lineBuffer = taosMemoryMalloc(parser->lineBufferCapacity);
5054
0
  if (!parser->lineBuffer) {
5055
0
    return terrno;
5056
0
  }
5057
5058
0
  parser->bufferPos = 0;
5059
0
  parser->bufferLen = 0;
5060
0
  parser->eof = false;
5061
0
  parser->pFile = pFile;
5062
5063
  // Fill initial buffer to detect quote type
5064
0
  int32_t code = csvParserFillBuffer(parser);
5065
0
  if (code != TSDB_CODE_SUCCESS) {
5066
0
    return code;
5067
0
  }
5068
5069
  // Auto-detect quote character by finding the first quote in the file
5070
  // Skip the header line and look for the first quote character in data
5071
0
  bool foundFirstQuote = false;
5072
0
  bool inFirstLine = true;
5073
5074
0
  for (size_t i = 0; i < parser->bufferLen && !foundFirstQuote; i++) {
5075
0
    char ch = parser->buffer[i];
5076
5077
    // Skip the first line (header)
5078
0
    if (inFirstLine) {
5079
0
      if (ch == '\n') {
5080
0
        inFirstLine = false;
5081
0
      }
5082
0
      continue;
5083
0
    }
5084
5085
    // Look for the first quote character in data lines
5086
0
    if (ch == CSV_QUOTE_SINGLE) {
5087
0
      parser->quote = CSV_QUOTE_SINGLE;
5088
0
      foundFirstQuote = true;
5089
0
    } else if (ch == CSV_QUOTE_DOUBLE) {
5090
0
      parser->quote = CSV_QUOTE_DOUBLE;
5091
0
      foundFirstQuote = true;
5092
0
    }
5093
0
  }
5094
5095
  // If no quotes found, keep default (single quote for TDengine compatibility)
5096
5097
  // Reset buffer position for actual parsing
5098
0
  parser->bufferPos = 0;
5099
5100
0
  return TSDB_CODE_SUCCESS;
5101
0
}
5102
5103
0
static void csvParserDestroy(SCsvParser* parser) {
5104
0
  if (parser) {
5105
0
    taosMemoryFree(parser->buffer);
5106
0
    taosMemoryFree(parser->lineBuffer);
5107
0
    memset(parser, 0, sizeof(SCsvParser));
5108
0
  }
5109
0
}
5110
5111
0
static int32_t csvParserFillBuffer(SCsvParser* parser) {
5112
0
  if (!parser || parser->eof) {
5113
0
    return TSDB_CODE_SUCCESS;
5114
0
  }
5115
5116
  // Move remaining data to beginning of buffer
5117
  // Since this function is only called when bufferPos >= bufferLen,
5118
  // we can simplify by always resetting the buffer
5119
0
  parser->bufferLen = 0;
5120
0
  parser->bufferPos = 0;
5121
5122
  // Read more data
5123
0
  size_t spaceLeft = parser->bufferSize - parser->bufferLen;
5124
0
  if (spaceLeft > 0) {
5125
0
    int64_t bytesRead = taosReadFile(parser->pFile, parser->buffer + parser->bufferLen, spaceLeft);
5126
0
    if (bytesRead < 0) {
5127
0
      return TAOS_SYSTEM_ERROR(errno);
5128
0
    }
5129
0
    if (bytesRead == 0) {
5130
0
      parser->eof = true;
5131
0
    } else {
5132
0
      parser->bufferLen += bytesRead;
5133
0
    }
5134
0
  }
5135
5136
0
  return TSDB_CODE_SUCCESS;
5137
0
}
5138
5139
// Destroy saved CSV parser in SVnodeModifyOpStmt
5140
0
static void destroySavedCsvParser(SVnodeModifyOpStmt* pStmt) {
5141
0
  if (pStmt && pStmt->pCsvParser) {
5142
0
    csvParserDestroy(pStmt->pCsvParser);
5143
0
    taosMemoryFree(pStmt->pCsvParser);
5144
0
    pStmt->pCsvParser = NULL;
5145
0
  }
5146
0
}
5147
5148
0
static int32_t csvParserExpandLineBuffer(SCsvParser* parser, size_t requiredLen) {
5149
0
  if (!parser || requiredLen <= parser->lineBufferCapacity) {
5150
0
    return TSDB_CODE_SUCCESS;
5151
0
  }
5152
5153
0
  size_t newCapacity = parser->lineBufferCapacity;
5154
0
  while (newCapacity < requiredLen) {
5155
0
    newCapacity *= 2;
5156
0
  }
5157
5158
0
  char* newLineBuffer = taosMemoryRealloc(parser->lineBuffer, newCapacity);
5159
0
  if (!newLineBuffer) {
5160
0
    return TSDB_CODE_OUT_OF_MEMORY;
5161
0
  }
5162
5163
0
  parser->lineBuffer = newLineBuffer;
5164
0
  parser->lineBufferCapacity = newCapacity;
5165
0
  return TSDB_CODE_SUCCESS;
5166
0
}