clientSmlTelnet.c 11.3 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
/*
 * 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/>.
 */

#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "clientSml.h"

X
Xiaoyu Wang 已提交
23
int32_t is_same_child_table_telnet(const void *a, const void *b) {
24 25
  SSmlLineInfo *t1 = (SSmlLineInfo *)a;
  SSmlLineInfo *t2 = (SSmlLineInfo *)b;
X
Xiaoyu Wang 已提交
26 27 28
  //  uError("is_same_child_table_telnet len:%d,%d %s,%s @@@ len:%d,%d %s,%s", t1->measureLen, t2->measureLen,
  //         t1->measure, t2->measure, t1->tagsLen, t2->tagsLen, t1->tags, t2->tags);
  if (t1 == NULL || t2 == NULL || t1->measure == NULL || t2->measure == NULL || t1->tags == NULL || t2->tags == NULL)
wmmhello's avatar
wmmhello 已提交
29
    return 1;
X
Xiaoyu Wang 已提交
30 31 32 33
  return (((t1->measureLen == t2->measureLen) && memcmp(t1->measure, t2->measure, t1->measureLen) == 0) &&
          ((t1->tagsLen == t2->tagsLen) && memcmp(t1->tags, t2->tags, t1->tagsLen) == 0))
             ? 0
             : 1;
34 35
}

wmmhello's avatar
wmmhello 已提交
36
int64_t smlParseOpenTsdbTime(SSmlHandle *info, const char *data, int32_t len) {
37 38 39 40 41 42 43
  uint8_t toPrecision = info->currSTableMeta ? info->currSTableMeta->tableInfo.precision : TSDB_TIME_PRECISION_NANO;

  if (unlikely(!data)) {
    smlBuildInvalidDataMsg(&info->msgBuf, "timestamp can not be null", NULL);
    return -1;
  }
  if (unlikely(len == 1 && data[0] == '0')) {
X
Xiaoyu Wang 已提交
44
    return taosGetTimestampNs() / smlFactorNS[toPrecision];
45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72
  }
  int8_t fromPrecision = smlGetTsTypeByLen(len);
  if (unlikely(fromPrecision == -1)) {
    smlBuildInvalidDataMsg(&info->msgBuf,
                           "timestamp precision can only be seconds(10 digits) or milli seconds(13 digits)", data);
    return -1;
  }
  int64_t ts = smlGetTimeValue(data, len, fromPrecision, toPrecision);
  if (unlikely(ts == -1)) {
    smlBuildInvalidDataMsg(&info->msgBuf, "invalid timestamp", data);
    return -1;
  }
  return ts;
}

static void smlParseTelnetElement(char **sql, char *sqlEnd, char **data, int32_t *len) {
  while (*sql < sqlEnd) {
    if (unlikely((**sql != SPACE && !(*data)))) {
      *data = *sql;
    } else if (unlikely(**sql == SPACE && *data)) {
      *len = *sql - *data;
      break;
    }
    (*sql)++;
  }
}

static int32_t smlParseTelnetTags(SSmlHandle *info, char *data, char *sqlEnd, SSmlLineInfo *elements, SSmlMsgBuf *msg) {
X
Xiaoyu Wang 已提交
73
  if (is_same_child_table_telnet(elements, &info->preLine) == 0) {
74
    elements->measureTag = info->preLine.measureTag;
75 76 77 78 79 80 81
    return TSDB_CODE_SUCCESS;
  }

  bool isSameMeasure = IS_SAME_SUPER_TABLE;

  int     cnt = 0;
  SArray *preLineKV = info->preLineTagKV;
X
Xiaoyu Wang 已提交
82 83
  if (info->dataFormat) {
    if (!isSameMeasure) {
84
      SSmlSTableMeta **tmp = (SSmlSTableMeta **)taosHashGet(info->superTables, elements->measure, elements->measureLen);
85
      SSmlSTableMeta *sMeta = NULL;
X
Xiaoyu Wang 已提交
86 87 88
      if (unlikely(tmp == NULL)) {
        STableMeta *pTableMeta = smlGetMeta(info, elements->measure, elements->measureLen);
        if (pTableMeta == NULL) {
89
          info->dataFormat = false;
X
Xiaoyu Wang 已提交
90
          info->reRun = true;
91 92
          return TSDB_CODE_SUCCESS;
        }
wmmhello's avatar
wmmhello 已提交
93 94
        sMeta = smlBuildSTableMeta(info->dataFormat);
        sMeta->tableMeta = pTableMeta;
95
        taosHashPut(info->superTables, elements->measure, elements->measureLen, &sMeta, POINTER_BYTES);
96 97 98 99 100
        for(int i = pTableMeta->tableInfo.numOfColumns; i < pTableMeta->tableInfo.numOfTags + pTableMeta->tableInfo.numOfColumns; i++){
          SSchema *tag = pTableMeta->schema + i;
          SSmlKv kv = {.key = tag->name, .keyLen = strlen(tag->name), .type = tag->type, .length = (tag->bytes - VARSTR_HEADER_SIZE) / TSDB_NCHAR_SIZE };
          taosArrayPush(sMeta->tags, &kv);
        }
101
        tmp = &sMeta;
102
      }
103
      info->currSTableMeta = (*tmp)->tableMeta;
104
      info->maxTagKVs = (*tmp)->tags;
105 106 107
    }
  }

X
Xiaoyu Wang 已提交
108
  taosArrayClear(preLineKV);
109 110 111 112 113 114
  const char *sql = data;
  while (sql < sqlEnd) {
    JUMP_SPACE(sql, sqlEnd)
    if (unlikely(*sql == '\0')) break;

    const char *key = sql;
X
Xiaoyu Wang 已提交
115
    size_t      keyLen = 0;
116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134

    // parse key
    while (sql < sqlEnd) {
      if (unlikely(*sql == SPACE)) {
        smlBuildInvalidDataMsg(msg, "invalid data", sql);
        return TSDB_CODE_SML_INVALID_DATA;
      }
      if (unlikely(*sql == EQUAL)) {
        keyLen = sql - key;
        sql++;
        break;
      }
      sql++;
    }

    if (unlikely(IS_INVALID_COL_LEN(keyLen))) {
      smlBuildInvalidDataMsg(msg, "invalid key or key is too long than 64", key);
      return TSDB_CODE_TSC_INVALID_COLUMN_LENGTH;
    }
X
Xiaoyu Wang 已提交
135 136 137 138
    //    if (smlCheckDuplicateKey(key, keyLen, dumplicateKey)) {
    //      smlBuildInvalidDataMsg(msg, "dumplicate key", key);
    //      return TSDB_CODE_TSC_DUP_NAMES;
    //    }
139 140 141

    // parse value
    const char *value = sql;
X
Xiaoyu Wang 已提交
142
    size_t      valueLen = 0;
143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164
    while (sql < sqlEnd) {
      // parse value
      if (unlikely(*sql == SPACE)) {
        break;
      }
      if (unlikely(*sql == EQUAL)) {
        smlBuildInvalidDataMsg(msg, "invalid data", sql);
        return TSDB_CODE_SML_INVALID_DATA;
      }
      sql++;
    }
    valueLen = sql - value;

    if (unlikely(valueLen == 0)) {
      smlBuildInvalidDataMsg(msg, "invalid value", value);
      return TSDB_CODE_TSC_INVALID_VALUE;
    }

    if (unlikely(valueLen > (TSDB_MAX_NCHAR_LEN - VARSTR_HEADER_SIZE) / TSDB_NCHAR_SIZE)) {
      return TSDB_CODE_PAR_INVALID_VAR_COLUMN_LEN;
    }

wmmhello's avatar
wmmhello 已提交
165
    SSmlKv kv = {.key = key, .keyLen = keyLen, .type = TSDB_DATA_TYPE_NCHAR, .value = value, .length = valueLen};
166

X
Xiaoyu Wang 已提交
167 168
    if (info->dataFormat) {
      if (unlikely(cnt + 1 > info->currSTableMeta->tableInfo.numOfTags)) {
169
        info->dataFormat = false;
X
Xiaoyu Wang 已提交
170
        info->reRun = true;
171 172
        return TSDB_CODE_SUCCESS;
      }
173 174 175 176 177 178 179 180 181 182 183 184 185 186
      if (unlikely(cnt >= taosArrayGetSize(info->maxTagKVs))) {
        info->dataFormat = false;
        info->reRun = true;
        return TSDB_CODE_SUCCESS;
      }
      SSmlKv *maxKV = (SSmlKv *)taosArrayGet(info->maxTagKVs, cnt);
      if (unlikely(!IS_SAME_KEY)) {
        info->dataFormat = false;
        info->reRun = true;
        return TSDB_CODE_SUCCESS;
      }
      if (unlikely(kv.length > maxKV->length)) {
        maxKV->length = kv.length;
        info->needModifySchema = true;
187 188
      }
    }
wmmhello's avatar
wmmhello 已提交
189
    taosArrayPush(preLineKV, &kv);
190 191
    cnt++;
  }
192

X
Xiaoyu Wang 已提交
193
  elements->measureTag = (char *)taosMemoryMalloc(elements->measureLen + elements->tagsLen);
194 195
  memcpy(elements->measureTag, elements->measure, elements->measureLen);
  memcpy(elements->measureTag + elements->measureLen, elements->tags, elements->tagsLen);
196
  elements->measureTagsLen = elements->measureLen + elements->tagsLen;
197

X
Xiaoyu Wang 已提交
198 199
  SSmlTableInfo **tmp =
      (SSmlTableInfo **)taosHashGet(info->childTables, elements->measureTag, elements->measureLen + elements->tagsLen);
200 201
  SSmlTableInfo *tinfo = NULL;
  if (unlikely(tmp == NULL)) {
202 203 204 205 206 207 208
    tinfo = smlBuildTableInfo(1, elements->measure, elements->measureLen);
    if (!tinfo) {
      return TSDB_CODE_OUT_OF_MEMORY;
    }
    tinfo->tags = taosArrayDup(preLineKV, NULL);

    smlSetCTableName(tinfo);
wmmhello's avatar
wmmhello 已提交
209
    tinfo->uid = info->uid++;
210 211 212 213 214
    if (info->dataFormat) {
      info->currSTableMeta->uid = tinfo->uid;
      tinfo->tableDataCtx = smlInitTableDataCtx(info->pQuery, info->currSTableMeta);
      if (tinfo->tableDataCtx == NULL) {
        smlBuildInvalidDataMsg(&info->msgBuf, "smlInitTableDataCtx error", NULL);
215
        smlDestroyTableInfo(info, tinfo);
216 217 218 219
        return TSDB_CODE_SML_INVALID_DATA;
      }
    }

X
Xiaoyu Wang 已提交
220 221 222 223 224
    //    SSmlLineInfo *key = (SSmlLineInfo *)taosMemoryMalloc(sizeof(SSmlLineInfo));
    //    *key = *elements;
    //    tinfo->key = key;
    taosHashPut(info->childTables, elements->measureTag, elements->measureLen + elements->tagsLen, &tinfo,
                POINTER_BYTES);
225
    tmp = &tinfo;
226
  }
227
  if (info->dataFormat) info->currTableDataCtx = (*tmp)->tableDataCtx;
228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250

  return TSDB_CODE_SUCCESS;
}

// format: <metric> <timestamp> <value> <tagk_1>=<tagv_1>[ <tagk_n>=<tagv_n>]
int32_t smlParseTelnetString(SSmlHandle *info, char *sql, char *sqlEnd, SSmlLineInfo *elements) {
  if (!sql) return TSDB_CODE_SML_INVALID_DATA;

  // parse metric
  smlParseTelnetElement(&sql, sqlEnd, &elements->measure, &elements->measureLen);
  if (unlikely((!(elements->measure) || IS_INVALID_TABLE_LEN(elements->measureLen)))) {
    smlBuildInvalidDataMsg(&info->msgBuf, "invalid data", sql);
    return TSDB_CODE_TSC_INVALID_TABLE_ID_LENGTH;
  }

  // parse timestamp
  smlParseTelnetElement(&sql, sqlEnd, &elements->timestamp, &elements->timestampLen);
  if (unlikely(!elements->timestamp || elements->timestampLen == 0)) {
    smlBuildInvalidDataMsg(&info->msgBuf, "invalid timestamp", sql);
    return TSDB_CODE_SML_INVALID_DATA;
  }

  bool needConverTime = false;  // get TS before parse tag(get meta), so need conver time
X
Xiaoyu Wang 已提交
251
  if (info->dataFormat && info->currSTableMeta == NULL) {
252 253 254 255 256 257 258
    needConverTime = true;
  }
  int64_t ts = smlParseOpenTsdbTime(info, elements->timestamp, elements->timestampLen);
  if (unlikely(ts < 0)) {
    smlBuildInvalidDataMsg(&info->msgBuf, "invalid timestamp", sql);
    return TSDB_CODE_INVALID_TIMESTAMP;
  }
X
Xiaoyu Wang 已提交
259 260 261 262 263
  SSmlKv kvTs = {.key = TS,
                 .keyLen = TS_LEN,
                 .type = TSDB_DATA_TYPE_TIMESTAMP,
                 .i = ts,
                 .length = (size_t)tDataTypes[TSDB_DATA_TYPE_TIMESTAMP].bytes};
264 265 266 267 268 269 270 271 272

  // parse value
  smlParseTelnetElement(&sql, sqlEnd, &elements->cols, &elements->colsLen);
  if (unlikely(!elements->cols || elements->colsLen == 0)) {
    smlBuildInvalidDataMsg(&info->msgBuf, "invalid value", sql);
    return TSDB_CODE_TSC_INVALID_VALUE;
  }

  SSmlKv kv = {.key = VALUE, .keyLen = VALUE_LEN, .value = elements->cols, .length = (size_t)elements->colsLen};
wmmhello's avatar
wmmhello 已提交
273
  if (smlParseValue(&kv, &info->msgBuf) != TSDB_CODE_SUCCESS) {
274 275
    return TSDB_CODE_TSC_INVALID_VALUE;
  }
wmmhello's avatar
wmmhello 已提交
276

277 278 279 280 281 282 283 284 285 286 287 288 289 290
  JUMP_SPACE(sql, sqlEnd)

  elements->tags = sql;
  elements->tagsLen = sqlEnd - sql;
  if (unlikely(!elements->tags || elements->tagsLen == 0)) {
    smlBuildInvalidDataMsg(&info->msgBuf, "invalid value", sql);
    return TSDB_CODE_TSC_INVALID_VALUE;
  }

  int ret = smlParseTelnetTags(info, sql, sqlEnd, elements, &info->msgBuf);
  if (unlikely(ret != TSDB_CODE_SUCCESS)) {
    return ret;
  }

X
Xiaoyu Wang 已提交
291
  if (unlikely(info->reRun)) {
292 293 294
    return TSDB_CODE_SUCCESS;
  }

X
Xiaoyu Wang 已提交
295 296
  if (info->dataFormat) {
    if (needConverTime) {
297 298 299
      kvTs.i = convertTimePrecision(kvTs.i, TSDB_TIME_PRECISION_NANO, info->currSTableMeta->tableInfo.precision);
    }
    ret = smlBuildCol(info->currTableDataCtx, info->currSTableMeta->schema, &kvTs, 0);
X
Xiaoyu Wang 已提交
300
    if (ret == TSDB_CODE_SUCCESS) {
301 302
      ret = smlBuildCol(info->currTableDataCtx, info->currSTableMeta->schema, &kv, 1);
    }
X
Xiaoyu Wang 已提交
303
    if (ret == TSDB_CODE_SUCCESS) {
304 305
      ret = smlBuildRow(info->currTableDataCtx);
    }
wmmhello's avatar
wmmhello 已提交
306
    clearColValArray(info->currTableDataCtx->pValues);
307 308 309 310
    if (unlikely(ret != TSDB_CODE_SUCCESS)) {
      smlBuildInvalidDataMsg(&info->msgBuf, "smlBuildCol error", NULL);
      return ret;
    }
X
Xiaoyu Wang 已提交
311 312
  } else {
    if (elements->colArray == NULL) {
313 314 315 316 317 318 319 320 321
      elements->colArray = taosArrayInit(16, sizeof(SSmlKv));
    }
    taosArrayPush(elements->colArray, &kvTs);
    taosArrayPush(elements->colArray, &kv);
  }
  info->preLine = *elements;

  return TSDB_CODE_SUCCESS;
}