trow.c 15.4 KB
Newer Older
H
refact  
Hongze Cheng 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13
/*
 * 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/>.
H
Hongze Cheng 已提交
14 15
 */

S
common  
Shengliang Guan 已提交
16
#define _DEFAULT_SOURCE
H
Hongze Cheng 已提交
17 18
#include "trow.h"

K
Kaili Xu 已提交
19 20 21 22 23 24
const uint8_t tdVTypeByte[3] = {
    TD_VTYPE_NORM_BYTE,  // TD_VTYPE_NORM
    TD_VTYPE_NONE_BYTE,  // TD_VTYPE_NONE
    TD_VTYPE_NULL_BYTE,  // TD_VTYPE_NULL
};

C
Cary Xu 已提交
25
// static void dataColSetNEleNull(SDataCol *pCol, int nEle);
C
Cary Xu 已提交
26 27
static void tdMergeTwoDataCols(SDataCols *target, SDataCols *src1, int *iter1, int limit1, SDataCols *src2, int *iter2,
                               int limit2, int tRows, bool forceSetNull);
C
update  
Cary Xu 已提交
28

C
Cary Xu 已提交
29
static FORCE_INLINE void dataColSetNullAt(SDataCol *pCol, int index, bool setBitmap) {
C
update  
Cary Xu 已提交
30 31 32 33 34 35 36 37 38
  if (IS_VAR_DATA_TYPE(pCol->type)) {
    pCol->dataOff[index] = pCol->len;
    char *ptr = POINTER_SHIFT(pCol->pData, pCol->len);
    setVardataNull(ptr, pCol->type);
    pCol->len += varDataTLen(ptr);
  } else {
    setNull(POINTER_SHIFT(pCol->pData, TYPE_BYTES[pCol->type] * index), pCol->type, pCol->bytes);
    pCol->len += TYPE_BYTES[pCol->type];
  }
C
Cary Xu 已提交
39 40
  if (setBitmap) {
    tdSetBitmapValType(pCol->pBitmap, index, TD_VTYPE_NONE);
C
update  
Cary Xu 已提交
41 42 43
  }
}

C
Cary Xu 已提交
44 45 46 47 48 49 50 51 52 53 54 55 56 57
// static void dataColSetNEleNull(SDataCol *pCol, int nEle) {
//   if (IS_VAR_DATA_TYPE(pCol->type)) {
//     pCol->len = 0;
//     for (int i = 0; i < nEle; i++) {
//       dataColSetNullAt(pCol, i);
//     }
//   } else {
//     setNullN(pCol->pData, pCol->type, pCol->bytes, nEle);
//     pCol->len = TYPE_BYTES[pCol->type] * nEle;
//   }
// }

int32_t tdSetBitmapValTypeN(void *pBitmap, int16_t nEle, TDRowValT valType) {
  TASSERT(valType < TD_VTYPE_MAX);
K
Kaili Xu 已提交
58 59 60 61 62 63 64 65 66 67
  int16_t nBytes = nEle / TD_VTYPE_PARTS;
  for (int i = 0; i < nBytes; ++i) {
    *(uint8_t *)pBitmap = tdVTypeByte[valType];
    pBitmap = POINTER_SHIFT(pBitmap, 1);
  }
  int16_t nLeft = nEle - nBytes * TD_VTYPE_BITS;

  for (int j = 0; j < nLeft; ++j) {
    tdSetBitmapValType(pBitmap, j, valType);
  }
C
Cary Xu 已提交
68
  return TSDB_CODE_SUCCESS;
K
Kaili Xu 已提交
69 70
}

C
Cary Xu 已提交
71
static FORCE_INLINE void dataColSetNoneAt(SDataCol *pCol, int index, bool setBitmap) {
K
Kaili Xu 已提交
72 73 74 75 76 77 78 79 80
  if (IS_VAR_DATA_TYPE(pCol->type)) {
    pCol->dataOff[index] = pCol->len;
    char *ptr = POINTER_SHIFT(pCol->pData, pCol->len);
    setVardataNull(ptr, pCol->type);
    pCol->len += varDataTLen(ptr);
  } else {
    setNull(POINTER_SHIFT(pCol->pData, TYPE_BYTES[pCol->type] * index), pCol->type, pCol->bytes);
    pCol->len += TYPE_BYTES[pCol->type];
  }
C
Cary Xu 已提交
81 82 83
  if(setBitmap) {
    tdSetBitmapValType(pCol->pBitmap, index, TD_VTYPE_NONE);
  }
K
Kaili Xu 已提交
84 85 86 87 88 89
}

static void dataColSetNEleNone(SDataCol *pCol, int nEle) {
  if (IS_VAR_DATA_TYPE(pCol->type)) {
    pCol->len = 0;
    for (int i = 0; i < nEle; ++i) {
C
Cary Xu 已提交
90
      dataColSetNoneAt(pCol, i, false);
K
Kaili Xu 已提交
91 92 93 94 95 96 97 98 99 100
    }
  } else {
    setNullN(pCol->pData, pCol->type, pCol->bytes, nEle);
    pCol->len = TYPE_BYTES[pCol->type] * nEle;
  }
#ifdef TD_SUPPORT_BITMAP
  tdSetBitmapValTypeN(pCol->pBitmap, nEle, TD_VTYPE_NONE);
#endif
}

H
more  
Hongze Cheng 已提交
101
#if 0
H
more  
Hongze Cheng 已提交
102
void trbSetRowInfo(SRowBuilder *pRB, bool del, uint16_t sver) {
H
Hongze Cheng 已提交
103 104 105
  // TODO
}

H
more  
Hongze Cheng 已提交
106 107
void trbSetRowVersion(SRowBuilder *pRB, uint64_t ver) {
  // TODO
H
Hongze Cheng 已提交
108 109
}

H
more  
Hongze Cheng 已提交
110 111
void trbSetRowTS(SRowBuilder *pRB, TSKEY ts) {
  // TODO
H
Hongze Cheng 已提交
112 113
}

H
more  
Hongze Cheng 已提交
114 115 116
int trbWriteCol(SRowBuilder *pRB, void *pData, col_id_t cid) {
  // TODO
  return 0;
H
more  
Hongze Cheng 已提交
117
}
C
Cary Xu 已提交
118

C
Cary Xu 已提交
119
#endif
C
Cary Xu 已提交
120

C
Cary Xu 已提交
121 122
STSRow* tdRowDup(STSRow *row) {
  STSRow* trow = malloc(TD_ROW_LEN(row));
C
Cary Xu 已提交
123 124
  if (trow == NULL) return NULL;

C
Cary Xu 已提交
125
  tdRowCpy(trow, row);
C
Cary Xu 已提交
126 127 128
  return trow;
}

C
update  
Cary Xu 已提交
129
int tdAppendValToDataCol(SDataCol *pCol, TDRowValT valType, const void *val, int numOfRows, int maxPoints) {
C
Cary Xu 已提交
130
  TASSERT(pCol != NULL);
C
update  
Cary Xu 已提交
131

C
Cary Xu 已提交
132
  // Assume that the columns not specified during insert/upsert mean None.
K
Kaili Xu 已提交
133 134 135
  if (isAllRowsNone(pCol)) {
    if (tdValIsNone(valType)) {
      // all None value yet, just return
C
update  
Cary Xu 已提交
136 137 138
      return 0;
    }

C
Cary Xu 已提交
139
    if (tdAllocMemForCol(pCol, maxPoints) < 0) return -1;
C
update  
Cary Xu 已提交
140
    if (numOfRows > 0) {
K
Kaili Xu 已提交
141 142
      // Find the first not None value, fill all previous values as None
      dataColSetNEleNone(pCol, numOfRows);
C
update  
Cary Xu 已提交
143 144
    }
  }
K
Kaili Xu 已提交
145
  if (!tdValTypeIsNorm(valType)) {
C
Cary Xu 已提交
146 147 148
    // TODO:
    // 1. back compatibility and easy to debug with codes of 2.0 to save NULL values.
    // 2. later on, considering further optimization, don't save Null/None for VarType.
K
Kaili Xu 已提交
149 150
    val = getNullValue(pCol->type);
  }
C
update  
Cary Xu 已提交
151 152 153 154 155 156 157 158 159 160 161 162
  if (IS_VAR_DATA_TYPE(pCol->type)) {
    // set offset
    pCol->dataOff[numOfRows] = pCol->len;
    // Copy data
    memcpy(POINTER_SHIFT(pCol->pData, pCol->len), val, varDataTLen(val));
    // Update the length
    pCol->len += varDataTLen(val);
  } else {
    ASSERT(pCol->len == TYPE_BYTES[pCol->type] * numOfRows);
    memcpy(POINTER_SHIFT(pCol->pData, pCol->len), val, pCol->bytes);
    pCol->len += pCol->bytes;
  }
K
Kaili Xu 已提交
163 164 165
#ifdef TD_SUPPORT_BITMAP
  tdSetBitmapValType(pCol->pBitmap, numOfRows, valType);
#endif
C
update  
Cary Xu 已提交
166 167 168
  return 0;
}

K
Kaili Xu 已提交
169 170
// internal
static int32_t tdAppendTpRowToDataCol(STSRow *pRow, STSchema *pSchema, SDataCols *pCols) {
C
Cary Xu 已提交
171
  ASSERT(pCols->numOfRows == 0 || dataColsKeyLast(pCols) < TD_ROW_KEY(pRow));
C
Cary Xu 已提交
172

K
Kaili Xu 已提交
173 174 175 176 177 178
  int   rcol = 1;
  int   dcol = 1;
  void *pBitmap = tdGetBitmapAddrTp(pRow, pSchema->flen);

  SDataCol *pDataCol = &(pCols->cols[0]);
  if (pDataCol->colId == PRIMARYKEY_TIMESTAMP_COL_ID) {
C
Cary Xu 已提交
179
    tdAppendValToDataCol(pDataCol, TD_VTYPE_NORM, &pRow->ts,  pCols->numOfRows, pCols->maxPoints);
K
Kaili Xu 已提交
180
  }
C
Cary Xu 已提交
181 182

  while (dcol < pCols->numOfCols) {
K
Kaili Xu 已提交
183
    pDataCol = &(pCols->cols[dcol]);
C
Cary Xu 已提交
184
    if (rcol >= schemaNCols(pSchema)) {
C
update  
Cary Xu 已提交
185
      tdAppendValToDataCol(pDataCol, TD_VTYPE_NULL, NULL, pCols->numOfRows, pCols->maxPoints);
K
Kaili Xu 已提交
186
      ++dcol;
C
Cary Xu 已提交
187 188 189 190
      continue;
    }

    STColumn *pRowCol = schemaColAt(pSchema, rcol);
C
update  
Cary Xu 已提交
191
    SCellVal  sVal = {0};
C
Cary Xu 已提交
192
    if (pRowCol->colId == pDataCol->colId) {
K
Kaili Xu 已提交
193 194
      if (tdGetTpRowValOfCol(&sVal, pRow, pBitmap, pRowCol->type, pRowCol->offset - sizeof(TSKEY), rcol - 1) < 0) {
        return terrno;
C
update  
Cary Xu 已提交
195
      }
K
Kaili Xu 已提交
196 197 198
      tdAppendValToDataCol(pDataCol, sVal.valType, sVal.val, pCols->numOfRows, pCols->maxPoints);
      ++dcol;
      ++rcol;
C
Cary Xu 已提交
199
    } else if (pRowCol->colId < pDataCol->colId) {
K
Kaili Xu 已提交
200
      ++rcol;
C
Cary Xu 已提交
201
    } else {
K
Kaili Xu 已提交
202 203
      tdAppendValToDataCol(pDataCol, TD_VTYPE_NULL, NULL, pCols->numOfRows, pCols->maxPoints);
      ++dcol;
C
Cary Xu 已提交
204 205
    }
  }
K
Kaili Xu 已提交
206
  ++pCols->numOfRows;
C
Cary Xu 已提交
207

K
Kaili Xu 已提交
208 209 210
  return TSDB_CODE_SUCCESS;
}
// internal
C
Cary Xu 已提交
211
static int32_t tdAppendKvRowToDataCol(STSRow *pRow, STSchema *pSchema, SDataCols *pCols) {
C
Cary Xu 已提交
212
  ASSERT(pCols->numOfRows == 0 || dataColsKeyLast(pCols) < TD_ROW_KEY(pRow));
C
Cary Xu 已提交
213

C
update  
Cary Xu 已提交
214
  int   rcol = 0;
K
Kaili Xu 已提交
215
  int   dcol = 1;
C
Cary Xu 已提交
216
  int   tRowCols = tdRowGetNCols(pRow) - 1;  // the primary TS key not included in kvRowColIdx part
K
Kaili Xu 已提交
217
  int   tSchemaCols = schemaNCols(pSchema) - 1;
C
Cary Xu 已提交
218
  void *pBitmap = tdGetBitmapAddrKv(pRow, tdRowGetNCols(pRow));
C
Cary Xu 已提交
219

K
Kaili Xu 已提交
220 221
  SDataCol *pDataCol = &(pCols->cols[0]);
  if (pDataCol->colId == PRIMARYKEY_TIMESTAMP_COL_ID) {
C
Cary Xu 已提交
222
    tdAppendValToDataCol(pDataCol, TD_VTYPE_NORM, &pRow->ts, pCols->numOfRows, pCols->maxPoints);
K
Kaili Xu 已提交
223 224
  }

C
Cary Xu 已提交
225
  while (dcol < pCols->numOfCols) {
K
Kaili Xu 已提交
226 227 228
    pDataCol = &(pCols->cols[dcol]);
    if (rcol >= tRowCols || rcol >= tSchemaCols) {
      tdAppendValToDataCol(pDataCol, TD_VTYPE_NULL, NULL, pCols->numOfRows, pCols->maxPoints);
C
Cary Xu 已提交
229 230 231 232
      ++dcol;
      continue;
    }

K
Kaili Xu 已提交
233 234 235 236 237 238 239
    SKvRowIdx *pIdx = tdKvRowColIdxAt(pRow, rcol);
    int16_t    colIdx = -1;
    if (pIdx) {
      colIdx = POINTER_DISTANCE(pRow->data, pIdx) / sizeof(SKvRowIdx);
    }
    SCellVal sVal = {0};
    if (pIdx->colId == pDataCol->colId) {
C
Cary Xu 已提交
240
      if (tdGetKvRowValOfCol(&sVal, pRow, pBitmap, pIdx->offset, colIdx) < 0) {
K
Kaili Xu 已提交
241 242 243
        return terrno;
      }
      tdAppendValToDataCol(pDataCol, sVal.valType, sVal.val, pCols->numOfRows, pCols->maxPoints);
C
Cary Xu 已提交
244 245
      ++dcol;
      ++rcol;
K
Kaili Xu 已提交
246
    } else if (pIdx->colId < pDataCol->colId) {
C
Cary Xu 已提交
247 248
      ++rcol;
    } else {
K
Kaili Xu 已提交
249
      tdAppendValToDataCol(pDataCol, TD_VTYPE_NULL, NULL, pCols->numOfRows, pCols->maxPoints);
C
Cary Xu 已提交
250 251 252
      ++dcol;
    }
  }
K
Kaili Xu 已提交
253 254 255
  ++pCols->numOfRows;

  return TSDB_CODE_SUCCESS;
C
Cary Xu 已提交
256 257
}

C
update  
Cary Xu 已提交
258
/**
K
Kaili Xu 已提交
259 260 261 262 263 264
 * @brief exposed
 *
 * @param pRow
 * @param pSchema
 * @param pCols
 * @param forceSetNull
C
update  
Cary Xu 已提交
265
 */
C
Cary Xu 已提交
266
int32_t tdAppendSTSRowToDataCol(STSRow *pRow, STSchema *pSchema, SDataCols *pCols, bool forceSetNull) {
C
Cary Xu 已提交
267
  if (TD_IS_TP_ROW(pRow)) {
C
Cary Xu 已提交
268
    return tdAppendTpRowToDataCol(pRow, pSchema, pCols);
C
Cary Xu 已提交
269
  } else if (TD_IS_KV_ROW(pRow)) {
C
Cary Xu 已提交
270
    return tdAppendKvRowToDataCol(pRow, pSchema, pCols);
C
Cary Xu 已提交
271 272 273
  } else {
    ASSERT(0);
  }
C
Cary Xu 已提交
274
  return TSDB_CODE_SUCCESS;
C
Cary Xu 已提交
275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292
}

int tdMergeDataCols(SDataCols *target, SDataCols *source, int rowsToMerge, int *pOffset, bool forceSetNull) {
  ASSERT(rowsToMerge > 0 && rowsToMerge <= source->numOfRows);
  ASSERT(target->numOfCols == source->numOfCols);
  int offset = 0;

  if (pOffset == NULL) {
    pOffset = &offset;
  }

  SDataCols *pTarget = NULL;

  if ((target->numOfRows == 0) || (dataColsKeyLast(target) < dataColsKeyAtRow(source, *pOffset))) {  // No overlap
    ASSERT(target->numOfRows + rowsToMerge <= target->maxPoints);
    for (int i = 0; i < rowsToMerge; i++) {
      for (int j = 0; j < source->numOfCols; j++) {
        if (source->cols[j].len > 0 || target->cols[j].len > 0) {
C
Cary Xu 已提交
293 294 295 296 297
          SCellVal sVal = {0};
          if (tdGetColDataOfRow(&sVal, source->cols + j, i + (*pOffset)) < 0) {
            TASSERT(0);
          }
          tdAppendValToDataCol(target->cols + j, sVal.valType, sVal.val, target->numOfRows, target->maxPoints);
C
Cary Xu 已提交
298 299
        }
      }
C
Cary Xu 已提交
300
      ++target->numOfRows;
C
Cary Xu 已提交
301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331
    }
    (*pOffset) += rowsToMerge;
  } else {
    pTarget = tdDupDataCols(target, true);
    if (pTarget == NULL) goto _err;

    int iter1 = 0;
    tdMergeTwoDataCols(target, pTarget, &iter1, pTarget->numOfRows, source, pOffset, source->numOfRows,
                       pTarget->numOfRows + rowsToMerge, forceSetNull);
  }

  tdFreeDataCols(pTarget);
  return 0;

_err:
  tdFreeDataCols(pTarget);
  return -1;
}

// src2 data has more priority than src1
static void tdMergeTwoDataCols(SDataCols *target, SDataCols *src1, int *iter1, int limit1, SDataCols *src2, int *iter2,
                               int limit2, int tRows, bool forceSetNull) {
  tdResetDataCols(target);
  ASSERT(limit1 <= src1->numOfRows && limit2 <= src2->numOfRows);

  while (target->numOfRows < tRows) {
    if (*iter1 >= limit1 && *iter2 >= limit2) break;

    TSKEY key1 = (*iter1 >= limit1) ? INT64_MAX : dataColsKeyAt(src1, *iter1);
    TKEY  tkey1 = (*iter1 >= limit1) ? TKEY_NULL : dataColsTKeyAt(src1, *iter1);
    TSKEY key2 = (*iter2 >= limit2) ? INT64_MAX : dataColsKeyAt(src2, *iter2);
C
Cary Xu 已提交
332
    // TKEY  tkey2 = (*iter2 >= limit2) ? TKEY_NULL : dataColsTKeyAt(src2, *iter2);
C
Cary Xu 已提交
333 334 335 336 337 338 339

    ASSERT(tkey1 == TKEY_NULL || (!TKEY_IS_DELETED(tkey1)));

    if (key1 < key2) {
      for (int i = 0; i < src1->numOfCols; i++) {
        ASSERT(target->cols[i].type == src1->cols[i].type);
        if (src1->cols[i].len > 0 || target->cols[i].len > 0) {
C
Cary Xu 已提交
340 341 342 343 344
          SCellVal sVal = {0};
          if (tdGetColDataOfRow(&sVal, src1->cols + i, *iter1) < 0) {
            TASSERT(0);
          }
          tdAppendValToDataCol(&(target->cols[i]), sVal.valType, sVal.val, target->numOfRows, target->maxPoints);
C
Cary Xu 已提交
345 346 347 348 349 350
        }
      }

      target->numOfRows++;
      (*iter1)++;
    } else if (key1 >= key2) {
C
Cary Xu 已提交
351 352
      // if ((key1 > key2) || (key1 == key2 && !TKEY_IS_DELETED(tkey2))) {
      if ((key1 > key2) || (key1 == key2)) {
C
Cary Xu 已提交
353
        for (int i = 0; i < src2->numOfCols; i++) {
C
Cary Xu 已提交
354
          SCellVal sVal = {0};
C
Cary Xu 已提交
355
          ASSERT(target->cols[i].type == src2->cols[i].type);
C
Cary Xu 已提交
356 357 358 359
          if (tdGetColDataOfRow(&sVal, src2->cols + i, *iter2) < 0) {
            TASSERT(0);
          }
          if (src2->cols[i].len > 0 && !tdValTypeIsNull(sVal.valType)) {
C
Cary Xu 已提交
360 361 362 363 364 365 366 367
            tdAppendValToDataCol(&(target->cols[i]), sVal.valType, sVal.val, target->numOfRows, target->maxPoints);
          } else if (!forceSetNull && key1 == key2 && src1->cols[i].len > 0) {
            if (tdGetColDataOfRow(&sVal, src1->cols + i, *iter1) < 0) {
              TASSERT(0);
            }
            tdAppendValToDataCol(&(target->cols[i]), sVal.valType, sVal.val, target->numOfRows, target->maxPoints);
          } else if (target->cols[i].len > 0) {
            dataColSetNullAt(&target->cols[i], target->numOfRows, true);
C
Cary Xu 已提交
368 369 370 371 372 373 374 375 376 377 378 379 380 381 382
          }
        }
        target->numOfRows++;
      }

      (*iter2)++;
      if (key1 == key2) (*iter1)++;
    }

    ASSERT(target->numOfRows <= target->maxPoints);
  }
}



C
Cary Xu 已提交
383
STSRow* mergeTwoRows(void *buffer, STSRow* row1, STSRow *row2, STSchema *pSchema1, STSchema *pSchema2) {
C
Cary Xu 已提交
384
#if 0
C
Cary Xu 已提交
385 386 387
  ASSERT(TD_ROW_KEY(row1) == TD_ROW_KEY(row2));
  ASSERT(schemaVersion(pSchema1) == TD_ROW_SVER(row1));
  ASSERT(schemaVersion(pSchema2) == TD_ROW_SVER(row2));
C
Cary Xu 已提交
388 389 390
  ASSERT(schemaVersion(pSchema1) >= schemaVersion(pSchema2));
#endif

C
Cary Xu 已提交
391
#if 0
C
Cary Xu 已提交
392 393 394 395 396
  SArray *stashRow = taosArrayInit(pSchema1->numOfCols, sizeof(SColInfo));
  if (stashRow == NULL) {
    return NULL;
  }

C
Cary Xu 已提交
397 398
  STSRow  pRow = buffer;
  STpRow dataRow = memRowDataBody(pRow);
C
Cary Xu 已提交
399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451
  memRowSetType(pRow, SMEM_ROW_DATA);
  dataRowSetVersion(dataRow, schemaVersion(pSchema1));  // use latest schema version
  dataRowSetLen(dataRow, (TDRowLenT)(TD_DATA_ROW_HEAD_SIZE + pSchema1->flen));

  TDRowLenT dataLen = 0, kvLen = TD_MEM_ROW_KV_HEAD_SIZE;

  int32_t  i = 0;  // row1
  int32_t  j = 0;  // row2
  int32_t  nCols1 = schemaNCols(pSchema1);
  int32_t  nCols2 = schemaNCols(pSchema2);
  SColInfo colInfo = {0};
  int32_t  kvIdx1 = 0, kvIdx2 = 0;

  while (i < nCols1) {
    STColumn *pCol = schemaColAt(pSchema1, i);
    void *    val1 = tdGetMemRowDataOfColEx(row1, pCol->colId, pCol->type, TD_DATA_ROW_HEAD_SIZE + pCol->offset, &kvIdx1);
    // if val1 != NULL, use val1;
    if (val1 != NULL && !isNull(val1, pCol->type)) {
      tdAppendColVal(dataRow, val1, pCol->type, pCol->offset);
      kvLen += tdGetColAppendLen(SMEM_ROW_KV, val1, pCol->type);
      setSColInfo(&colInfo, pCol->colId, pCol->type, val1);
      taosArrayPush(stashRow, &colInfo);
      ++i;  // next col
      continue;
    }

    void *val2 = NULL;
    while (j < nCols2) {
      STColumn *tCol = schemaColAt(pSchema2, j);
      if (tCol->colId < pCol->colId) {
        ++j;
        continue;
      }
      if (tCol->colId == pCol->colId) {
        val2 = tdGetMemRowDataOfColEx(row2, tCol->colId, tCol->type, TD_DATA_ROW_HEAD_SIZE + tCol->offset, &kvIdx2);
      } else if (tCol->colId > pCol->colId) {
        // set NULL
      }
      break;
    }  // end of while(j<nCols2)
    if (val2 == NULL) {
      val2 = (void *)getNullValue(pCol->type);
    }
    tdAppendColVal(dataRow, val2, pCol->type, pCol->offset);
    if (!isNull(val2, pCol->type)) {
      kvLen += tdGetColAppendLen(SMEM_ROW_KV, val2, pCol->type);
      setSColInfo(&colInfo, pCol->colId, pCol->type, val2);
      taosArrayPush(stashRow, &colInfo);
    }

    ++i;  // next col
  }

C
Cary Xu 已提交
452
  dataLen = TD_ROW_LEN(pRow);
C
Cary Xu 已提交
453 454 455 456

  if (kvLen < dataLen) {
    // scan stashRow and generate SKVRow
    memset(buffer, 0, sizeof(dataLen));
C
Cary Xu 已提交
457
    STSRow tRow = buffer;
C
Cary Xu 已提交
458 459 460 461 462 463 464 465 466 467 468 469 470 471
    memRowSetType(tRow, SMEM_ROW_KV);
    SKVRow kvRow = (SKVRow)memRowKvBody(tRow);
    int16_t nKvNCols = (int16_t) taosArrayGetSize(stashRow);
    kvRowSetLen(kvRow, (TDRowLenT)(TD_KV_ROW_HEAD_SIZE + sizeof(SColIdx) * nKvNCols));
    kvRowSetNCols(kvRow, nKvNCols);
    memRowSetKvVersion(tRow, pSchema1->version);

    int32_t toffset = 0;
    int16_t k;
    for (k = 0; k < nKvNCols; ++k) {
      SColInfo *pColInfo = taosArrayGet(stashRow, k);
      tdAppendKvColVal(kvRow, pColInfo->colVal, true, pColInfo->colId, pColInfo->colType, toffset);
      toffset += sizeof(SColIdx);
    }
C
Cary Xu 已提交
472
    ASSERT(kvLen == TD_ROW_LEN(tRow));
C
Cary Xu 已提交
473 474 475
  }
  taosArrayDestroy(stashRow);
  return buffer;
C
Cary Xu 已提交
476 477
  #endif
  return NULL;
C
Cary Xu 已提交
478
}