parUtil.c 17.3 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14
/*
 * 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/>.
 */
15

X
Xiaoyu Wang 已提交
16
#include "parUtil.h"
17
#include "cJSON.h"
18

19 20 21 22 23 24 25
static char* getSyntaxErrFormat(int32_t errCode) {
  switch (errCode) {
    case TSDB_CODE_PAR_SYNTAX_ERROR:
      return "syntax error near \"%s\"";
    case TSDB_CODE_PAR_INCOMPLETE_SQL:
      return "Incomplete SQL statement";
    case TSDB_CODE_PAR_INVALID_COLUMN:
X
Xiaoyu Wang 已提交
26
      return "Invalid column name: %s";
27
    case TSDB_CODE_PAR_TABLE_NOT_EXIST:
X
Xiaoyu Wang 已提交
28
      return "Table does not exist: %s";
29
    case TSDB_CODE_PAR_AMBIGUOUS_COLUMN:
X
Xiaoyu Wang 已提交
30
      return "Column ambiguously defined: %s";
31
    case TSDB_CODE_PAR_WRONG_VALUE_TYPE:
X
Xiaoyu Wang 已提交
32
      return "Invalid value type: %s";
33 34 35 36 37 38 39 40 41 42 43
    case TSDB_CODE_PAR_ILLEGAL_USE_AGG_FUNCTION:
      return "There mustn't be aggregation";
    case TSDB_CODE_PAR_WRONG_NUMBER_OF_SELECT:
      return "ORDER BY item must be the number of a SELECT-list expression";
    case TSDB_CODE_PAR_GROUPBY_LACK_EXPRESSION:
      return "Not a GROUP BY expression";
    case TSDB_CODE_PAR_NOT_SELECTED_EXPRESSION:
      return "Not SELECTed expression";
    case TSDB_CODE_PAR_NOT_SINGLE_GROUP:
      return "Not a single-group group function";
    case TSDB_CODE_PAR_TAGS_NOT_MATCHED:
44
      return "Tags number not matched";
45
    case TSDB_CODE_PAR_INVALID_TAG_NAME:
X
Xiaoyu Wang 已提交
46
      return "Invalid tag name: %s";
47
    case TSDB_CODE_PAR_NAME_OR_PASSWD_TOO_LONG:
48
      return "Name or password too long";
49
    case TSDB_CODE_PAR_PASSWD_EMPTY:
50
      return "Password can not be empty";
51
    case TSDB_CODE_PAR_INVALID_PORT:
52
      return "Port should be an integer that is less than 65535 and greater than 0";
53
    case TSDB_CODE_PAR_INVALID_ENDPOINT:
54 55 56
      return "Endpoint should be in the format of 'fqdn:port'";
    case TSDB_CODE_PAR_EXPRIE_STATEMENT:
      return "This statement is no longer supported";
X
Xiaoyu Wang 已提交
57 58
    case TSDB_CODE_PAR_INTER_VALUE_TOO_SMALL:
      return "Interval cannot be less than %d us";
X
Xiaoyu Wang 已提交
59
    case TSDB_CODE_PAR_DB_NOT_SPECIFIED:
60
      return "Database not specified";
X
Xiaoyu Wang 已提交
61
    case TSDB_CODE_PAR_INVALID_IDENTIFIER_NAME:
X
Xiaoyu Wang 已提交
62
      return "Invalid identifier name: %s";
X
Xiaoyu Wang 已提交
63
    case TSDB_CODE_PAR_CORRESPONDING_STABLE_ERR:
64
      return "Corresponding super table not in this db";
X
Xiaoyu Wang 已提交
65
    case TSDB_CODE_PAR_INVALID_RANGE_OPTION:
X
Xiaoyu Wang 已提交
66
      return "Invalid option %s: %" PRId64 " valid range: [%d, %d]";
X
Xiaoyu Wang 已提交
67
    case TSDB_CODE_PAR_INVALID_STR_OPTION:
68
      return "Invalid option %s: %s";
X
Xiaoyu Wang 已提交
69
    case TSDB_CODE_PAR_INVALID_ENUM_OPTION:
X
Xiaoyu Wang 已提交
70
      return "Invalid option %s: %" PRId64 ", only %d, %d allowed";
X
Xiaoyu Wang 已提交
71
    case TSDB_CODE_PAR_INVALID_KEEP_NUM:
72
      return "Invalid number of keep options";
X
Xiaoyu Wang 已提交
73
    case TSDB_CODE_PAR_INVALID_KEEP_ORDER:
74
      return "Invalid keep value, should be keep0 <= keep1 <= keep2";
X
Xiaoyu Wang 已提交
75
    case TSDB_CODE_PAR_INVALID_KEEP_VALUE:
76
      return "Invalid option keep: %d, %d, %d valid range: [%d, %d]";
X
Xiaoyu Wang 已提交
77
    case TSDB_CODE_PAR_INVALID_COMMENT_OPTION:
78
      return "Invalid option comment, length cannot exceed %d";
X
Xiaoyu Wang 已提交
79
    case TSDB_CODE_PAR_INVALID_F_RANGE_OPTION:
80
      return "Invalid option %s: %f valid range: [%d, %d]";
X
Xiaoyu Wang 已提交
81
    case TSDB_CODE_PAR_INVALID_ROLLUP_OPTION:
82
      return "Invalid option rollup: only one function is allowed";
X
Xiaoyu Wang 已提交
83
    case TSDB_CODE_PAR_INVALID_RETENTIONS_OPTION:
84
      return "Invalid option retentions";
X
Xiaoyu Wang 已提交
85 86
    case TSDB_CODE_PAR_GROUPBY_WINDOW_COEXIST:
      return "GROUP BY and WINDOW-clause can't be used together";
87 88 89
    case TSDB_CODE_PAR_INVALID_OPTION_UNIT:
      return "Invalid option %s unit: %c, only m, h, d allowed";
    case TSDB_CODE_PAR_INVALID_KEEP_UNIT:
X
Xiaoyu Wang 已提交
90
      return "Invalid option keep unit: %c, only m, h, d allowed";
X
Xiaoyu Wang 已提交
91 92
    case TSDB_CODE_PAR_AGG_FUNC_NESTING:
      return "Aggregate functions do not support nesting";
X
Xiaoyu Wang 已提交
93
    case TSDB_CODE_PAR_INVALID_STATE_WIN_TYPE:
94
      return "Only support STATE_WINDOW on integer/bool/varchar column";
X
Xiaoyu Wang 已提交
95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114
    case TSDB_CODE_PAR_INVALID_STATE_WIN_COL:
      return "Not support STATE_WINDOW on tag column";
    case TSDB_CODE_PAR_INVALID_STATE_WIN_TABLE:
      return "STATE_WINDOW not support for super table query";
    case TSDB_CODE_PAR_INTER_SESSION_GAP:
      return "SESSION gap should be fixed time window, and greater than 0";
    case TSDB_CODE_PAR_INTER_SESSION_COL:
      return "Only support SESSION on primary timestamp column";
    case TSDB_CODE_PAR_INTER_OFFSET_NEGATIVE:
      return "Interval offset cannot be negative";
    case TSDB_CODE_PAR_INTER_OFFSET_UNIT:
      return "Cannot use 'year' as offset when interval is 'month'";
    case TSDB_CODE_PAR_INTER_OFFSET_TOO_BIG:
      return "Interval offset should be shorter than interval";
    case TSDB_CODE_PAR_INTER_SLIDING_UNIT:
      return "Does not support sliding when interval is natural month/year";
    case TSDB_CODE_PAR_INTER_SLIDING_TOO_BIG:
      return "sliding value no larger than the interval value";
    case TSDB_CODE_PAR_INTER_SLIDING_TOO_SMALL:
      return "sliding value can not less than 1% of interval value";
115 116
    case TSDB_CODE_PAR_ONLY_ONE_JSON_TAG:
      return "Only one tag if there is a json tag";
X
Xiaoyu Wang 已提交
117 118
    case TSDB_CODE_PAR_INCORRECT_NUM_OF_COL:
      return "Query block has incorrect number of result columns";
X
Xiaoyu Wang 已提交
119 120 121 122 123 124 125 126
    case TSDB_CODE_PAR_INCORRECT_TIMESTAMP_VAL:
      return "Incorrect TIMESTAMP value: %s";
    case TSDB_CODE_PAR_INVALID_DAYS_VALUE:
      return "Invalid days value, should be keep2 >= keep1 >= keep0 >= days";
    case TSDB_CODE_PAR_OFFSET_LESS_ZERO:
      return "soffset/offset can not be less than 0";
    case TSDB_CODE_PAR_SLIMIT_LEAK_PARTITION_BY:
      return "slimit/soffset only available for PARTITION BY query";
X
Xiaoyu Wang 已提交
127 128
    case TSDB_CODE_PAR_INVALID_TOPIC_QUERY:
      return "Invalid topic query";
X
Xiaoyu Wang 已提交
129 130
    case TSDB_CODE_PAR_INVALID_DROP_STABLE:
      return "Cannot drop super table in batch";
X
Xiaoyu Wang 已提交
131
    case TSDB_CODE_PAR_INVALID_FILL_TIME_RANGE:
132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148
      return "Start(end) time of query range required or time range too large";
    case TSDB_CODE_PAR_DUPLICATED_COLUMN:
      return "Duplicated column names";
    case TSDB_CODE_PAR_INVALID_TAGS_LENGTH:
      return "Tags length exceeds max length %d";
    case TSDB_CODE_PAR_INVALID_ROW_LENGTH:
      return "Row length exceeds max length %d";
    case TSDB_CODE_PAR_INVALID_COLUMNS_NUM:
      return "Illegal number of columns";
    case TSDB_CODE_PAR_TOO_MANY_COLUMNS:
      return "Too many columns";
    case TSDB_CODE_PAR_INVALID_FIRST_COLUMN:
      return "First column must be timestamp";
    case TSDB_CODE_PAR_INVALID_VAR_COLUMN_LEN:
      return "Invalid binary/nchar column length";
    case TSDB_CODE_PAR_INVALID_TAGS_NUM:
      return "Invalid number of tag columns";
X
Xiaoyu Wang 已提交
149 150
    case TSDB_CODE_PAR_INVALID_INTERNAL_PK:
      return "Invalid _c0 or _rowts expression";
151 152 153 154
    case TSDB_CODE_PAR_INVALID_TIMELINE_FUNC:
      return "Invalid timeline function";
    case TSDB_CODE_PAR_INVALID_PASSWD:
      return "Invalid password";
X
Xiaoyu Wang 已提交
155 156
    case TSDB_CODE_PAR_INVALID_ALTER_TABLE:
      return "Invalid alter table statement";
X
Xiaoyu Wang 已提交
157 158 159 160
    case TSDB_CODE_PAR_CANNOT_DROP_PRIMARY_KEY:
      return "Primary timestamp column cannot be dropped";
    case TSDB_CODE_PAR_INVALID_MODIFY_COL:
      return "Only binary/nchar column length could be modified";
161 162
    case TSDB_CODE_PAR_INVALID_TBNAME:
      return "Invalid tbname pseudo column";
163 164 165 166
    case TSDB_CODE_PAR_INVALID_FUNCTION_NAME:
      return "Invalid function name";
    case TSDB_CODE_PAR_COMMENT_TOO_LONG:
      return "Comment too long";
167
    case TSDB_CODE_PAR_NOT_ALLOWED_FUNC:
168
      return "Some functions are allowed only in the SELECT list of a query. "
169
             "And, cannot be mixed with other non scalar functions or columns.";
170 171
    case TSDB_CODE_PAR_NOT_ALLOWED_WIN_QUERY:
      return "Window query not supported, since the result of subquery not include valid timestamp column";
172 173 174 175 176 177 178 179 180 181 182 183 184 185 186
    case TSDB_CODE_OUT_OF_MEMORY:
      return "Out of memory";
    default:
      return "Unknown error";
  }
}

int32_t generateSyntaxErrMsg(SMsgBuf* pBuf, int32_t errCode, ...) {
  va_list vArgList;
  va_start(vArgList, errCode);
  vsnprintf(pBuf->buf, pBuf->len, getSyntaxErrFormat(errCode), vArgList);
  va_end(vArgList);
  return errCode;
}

X
Xiaoyu Wang 已提交
187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202
int32_t buildInvalidOperationMsg(SMsgBuf* pBuf, const char* msg) {
  strncpy(pBuf->buf, msg, pBuf->len);
  return TSDB_CODE_TSC_INVALID_OPERATION;
}

int32_t buildSyntaxErrMsg(SMsgBuf* pBuf, const char* additionalInfo, const char* sourceStr) {
  const char* msgFormat1 = "syntax error near \'%s\'";
  const char* msgFormat2 = "syntax error near \'%s\' (%s)";
  const char* msgFormat3 = "%s";

  const char* prefix = "syntax error";
  if (sourceStr == NULL) {
    assert(additionalInfo != NULL);
    snprintf(pBuf->buf, pBuf->len, msgFormat1, additionalInfo);
    return TSDB_CODE_TSC_SQL_SYNTAX_ERROR;
  }
203

X
Xiaoyu Wang 已提交
204 205 206 207 208 209 210 211 212 213 214 215
  char buf[64] = {0};  // only extract part of sql string
  strncpy(buf, sourceStr, tListLen(buf) - 1);

  if (additionalInfo != NULL) {
    snprintf(pBuf->buf, pBuf->len, msgFormat2, buf, additionalInfo);
  } else {
    const char* msgFormat = (0 == strncmp(sourceStr, prefix, strlen(prefix))) ? msgFormat3 : msgFormat1;
    snprintf(pBuf->buf, pBuf->len, msgFormat, buf);
  }

  return TSDB_CODE_TSC_SQL_SYNTAX_ERROR;
}
216

X
Xiaoyu Wang 已提交
217
SSchema* getTableColumnSchema(const STableMeta* pTableMeta) {
X
Xiaoyu Wang 已提交
218
  assert(pTableMeta != NULL);
X
Xiaoyu Wang 已提交
219
  return (SSchema*)pTableMeta->schema;
220 221
}

X
Xiaoyu Wang 已提交
222
static SSchema* getOneColumnSchema(const STableMeta* pTableMeta, int32_t colIndex) {
X
Xiaoyu Wang 已提交
223 224
  assert(pTableMeta != NULL && pTableMeta->schema != NULL && colIndex >= 0 &&
         colIndex < (getNumOfColumns(pTableMeta) + getNumOfTags(pTableMeta)));
225

X
Xiaoyu Wang 已提交
226
  SSchema* pSchema = (SSchema*)pTableMeta->schema;
X
Xiaoyu Wang 已提交
227
  return &pSchema[colIndex];
228
}
229

X
Xiaoyu Wang 已提交
230
SSchema* getTableTagSchema(const STableMeta* pTableMeta) {
X
Xiaoyu Wang 已提交
231 232
  assert(pTableMeta != NULL &&
         (pTableMeta->tableType == TSDB_SUPER_TABLE || pTableMeta->tableType == TSDB_CHILD_TABLE));
X
Xiaoyu Wang 已提交
233
  return getOneColumnSchema(pTableMeta, getTableInfo(pTableMeta).numOfColumns);
234 235
}

X
Xiaoyu Wang 已提交
236 237 238 239
int32_t getNumOfColumns(const STableMeta* pTableMeta) {
  assert(pTableMeta != NULL);
  // table created according to super table, use data from super table
  return getTableInfo(pTableMeta).numOfColumns;
240 241
}

X
Xiaoyu Wang 已提交
242 243 244
int32_t getNumOfTags(const STableMeta* pTableMeta) {
  assert(pTableMeta != NULL);
  return getTableInfo(pTableMeta).numOfTags;
245 246
}

X
Xiaoyu Wang 已提交
247
STableComInfo getTableInfo(const STableMeta* pTableMeta) {
248
  assert(pTableMeta != NULL);
X
Xiaoyu Wang 已提交
249
  return pTableMeta->tableInfo;
H
Haojun Liao 已提交
250
}
251

X
Xiaoyu Wang 已提交
252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268
static uint32_t getTableMetaSize(const STableMeta* pTableMeta) {
  int32_t totalCols = 0;
  if (pTableMeta->tableInfo.numOfColumns >= 0) {
    totalCols = pTableMeta->tableInfo.numOfColumns + pTableMeta->tableInfo.numOfTags;
  }

  return sizeof(STableMeta) + totalCols * sizeof(SSchema);
}

STableMeta* tableMetaDup(const STableMeta* pTableMeta) {
  size_t size = getTableMetaSize(pTableMeta);

  STableMeta* p = taosMemoryMalloc(size);
  memcpy(p, pTableMeta, size);
  return p;
}

269
int32_t trimString(const char* src, int32_t len, char* dst, int32_t dlen) {
X
Xiaoyu Wang 已提交
270
  if (len <= 0 || dlen <= 0) return 0;
271

X
Xiaoyu Wang 已提交
272
  char    delim = src[0];
273 274 275
  int32_t j = 0;
  for (uint32_t k = 1; k < len - 1; ++k) {
    if (j >= dlen) {
276 277
      dst[j - 1] = '\0';
      return j;
278
    }
X
Xiaoyu Wang 已提交
279
    if (src[k] == delim && src[k + 1] == delim) {  // deal with "", ''
280 281 282 283 284
      dst[j] = src[k + 1];
      j++;
      k++;
      continue;
    }
285

X
Xiaoyu Wang 已提交
286 287
    if (src[k] == '\\') {  // deal with escape character
      if (src[k + 1] == 'n') {
288
        dst[j] = '\n';
X
Xiaoyu Wang 已提交
289
      } else if (src[k + 1] == 'r') {
290
        dst[j] = '\r';
X
Xiaoyu Wang 已提交
291
      } else if (src[k + 1] == 't') {
292
        dst[j] = '\t';
X
Xiaoyu Wang 已提交
293
      } else if (src[k + 1] == '\\') {
294
        dst[j] = '\\';
X
Xiaoyu Wang 已提交
295
      } else if (src[k + 1] == '\'') {
296
        dst[j] = '\'';
X
Xiaoyu Wang 已提交
297
      } else if (src[k + 1] == '"') {
298
        dst[j] = '"';
X
Xiaoyu Wang 已提交
299
      } else if (src[k + 1] == '%' || src[k + 1] == '_') {
300
        dst[j++] = src[k];
X
Xiaoyu Wang 已提交
301 302 303
        dst[j] = src[k + 1];
      } else {
        dst[j] = src[k + 1];
304 305 306 307 308 309
      }
      j++;
      k++;
      continue;
    }

310 311 312 313 314 315
    dst[j] = src[k];
    j++;
  }
  dst[j] = '\0';
  return j;
}
316

X
Xiaoyu Wang 已提交
317
static bool isValidateTag(char* input) {
318 319 320 321 322 323 324
  if (!input) return false;
  for (size_t i = 0; i < strlen(input); ++i) {
    if (isprint(input[i]) == 0) return false;
  }
  return true;
}

X
Xiaoyu Wang 已提交
325
int parseJsontoTagData(const char* json, SKVRowBuilder* kvRowBuilder, SMsgBuf* pMsgBuf, int16_t startColId) {
326
  // set json NULL data
327
  uint8_t jsonNULL = TSDB_DATA_TYPE_NULL;
X
Xiaoyu Wang 已提交
328 329
  int     jsonIndex = startColId + 1;
  if (!json || strcasecmp(json, TSDB_DATA_NULL_STR_L) == 0) {
330
    tdAddColToKVRow(kvRowBuilder, jsonIndex, &jsonNULL, CHAR_BYTES);
331 332 333 334
    return TSDB_CODE_SUCCESS;
  }

  // set json real data
X
Xiaoyu Wang 已提交
335 336
  cJSON* root = cJSON_Parse(json);
  if (root == NULL) {
337 338 339 340
    return buildSyntaxErrMsg(pMsgBuf, "json parse error", json);
  }

  int size = cJSON_GetArraySize(root);
X
Xiaoyu Wang 已提交
341
  if (!cJSON_IsObject(root)) {
342 343 344
    return buildSyntaxErrMsg(pMsgBuf, "json error invalide value", json);
  }

X
Xiaoyu Wang 已提交
345 346
  int       retCode = 0;
  char*     tagKV = NULL;
347
  SHashObj* keyHash = taosHashInit(8, taosGetDefaultHashFunction(TSDB_DATA_TYPE_BINARY), false, false);
X
Xiaoyu Wang 已提交
348
  for (int i = 0; i < size; i++) {
349 350 351
    cJSON* item = cJSON_GetArrayItem(root, i);
    if (!item) {
      qError("json inner error:%d", i);
352
      retCode = buildSyntaxErrMsg(pMsgBuf, "json inner error", json);
353 354 355
      goto end;
    }

X
Xiaoyu Wang 已提交
356 357
    char* jsonKey = item->string;
    if (!isValidateTag(jsonKey)) {
358
      retCode = buildSyntaxErrMsg(pMsgBuf, "json key not validate", jsonKey);
359 360
      goto end;
    }
X
Xiaoyu Wang 已提交
361 362 363 364 365
    //    if(strlen(jsonKey) > TSDB_MAX_JSON_KEY_LEN){
    //      tscError("json key too long error");
    //      retCode =  tscSQLSyntaxErrMsg(errMsg, "json key too long, more than 256", NULL);
    //      goto end;
    //    }
366
    size_t keyLen = strlen(jsonKey);
X
Xiaoyu Wang 已提交
367
    if (keyLen == 0 || taosHashGet(keyHash, jsonKey, keyLen) != NULL) {
368 369
      continue;
    }
wmmhello's avatar
wmmhello 已提交
370 371
    // key: keyLen + VARSTR_HEADER_SIZE, value type: CHAR_BYTES, value reserved: DOUBLE_BYTES
    tagKV = taosMemoryCalloc(keyLen + VARSTR_HEADER_SIZE + CHAR_BYTES + DOUBLE_BYTES, 1);
X
Xiaoyu Wang 已提交
372
    if (!tagKV) {
373 374 375 376 377
      retCode = TSDB_CODE_TSC_OUT_OF_MEMORY;
      goto end;
    }
    strncpy(varDataVal(tagKV), jsonKey, keyLen);
    varDataSetLen(tagKV, keyLen);
X
Xiaoyu Wang 已提交
378
    if (taosHashGetSize(keyHash) == 0) {
379
      uint8_t jsonNotNULL = TSDB_DATA_TYPE_JSON;
X
Xiaoyu Wang 已提交
380
      tdAddColToKVRow(kvRowBuilder, jsonIndex++, &jsonNotNULL, CHAR_BYTES);  // add json type
381
    }
X
Xiaoyu Wang 已提交
382 383
    taosHashPut(keyHash, jsonKey, keyLen, &keyLen,
                CHAR_BYTES);  // add key to hash to remove dumplicate, value is useless
384

X
Xiaoyu Wang 已提交
385 386
    if (item->type == cJSON_String) {  // add json value  format: type|data
      char*   jsonValue = item->valuestring;
387
      int32_t valLen = (int32_t)strlen(jsonValue);
388
      int32_t totalLen = keyLen + VARSTR_HEADER_SIZE + valLen * TSDB_NCHAR_SIZE + VARSTR_HEADER_SIZE + CHAR_BYTES;
X
Xiaoyu Wang 已提交
389 390
      char*   tmp = taosMemoryRealloc(tagKV, totalLen);
      if (!tmp) {
391 392
        retCode = TSDB_CODE_TSC_OUT_OF_MEMORY;
        goto end;
393 394 395 396 397 398
      }
      tagKV = tmp;
      char* valueType = POINTER_SHIFT(tagKV, keyLen + VARSTR_HEADER_SIZE);
      char* valueData = POINTER_SHIFT(tagKV, keyLen + VARSTR_HEADER_SIZE + CHAR_BYTES);
      *valueType = TSDB_DATA_TYPE_NCHAR;
      if (valLen > 0 && !taosMbsToUcs4(jsonValue, valLen, (TdUcs4*)varDataVal(valueData),
X
Xiaoyu Wang 已提交
399 400 401
                                       (int32_t)(valLen * TSDB_NCHAR_SIZE), &valLen)) {
        qError("charset:%s to %s. val:%s, errno:%s, convert failed.", DEFAULT_UNICODE_ENCODEC, tsCharset, jsonValue,
               strerror(errno));
402 403 404 405
        retCode = buildSyntaxErrMsg(pMsgBuf, "charset convert json error", jsonValue);
        goto end;
      }

406 407
      varDataSetLen(valueData, valLen);
      tdAddColToKVRow(kvRowBuilder, jsonIndex++, tagKV, totalLen);
X
Xiaoyu Wang 已提交
408 409
    } else if (item->type == cJSON_Number) {
      if (!isfinite(item->valuedouble)) {
410
        qError("json value is invalidate");
X
Xiaoyu Wang 已提交
411
        retCode = buildSyntaxErrMsg(pMsgBuf, "json value number is illegal", json);
412 413
        goto end;
      }
414 415
      char* valueType = POINTER_SHIFT(tagKV, keyLen + VARSTR_HEADER_SIZE);
      char* valueData = POINTER_SHIFT(tagKV, keyLen + VARSTR_HEADER_SIZE + CHAR_BYTES);
wmmhello's avatar
wmmhello 已提交
416 417 418
      *valueType = TSDB_DATA_TYPE_DOUBLE;
      *((double*)valueData) = item->valuedouble;
      tdAddColToKVRow(kvRowBuilder, jsonIndex++, tagKV, keyLen + VARSTR_HEADER_SIZE + CHAR_BYTES + DOUBLE_BYTES);
X
Xiaoyu Wang 已提交
419
    } else if (item->type == cJSON_True || item->type == cJSON_False) {
420 421 422 423 424
      char* valueType = POINTER_SHIFT(tagKV, keyLen + VARSTR_HEADER_SIZE);
      char* valueData = POINTER_SHIFT(tagKV, keyLen + VARSTR_HEADER_SIZE + CHAR_BYTES);
      *valueType = TSDB_DATA_TYPE_BOOL;
      *valueData = (char)(item->valueint);
      tdAddColToKVRow(kvRowBuilder, jsonIndex++, tagKV, keyLen + VARSTR_HEADER_SIZE + CHAR_BYTES + CHAR_BYTES);
X
Xiaoyu Wang 已提交
425
    } else if (item->type == cJSON_NULL) {
426 427 428
      char* valueType = POINTER_SHIFT(tagKV, keyLen + VARSTR_HEADER_SIZE);
      *valueType = TSDB_DATA_TYPE_NULL;
      tdAddColToKVRow(kvRowBuilder, jsonIndex++, tagKV, keyLen + VARSTR_HEADER_SIZE + CHAR_BYTES);
X
Xiaoyu Wang 已提交
429
    } else {
430 431 432 433 434
      retCode = buildSyntaxErrMsg(pMsgBuf, "invalidate json value", json);
      goto end;
    }
  }

X
Xiaoyu Wang 已提交
435
  if (taosHashGetSize(keyHash) == 0) {  // set json NULL true
436
    tdAddColToKVRow(kvRowBuilder, jsonIndex, &jsonNULL, CHAR_BYTES);
437 438 439
  }

end:
440
  taosMemoryFree(tagKV);
441 442 443 444
  taosHashCleanup(keyHash);
  cJSON_Delete(root);
  return retCode;
}