tscParseInsert.c 47.5 KB
Newer Older
H
hzcheng 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
/*
 * Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
 *
 * This program is free software: you can use, redistribute, and/or modify
 * it under the terms of the GNU Affero General Public License, version 3
 * or later ("AGPL"), as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */

#define _DEFAULT_SOURCE /* See feature_test_macros(7) */
#define _GNU_SOURCE

#define _XOPEN_SOURCE

21
#include "os.h"
22 23

#include "hash.h"
H
hzcheng 已提交
24 25 26
#include "tscUtil.h"
#include "tschemautil.h"
#include "tsclient.h"
27
#include "ttokendef.h"
H
hzcheng 已提交
28
#include "taosdef.h"
H
hzcheng 已提交
29

S
slguan 已提交
30
#include "tscLog.h"
H
hjxilinx 已提交
31
#include "tscSubquery.h"
H
hzcheng 已提交
32 33 34
#include "tstoken.h"
#include "ttime.h"

S
slguan 已提交
35
#include "tdataformat.h"
36

S
slguan 已提交
37
enum {
S
slguan 已提交
38 39 40 41
  TSDB_USE_SERVER_TS = 0,
  TSDB_USE_CLI_TS = 1,
};

L
lihui 已提交
42
static int32_t tscAllocateMemIfNeed(STableDataBlocks *pDataBlock, int32_t rowSize, int32_t * numOfRows);
H
hzcheng 已提交
43

S
slguan 已提交
44
static int32_t tscToInteger(SSQLToken *pToken, int64_t *value, char **endPtr) {
45 46 47 48
  if (pToken->n == 0) {
    return TK_ILLEGAL;
  }
  
H
hzcheng 已提交
49
  int32_t radix = 10;
50
  
H
Haojun Liao 已提交
51
  int32_t radixList[3] = {16, 8, 2}; // the integer number with different radix: hex, oct, bin
52 53
  if (pToken->type == TK_HEX || pToken->type == TK_OCT || pToken->type == TK_BIN) {
    radix = radixList[pToken->type - TK_HEX];
H
hzcheng 已提交
54 55
  }

L
lihui 已提交
56
  errno = 0;
S
slguan 已提交
57
  *value = strtoll(pToken->z, endPtr, radix);
58 59 60 61 62
  
  // not a valid integer number, return error
  if ((pToken->type == TK_STRING || pToken->type == TK_ID) && ((*endPtr - pToken->z) != pToken->n)) {
    return TK_ILLEGAL;
  }
S
slguan 已提交
63

H
Haojun Liao 已提交
64
  return pToken->type;
H
hzcheng 已提交
65 66
}

S
slguan 已提交
67
static int32_t tscToDouble(SSQLToken *pToken, double *value, char **endPtr) {
68 69 70 71
  if (pToken->n == 0) {
    return TK_ILLEGAL;
  }
  
L
lihui 已提交
72
  errno = 0;
S
slguan 已提交
73
  *value = strtod(pToken->z, endPtr);
74 75 76 77 78 79 80
  
  // not a valid integer number, return error
  if ((pToken->type == TK_STRING || pToken->type == TK_ID) && ((*endPtr - pToken->z) != pToken->n)) {
    return TK_ILLEGAL;
  } else {
    return pToken->type;
  }
S
slguan 已提交
81
}
H
hzcheng 已提交
82

S
slguan 已提交
83 84 85 86 87 88
int tsParseTime(SSQLToken *pToken, int64_t *time, char **next, char *error, int16_t timePrec) {
  int32_t   index = 0;
  SSQLToken sToken;
  int64_t   interval;
  int64_t   useconds = 0;
  char *    pTokenEnd = *next;
H
hzcheng 已提交
89

S
slguan 已提交
90
  index = 0;
H
hzcheng 已提交
91

S
slguan 已提交
92
  if (pToken->type == TK_NOW) {
H
hzcheng 已提交
93
    useconds = taosGetTimestamp(timePrec);
S
slguan 已提交
94
  } else if (strncmp(pToken->z, "0", 1) == 0 && pToken->n == 1) {
H
hzcheng 已提交
95
    // do nothing
S
slguan 已提交
96 97
  } else if (pToken->type == TK_INTEGER) {
    useconds = str2int64(pToken->z);
H
hzcheng 已提交
98 99
  } else {
    // strptime("2001-11-12 18:31:01", "%Y-%m-%d %H:%M:%S", &tm);
dengyihao's avatar
dengyihao 已提交
100
    if (taosParseTime(pToken->z, time, pToken->n, timePrec, tsDaylight) != TSDB_CODE_SUCCESS) {
H
hjxilinx 已提交
101
      return tscInvalidSQLErrMsg(error, "invalid timestamp format", pToken->z);
H
hzcheng 已提交
102 103 104 105 106
    }

    return TSDB_CODE_SUCCESS;
  }

S
slguan 已提交
107 108 109 110
  for (int k = pToken->n; pToken->z[k] != '\0'; k++) {
    if (pToken->z[k] == ' ' || pToken->z[k] == '\t') continue;
    if (pToken->z[k] == ',') {
      *next = pTokenEnd;
H
hzcheng 已提交
111 112 113 114 115 116 117 118
      *time = useconds;
      return 0;
    }

    break;
  }

  /*
S
slguan 已提交
119 120 121
   * time expression:
   * e.g., now+12a, now-5h
   */
S
slguan 已提交
122 123 124 125
  SSQLToken valueToken;
  index = 0;
  sToken = tStrGetToken(pTokenEnd, &index, false, 0, NULL);
  pTokenEnd += index;
126

S
slguan 已提交
127 128 129 130
  if (sToken.type == TK_MINUS || sToken.type == TK_PLUS) {
    index = 0;
    valueToken = tStrGetToken(pTokenEnd, &index, false, 0, NULL);
    pTokenEnd += index;
131

S
slguan 已提交
132
    if (valueToken.n < 2) {
H
hjxilinx 已提交
133
      return tscInvalidSQLErrMsg(error, "value expected in timestamp", sToken.z);
H
hzcheng 已提交
134 135
    }

S
slguan 已提交
136
    if (getTimestampInUsFromStr(valueToken.z, valueToken.n, &interval) != TSDB_CODE_SUCCESS) {
137
      return TSDB_CODE_TSC_INVALID_SQL;
H
hzcheng 已提交
138
    }
139

H
hzcheng 已提交
140 141 142 143
    if (timePrec == TSDB_TIME_PRECISION_MILLI) {
      interval /= 1000;
    }

S
slguan 已提交
144
    if (sToken.type == TK_PLUS) {
H
hzcheng 已提交
145 146 147 148 149 150 151 152 153 154 155 156
      useconds += interval;
    } else {
      useconds = (useconds >= interval) ? useconds - interval : 0;
    }

    *next = pTokenEnd;
  }

  *time = useconds;
  return TSDB_CODE_SUCCESS;
}

S
slguan 已提交
157
int32_t tsParseOneColumnData(SSchema *pSchema, SSQLToken *pToken, char *payload, char *msg, char **str, bool primaryKey,
S
slguan 已提交
158 159 160
                             int16_t timePrec) {
  int64_t iv;
  int32_t numType;
S
slguan 已提交
161
  char *  endptr = NULL;
162 163
  errno = 0;  // clear the previous existed error information

H
hzcheng 已提交
164 165
  switch (pSchema->type) {
    case TSDB_DATA_TYPE_BOOL: {  // bool
S
slguan 已提交
166 167
      if ((pToken->type == TK_BOOL || pToken->type == TK_STRING) && (pToken->n != 0)) {
        if (strncmp(pToken->z, "true", pToken->n) == 0) {
S
slguan 已提交
168
          *(uint8_t *)payload = TSDB_TRUE;
S
slguan 已提交
169
        } else if (strncmp(pToken->z, "false", pToken->n) == 0) {
S
slguan 已提交
170
          *(uint8_t *)payload = TSDB_FALSE;
S
slguan 已提交
171 172
        } else if (strncasecmp(TSDB_DATA_NULL_STR_L, pToken->z, pToken->n) == 0) {
          *(uint8_t *)payload = TSDB_DATA_BOOL_NULL;
H
hzcheng 已提交
173
        } else {
H
hjxilinx 已提交
174
          return tscInvalidSQLErrMsg(msg, "invalid bool data", pToken->z);
H
hzcheng 已提交
175
        }
S
slguan 已提交
176 177 178 179 180 181 182 183 184
      } else if (pToken->type == TK_INTEGER) {
        iv = strtoll(pToken->z, NULL, 10);
        *(uint8_t *)payload = (int8_t)((iv == 0) ? TSDB_FALSE : TSDB_TRUE);
      } else if (pToken->type == TK_FLOAT) {
        double dv = strtod(pToken->z, NULL);
        *(uint8_t *)payload = (int8_t)((dv == 0) ? TSDB_FALSE : TSDB_TRUE);
      } else if (pToken->type == TK_NULL) {
        *(uint8_t *)payload = TSDB_DATA_BOOL_NULL;
      } else {
H
hjxilinx 已提交
185
        return tscInvalidSQLErrMsg(msg, "invalid bool data", pToken->z);
H
hzcheng 已提交
186 187 188 189
      }
      break;
    }
    case TSDB_DATA_TYPE_TINYINT:
S
slguan 已提交
190 191 192 193 194
      if (pToken->type == TK_NULL) {
        *((int8_t *)payload) = TSDB_DATA_TINYINT_NULL;
      } else if ((pToken->type == TK_STRING) && (pToken->n != 0) &&
                 (strncasecmp(TSDB_DATA_NULL_STR_L, pToken->z, pToken->n) == 0)) {
        *((int8_t *)payload) = TSDB_DATA_TINYINT_NULL;
H
hzcheng 已提交
195
      } else {
S
slguan 已提交
196
        numType = tscToInteger(pToken, &iv, &endptr);
L
lihui 已提交
197
        if (TK_ILLEGAL == numType) {
H
hjxilinx 已提交
198
          return tscInvalidSQLErrMsg(msg, "invalid tinyint data", pToken->z);
L
lihui 已提交
199
        } else if (errno == ERANGE || iv > INT8_MAX || iv <= INT8_MIN) {
H
hjxilinx 已提交
200
          return tscInvalidSQLErrMsg(msg, "tinyint data overflow", pToken->z);
H
hzcheng 已提交
201 202
        }

203
        *((int8_t *)payload) = (int8_t)iv;
H
hzcheng 已提交
204 205 206 207 208
      }

      break;

    case TSDB_DATA_TYPE_SMALLINT:
S
slguan 已提交
209 210 211 212 213
      if (pToken->type == TK_NULL) {
        *((int16_t *)payload) = TSDB_DATA_SMALLINT_NULL;
      } else if ((pToken->type == TK_STRING) && (pToken->n != 0) &&
                 (strncasecmp(TSDB_DATA_NULL_STR_L, pToken->z, pToken->n) == 0)) {
        *((int16_t *)payload) = TSDB_DATA_SMALLINT_NULL;
H
hzcheng 已提交
214
      } else {
S
slguan 已提交
215
        numType = tscToInteger(pToken, &iv, &endptr);
L
lihui 已提交
216
        if (TK_ILLEGAL == numType) {
H
hjxilinx 已提交
217
          return tscInvalidSQLErrMsg(msg, "invalid smallint data", pToken->z);
L
lihui 已提交
218
        } else if (errno == ERANGE || iv > INT16_MAX || iv <= INT16_MIN) {
H
hjxilinx 已提交
219
          return tscInvalidSQLErrMsg(msg, "smallint data overflow", pToken->z);
H
hzcheng 已提交
220 221
        }

S
slguan 已提交
222
        *((int16_t *)payload) = (int16_t)iv;
H
hzcheng 已提交
223 224 225 226
      }
      break;

    case TSDB_DATA_TYPE_INT:
S
slguan 已提交
227 228 229 230
      if (pToken->type == TK_NULL) {
        *((int32_t *)payload) = TSDB_DATA_INT_NULL;
      } else if ((pToken->type == TK_STRING) && (pToken->n != 0) &&
                 (strncasecmp(TSDB_DATA_NULL_STR_L, pToken->z, pToken->n) == 0)) {
S
slguan 已提交
231
        *((int32_t *)payload) = TSDB_DATA_INT_NULL;
H
hzcheng 已提交
232
      } else {
S
slguan 已提交
233
        numType = tscToInteger(pToken, &iv, &endptr);
L
lihui 已提交
234
        if (TK_ILLEGAL == numType) {
H
hjxilinx 已提交
235
          return tscInvalidSQLErrMsg(msg, "invalid int data", pToken->z);
L
lihui 已提交
236
        } else if (errno == ERANGE || iv > INT32_MAX || iv <= INT32_MIN) {
H
hjxilinx 已提交
237
          return tscInvalidSQLErrMsg(msg, "int data overflow", pToken->z);
H
hzcheng 已提交
238 239
        }

S
slguan 已提交
240
        *((int32_t *)payload) = (int32_t)iv;
H
hzcheng 已提交
241 242 243 244 245
      }

      break;

    case TSDB_DATA_TYPE_BIGINT:
S
slguan 已提交
246 247 248 249
      if (pToken->type == TK_NULL) {
        *((int64_t *)payload) = TSDB_DATA_BIGINT_NULL;
      } else if ((pToken->type == TK_STRING) && (pToken->n != 0) &&
                 (strncasecmp(TSDB_DATA_NULL_STR_L, pToken->z, pToken->n) == 0)) {
S
slguan 已提交
250
        *((int64_t *)payload) = TSDB_DATA_BIGINT_NULL;
H
hzcheng 已提交
251
      } else {
S
slguan 已提交
252
        numType = tscToInteger(pToken, &iv, &endptr);
L
lihui 已提交
253
        if (TK_ILLEGAL == numType) {
H
hjxilinx 已提交
254
          return tscInvalidSQLErrMsg(msg, "invalid bigint data", pToken->z);
B
Bomin Zhang 已提交
255
        } else if (errno == ERANGE || iv == INT64_MIN) {
H
hjxilinx 已提交
256
          return tscInvalidSQLErrMsg(msg, "bigint data overflow", pToken->z);
H
hzcheng 已提交
257
        }
S
slguan 已提交
258 259

        *((int64_t *)payload) = iv;
H
hzcheng 已提交
260 261 262 263
      }
      break;

    case TSDB_DATA_TYPE_FLOAT:
S
slguan 已提交
264 265 266 267
      if (pToken->type == TK_NULL) {
        *((int32_t *)payload) = TSDB_DATA_FLOAT_NULL;
      } else if ((pToken->type == TK_STRING) && (pToken->n != 0) &&
                 (strncasecmp(TSDB_DATA_NULL_STR_L, pToken->z, pToken->n) == 0)) {
S
slguan 已提交
268
        *((int32_t *)payload) = TSDB_DATA_FLOAT_NULL;
H
hzcheng 已提交
269
      } else {
S
slguan 已提交
270 271
        double dv;
        if (TK_ILLEGAL == tscToDouble(pToken, &dv, &endptr)) {
H
hjxilinx 已提交
272
          return tscInvalidSQLErrMsg(msg, "illegal float data", pToken->z);
S
slguan 已提交
273 274 275 276
        }

        float fv = (float)dv;
        if (((dv == HUGE_VAL || dv == -HUGE_VAL) && errno == ERANGE) || (fv > FLT_MAX || fv < -FLT_MAX)) {
H
hjxilinx 已提交
277
          return tscInvalidSQLErrMsg(msg, "illegal float data", pToken->z);
H
hzcheng 已提交
278 279
        }

S
slguan 已提交
280 281
        if (isinf(fv) || isnan(fv)) {
          *((int32_t *)payload) = TSDB_DATA_FLOAT_NULL;
H
hzcheng 已提交
282
        }
S
slguan 已提交
283 284

        *((float *)payload) = fv;
H
hzcheng 已提交
285 286 287 288
      }
      break;

    case TSDB_DATA_TYPE_DOUBLE:
S
slguan 已提交
289 290 291 292
      if (pToken->type == TK_NULL) {
        *((int64_t *)payload) = TSDB_DATA_DOUBLE_NULL;
      } else if ((pToken->type == TK_STRING) && (pToken->n != 0) &&
                 (strncasecmp(TSDB_DATA_NULL_STR_L, pToken->z, pToken->n) == 0)) {
S
slguan 已提交
293
        *((int64_t *)payload) = TSDB_DATA_DOUBLE_NULL;
H
hzcheng 已提交
294
      } else {
S
slguan 已提交
295 296
        double dv;
        if (TK_ILLEGAL == tscToDouble(pToken, &dv, &endptr)) {
H
hjxilinx 已提交
297
          return tscInvalidSQLErrMsg(msg, "illegal double data", pToken->z);
H
hzcheng 已提交
298 299
        }

S
slguan 已提交
300
        if (((dv == HUGE_VAL || dv == -HUGE_VAL) && errno == ERANGE) || (dv > DBL_MAX || dv < -DBL_MAX)) {
H
hjxilinx 已提交
301
          return tscInvalidSQLErrMsg(msg, "illegal double data", pToken->z);
S
slguan 已提交
302 303 304 305 306 307
        }

        if (isinf(dv) || isnan(dv)) {
          *((int64_t *)payload) = TSDB_DATA_DOUBLE_NULL;
        } else {
          *((double *)payload) = dv;
H
hzcheng 已提交
308 309 310 311 312
        }
      }
      break;

    case TSDB_DATA_TYPE_BINARY:
S
slguan 已提交
313 314
      // binary data cannot be null-terminated char string, otherwise the last char of the string is lost
      if (pToken->type == TK_NULL) {
315
        setVardataNull(payload, TSDB_DATA_TYPE_BINARY);
H
hjxilinx 已提交
316
      } else { // too long values will return invalid sql, not be truncated automatically
H
hjxilinx 已提交
317
        if (pToken->n + VARSTR_HEADER_SIZE > pSchema->bytes) { //todo refactor
H
hjxilinx 已提交
318
          return tscInvalidSQLErrMsg(msg, "string data overflow", pToken->z);
S
slguan 已提交
319
        }
H
hjxilinx 已提交
320
        
321
        STR_WITH_SIZE_TO_VARSTR(payload, pToken->z, pToken->n);
H
hzcheng 已提交
322 323 324 325 326
      }

      break;

    case TSDB_DATA_TYPE_NCHAR:
S
slguan 已提交
327
      if (pToken->type == TK_NULL) {
328
        setVardataNull(payload, TSDB_DATA_TYPE_NCHAR);
H
hzcheng 已提交
329
      } else {
H
hjxilinx 已提交
330
        // if the converted output len is over than pColumnModel->bytes, return error: 'Argument list too long'
331 332
        size_t output = 0;
        if (!taosMbsToUcs4(pToken->z, pToken->n, varDataVal(payload), pSchema->bytes - VARSTR_HEADER_SIZE, &output)) {
H
hjxilinx 已提交
333 334
          char buf[512] = {0};
          snprintf(buf, tListLen(buf), "%s", strerror(errno));
H
hjxilinx 已提交
335
          return tscInvalidSQLErrMsg(msg, buf, pToken->z);
H
hzcheng 已提交
336
        }
337
        
338
        varDataSetLen(payload, output);
H
hzcheng 已提交
339 340 341 342
      }
      break;

    case TSDB_DATA_TYPE_TIMESTAMP: {
S
slguan 已提交
343
      if (pToken->type == TK_NULL) {
H
hzcheng 已提交
344
        if (primaryKey) {
S
slguan 已提交
345
          *((int64_t *)payload) = 0;
H
hzcheng 已提交
346
        } else {
S
slguan 已提交
347
          *((int64_t *)payload) = TSDB_DATA_BIGINT_NULL;
H
hzcheng 已提交
348 349
        }
      } else {
S
slguan 已提交
350 351
        int64_t temp;
        if (tsParseTime(pToken, &temp, str, msg, timePrec) != TSDB_CODE_SUCCESS) {
H
hjxilinx 已提交
352
          return tscInvalidSQLErrMsg(msg, "invalid timestamp", pToken->z);
H
hzcheng 已提交
353
        }
H
hjxilinx 已提交
354
        
S
slguan 已提交
355
        *((int64_t *)payload) = temp;
H
hzcheng 已提交
356 357 358 359 360 361
      }

      break;
    }
  }

H
hjxilinx 已提交
362
  return TSDB_CODE_SUCCESS;
H
hzcheng 已提交
363 364
}

S
slguan 已提交
365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384
/*
 * The server time/client time should not be mixed up in one sql string
 * Do not employ sort operation is not involved if server time is used.
 */
static int32_t tsCheckTimestamp(STableDataBlocks *pDataBlocks, const char *start) {
  // once the data block is disordered, we do NOT keep previous timestamp any more
  if (!pDataBlocks->ordered) {
    return TSDB_CODE_SUCCESS;
  }

  TSKEY k = *(TSKEY *)start;

  if (k == 0) {
    if (pDataBlocks->tsSource == TSDB_USE_CLI_TS) {
      return -1;
    } else if (pDataBlocks->tsSource == -1) {
      pDataBlocks->tsSource = TSDB_USE_SERVER_TS;
    }
  } else {
    if (pDataBlocks->tsSource == TSDB_USE_SERVER_TS) {
H
hjxilinx 已提交
385
      return -1;  // client time/server time can not be mixed
386

S
slguan 已提交
387 388 389 390 391 392 393 394 395 396 397 398 399
    } else if (pDataBlocks->tsSource == -1) {
      pDataBlocks->tsSource = TSDB_USE_CLI_TS;
    }
  }

  if (k <= pDataBlocks->prevTS && (pDataBlocks->tsSource == TSDB_USE_CLI_TS)) {
    pDataBlocks->ordered = false;
  }

  pDataBlocks->prevTS = k;
  return TSDB_CODE_SUCCESS;
}

S
slguan 已提交
400
int tsParseOneRowData(char **str, STableDataBlocks *pDataBlocks, SSchema schema[], SParsedDataColInfo *spd, char *error,
401 402
                      int16_t timePrec, int32_t *code, char *tmpTokenBuf) {
  int32_t index = 0;
H
hjxilinx 已提交
403
  SSQLToken sToken = {0};
S
slguan 已提交
404
  char *    payload = pDataBlocks->pData + pDataBlocks->size;
S
slguan 已提交
405

S
slguan 已提交
406
  // 1. set the parsed value from sql string
H
hzcheng 已提交
407
  int32_t rowSize = 0;
408
  for (int i = 0; i < spd->numOfAssignedCols; ++i) {
S
slguan 已提交
409
    // the start position in data block buffer of current value in sql
410 411
    char *   start = payload + spd->elems[i].offset;
    int16_t  colIndex = spd->elems[i].colIndex;
S
slguan 已提交
412
    SSchema *pSchema = schema + colIndex;
S
slguan 已提交
413
    rowSize += pSchema->bytes;
H
hzcheng 已提交
414

S
slguan 已提交
415 416 417 418 419 420 421 422 423
    index = 0;
    sToken = tStrGetToken(*str, &index, true, 0, NULL);
    *str += index;

    if (sToken.type == TK_QUESTION) {
      uint32_t offset = start - pDataBlocks->pData;
      if (tscAddParamToDataBlock(pDataBlocks, pSchema->type, (uint8_t)timePrec, pSchema->bytes, offset) != NULL) {
        continue;
      }
424

S
slguan 已提交
425
      strcpy(error, "client out of memory");
426
      *code = TSDB_CODE_TSC_OUT_OF_MEMORY;
H
hzcheng 已提交
427 428 429
      return -1;
    }

430 431 432
    int16_t type = sToken.type;
    if ((type != TK_NOW && type != TK_INTEGER && type != TK_STRING && type != TK_FLOAT && type != TK_BOOL &&
         type != TK_NULL && type != TK_HEX && type != TK_OCT && type != TK_BIN) || (sToken.n == 0) || (type == TK_RP)) {
H
hjxilinx 已提交
433
      tscInvalidSQLErrMsg(error, "invalid data or symbol", sToken.z);
434
      *code = TSDB_CODE_TSC_INVALID_SQL;
S
slguan 已提交
435
      return -1;
H
hzcheng 已提交
436 437
    }

S
slguan 已提交
438 439
    // Remove quotation marks
    if (TK_STRING == sToken.type) {
L
[1292]  
lihui 已提交
440
      // delete escape character: \\, \', \"
441
      char    delim = sToken.z[0];
L
[1292]  
lihui 已提交
442 443
      int32_t cnt = 0;
      int32_t j = 0;
444
      for (int32_t k = 1; k < sToken.n - 1; ++k) {
F
fang 已提交
445 446
        if (sToken.z[k] == delim || sToken.z[k] == '\\') {
          if (sToken.z[k + 1] == delim) {
L
[1292]  
lihui 已提交
447
            cnt++;
L
lihui 已提交
448 449 450
            tmpTokenBuf[j] = sToken.z[k + 1];
            j++;
            k++;
L
[1292]  
lihui 已提交
451 452 453
            continue;
          }
        }
454

L
[NONE]  
lihui 已提交
455
        tmpTokenBuf[j] = sToken.z[k];
L
[1292]  
lihui 已提交
456 457
        j++;
      }
458
      tmpTokenBuf[j] = 0;
L
[1292]  
lihui 已提交
459
      sToken.z = tmpTokenBuf;
460
      sToken.n -= 2 + cnt;
H
hzcheng 已提交
461 462
    }

S
slguan 已提交
463 464
    bool    isPrimaryKey = (colIndex == PRIMARYKEY_TIMESTAMP_COL_INDEX);
    int32_t ret = tsParseOneColumnData(pSchema, &sToken, start, error, str, isPrimaryKey, timePrec);
S
slguan 已提交
465
    if (ret != TSDB_CODE_SUCCESS) {
466
      *code = TSDB_CODE_TSC_INVALID_SQL;
H
hzcheng 已提交
467 468
      return -1;  // NOTE: here 0 mean error!
    }
469

S
slguan 已提交
470
    if (isPrimaryKey && tsCheckTimestamp(pDataBlocks, start) != TSDB_CODE_SUCCESS) {
H
hjxilinx 已提交
471
      tscInvalidSQLErrMsg(error, "client time/server time can not be mixed up", sToken.z);
472
      *code = TSDB_CODE_TSC_INVALID_TIME_STAMP;
S
slguan 已提交
473
      return -1;
474
    }
H
hzcheng 已提交
475 476
  }

S
slguan 已提交
477
  // 2. set the null value for the columns that do not assign values
478
  if (spd->numOfAssignedCols < spd->numOfCols) {
S
slguan 已提交
479
    char *ptr = payload;
H
hzcheng 已提交
480 481

    for (int32_t i = 0; i < spd->numOfCols; ++i) {
482
      
483
      if (!spd->hasVal[i]) {  // current column do not have any value to insert, set it to null
484 485 486 487 488 489 490 491 492
        if (schema[i].type == TSDB_DATA_TYPE_BINARY) {
          varDataSetLen(ptr, sizeof(int8_t));
          *(uint8_t*) varDataVal(ptr) = TSDB_DATA_BINARY_NULL;
        } else if (schema[i].type == TSDB_DATA_TYPE_NCHAR) {
          varDataSetLen(ptr, sizeof(int32_t));
          *(uint32_t*) varDataVal(ptr) = TSDB_DATA_NCHAR_NULL;
        } else {
          setNull(ptr, schema[i].type, schema[i].bytes);
        }
H
hzcheng 已提交
493
      }
494
      
H
hzcheng 已提交
495 496 497 498 499 500 501 502 503
      ptr += schema[i].bytes;
    }

    rowSize = ptr - payload;
  }

  return rowSize;
}

S
slguan 已提交
504 505 506 507 508 509 510 511 512
static int32_t rowDataCompar(const void *lhs, const void *rhs) {
  TSKEY left = *(TSKEY *)lhs;
  TSKEY right = *(TSKEY *)rhs;

  if (left == right) {
    return 0;
  } else {
    return left > right ? 1 : -1;
  }
513 514
}

H
hjxilinx 已提交
515
int tsParseValues(char **str, STableDataBlocks *pDataBlock, STableMeta *pTableMeta, int maxRows,
516
                  SParsedDataColInfo *spd, char *error, int32_t *code, char *tmpTokenBuf) {
S
slguan 已提交
517 518
  int32_t   index = 0;
  SSQLToken sToken;
H
hzcheng 已提交
519 520 521

  int16_t numOfRows = 0;

H
hjxilinx 已提交
522
  SSchema *pSchema = tscGetTableSchema(pTableMeta);
H
hjxilinx 已提交
523
  STableComInfo tinfo = tscGetTableInfo(pTableMeta);
H
hjxilinx 已提交
524 525
  
  int32_t  precision = tinfo.precision;
S
slguan 已提交
526 527

  if (spd->hasVal[0] == false) {
S
slguan 已提交
528
    strcpy(error, "primary timestamp column can not be null");
529
    *code = TSDB_CODE_TSC_INVALID_SQL;
H
hzcheng 已提交
530 531 532 533
    return -1;
  }

  while (1) {
S
slguan 已提交
534 535 536
    index = 0;
    sToken = tStrGetToken(*str, &index, false, 0, NULL);
    if (sToken.n == 0 || sToken.type != TK_LP) break;
H
hzcheng 已提交
537

S
slguan 已提交
538
    *str += index;
H
hjxilinx 已提交
539
    if (numOfRows >= maxRows || pDataBlock->size + tinfo.rowSize >= pDataBlock->nAllocSize) {
L
lihui 已提交
540
      int32_t tSize;
H
hjxilinx 已提交
541
      int32_t retcode = tscAllocateMemIfNeed(pDataBlock, tinfo.rowSize, &tSize);
L
lihui 已提交
542
      if (retcode != TSDB_CODE_SUCCESS) {  //TODO pass the correct error code to client
S
slguan 已提交
543
        strcpy(error, "client out of memory");
L
lihui 已提交
544
        *code = retcode;
S
slguan 已提交
545 546
        return -1;
      }
L
lihui 已提交
547 548
      ASSERT(tSize > maxRows);
      maxRows = tSize;
H
hzcheng 已提交
549 550
    }

L
[1292]  
lihui 已提交
551
    int32_t len = tsParseOneRowData(str, pDataBlock, pSchema, spd, error, precision, code, tmpTokenBuf);
552
    if (len <= 0) {  // error message has been set in tsParseOneRowData
H
hzcheng 已提交
553 554 555 556 557
      return -1;
    }

    pDataBlock->size += len;

S
slguan 已提交
558 559 560 561
    index = 0;
    sToken = tStrGetToken(*str, &index, false, 0, NULL);
    *str += index;
    if (sToken.n == 0 || sToken.type != TK_RP) {
H
hjxilinx 已提交
562
      tscInvalidSQLErrMsg(error, ") expected", *str);
563
      *code = TSDB_CODE_TSC_INVALID_SQL;
H
hzcheng 已提交
564 565 566 567 568 569 570 571
      return -1;
    }

    numOfRows++;
  }

  if (numOfRows <= 0) {
    strcpy(error, "no any data points");
572
    *code = TSDB_CODE_TSC_INVALID_SQL;
S
slguan 已提交
573 574 575
    return -1;
  } else {
    return numOfRows;
H
hzcheng 已提交
576 577 578
  }
}

S
slguan 已提交
579
static void tscSetAssignedColumnInfo(SParsedDataColInfo *spd, SSchema *pSchema, int32_t numOfCols) {
H
hzcheng 已提交
580
  spd->numOfCols = numOfCols;
581
  spd->numOfAssignedCols = numOfCols;
H
hzcheng 已提交
582 583 584 585 586 587 588 589 590 591 592

  for (int32_t i = 0; i < numOfCols; ++i) {
    spd->hasVal[i] = true;
    spd->elems[i].colIndex = i;

    if (i > 0) {
      spd->elems[i].offset = spd->elems[i - 1].offset + pSchema[i - 1].bytes;
    }
  }
}

L
lihui 已提交
593
int32_t tscAllocateMemIfNeed(STableDataBlocks *pDataBlock, int32_t rowSize, int32_t * numOfRows) {
S
slguan 已提交
594
  size_t    remain = pDataBlock->nAllocSize - pDataBlock->size;
S
slguan 已提交
595
  const int factor = 5;
S
slguan 已提交
596
  uint32_t nAllocSizeOld = pDataBlock->nAllocSize;
L
[#1102]  
lihui 已提交
597
  
H
hzcheng 已提交
598
  // expand the allocated size
S
slguan 已提交
599 600
  if (remain < rowSize * factor) {
    while (remain < rowSize * factor) {
S
slguan 已提交
601
      pDataBlock->nAllocSize = (uint32_t)(pDataBlock->nAllocSize * 1.5);
S
slguan 已提交
602 603
      remain = pDataBlock->nAllocSize - pDataBlock->size;
    }
H
hzcheng 已提交
604

S
slguan 已提交
605 606 607 608 609
    char *tmp = realloc(pDataBlock->pData, (size_t)pDataBlock->nAllocSize);
    if (tmp != NULL) {
      pDataBlock->pData = tmp;
      memset(pDataBlock->pData + pDataBlock->size, 0, pDataBlock->nAllocSize - pDataBlock->size);
    } else {
H
hjxilinx 已提交
610
      // do nothing, if allocate more memory failed
S
slguan 已提交
611
      pDataBlock->nAllocSize = nAllocSizeOld;
L
[#1102]  
lihui 已提交
612
      *numOfRows = (int32_t)(pDataBlock->nAllocSize - pDataBlock->headerSize) / rowSize;
613
      return TSDB_CODE_TSC_OUT_OF_MEMORY;
S
slguan 已提交
614
    }
H
hzcheng 已提交
615 616
  }

L
[#1102]  
lihui 已提交
617
  *numOfRows = (int32_t)(pDataBlock->nAllocSize - pDataBlock->headerSize) / rowSize;
L
lihui 已提交
618
  return TSDB_CODE_SUCCESS;
H
hzcheng 已提交
619 620
}

621 622
static void tsSetBlockInfo(SSubmitBlk *pBlocks, const STableMeta *pTableMeta, int32_t numOfRows) {
  pBlocks->tid = pTableMeta->sid;
H
hjxilinx 已提交
623 624
  pBlocks->uid = pTableMeta->uid;
  pBlocks->sversion = pTableMeta->sversion;
S
slguan 已提交
625
  pBlocks->numOfRows += numOfRows;
H
hzcheng 已提交
626 627
}

S
slguan 已提交
628
// data block is disordered, sort it in ascending order
H
hjxilinx 已提交
629
void tscSortRemoveDataBlockDupRows(STableDataBlocks *dataBuf) {
630
  SSubmitBlk *pBlocks = (SSubmitBlk *)dataBuf->pData;
S
slguan 已提交
631 632

  // size is less than the total size, since duplicated rows may be removed yet.
633
  assert(pBlocks->numOfRows * dataBuf->rowSize + sizeof(SSubmitBlk) == dataBuf->size);
S
slguan 已提交
634

S
slguan 已提交
635 636 637 638 639
  // if use server time, this block must be ordered
  if (dataBuf->tsSource == TSDB_USE_SERVER_TS) {
    assert(dataBuf->ordered);
  }

S
slguan 已提交
640
  if (!dataBuf->ordered) {
641
    char *pBlockData = pBlocks->data;
S
slguan 已提交
642
    qsort(pBlockData, pBlocks->numOfRows, dataBuf->rowSize, rowDataCompar);
H
hzcheng 已提交
643

S
slguan 已提交
644 645
    int32_t i = 0;
    int32_t j = 1;
H
hzcheng 已提交
646

S
slguan 已提交
647
    while (j < pBlocks->numOfRows) {
S
slguan 已提交
648 649
      TSKEY ti = *(TSKEY *)(pBlockData + dataBuf->rowSize * i);
      TSKEY tj = *(TSKEY *)(pBlockData + dataBuf->rowSize * j);
H
hzcheng 已提交
650

S
slguan 已提交
651 652 653 654
      if (ti == tj) {
        ++j;
        continue;
      }
H
hzcheng 已提交
655

S
slguan 已提交
656 657 658 659 660 661 662 663 664
      int32_t nextPos = (++i);
      if (nextPos != j) {
        memmove(pBlockData + dataBuf->rowSize * nextPos, pBlockData + dataBuf->rowSize * j, dataBuf->rowSize);
      }

      ++j;
    }

    dataBuf->ordered = true;
H
hzcheng 已提交
665

S
slguan 已提交
666
    pBlocks->numOfRows = i + 1;
667
    dataBuf->size = sizeof(SSubmitBlk) + dataBuf->rowSize * pBlocks->numOfRows;
S
slguan 已提交
668
  }
S
slguan 已提交
669 670
}

671
static int32_t doParseInsertStatement(SSqlObj *pSql, void *pTableList, char **str, SParsedDataColInfo *spd,
S
slguan 已提交
672
                                      int32_t *totalNum) {
S
slguan 已提交
673
  SSqlCmd *       pCmd = &pSql->cmd;
674
  STableMetaInfo *pTableMetaInfo = tscGetTableMetaInfoFromCmd(pCmd, pCmd->clauseIndex, 0);
H
hjxilinx 已提交
675
  STableMeta *    pTableMeta = pTableMetaInfo->pTableMeta;
H
hjxilinx 已提交
676
  STableComInfo tinfo = tscGetTableInfo(pTableMeta);
H
hjxilinx 已提交
677
  
H
hjxilinx 已提交
678
  STableDataBlocks *dataBuf = NULL;
679
  int32_t ret = tscGetDataBlockFromList(pTableList, pCmd->pDataBlocks, pTableMeta->uid, TSDB_DEFAULT_PAYLOAD_SIZE,
680
                                        sizeof(SSubmitBlk), tinfo.rowSize, pTableMetaInfo->name,
H
hjxilinx 已提交
681
                                        pTableMeta, &dataBuf);
H
hjxilinx 已提交
682 683 684 685
  if (ret != TSDB_CODE_SUCCESS) {
    return ret;
  }
  
L
lihui 已提交
686
  int32_t maxNumOfRows;
H
hjxilinx 已提交
687
  ret = tscAllocateMemIfNeed(dataBuf, tinfo.rowSize, &maxNumOfRows);
L
lihui 已提交
688
  if (TSDB_CODE_SUCCESS != ret) {
689
    return TSDB_CODE_TSC_OUT_OF_MEMORY;
S
slguan 已提交
690
  }
691

692
  int32_t code = TSDB_CODE_TSC_INVALID_SQL;
693
  char *  tmpTokenBuf = calloc(1, 4096);  // used for deleting Escape character: \\, \', \"
L
[1292]  
lihui 已提交
694
  if (NULL == tmpTokenBuf) {
695
    return TSDB_CODE_TSC_OUT_OF_MEMORY;
L
[1292]  
lihui 已提交
696
  }
L
lihui 已提交
697

H
hjxilinx 已提交
698
  int32_t numOfRows = tsParseValues(str, dataBuf, pTableMeta, maxNumOfRows, spd, pCmd->payload, &code, tmpTokenBuf);
L
[1292]  
lihui 已提交
699
  free(tmpTokenBuf);
H
hzcheng 已提交
700
  if (numOfRows <= 0) {
L
[1292]  
lihui 已提交
701
    return code;
H
hzcheng 已提交
702 703
  }

S
slguan 已提交
704
  for (uint32_t i = 0; i < dataBuf->numOfParams; ++i) {
705
    SParamInfo *param = dataBuf->params + i;
S
slguan 已提交
706 707
    if (param->idx == -1) {
      param->idx = pCmd->numOfParams++;
708
      param->offset -= sizeof(SSubmitBlk);
S
slguan 已提交
709 710 711
    }
  }

712
  SSubmitBlk *pBlocks = (SSubmitBlk *)(dataBuf->pData);
H
hjxilinx 已提交
713
  tsSetBlockInfo(pBlocks, pTableMeta, numOfRows);
S
slguan 已提交
714

H
hjxilinx 已提交
715
  dataBuf->vgId = pTableMeta->vgroupInfo.vgId;
S
slguan 已提交
716
  dataBuf->numOfTables = 1;
H
hzcheng 已提交
717 718

  /*
S
slguan 已提交
719 720
   * the value of pRes->numOfRows does not affect the true result of AFFECTED ROWS,
   * which is actually returned from server.
H
hzcheng 已提交
721
   */
S
slguan 已提交
722
  *totalNum += numOfRows;
H
hzcheng 已提交
723 724 725
  return TSDB_CODE_SUCCESS;
}

726
static int32_t tscCheckIfCreateTable(char **sqlstr, SSqlObj *pSql) {
S
slguan 已提交
727
  int32_t   index = 0;
728 729
  SSQLToken sToken = {0};
  SSQLToken tableToken = {0};
S
slguan 已提交
730
  int32_t   code = TSDB_CODE_SUCCESS;
731 732 733 734 735 736
  
  const int32_t TABLE_INDEX = 0;
  const int32_t STABLE_INDEX = 1;
  
  SSqlCmd *   pCmd = &pSql->cmd;
  SQueryInfo *pQueryInfo = tscGetQueryInfoDetail(pCmd, 0);
H
hzcheng 已提交
737

S
slguan 已提交
738
  char *sql = *sqlstr;
739

S
slguan 已提交
740 741 742 743
  // get the token of specified table
  index = 0;
  tableToken = tStrGetToken(sql, &index, false, 0, NULL);
  sql += index;
H
hzcheng 已提交
744

S
slguan 已提交
745 746
  char *cstart = NULL;
  char *cend = NULL;
H
hzcheng 已提交
747

S
slguan 已提交
748 749 750 751 752
  // skip possibly exists column list
  index = 0;
  sToken = tStrGetToken(sql, &index, false, 0, NULL);
  sql += index;

H
hzcheng 已提交
753
  int32_t numOfColList = 0;
S
slguan 已提交
754
  bool    createTable = false;
H
hzcheng 已提交
755

S
slguan 已提交
756 757 758
  if (sToken.type == TK_LP) {
    cstart = &sToken.z[0];
    index = 0;
H
hzcheng 已提交
759
    while (1) {
S
slguan 已提交
760 761 762
      sToken = tStrGetToken(sql, &index, false, 0, NULL);
      if (sToken.type == TK_RP) {
        cend = &sToken.z[0];
H
hzcheng 已提交
763 764 765 766 767 768
        break;
      }

      ++numOfColList;
    }

S
slguan 已提交
769 770
    sToken = tStrGetToken(sql, &index, false, 0, NULL);
    sql += index;
H
hzcheng 已提交
771 772 773
  }

  if (numOfColList == 0 && cstart != NULL) {
774
    return TSDB_CODE_TSC_INVALID_SQL;
H
hzcheng 已提交
775
  }
776
  
H
hjxilinx 已提交
777
  STableMetaInfo* pTableMetaInfo = tscGetMetaInfo(pQueryInfo, TABLE_INDEX);
778 779
  
  if (sToken.type == TK_USING) {  // create table if not exists according to the super table
S
slguan 已提交
780 781 782 783
    index = 0;
    sToken = tStrGetToken(sql, &index, false, 0, NULL);
    sql += index;

S
slguan 已提交
784
    STagData *pTag = (STagData *)pCmd->payload;
S
slguan 已提交
785
    memset(pTag, 0, sizeof(STagData));
786 787
    
    /*
H
hjxilinx 已提交
788
     * the source super table is moved to the secondary position of the pTableMetaInfo list
789 790
     */
    if (pQueryInfo->numOfTables < 2) {
H
hjxilinx 已提交
791
      tscAddEmptyMetaInfo(pQueryInfo);
792
    }
H
hzcheng 已提交
793

H
hjxilinx 已提交
794
    STableMetaInfo *pSTableMeterMetaInfo = tscGetMetaInfo(pQueryInfo, STABLE_INDEX);
H
Haojun Liao 已提交
795
    tscSetTableFullName(pSTableMeterMetaInfo, &sToken, pSql);
796

B
Bomin Zhang 已提交
797
    tstrncpy(pTag->name, pSTableMeterMetaInfo->name, sizeof(pTag->name));
H
hjxilinx 已提交
798
    code = tscGetTableMeta(pSql, pSTableMeterMetaInfo);
H
hzcheng 已提交
799 800 801 802
    if (code != TSDB_CODE_SUCCESS) {
      return code;
    }

weixin_48148422's avatar
weixin_48148422 已提交
803
    if (!UTIL_TABLE_IS_SUPER_TABLE(pSTableMeterMetaInfo)) {
H
hjxilinx 已提交
804
      return tscInvalidSQLErrMsg(pCmd->payload, "create table only from super table is allowed", sToken.z);
S
slguan 已提交
805 806
    }

H
hjxilinx 已提交
807
    SSchema *pTagSchema = tscGetTableTagSchema(pSTableMeterMetaInfo->pTableMeta);
H
hjxilinx 已提交
808
    STableComInfo tinfo = tscGetTableInfo(pSTableMeterMetaInfo->pTableMeta);
H
hjxilinx 已提交
809
    
S
slguan 已提交
810 811 812
    index = 0;
    sToken = tStrGetToken(sql, &index, false, 0, NULL);
    sql += index;
L
lihui 已提交
813

814
    SParsedDataColInfo spd = {0};
H
hjxilinx 已提交
815 816
    
    uint8_t numOfTags = tscGetNumOfTags(pSTableMeterMetaInfo->pTableMeta);
L
lihui 已提交
817 818 819 820 821 822
    spd.numOfCols = numOfTags;

    // if specify some tags column
    if (sToken.type != TK_LP) {
      tscSetAssignedColumnInfo(&spd, pTagSchema, numOfTags);
    } else {
823 824
      /* insert into tablename (col1, col2,..., coln) using superTableName (tagName1, tagName2, ..., tagNamen)
       * tags(tagVal1, tagVal2, ..., tagValn) values(v1, v2,... vn); */
L
lihui 已提交
825 826 827 828 829 830 831 832 833 834 835
      int16_t offset[TSDB_MAX_COLUMNS] = {0};
      for (int32_t t = 1; t < numOfTags; ++t) {
        offset[t] = offset[t - 1] + pTagSchema[t - 1].bytes;
      }

      while (1) {
        index = 0;
        sToken = tStrGetToken(sql, &index, false, 0, NULL);
        sql += index;

        if (TK_STRING == sToken.type) {
H
Haojun Liao 已提交
836 837
          strdequote(sToken.z);
          sToken.n = strtrim(sToken.z);
L
lihui 已提交
838 839 840 841 842 843 844 845 846 847 848 849
        }

        if (sToken.type == TK_RP) {
          break;
        }

        bool findColumnIndex = false;

        // todo speedup by using hash list
        for (int32_t t = 0; t < numOfTags; ++t) {
          if (strncmp(sToken.z, pTagSchema[t].name, sToken.n) == 0 && strlen(pTagSchema[t].name) == sToken.n) {
            SParsedColElem *pElem = &spd.elems[spd.numOfAssignedCols++];
850
            pElem->offset = offset[t];
L
lihui 已提交
851 852 853 854 855 856
            pElem->colIndex = t;

            if (spd.hasVal[t] == true) {
              return tscInvalidSQLErrMsg(pCmd->payload, "duplicated tag name", sToken.z);
            }

857
            spd.hasVal[t] = true;
L
lihui 已提交
858 859 860 861 862 863 864 865 866 867 868 869 870
            findColumnIndex = true;
            break;
          }
        }

        if (!findColumnIndex) {
          return tscInvalidSQLErrMsg(pCmd->payload, "invalid tag name", sToken.z);
        }
      }

      if (spd.numOfAssignedCols == 0 || spd.numOfAssignedCols > numOfTags) {
        return tscInvalidSQLErrMsg(pCmd->payload, "tag name expected", sToken.z);
      }
L
lihui 已提交
871 872 873 874

      index = 0;
      sToken = tStrGetToken(sql, &index, false, 0, NULL);
      sql += index;
L
lihui 已提交
875
    }
876

S
slguan 已提交
877
    if (sToken.type != TK_TAGS) {
L
lihui 已提交
878
      return tscInvalidSQLErrMsg(pCmd->payload, "keyword TAGS expected", sToken.z);
H
hzcheng 已提交
879 880
    }

S
slguan 已提交
881 882
    uint32_t ignoreTokenTypes = TK_LP;
    uint32_t numOfIgnoreToken = 1;
L
lihui 已提交
883
    for (int i = 0; i < spd.numOfAssignedCols; ++i) {
884
      char *  tagVal = pTag->data + spd.elems[i].offset;
L
lihui 已提交
885
      int16_t colIndex = spd.elems[i].colIndex;
886

S
slguan 已提交
887 888 889 890
      index = 0;
      sToken = tStrGetToken(sql, &index, true, numOfIgnoreToken, &ignoreTokenTypes);
      sql += index;
      if (sToken.n == 0) {
H
hzcheng 已提交
891
        break;
S
slguan 已提交
892 893 894
      } else if (sToken.type == TK_RP) {
        break;
      }
H
hzcheng 已提交
895

S
slguan 已提交
896 897 898 899
      // Remove quotation marks
      if (TK_STRING == sToken.type) {
        sToken.z++;
        sToken.n -= 2;
H
hzcheng 已提交
900 901
      }

H
hjxilinx 已提交
902
      code = tsParseOneColumnData(&pTagSchema[colIndex], &sToken, tagVal, pCmd->payload, &sql, false, tinfo.precision);
H
hzcheng 已提交
903
      if (code != TSDB_CODE_SUCCESS) {
H
hjxilinx 已提交
904
        return code;
H
hzcheng 已提交
905 906
      }

907 908
      if ((pTagSchema[colIndex].type == TSDB_DATA_TYPE_BINARY || pTagSchema[colIndex].type == TSDB_DATA_TYPE_NCHAR) &&
          sToken.n > pTagSchema[colIndex].bytes) {
H
hjxilinx 已提交
909
        return tscInvalidSQLErrMsg(pCmd->payload, "string too long", sToken.z);
S
slguan 已提交
910
      }
L
lihui 已提交
911
    }
S
slguan 已提交
912

L
lihui 已提交
913 914 915 916 917
    index = 0;
    sToken = tStrGetToken(sql, &index, false, 0, NULL);
    sql += index;
    if (sToken.n == 0 || sToken.type != TK_RP) {
      return tscInvalidSQLErrMsg(pCmd->payload, ") expected", sToken.z);
H
hzcheng 已提交
918 919
    }

L
lihui 已提交
920 921 922
    // 2. set the null value for the columns that do not assign values
    if (spd.numOfAssignedCols < spd.numOfCols) {
      char *ptr = pTag->data;
923

L
lihui 已提交
924
      for (int32_t i = 0; i < spd.numOfCols; ++i) {
925
        if (!spd.hasVal[i]) {  // current tag column do not have any value to insert, set it to null
926 927 928 929 930
          if (pTagSchema[i].type == TSDB_DATA_TYPE_BINARY || pTagSchema[i].type == TSDB_DATA_TYPE_NCHAR) {
            setVardataNull(ptr, pTagSchema[i].type);
          } else {
            setNull(ptr, pTagSchema[i].type, pTagSchema[i].bytes);
          }
L
lihui 已提交
931
        }
932

L
lihui 已提交
933
        ptr += pTagSchema[i].bytes;
934
      }
H
hzcheng 已提交
935 936
    }

937
    // 3. calculate the actual data size of STagData
938
    pCmd->payloadLen = sizeof(pTag->name) + sizeof(pTag->dataLen);
939
    for (int32_t t = 0; t < numOfTags; ++t) {
940
      pTag->dataLen += pTagSchema[t].bytes;
941 942
      pCmd->payloadLen += pTagSchema[t].bytes;
    }
943
    pTag->dataLen = htonl(pTag->dataLen);
944

H
hzcheng 已提交
945
    if (tscValidateName(&tableToken) != TSDB_CODE_SUCCESS) {
L
lihui 已提交
946
      return tscInvalidSQLErrMsg(pCmd->payload, "invalid table name", *sqlstr);
H
hzcheng 已提交
947 948
    }

H
Haojun Liao 已提交
949
    int32_t ret = tscSetTableFullName(pTableMetaInfo, &tableToken, pSql);
H
hzcheng 已提交
950 951 952 953 954
    if (ret != TSDB_CODE_SUCCESS) {
      return ret;
    }

    createTable = true;
H
hjxilinx 已提交
955
    code = tscGetMeterMetaEx(pSql, pTableMetaInfo, true);
956
    if (TSDB_CODE_TSC_ACTION_IN_PROGRESS == code) {
H
hjxilinx 已提交
957 958 959
      return code;
    }
    
H
hzcheng 已提交
960 961 962 963
  } else {
    if (cstart != NULL) {
      sql = cstart;
    } else {
S
slguan 已提交
964
      sql = sToken.z;
H
hzcheng 已提交
965
    }
B
Bomin Zhang 已提交
966
    code = tscGetMeterMetaEx(pSql, pTableMetaInfo, false);
H
hjxilinx 已提交
967
    
968
    if (pCmd->curSql == NULL) {
969
      assert(code == TSDB_CODE_TSC_ACTION_IN_PROGRESS);
H
hjxilinx 已提交
970
    }
H
hzcheng 已提交
971 972 973 974 975
  }

  int32_t len = cend - cstart + 1;
  if (cstart != NULL && createTable == true) {
    /* move the column list to start position of the next accessed points */
W
WangXin 已提交
976
    memmove(sql - len, cstart, len);
H
hzcheng 已提交
977 978 979 980 981
    *sqlstr = sql - len;
  } else {
    *sqlstr = sql;
  }

982
  if (*sqlstr == NULL) {
983
    code = TSDB_CODE_TSC_INVALID_SQL;
984 985
  }
  
H
hzcheng 已提交
986 987 988
  return code;
}

H
Hui Li 已提交
989
int validateTableName(char *tblName, int len, SSQLToken* psTblToken) {
S
slguan 已提交
990
  char buf[TSDB_TABLE_ID_LEN] = {0};
B
Bomin Zhang 已提交
991
  tstrncpy(buf, tblName, sizeof(buf));
S
slguan 已提交
992

H
Hui Li 已提交
993 994 995 996
  psTblToken->n    = len;
  psTblToken->type = TK_ID;
  psTblToken->z    = buf;
  tSQLGetToken(buf, &psTblToken->type);
S
slguan 已提交
997

H
Hui Li 已提交
998
  return tscValidateName(psTblToken);
H
huili 已提交
999 1000
}

1001 1002 1003 1004 1005 1006 1007 1008 1009
static int32_t validateDataSource(SSqlCmd *pCmd, int8_t type, const char *sql) {
  if (pCmd->dataSourceType != 0 && pCmd->dataSourceType != type) {
    return tscInvalidSQLErrMsg(pCmd->payload, "keyword VALUES and FILE are not allowed to mix up", sql);
  }

  pCmd->dataSourceType = type;
  return TSDB_CODE_SUCCESS;
}

H
hzcheng 已提交
1010 1011 1012 1013 1014 1015 1016 1017 1018
/**
 * usage: insert into table1 values() () table2 values()()
 *
 * @param str
 * @param acct
 * @param db
 * @param pSql
 * @return
 */
H
Haojun Liao 已提交
1019
int tsParseInsertSql(SSqlObj *pSql) {
S
slguan 已提交
1020
  SSqlCmd *pCmd = &pSql->cmd;
H
Haojun Liao 已提交
1021
  char* str = pCmd->curSql;
1022

S
slguan 已提交
1023
  int32_t totalNum = 0;
1024 1025 1026 1027 1028
  int32_t code = TSDB_CODE_SUCCESS;

  SQueryInfo *pQueryInfo = tscGetQueryInfoDetail(pCmd, 0);
  assert(pQueryInfo != NULL);

H
Haojun Liao 已提交
1029
  STableMetaInfo *pTableMetaInfo = NULL;
1030
  if (pQueryInfo->numOfTables == 0) {
H
hjxilinx 已提交
1031
    pTableMetaInfo = tscAddEmptyMetaInfo(pQueryInfo);
1032
  } else {
H
hjxilinx 已提交
1033
    pTableMetaInfo = tscGetMetaInfo(pQueryInfo, 0);
1034
  }
H
hzcheng 已提交
1035

H
Haojun Liao 已提交
1036
  // TODO: 2048 is added because TSDB_MAX_TAGS_LEN now is 65536, but TSDB_PAYLOAD_SIZE is 65380
B
Bomin Zhang 已提交
1037
  if ((code = tscAllocPayload(pCmd, TSDB_PAYLOAD_SIZE + 2048)) != TSDB_CODE_SUCCESS) {
H
hzcheng 已提交
1038 1039 1040
    return code;
  }

H
Haojun Liao 已提交
1041
  if (NULL == pCmd->pTableList) {
1042
    pCmd->pTableList = taosHashInit(128, taosGetDefaultHashFunction(TSDB_DATA_TYPE_BIGINT), false);
1043

L
lihui 已提交
1044
    pSql->cmd.pDataBlocks = tscCreateBlockArrayList();
1045
    if (NULL == pCmd->pTableList || NULL == pSql->cmd.pDataBlocks) {
1046
      code = TSDB_CODE_TSC_OUT_OF_MEMORY;
H
Haojun Liao 已提交
1047
      goto _error;
L
lihui 已提交
1048 1049
    }
  } else {
1050
    str = pCmd->curSql;
L
lihui 已提交
1051 1052
  }
  
H
Haojun Liao 已提交
1053
  tscTrace("%p create data block list for submit data:%p, pTableList:%p", pSql, pCmd->pDataBlocks, pCmd->pTableList);
H
hzcheng 已提交
1054 1055

  while (1) {
1056
    int32_t   index = 0;
S
slguan 已提交
1057
    SSQLToken sToken = tStrGetToken(str, &index, false, 0, NULL);
1058 1059 1060 1061 1062 1063 1064 1065

    // no data in the sql string anymore.
    if (sToken.n == 0) {
      /*
       * if the data is from the data file, no data has been generated yet. So, there no data to
       * merge or submit, save the file path and parse the file in other routines.
       */
      if (pCmd->dataSourceType == DATA_FROM_DATA_FILE) {
S
slguan 已提交
1066 1067 1068
        goto _clean;
      }

1069 1070 1071 1072 1073
      /*
       * if no data has been generated during parsing the sql string, error msg will return
       * Otherwise, create the first submit block and submit to virtual node.
       */
      if (totalNum == 0) {
1074
        code = TSDB_CODE_TSC_INVALID_SQL;
H
Haojun Liao 已提交
1075
        goto _error;
1076 1077
      } else {
        break;
H
hzcheng 已提交
1078 1079 1080
      }
    }

1081
    pCmd->curSql = sToken.z;
H
Hui Li 已提交
1082
    SSQLToken sTblToken;
S
slguan 已提交
1083
    // Check if the table name available or not
H
Hui Li 已提交
1084
    if (validateTableName(sToken.z, sToken.n, &sTblToken) != TSDB_CODE_SUCCESS) {
H
hjxilinx 已提交
1085
      code = tscInvalidSQLErrMsg(pCmd->payload, "table name invalid", sToken.z);
H
Haojun Liao 已提交
1086
      goto _error;
H
huili 已提交
1087 1088
    }

H
Hui Li 已提交
1089
    if ((code = tscSetTableFullName(pTableMetaInfo, &sTblToken, pSql)) != TSDB_CODE_SUCCESS) {
H
Haojun Liao 已提交
1090
      goto _error;
H
hzcheng 已提交
1091 1092
    }

1093 1094
    if ((code = tscCheckIfCreateTable(&str, pSql)) != TSDB_CODE_SUCCESS) {
      /*
H
Haojun Liao 已提交
1095 1096
       * After retrieving the table meta from server, the sql string will be parsed from the paused position.
       * And during the getTableMetaCallback function, the sql string will be parsed from the paused position.
1097
       */
1098
      if (TSDB_CODE_TSC_ACTION_IN_PROGRESS == code) {
H
hjxilinx 已提交
1099
        return code;
H
hzcheng 已提交
1100
      }
H
hjxilinx 已提交
1101
      
H
Haojun Liao 已提交
1102
      tscError("%p async insert parse error, code:%s", pSql, tstrerror(code));
1103
      pCmd->curSql = NULL;
H
Haojun Liao 已提交
1104
      goto _error;
H
hzcheng 已提交
1105 1106
    }

weixin_48148422's avatar
weixin_48148422 已提交
1107
    if (UTIL_TABLE_IS_SUPER_TABLE(pTableMetaInfo)) {
H
hjxilinx 已提交
1108
      code = tscInvalidSQLErrMsg(pCmd->payload, "insert data into super table is not supported", NULL);
H
Haojun Liao 已提交
1109
      goto _error;
H
hzcheng 已提交
1110 1111
    }

S
slguan 已提交
1112 1113 1114
    index = 0;
    sToken = tStrGetToken(str, &index, false, 0, NULL);
    str += index;
1115

S
slguan 已提交
1116
    if (sToken.n == 0) {
1117
      code = tscInvalidSQLErrMsg(pCmd->payload, "keyword VALUES or FILE required", sToken.z);
H
Haojun Liao 已提交
1118
      goto _error;
H
hzcheng 已提交
1119
    }
H
hjxilinx 已提交
1120
    
H
hjxilinx 已提交
1121
    STableComInfo tinfo = tscGetTableInfo(pTableMetaInfo->pTableMeta);
H
hjxilinx 已提交
1122
    
S
slguan 已提交
1123
    if (sToken.type == TK_VALUES) {
H
hjxilinx 已提交
1124
      SParsedDataColInfo spd = {.numOfCols = tinfo.numOfColumns};
H
hjxilinx 已提交
1125 1126
      
      SSchema *pSchema = tscGetTableSchema(pTableMetaInfo->pTableMeta);
H
hjxilinx 已提交
1127
      tscSetAssignedColumnInfo(&spd, pSchema, tinfo.numOfColumns);
H
hzcheng 已提交
1128

1129
      if (validateDataSource(pCmd, DATA_FROM_SQL_STRING, sToken.z) != TSDB_CODE_SUCCESS) {
H
Haojun Liao 已提交
1130
        goto _error;
H
hzcheng 已提交
1131 1132 1133 1134 1135 1136
      }

      /*
       * app here insert data in different vnodes, so we need to set the following
       * data in another submit procedure using async insert routines
       */
1137
      code = doParseInsertStatement(pSql, pCmd->pTableList, &str, &spd, &totalNum);
H
hzcheng 已提交
1138
      if (code != TSDB_CODE_SUCCESS) {
H
Haojun Liao 已提交
1139
        goto _error;
H
hzcheng 已提交
1140
      }
S
slguan 已提交
1141
    } else if (sToken.type == TK_FILE) {
1142
      if (validateDataSource(pCmd, DATA_FROM_DATA_FILE, sToken.z) != TSDB_CODE_SUCCESS) {
H
Haojun Liao 已提交
1143
        goto _error;
H
hzcheng 已提交
1144 1145
      }

S
slguan 已提交
1146 1147 1148 1149
      index = 0;
      sToken = tStrGetToken(str, &index, false, 0, NULL);
      str += index;
      if (sToken.n == 0) {
H
hjxilinx 已提交
1150
        code = tscInvalidSQLErrMsg(pCmd->payload, "file path is required following keyword FILE", sToken.z);
H
Haojun Liao 已提交
1151
        goto _error;
H
hzcheng 已提交
1152 1153
      }

S
slguan 已提交
1154
      char fname[PATH_MAX] = {0};
S
slguan 已提交
1155
      strncpy(fname, sToken.z, sToken.n);
S
slguan 已提交
1156
      strdequote(fname);
1157

H
hzcheng 已提交
1158 1159
      wordexp_t full_path;
      if (wordexp(fname, &full_path, 0) != 0) {
H
hjxilinx 已提交
1160
        code = tscInvalidSQLErrMsg(pCmd->payload, "invalid filename", sToken.z);
H
Haojun Liao 已提交
1161
        goto _error;
H
hzcheng 已提交
1162 1163 1164 1165
      }
      strcpy(fname, full_path.we_wordv[0]);
      wordfree(&full_path);

H
hjxilinx 已提交
1166
      STableDataBlocks *pDataBlock = NULL;
H
hjxilinx 已提交
1167
      STableMeta* pTableMeta = pTableMetaInfo->pTableMeta;
1168
      
1169
      int32_t ret = tscCreateDataBlock(PATH_MAX, tinfo.rowSize, sizeof(SSubmitBlk), pTableMetaInfo->name,
H
hjxilinx 已提交
1170
                                       pTableMeta, &pDataBlock);
H
hjxilinx 已提交
1171
      if (ret != TSDB_CODE_SUCCESS) {
H
Haojun Liao 已提交
1172
        goto _error;
H
hjxilinx 已提交
1173
      }
1174

S
slguan 已提交
1175 1176
      tscAppendDataBlock(pCmd->pDataBlocks, pDataBlock);
      strcpy(pDataBlock->filename, fname);
S
slguan 已提交
1177
    } else if (sToken.type == TK_LP) {
H
hzcheng 已提交
1178
      /* insert into tablename(col1, col2,..., coln) values(v1, v2,... vn); */
1179
      STableMeta *pTableMeta = tscGetTableMetaInfoFromCmd(pCmd, pCmd->clauseIndex, 0)->pTableMeta;
H
hjxilinx 已提交
1180
      SSchema *   pSchema = tscGetTableSchema(pTableMeta);
H
hzcheng 已提交
1181

1182
      if (validateDataSource(pCmd, DATA_FROM_SQL_STRING, sToken.z) != TSDB_CODE_SUCCESS) {
H
Haojun Liao 已提交
1183
        goto _error;
H
hzcheng 已提交
1184 1185
      }

1186
      SParsedDataColInfo spd = {0};
H
hjxilinx 已提交
1187
      spd.numOfCols = tinfo.numOfColumns;
H
hzcheng 已提交
1188 1189

      int16_t offset[TSDB_MAX_COLUMNS] = {0};
H
hjxilinx 已提交
1190
      for (int32_t t = 1; t < tinfo.numOfColumns; ++t) {
H
hzcheng 已提交
1191 1192 1193 1194
        offset[t] = offset[t - 1] + pSchema[t - 1].bytes;
      }

      while (1) {
S
slguan 已提交
1195 1196 1197 1198 1199
        index = 0;
        sToken = tStrGetToken(str, &index, false, 0, NULL);
        str += index;

        if (TK_STRING == sToken.type) {
H
Haojun Liao 已提交
1200 1201
          strdequote(sToken.z);
          sToken.n = strtrim(sToken.z);
S
slguan 已提交
1202 1203 1204
        }

        if (sToken.type == TK_RP) {
H
hzcheng 已提交
1205 1206 1207 1208 1209 1210
          break;
        }

        bool findColumnIndex = false;

        // todo speedup by using hash list
H
hjxilinx 已提交
1211
        for (int32_t t = 0; t < tinfo.numOfColumns; ++t) {
S
slguan 已提交
1212
          if (strncmp(sToken.z, pSchema[t].name, sToken.n) == 0 && strlen(pSchema[t].name) == sToken.n) {
S
slguan 已提交
1213
            SParsedColElem *pElem = &spd.elems[spd.numOfAssignedCols++];
H
hzcheng 已提交
1214 1215 1216 1217
            pElem->offset = offset[t];
            pElem->colIndex = t;

            if (spd.hasVal[t] == true) {
H
hjxilinx 已提交
1218
              code = tscInvalidSQLErrMsg(pCmd->payload, "duplicated column name", sToken.z);
H
Haojun Liao 已提交
1219
              goto _error;
H
hzcheng 已提交
1220 1221 1222 1223 1224 1225 1226 1227
            }

            spd.hasVal[t] = true;
            findColumnIndex = true;
            break;
          }
        }

S
slguan 已提交
1228
        if (!findColumnIndex) {
H
hjxilinx 已提交
1229
          code = tscInvalidSQLErrMsg(pCmd->payload, "invalid column name", sToken.z);
H
Haojun Liao 已提交
1230
          goto _error;
H
hzcheng 已提交
1231 1232 1233
        }
      }

H
hjxilinx 已提交
1234
      if (spd.numOfAssignedCols == 0 || spd.numOfAssignedCols > tinfo.numOfColumns) {
H
hjxilinx 已提交
1235
        code = tscInvalidSQLErrMsg(pCmd->payload, "column name expected", sToken.z);
H
Haojun Liao 已提交
1236
        goto _error;
H
hzcheng 已提交
1237 1238
      }

S
slguan 已提交
1239 1240 1241 1242 1243
      index = 0;
      sToken = tStrGetToken(str, &index, false, 0, NULL);
      str += index;

      if (sToken.type != TK_VALUES) {
H
hjxilinx 已提交
1244
        code = tscInvalidSQLErrMsg(pCmd->payload, "keyword VALUES is expected", sToken.z);
H
Haojun Liao 已提交
1245
        goto _error;
H
hzcheng 已提交
1246 1247
      }

1248
      code = doParseInsertStatement(pSql, pCmd->pTableList, &str, &spd, &totalNum);
H
hzcheng 已提交
1249
      if (code != TSDB_CODE_SUCCESS) {
H
Haojun Liao 已提交
1250
        goto _error;
H
hzcheng 已提交
1251 1252
      }
    } else {
H
hjxilinx 已提交
1253
      code = tscInvalidSQLErrMsg(pCmd->payload, "keyword VALUES or FILE are required", sToken.z);
H
Haojun Liao 已提交
1254
      goto _error;
H
hzcheng 已提交
1255 1256 1257
    }
  }

S
slguan 已提交
1258 1259 1260 1261
  // we need to keep the data blocks if there are parameters in the sql
  if (pCmd->numOfParams > 0) {
    goto _clean;
  }
1262

H
hjxilinx 已提交
1263
  if (pCmd->pDataBlocks->nSize > 0) { // merge according to vgId
S
slguan 已提交
1264
    if ((code = tscMergeTableDataBlocks(pSql, pCmd->pDataBlocks)) != TSDB_CODE_SUCCESS) {
H
Haojun Liao 已提交
1265
      goto _error;
S
slguan 已提交
1266
    }
H
hzcheng 已提交
1267
  } else {
S
slguan 已提交
1268
    pCmd->pDataBlocks = tscDestroyBlockArrayList(pCmd->pDataBlocks);
H
hzcheng 已提交
1269 1270 1271 1272 1273
  }

  code = TSDB_CODE_SUCCESS;
  goto _clean;

H
Haojun Liao 已提交
1274
_error:
S
slguan 已提交
1275
  pCmd->pDataBlocks = tscDestroyBlockArrayList(pCmd->pDataBlocks);
H
hzcheng 已提交
1276 1277

_clean:
1278 1279
  taosHashCleanup(pCmd->pTableList);
  pCmd->pTableList = NULL;
H
hjxilinx 已提交
1280
  
1281 1282
  pCmd->curSql    = NULL;
  pCmd->parseFinished  = 1;
H
hjxilinx 已提交
1283
  
H
hzcheng 已提交
1284 1285 1286
  return code;
}

H
Haojun Liao 已提交
1287
int tsInsertInitialCheck(SSqlObj *pSql) {
S
slguan 已提交
1288
  if (!pSql->pTscObj->writeAuth) {
1289
    return TSDB_CODE_TSC_NO_WRITE_AUTH;
S
slguan 已提交
1290
  }
H
hzcheng 已提交
1291

H
hjxilinx 已提交
1292
  int32_t  index = 0;
S
slguan 已提交
1293
  SSqlCmd *pCmd = &pSql->cmd;
1294 1295

  SSQLToken sToken = tStrGetToken(pSql->sqlstr, &index, false, 0, NULL);
H
hjxilinx 已提交
1296
  assert(sToken.type == TK_INSERT || sToken.type == TK_IMPORT);
1297 1298 1299

  pCmd->count = 0;
  pCmd->command = TSDB_SQL_INSERT;
1300
  pSql->res.numOfRows = 0;
1301 1302

  SQueryInfo *pQueryInfo = NULL;
1303
  tscGetQueryInfoDetailSafely(pCmd, pCmd->clauseIndex, &pQueryInfo);
1304

H
Haojun Liao 已提交
1305
  TSDB_QUERY_SET_TYPE(pQueryInfo->type, TSDB_QUERY_TYPE_INSERT | pCmd->insertType);
1306 1307

  sToken = tStrGetToken(pSql->sqlstr, &index, false, 0, NULL);
S
slguan 已提交
1308
  if (sToken.type != TK_INTO) {
H
hjxilinx 已提交
1309
    return tscInvalidSQLErrMsg(pCmd->payload, "keyword INTO is expected", sToken.z);
S
slguan 已提交
1310
  }
1311

H
Haojun Liao 已提交
1312 1313
  pCmd->curSql = sToken.z + sToken.n;
  return TSDB_CODE_SUCCESS;
H
hzcheng 已提交
1314 1315
}

H
Haojun Liao 已提交
1316
int tsParseSql(SSqlObj *pSql, bool initial) {
H
hzcheng 已提交
1317
  int32_t ret = TSDB_CODE_SUCCESS;
H
Haojun Liao 已提交
1318
  SSqlCmd* pCmd = &pSql->cmd;
H
Haojun Liao 已提交
1319

H
Haojun Liao 已提交
1320
  if ((!pCmd->parseFinished) && (!initial)) {
H
Haojun Liao 已提交
1321
    tscTrace("%p resume to parse sql: %s", pSql, pCmd->curSql);
H
[TD-98]  
hjxilinx 已提交
1322
  }
L
lihui 已提交
1323
  
H
hjxilinx 已提交
1324
  if (tscIsInsertData(pSql->sqlstr)) {
H
hzcheng 已提交
1325
    /*
1326 1327
     * Set the fp before parse the sql string, in case of getTableMeta failed, in which
     * the error handle callback function can rightfully restore the user-defined callback function (fp).
H
hzcheng 已提交
1328
     */
H
Haojun Liao 已提交
1329
    if (initial && (pSql->cmd.insertType != TSDB_QUERY_TYPE_STMT_INSERT)) {
H
[TD-98]  
hjxilinx 已提交
1330
      pSql->fetchFp = pSql->fp;
H
hjxilinx 已提交
1331
      pSql->fp = (void(*)())tscHandleMultivnodeInsert;
H
hzcheng 已提交
1332
    }
H
Haojun Liao 已提交
1333
    
H
Haojun Liao 已提交
1334
    if (initial && ((ret = tsInsertInitialCheck(pSql)) != TSDB_CODE_SUCCESS)) {
H
Haojun Liao 已提交
1335 1336 1337
      return ret;
    }
    
1338
    ret = tsParseInsertSql(pSql);
H
hzcheng 已提交
1339
  } else {
S
slguan 已提交
1340
    ret = tscAllocPayload(&pSql->cmd, TSDB_DEFAULT_PAYLOAD_SIZE);
1341 1342 1343
    if (TSDB_CODE_SUCCESS != ret) {
      return ret;
    }
H
Haojun Liao 已提交
1344

1345
    SSqlInfo SQLInfo = qSQLParse(pSql->sqlstr);
H
hzcheng 已提交
1346 1347 1348 1349 1350
    ret = tscToSQLCmd(pSql, &SQLInfo);
    SQLInfoDestroy(&SQLInfo);
  }

  /*
1351
   * the pRes->code may be modified or released by another thread in tscTableMetaCallBack function,
H
Haojun Liao 已提交
1352 1353 1354
   * so do NOT use pRes->code to determine if the getTableMeta function
   * invokes new threads to get data from mgmt node or simply retrieves data from cache.
   * do NOT assign return code to pRes->code for the same reason since it may be released by another thread already.
H
hzcheng 已提交
1355 1356 1357 1358
   */
  return ret;
}

S
slguan 已提交
1359 1360 1361
static int doPackSendDataBlock(SSqlObj *pSql, int32_t numOfRows, STableDataBlocks *pTableDataBlocks) {
  int32_t  code = TSDB_CODE_SUCCESS;
  SSqlCmd *pCmd = &pSql->cmd;
S
slguan 已提交
1362

1363
  assert(pCmd->numOfClause == 1);
1364
  STableMeta *pTableMeta = tscGetTableMetaInfoFromCmd(pCmd, pCmd->clauseIndex, 0)->pTableMeta;
S
slguan 已提交
1365

1366
  SSubmitBlk *pBlocks = (SSubmitBlk *)(pTableDataBlocks->pData);
H
hjxilinx 已提交
1367
  tsSetBlockInfo(pBlocks, pTableMeta, numOfRows);
S
slguan 已提交
1368

S
slguan 已提交
1369 1370 1371
  if ((code = tscMergeTableDataBlocks(pSql, pCmd->pDataBlocks)) != TSDB_CODE_SUCCESS) {
    return code;
  }
S
slguan 已提交
1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385

  // the pDataBlock is different from the pTableDataBlocks
  STableDataBlocks *pDataBlock = pCmd->pDataBlocks->pData[0];
  if ((code = tscCopyDataBlockToPayload(pSql, pDataBlock)) != TSDB_CODE_SUCCESS) {
    return code;
  }

  if ((code = tscProcessSql(pSql)) != TSDB_CODE_SUCCESS) {
    return code;
  }

  return TSDB_CODE_SUCCESS;
}

L
[1292]  
lihui 已提交
1386
static int tscInsertDataFromFile(SSqlObj *pSql, FILE *fp, char *tmpTokenBuf) {
S
slguan 已提交
1387 1388 1389 1390
  size_t          readLen = 0;
  char *          line = NULL;
  size_t          n = 0;
  int             len = 0;
L
lihui 已提交
1391
  int32_t         maxRows = 0;
S
slguan 已提交
1392 1393 1394 1395
  SSqlCmd *       pCmd = &pSql->cmd;
  int             numOfRows = 0;
  int32_t         code = 0;
  int             nrows = 0;
1396
  
1397
  STableMetaInfo *pTableMetaInfo = tscGetTableMetaInfoFromCmd(pCmd, pCmd->clauseIndex, 0);
H
hjxilinx 已提交
1398
  STableMeta *    pTableMeta = pTableMetaInfo->pTableMeta;
H
hjxilinx 已提交
1399
  STableComInfo tinfo = tscGetTableInfo(pTableMeta);
H
hjxilinx 已提交
1400
  
1401 1402
  assert(pCmd->numOfClause == 1);
  
H
hjxilinx 已提交
1403
  int32_t rowSize = tinfo.rowSize;
S
slguan 已提交
1404 1405

  pCmd->pDataBlocks = tscCreateBlockArrayList();
H
hjxilinx 已提交
1406
  STableDataBlocks *pTableDataBlock = NULL;
1407
  int32_t           ret = tscCreateDataBlock(TSDB_PAYLOAD_SIZE, rowSize, sizeof(SSubmitBlk),
H
hjxilinx 已提交
1408
                                   pTableMetaInfo->name, pTableMeta, &pTableDataBlock);
H
hjxilinx 已提交
1409 1410 1411
  if (ret != TSDB_CODE_SUCCESS) {
    return -1;
  }
1412

S
slguan 已提交
1413 1414
  tscAppendDataBlock(pCmd->pDataBlocks, pTableDataBlock);

L
lihui 已提交
1415 1416
  code = tscAllocateMemIfNeed(pTableDataBlock, rowSize, &maxRows);
  if (TSDB_CODE_SUCCESS != code) return -1;
H
hzcheng 已提交
1417 1418

  int                count = 0;
H
hjxilinx 已提交
1419 1420
  SParsedDataColInfo spd = {.numOfCols = tinfo.numOfColumns};
  SSchema *          pSchema = tscGetTableSchema(pTableMeta);
H
hzcheng 已提交
1421

H
hjxilinx 已提交
1422
  tscSetAssignedColumnInfo(&spd, pSchema, tinfo.numOfColumns);
H
hzcheng 已提交
1423

H
huili 已提交
1424
  while ((readLen = getline(&line, &n, fp)) != -1) {
H
hzcheng 已提交
1425 1426
    // line[--readLen] = '\0';
    if (('\r' == line[readLen - 1]) || ('\n' == line[readLen - 1])) line[--readLen] = 0;
1427
    if (readLen == 0) continue;  // fang, <= to ==
H
huili 已提交
1428

S
slguan 已提交
1429
    char *lineptr = line;
H
hzcheng 已提交
1430
    strtolower(line, line);
H
hjxilinx 已提交
1431
    
H
hjxilinx 已提交
1432
    len = tsParseOneRowData(&lineptr, pTableDataBlock, pSchema, &spd, pCmd->payload, tinfo.precision, &code, tmpTokenBuf);
S
slguan 已提交
1433
    if (len <= 0 || pTableDataBlock->numOfParams > 0) {
L
[1292]  
lihui 已提交
1434 1435
      pSql->res.code = code;
      return (-code);
S
slguan 已提交
1436
    }
1437

S
slguan 已提交
1438
    pTableDataBlock->size += len;
H
hzcheng 已提交
1439 1440 1441 1442

    count++;
    nrows++;
    if (count >= maxRows) {
S
slguan 已提交
1443 1444
      if ((code = doPackSendDataBlock(pSql, count, pTableDataBlock)) != TSDB_CODE_SUCCESS) {
        return -code;
H
hzcheng 已提交
1445
      }
S
slguan 已提交
1446 1447

      pTableDataBlock = pCmd->pDataBlocks->pData[0];
1448
      pTableDataBlock->size = sizeof(SSubmitBlk);
H
hjxilinx 已提交
1449
      pTableDataBlock->rowSize = tinfo.rowSize;
S
slguan 已提交
1450

H
hzcheng 已提交
1451
      numOfRows += pSql->res.numOfRows;
S
slguan 已提交
1452
      pSql->res.numOfRows = 0;
H
hzcheng 已提交
1453 1454 1455 1456 1457
      count = 0;
    }
  }

  if (count > 0) {
S
slguan 已提交
1458 1459
    if ((code = doPackSendDataBlock(pSql, count, pTableDataBlock)) != TSDB_CODE_SUCCESS) {
      return -code;
H
hzcheng 已提交
1460
    }
S
slguan 已提交
1461

H
hzcheng 已提交
1462
    numOfRows += pSql->res.numOfRows;
S
slguan 已提交
1463
    pSql->res.numOfRows = 0;
H
hzcheng 已提交
1464 1465 1466
  }

  if (line) tfree(line);
S
slguan 已提交
1467

H
hzcheng 已提交
1468 1469 1470
  return numOfRows;
}

1471
void tscProcessMultiVnodesInsertFromFile(SSqlObj *pSql) {
S
slguan 已提交
1472
  SSqlCmd *pCmd = &pSql->cmd;
H
hzcheng 已提交
1473 1474 1475 1476
  if (pCmd->command != TSDB_SQL_INSERT) {
    return;
  }

1477
  SQueryInfo *    pQueryInfo = tscGetQueryInfoDetail(pCmd, 0);
H
hjxilinx 已提交
1478
  STableMetaInfo *pTableMetaInfo = tscGetMetaInfo(pQueryInfo, 0);
1479

S
slguan 已提交
1480 1481
  STableDataBlocks *pDataBlock = NULL;
  int32_t           affected_rows = 0;
H
hzcheng 已提交
1482

1483
  assert(pCmd->dataSourceType == DATA_FROM_DATA_FILE && pCmd->pDataBlocks != NULL);
S
slguan 已提交
1484 1485
  SDataBlockList *pDataBlockList = pCmd->pDataBlocks;
  pCmd->pDataBlocks = NULL;
H
hzcheng 已提交
1486

S
slguan 已提交
1487
  char path[PATH_MAX] = {0};
H
hzcheng 已提交
1488

S
slguan 已提交
1489 1490
  for (int32_t i = 0; i < pDataBlockList->nSize; ++i) {
    pDataBlock = pDataBlockList->pData[i];
H
hzcheng 已提交
1491 1492 1493
    if (pDataBlock == NULL) {
      continue;
    }
1494

S
slguan 已提交
1495 1496 1497 1498
    if (TSDB_CODE_SUCCESS != tscAllocPayload(pCmd, TSDB_PAYLOAD_SIZE)) {
      tscError("%p failed to malloc when insert file", pSql);
      continue;
    }
H
hzcheng 已提交
1499 1500
    pCmd->count = 1;

B
Bomin Zhang 已提交
1501
    tstrncpy(path, pDataBlock->filename, sizeof(path));
S
slguan 已提交
1502 1503

    FILE *fp = fopen(path, "r");
H
hzcheng 已提交
1504
    if (fp == NULL) {
S
slguan 已提交
1505
      tscError("%p failed to open file %s to load data from file, reason:%s", pSql, path, strerror(errno));
H
hzcheng 已提交
1506 1507 1508
      continue;
    }

B
Bomin Zhang 已提交
1509
    tstrncpy(pTableMetaInfo->name, pDataBlock->tableId, sizeof(pTableMetaInfo->name));
S
slguan 已提交
1510 1511
    memset(pDataBlock->pData, 0, pDataBlock->nAllocSize);

H
hjxilinx 已提交
1512
    int32_t ret = tscGetTableMeta(pSql, pTableMetaInfo);
S
slguan 已提交
1513 1514 1515 1516
    if (ret != TSDB_CODE_SUCCESS) {
      tscError("%p get meter meta failed, abort", pSql);
      continue;
    }
1517 1518

    char *tmpTokenBuf = calloc(1, 4096);  // used for deleting Escape character: \\, \', \"
L
[1292]  
lihui 已提交
1519 1520 1521 1522
    if (NULL == tmpTokenBuf) {
      tscError("%p calloc failed", pSql);
      continue;
    }
S
slguan 已提交
1523

L
[1292]  
lihui 已提交
1524 1525
    int nrows = tscInsertDataFromFile(pSql, fp, tmpTokenBuf);
    free(tmpTokenBuf);
1526

S
slguan 已提交
1527 1528
    pCmd->pDataBlocks = tscDestroyBlockArrayList(pCmd->pDataBlocks);

H
hzcheng 已提交
1529 1530
    if (nrows < 0) {
      fclose(fp);
S
slguan 已提交
1531
      tscTrace("%p no records(%d) in file %s", pSql, nrows, path);
H
hzcheng 已提交
1532 1533 1534
      continue;
    }

S
slguan 已提交
1535
    fclose(fp);
H
hzcheng 已提交
1536 1537
    affected_rows += nrows;

S
slguan 已提交
1538
    tscTrace("%p Insert data %d records from file %s", pSql, nrows, path);
H
hzcheng 已提交
1539 1540 1541 1542 1543
  }

  pSql->res.numOfRows = affected_rows;

  // all data have been submit to vnode, release data blocks
S
slguan 已提交
1544 1545
  pCmd->pDataBlocks = tscDestroyBlockArrayList(pCmd->pDataBlocks);
  tscDestroyBlockArrayList(pDataBlockList);
H
hzcheng 已提交
1546
}