homework-jianmu/source/common/src/tdataformat.c

3599 lines
113 KiB
C

/*
* 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
#include "tdataformat.h"
#include "tRealloc.h"
#include "tcoding.h"
#include "tdatablock.h"
#include "tlog.h"
static int32_t (*tColDataAppendValueImpl[8][3])(SColData *pColData, uint8_t *pData, uint32_t nData);
static int32_t (*tColDataUpdateValueImpl[8][3])(SColData *pColData, uint8_t *pData, uint32_t nData, bool forward);
// SBuffer ================================
void tBufferDestroy(SBuffer *pBuffer) {
tFree(pBuffer->pBuf);
pBuffer->pBuf = NULL;
}
int32_t tBufferInit(SBuffer *pBuffer, int64_t size) {
pBuffer->nBuf = 0;
return tRealloc(&pBuffer->pBuf, size);
}
int32_t tBufferPut(SBuffer *pBuffer, const void *pData, int64_t nData) {
int32_t code = 0;
code = tRealloc(&pBuffer->pBuf, pBuffer->nBuf + nData);
if (code) return code;
memcpy(pBuffer->pBuf + pBuffer->nBuf, pData, nData);
pBuffer->nBuf += nData;
return code;
}
int32_t tBufferReserve(SBuffer *pBuffer, int64_t nData, void **ppData) {
int32_t code = tRealloc(&pBuffer->pBuf, pBuffer->nBuf + nData);
if (code) return code;
*ppData = pBuffer->pBuf + pBuffer->nBuf;
pBuffer->nBuf += nData;
return code;
}
// ================================
static int32_t tGetTagVal(uint8_t *p, STagVal *pTagVal, int8_t isJson);
// SRow ========================================================================
#define KV_FLG_LIT ((uint8_t)0x10)
#define KV_FLG_MID ((uint8_t)0x20)
#define KV_FLG_BIG ((uint8_t)0x30)
#define BIT_FLG_NONE ((uint8_t)0x0)
#define BIT_FLG_NULL ((uint8_t)0x1)
#define BIT_FLG_VALUE ((uint8_t)0x2)
#pragma pack(push, 1)
typedef struct {
int16_t nCol;
char idx[]; // uint8_t * | uint16_t * | uint32_t *
} SKVIdx;
#pragma pack(pop)
#define ROW_SET_BITMAP(PB, FLAG, IDX, VAL) \
do { \
if (PB) { \
switch (FLAG) { \
case (HAS_NULL | HAS_NONE): \
SET_BIT1(PB, IDX, VAL); \
break; \
case (HAS_VALUE | HAS_NONE): \
SET_BIT1(PB, IDX, (VAL) ? (VAL)-1 : 0); \
break; \
case (HAS_VALUE | HAS_NULL): \
SET_BIT1(PB, IDX, (VAL)-1); \
break; \
case (HAS_VALUE | HAS_NULL | HAS_NONE): \
SET_BIT2(PB, IDX, VAL); \
break; \
default: \
ASSERT(0); \
break; \
} \
} \
} while (0)
int32_t tRowBuild(SArray *aColVal, const STSchema *pTSchema, SRow **ppRow) {
int32_t code = 0;
ASSERT(TARRAY_SIZE(aColVal) > 0);
ASSERT(((SColVal *)aColVal->pData)[0].cid == PRIMARYKEY_TIMESTAMP_COL_ID);
ASSERT(((SColVal *)aColVal->pData)[0].type == TSDB_DATA_TYPE_TIMESTAMP);
// scan ---------------
SRow *pRow = NULL;
SColVal *colVals = (SColVal *)TARRAY_DATA(aColVal);
uint8_t flag = 0;
int32_t iColVal = 1;
const int32_t nColVal = TARRAY_SIZE(aColVal);
SColVal *pColVal = (iColVal < nColVal) ? &colVals[iColVal] : NULL;
int32_t iTColumn = 1;
const STColumn *pTColumn = pTSchema->columns + iTColumn;
int32_t ntp = 0;
int32_t nkv = 0;
int32_t maxIdx = 0;
int32_t nIdx = 0;
while (pTColumn) {
if (pColVal) {
if (pColVal->cid == pTColumn->colId) {
if (COL_VAL_IS_VALUE(pColVal)) { // VALUE
flag |= HAS_VALUE;
maxIdx = nkv;
if (IS_VAR_DATA_TYPE(pTColumn->type)) {
ntp = ntp + tPutU32v(NULL, pColVal->value.nData) + pColVal->value.nData;
nkv = nkv + tPutI16v(NULL, pTColumn->colId) + tPutU32v(NULL, pColVal->value.nData) + pColVal->value.nData;
} else {
nkv = nkv + tPutI16v(NULL, pTColumn->colId) + pTColumn->bytes;
}
nIdx++;
} else if (COL_VAL_IS_NONE(pColVal)) { // NONE
flag |= HAS_NONE;
} else if (COL_VAL_IS_NULL(pColVal)) { // NULL
flag |= HAS_NULL;
maxIdx = nkv;
nkv += tPutI16v(NULL, -pTColumn->colId);
nIdx++;
} else {
if (ASSERTS(0, "invalid input")) {
code = TSDB_CODE_INVALID_PARA;
goto _exit;
}
}
pTColumn = (++iTColumn < pTSchema->numOfCols) ? pTSchema->columns + iTColumn : NULL;
pColVal = (++iColVal < nColVal) ? &colVals[iColVal] : NULL;
} else if (pColVal->cid > pTColumn->colId) { // NONE
flag |= HAS_NONE;
pTColumn = (++iTColumn < pTSchema->numOfCols) ? pTSchema->columns + iTColumn : NULL;
} else {
pColVal = (++iColVal < nColVal) ? &colVals[iColVal] : NULL;
}
} else { // NONE
flag |= HAS_NONE;
pTColumn = (++iTColumn < pTSchema->numOfCols) ? pTSchema->columns + iTColumn : NULL;
}
}
// compare ---------------
switch (flag) {
case HAS_NONE:
case HAS_NULL:
ntp = sizeof(SRow);
break;
case HAS_VALUE:
ntp = sizeof(SRow) + pTSchema->flen + ntp;
break;
case (HAS_NULL | HAS_NONE):
ntp = sizeof(SRow) + BIT1_SIZE(pTSchema->numOfCols - 1);
break;
case (HAS_VALUE | HAS_NONE):
case (HAS_VALUE | HAS_NULL):
ntp = sizeof(SRow) + BIT1_SIZE(pTSchema->numOfCols - 1) + pTSchema->flen + ntp;
break;
case (HAS_VALUE | HAS_NULL | HAS_NONE):
ntp = sizeof(SRow) + BIT2_SIZE(pTSchema->numOfCols - 1) + pTSchema->flen + ntp;
break;
default:
if (ASSERTS(0, "impossible")) {
code = TSDB_CODE_INVALID_PARA;
goto _exit;
}
}
if (maxIdx <= UINT8_MAX) {
nkv = sizeof(SRow) + sizeof(SKVIdx) + nIdx + nkv;
flag |= KV_FLG_LIT;
} else if (maxIdx <= UINT16_MAX) {
nkv = sizeof(SRow) + sizeof(SKVIdx) + (nIdx << 1) + nkv;
flag |= KV_FLG_MID;
} else {
nkv = sizeof(SRow) + sizeof(SKVIdx) + (nIdx << 2) + nkv;
flag |= KV_FLG_BIG;
}
int32_t nRow;
if (nkv < ntp) {
nRow = nkv;
} else {
nRow = ntp;
flag &= ((uint8_t)0x0f);
}
// alloc --------------
pRow = taosMemoryMalloc(nRow);
if (NULL == pRow) {
code = TSDB_CODE_OUT_OF_MEMORY;
goto _exit;
}
// build --------------
pColVal = &colVals[0];
pRow->flag = flag;
pRow->rsv = 0;
pRow->sver = pTSchema->version;
pRow->len = nRow;
memcpy(&pRow->ts, &pColVal->value.val, sizeof(TSKEY));
if (flag == HAS_NONE || flag == HAS_NULL) {
goto _exit;
}
iColVal = 1;
pColVal = (iColVal < nColVal) ? &colVals[iColVal] : NULL;
iTColumn = 1;
pTColumn = pTSchema->columns + iTColumn;
if (flag >> 4) { // KV
SKVIdx *pIdx = (SKVIdx *)pRow->data;
int32_t iIdx = 0;
int32_t nv = 0;
uint8_t *pv = NULL;
if (flag & KV_FLG_LIT) {
pv = pIdx->idx + nIdx;
} else if (flag & KV_FLG_MID) {
pv = pIdx->idx + (nIdx << 1);
} else {
pv = pIdx->idx + (nIdx << 2);
}
pIdx->nCol = nIdx;
while (pTColumn) {
if (pColVal) {
if (pColVal->cid == pTColumn->colId) {
if (COL_VAL_IS_VALUE(pColVal)) {
if (flag & KV_FLG_LIT) {
((uint8_t *)pIdx->idx)[iIdx] = (uint8_t)nv;
} else if (flag & KV_FLG_MID) {
((uint16_t *)pIdx->idx)[iIdx] = (uint16_t)nv;
} else {
((uint32_t *)pIdx->idx)[iIdx] = (uint32_t)nv;
}
iIdx++;
nv += tPutI16v(pv + nv, pTColumn->colId);
if (IS_VAR_DATA_TYPE(pTColumn->type)) {
nv += tPutU32v(pv + nv, pColVal->value.nData);
memcpy(pv + nv, pColVal->value.pData, pColVal->value.nData);
nv += pColVal->value.nData;
} else {
memcpy(pv + nv, &pColVal->value.val, pTColumn->bytes);
nv += pTColumn->bytes;
}
} else if (COL_VAL_IS_NULL(pColVal)) {
if (flag & KV_FLG_LIT) {
((uint8_t *)pIdx->idx)[iIdx] = (uint8_t)nv;
} else if (flag & KV_FLG_MID) {
((uint16_t *)pIdx->idx)[iIdx] = (uint16_t)nv;
} else {
((uint32_t *)pIdx->idx)[iIdx] = (uint32_t)nv;
}
iIdx++;
nv += tPutI16v(pv + nv, -pTColumn->colId);
}
pTColumn = (++iTColumn < pTSchema->numOfCols) ? pTSchema->columns + iTColumn : NULL;
pColVal = (++iColVal < nColVal) ? &colVals[iColVal] : NULL;
} else if (pColVal->cid > pTColumn->colId) { // NONE
pTColumn = (++iTColumn < pTSchema->numOfCols) ? pTSchema->columns + iTColumn : NULL;
} else {
pColVal = (++iColVal < nColVal) ? &colVals[iColVal] : NULL;
}
} else { // NONE
pTColumn = (++iTColumn < pTSchema->numOfCols) ? pTSchema->columns + iTColumn : NULL;
}
}
} else { // TUPLE
uint8_t *pb = NULL;
uint8_t *pf = NULL;
uint8_t *pv = NULL;
int32_t nv = 0;
switch (flag) {
case (HAS_NULL | HAS_NONE):
pb = pRow->data;
break;
case HAS_VALUE:
pf = pRow->data;
pv = pf + pTSchema->flen;
break;
case (HAS_VALUE | HAS_NONE):
case (HAS_VALUE | HAS_NULL):
pb = pRow->data;
pf = pb + BIT1_SIZE(pTSchema->numOfCols - 1);
pv = pf + pTSchema->flen;
break;
case (HAS_VALUE | HAS_NULL | HAS_NONE):
pb = pRow->data;
pf = pb + BIT2_SIZE(pTSchema->numOfCols - 1);
pv = pf + pTSchema->flen;
break;
default:
if (ASSERTS(0, "impossible")) {
code = TSDB_CODE_INVALID_PARA;
goto _exit;
}
}
if (pb) {
if (flag == (HAS_VALUE | HAS_NULL | HAS_NONE)) {
memset(pb, 0, BIT2_SIZE(pTSchema->numOfCols - 1));
} else {
memset(pb, 0, BIT1_SIZE(pTSchema->numOfCols - 1));
}
}
// build impl
while (pTColumn) {
if (pColVal) {
if (pColVal->cid == pTColumn->colId) {
if (COL_VAL_IS_VALUE(pColVal)) { // VALUE
ROW_SET_BITMAP(pb, flag, iTColumn - 1, BIT_FLG_VALUE);
if (IS_VAR_DATA_TYPE(pTColumn->type)) {
*(int32_t *)(pf + pTColumn->offset) = nv;
nv += tPutU32v(pv + nv, pColVal->value.nData);
if (pColVal->value.nData) {
memcpy(pv + nv, pColVal->value.pData, pColVal->value.nData);
nv += pColVal->value.nData;
}
} else {
memcpy(pf + pTColumn->offset, &pColVal->value.val, TYPE_BYTES[pTColumn->type]);
}
} else if (COL_VAL_IS_NONE(pColVal)) { // NONE
ROW_SET_BITMAP(pb, flag, iTColumn - 1, BIT_FLG_NONE);
if (pf) memset(pf + pTColumn->offset, 0, TYPE_BYTES[pTColumn->type]);
} else { // NULL
ROW_SET_BITMAP(pb, flag, iTColumn - 1, BIT_FLG_NULL);
if (pf) memset(pf + pTColumn->offset, 0, TYPE_BYTES[pTColumn->type]);
}
pTColumn = (++iTColumn < pTSchema->numOfCols) ? pTSchema->columns + iTColumn : NULL;
pColVal = (++iColVal < nColVal) ? &colVals[iColVal] : NULL;
} else if (pColVal->cid > pTColumn->colId) { // NONE
ROW_SET_BITMAP(pb, flag, iTColumn - 1, BIT_FLG_NONE);
if (pf) memset(pf + pTColumn->offset, 0, TYPE_BYTES[pTColumn->type]);
pTColumn = (++iTColumn < pTSchema->numOfCols) ? pTSchema->columns + iTColumn : NULL;
} else {
pColVal = (++iColVal < nColVal) ? &colVals[iColVal] : NULL;
}
} else { // NONE
ROW_SET_BITMAP(pb, flag, iTColumn - 1, BIT_FLG_NONE);
if (pf) memset(pf + pTColumn->offset, 0, TYPE_BYTES[pTColumn->type]);
pTColumn = (++iTColumn < pTSchema->numOfCols) ? pTSchema->columns + iTColumn : NULL;
}
}
}
_exit:
if (code) {
*ppRow = NULL;
tRowDestroy(pRow);
} else {
*ppRow = pRow;
}
return code;
}
int32_t tRowGet(SRow *pRow, STSchema *pTSchema, int32_t iCol, SColVal *pColVal) {
ASSERT(iCol < pTSchema->numOfCols);
ASSERT(pRow->sver == pTSchema->version);
STColumn *pTColumn = pTSchema->columns + iCol;
if (iCol == 0) {
pColVal->cid = pTColumn->colId;
pColVal->type = pTColumn->type;
pColVal->flag = CV_FLAG_VALUE;
memcpy(&pColVal->value.val, &pRow->ts, sizeof(TSKEY));
return 0;
}
if (pRow->flag == HAS_NONE) {
*pColVal = COL_VAL_NONE(pTColumn->colId, pTColumn->type);
return 0;
}
if (pRow->flag == HAS_NULL) {
*pColVal = COL_VAL_NULL(pTColumn->colId, pTColumn->type);
return 0;
}
if (pRow->flag >> 4) { // KV Row
SKVIdx *pIdx = (SKVIdx *)pRow->data;
uint8_t *pv = NULL;
if (pRow->flag & KV_FLG_LIT) {
pv = pIdx->idx + pIdx->nCol;
} else if (pRow->flag & KV_FLG_MID) {
pv = pIdx->idx + (pIdx->nCol << 1);
} else {
pv = pIdx->idx + (pIdx->nCol << 2);
}
int16_t lidx = 0;
int16_t ridx = pIdx->nCol - 1;
while (lidx <= ridx) {
int16_t mid = (lidx + ridx) >> 1;
uint8_t *pData = NULL;
if (pRow->flag & KV_FLG_LIT) {
pData = pv + ((uint8_t *)pIdx->idx)[mid];
} else if (pRow->flag & KV_FLG_MID) {
pData = pv + ((uint16_t *)pIdx->idx)[mid];
} else {
pData = pv + ((uint32_t *)pIdx->idx)[mid];
}
int16_t cid;
pData += tGetI16v(pData, &cid);
if (TABS(cid) == pTColumn->colId) {
if (cid < 0) {
*pColVal = COL_VAL_NULL(pTColumn->colId, pTColumn->type);
} else {
pColVal->cid = pTColumn->colId;
pColVal->type = pTColumn->type;
pColVal->flag = CV_FLAG_VALUE;
if (IS_VAR_DATA_TYPE(pTColumn->type)) {
pData += tGetU32v(pData, &pColVal->value.nData);
if (pColVal->value.nData > 0) {
pColVal->value.pData = pData;
} else {
pColVal->value.pData = NULL;
}
} else {
memcpy(&pColVal->value.val, pData, pTColumn->bytes);
}
}
return 0;
} else if (TABS(cid) < pTColumn->colId) {
lidx = mid + 1;
} else {
ridx = mid - 1;
}
}
*pColVal = COL_VAL_NONE(pTColumn->colId, pTColumn->type);
} else { // Tuple Row
if (pRow->flag == HAS_VALUE) {
pColVal->cid = pTColumn->colId;
pColVal->type = pTColumn->type;
pColVal->flag = CV_FLAG_VALUE;
if (IS_VAR_DATA_TYPE(pTColumn->type)) {
uint8_t *pData = pRow->data + pTSchema->flen + *(int32_t *)(pRow->data + pTColumn->offset);
pData += tGetU32v(pData, &pColVal->value.nData);
if (pColVal->value.nData) {
pColVal->value.pData = pData;
} else {
pColVal->value.pData = NULL;
}
} else {
memcpy(&pColVal->value.val, pRow->data + pTColumn->offset, TYPE_BYTES[pTColumn->type]);
}
} else {
uint8_t *pf;
uint8_t *pv;
uint8_t bv = BIT_FLG_VALUE;
switch (pRow->flag) {
case (HAS_NULL | HAS_NONE):
bv = GET_BIT1(pRow->data, iCol - 1);
break;
case (HAS_VALUE | HAS_NONE):
bv = GET_BIT1(pRow->data, iCol - 1);
if (bv) bv++;
pf = pRow->data + BIT1_SIZE(pTSchema->numOfCols - 1);
pv = pf + pTSchema->flen;
break;
case (HAS_VALUE | HAS_NULL):
bv = GET_BIT1(pRow->data, iCol - 1);
bv++;
pf = pRow->data + BIT1_SIZE(pTSchema->numOfCols - 1);
pv = pf + pTSchema->flen;
break;
case (HAS_VALUE | HAS_NULL | HAS_NONE):
bv = GET_BIT2(pRow->data, iCol - 1);
pf = pRow->data + BIT2_SIZE(pTSchema->numOfCols - 1);
pv = pf + pTSchema->flen;
break;
default:
ASSERTS(0, "invalid row format");
return TSDB_CODE_INVALID_DATA_FMT;
}
if (bv == BIT_FLG_NONE) {
*pColVal = COL_VAL_NONE(pTColumn->colId, pTColumn->type);
return 0;
} else if (bv == BIT_FLG_NULL) {
*pColVal = COL_VAL_NULL(pTColumn->colId, pTColumn->type);
return 0;
}
pColVal->cid = pTColumn->colId;
pColVal->type = pTColumn->type;
pColVal->flag = CV_FLAG_VALUE;
if (IS_VAR_DATA_TYPE(pTColumn->type)) {
uint8_t *pData = pv + *(int32_t *)(pf + pTColumn->offset);
pData += tGetU32v(pData, &pColVal->value.nData);
if (pColVal->value.nData) {
pColVal->value.pData = pData;
} else {
pColVal->value.pData = NULL;
}
} else {
memcpy(&pColVal->value.val, pf + pTColumn->offset, TYPE_BYTES[pTColumn->type]);
}
}
}
return 0;
}
void tRowDestroy(SRow *pRow) {
if (pRow) taosMemoryFree(pRow);
}
static int32_t tRowPCmprFn(const void *p1, const void *p2) {
if ((*(SRow **)p1)->ts < (*(SRow **)p2)->ts) {
return -1;
} else if ((*(SRow **)p1)->ts > (*(SRow **)p2)->ts) {
return 1;
}
return 0;
}
static void tRowPDestroy(SRow **ppRow) { tRowDestroy(*ppRow); }
static int32_t tRowMergeImpl(SArray *aRowP, STSchema *pTSchema, int32_t iStart, int32_t iEnd, int8_t flag) {
int32_t code = 0;
int32_t nRow = iEnd - iStart;
SRowIter **aIter = NULL;
SArray *aColVal = NULL;
SRow *pRow = NULL;
aIter = taosMemoryCalloc(nRow, sizeof(SRowIter *));
if (aIter == NULL) {
code = TSDB_CODE_OUT_OF_MEMORY;
goto _exit;
}
for (int32_t i = 0; i < nRow; i++) {
SRow *pRowT = taosArrayGetP(aRowP, iStart + i);
code = tRowIterOpen(pRowT, pTSchema, &aIter[i]);
if (code) goto _exit;
}
// merge
aColVal = taosArrayInit(pTSchema->numOfCols, sizeof(SColVal));
if (aColVal == NULL) {
code = TSDB_CODE_OUT_OF_MEMORY;
goto _exit;
}
for (int32_t iCol = 0; iCol < pTSchema->numOfCols; iCol++) {
SColVal *pColVal = NULL;
for (int32_t iRow = 0; iRow < nRow; iRow++) {
SColVal *pColValT = tRowIterNext(aIter[iRow]);
// todo: take strategy according to the flag
if (COL_VAL_IS_VALUE(pColValT)) {
pColVal = pColValT;
} else if (COL_VAL_IS_NULL(pColValT)) {
if (pColVal == NULL) {
pColVal = pColValT;
}
}
}
if (pColVal) taosArrayPush(aColVal, pColVal);
}
// build
code = tRowBuild(aColVal, pTSchema, &pRow);
if (code) goto _exit;
taosArrayRemoveBatch(aRowP, iStart, nRow, (FDelete)tRowPDestroy);
taosArrayInsert(aRowP, iStart, &pRow);
_exit:
if (aIter) {
for (int32_t i = 0; i < nRow; i++) {
tRowIterClose(&aIter[i]);
}
taosMemoryFree(aIter);
}
if (aColVal) taosArrayDestroy(aColVal);
if (code) tRowDestroy(pRow);
return code;
}
int32_t tRowSort(SArray *aRowP) {
if (TARRAY_SIZE(aRowP) <= 1) return 0;
int32_t code = taosArrayMSort(aRowP, tRowPCmprFn);
if (code != TSDB_CODE_SUCCESS) {
uError("taosArrayMSort failed caused by %d", code);
}
return code;
}
int32_t tRowMerge(SArray *aRowP, STSchema *pTSchema, int8_t flag) {
int32_t code = 0;
int32_t iStart = 0;
while (iStart < aRowP->size) {
SRow *pRow = (SRow *)taosArrayGetP(aRowP, iStart);
int32_t iEnd = iStart + 1;
while (iEnd < aRowP->size) {
SRow *pRowT = (SRow *)taosArrayGetP(aRowP, iEnd);
if (pRow->ts != pRowT->ts) break;
iEnd++;
}
if (iEnd - iStart > 1) {
code = tRowMergeImpl(aRowP, pTSchema, iStart, iEnd, flag);
if (code) return code;
}
// the array is also changing, so the iStart just ++ instead of iEnd
iStart++;
}
return code;
}
// SRowIter ========================================
struct SRowIter {
SRow *pRow;
STSchema *pTSchema;
int32_t iTColumn;
union {
struct { // kv
int32_t iCol;
SKVIdx *pIdx;
};
struct { // tuple
uint8_t *pb;
uint8_t *pf;
};
};
uint8_t *pv;
SColVal cv;
};
int32_t tRowIterOpen(SRow *pRow, STSchema *pTSchema, SRowIter **ppIter) {
ASSERT(pRow->sver == pTSchema->version);
int32_t code = 0;
SRowIter *pIter = taosMemoryCalloc(1, sizeof(*pIter));
if (pIter == NULL) {
code = TSDB_CODE_OUT_OF_MEMORY;
goto _exit;
}
pIter->pRow = pRow;
pIter->pTSchema = pTSchema;
pIter->iTColumn = 0;
if (pRow->flag == HAS_NONE || pRow->flag == HAS_NULL) goto _exit;
if (pRow->flag >> 4) {
pIter->iCol = 0;
pIter->pIdx = (SKVIdx *)pRow->data;
if (pRow->flag & KV_FLG_LIT) {
pIter->pv = pIter->pIdx->idx + pIter->pIdx->nCol;
} else if (pRow->flag & KV_FLG_MID) {
pIter->pv = pIter->pIdx->idx + (pIter->pIdx->nCol << 1); // * sizeof(uint16_t)
} else {
pIter->pv = pIter->pIdx->idx + (pIter->pIdx->nCol << 2); // * sizeof(uint32_t)
}
} else {
switch (pRow->flag) {
case (HAS_NULL | HAS_NONE):
pIter->pb = pRow->data;
break;
case HAS_VALUE:
pIter->pf = pRow->data;
pIter->pv = pIter->pf + pTSchema->flen;
break;
case (HAS_VALUE | HAS_NONE):
case (HAS_VALUE | HAS_NULL):
pIter->pb = pRow->data;
pIter->pf = pRow->data + BIT1_SIZE(pTSchema->numOfCols - 1);
pIter->pv = pIter->pf + pTSchema->flen;
break;
case (HAS_VALUE | HAS_NULL | HAS_NONE):
pIter->pb = pRow->data;
pIter->pf = pRow->data + BIT2_SIZE(pTSchema->numOfCols - 1);
pIter->pv = pIter->pf + pTSchema->flen;
break;
default:
ASSERT(0);
break;
}
}
_exit:
if (code) {
*ppIter = NULL;
} else {
*ppIter = pIter;
}
return code;
}
void tRowIterClose(SRowIter **ppIter) {
SRowIter *pIter = *ppIter;
if (pIter) {
taosMemoryFree(pIter);
}
*ppIter = NULL;
}
SColVal *tRowIterNext(SRowIter *pIter) {
if (pIter->iTColumn >= pIter->pTSchema->numOfCols) {
return NULL;
}
STColumn *pTColumn = pIter->pTSchema->columns + pIter->iTColumn;
// timestamp
if (0 == pIter->iTColumn) {
pIter->cv.cid = pTColumn->colId;
pIter->cv.type = pTColumn->type;
pIter->cv.flag = CV_FLAG_VALUE;
memcpy(&pIter->cv.value.val, &pIter->pRow->ts, sizeof(TSKEY));
goto _exit;
}
if (pIter->pRow->flag == HAS_NONE) {
pIter->cv = COL_VAL_NONE(pTColumn->colId, pTColumn->type);
goto _exit;
}
if (pIter->pRow->flag == HAS_NULL) {
pIter->cv = COL_VAL_NULL(pTColumn->colId, pTColumn->type);
goto _exit;
}
if (pIter->pRow->flag >> 4) { // KV
if (pIter->iCol < pIter->pIdx->nCol) {
uint8_t *pData;
if (pIter->pRow->flag & KV_FLG_LIT) {
pData = pIter->pv + ((uint8_t *)pIter->pIdx->idx)[pIter->iCol];
} else if (pIter->pRow->flag & KV_FLG_MID) {
pData = pIter->pv + ((uint16_t *)pIter->pIdx->idx)[pIter->iCol];
} else {
pData = pIter->pv + ((uint32_t *)pIter->pIdx->idx)[pIter->iCol];
}
int16_t cid;
pData += tGetI16v(pData, &cid);
if (TABS(cid) == pTColumn->colId) {
if (cid < 0) {
pIter->cv = COL_VAL_NULL(pTColumn->colId, pTColumn->type);
} else {
pIter->cv.cid = pTColumn->colId;
pIter->cv.type = pTColumn->type;
pIter->cv.flag = CV_FLAG_VALUE;
if (IS_VAR_DATA_TYPE(pTColumn->type)) {
pData += tGetU32v(pData, &pIter->cv.value.nData);
if (pIter->cv.value.nData > 0) {
pIter->cv.value.pData = pData;
} else {
pIter->cv.value.pData = NULL;
}
} else {
memcpy(&pIter->cv.value.val, pData, pTColumn->bytes);
}
}
pIter->iCol++;
goto _exit;
} else if (TABS(cid) > pTColumn->colId) {
pIter->cv = COL_VAL_NONE(pTColumn->colId, pTColumn->type);
goto _exit;
} else {
ASSERT(0);
}
} else {
pIter->cv = COL_VAL_NONE(pTColumn->colId, pTColumn->type);
goto _exit;
}
} else { // Tuple
uint8_t bv = BIT_FLG_VALUE;
if (pIter->pb) {
switch (pIter->pRow->flag) {
case (HAS_NULL | HAS_NONE):
bv = GET_BIT1(pIter->pb, pIter->iTColumn - 1);
break;
case (HAS_VALUE | HAS_NONE):
bv = GET_BIT1(pIter->pb, pIter->iTColumn - 1);
if (bv) bv++;
break;
case (HAS_VALUE | HAS_NULL):
bv = GET_BIT1(pIter->pb, pIter->iTColumn - 1) + 1;
break;
case (HAS_VALUE | HAS_NULL | HAS_NONE):
bv = GET_BIT2(pIter->pb, pIter->iTColumn - 1);
break;
default:
ASSERT(0);
break;
}
if (bv == BIT_FLG_NONE) {
pIter->cv = COL_VAL_NONE(pTColumn->colId, pTColumn->type);
goto _exit;
} else if (bv == BIT_FLG_NULL) {
pIter->cv = COL_VAL_NULL(pTColumn->colId, pTColumn->type);
goto _exit;
}
}
pIter->cv.cid = pTColumn->colId;
pIter->cv.type = pTColumn->type;
pIter->cv.flag = CV_FLAG_VALUE;
if (IS_VAR_DATA_TYPE(pTColumn->type)) {
uint8_t *pData = pIter->pv + *(int32_t *)(pIter->pf + pTColumn->offset);
pData += tGetU32v(pData, &pIter->cv.value.nData);
if (pIter->cv.value.nData > 0) {
pIter->cv.value.pData = pData;
} else {
pIter->cv.value.pData = NULL;
}
} else {
memcpy(&pIter->cv.value.val, pIter->pf + pTColumn->offset, TYPE_BYTES[pTColumn->type]);
}
goto _exit;
}
_exit:
pIter->iTColumn++;
return &pIter->cv;
}
static int32_t tRowNoneUpsertColData(SColData *aColData, int32_t nColData, int32_t flag) {
int32_t code = 0;
if (flag) return code;
for (int32_t iColData = 0; iColData < nColData; iColData++) {
code = tColDataAppendValueImpl[aColData[iColData].flag][CV_FLAG_NONE](&aColData[iColData], NULL, 0);
if (code) return code;
}
return code;
}
static int32_t tRowNullUpsertColData(SColData *aColData, int32_t nColData, STSchema *pSchema, int32_t flag) {
int32_t code = 0;
int32_t iColData = 0;
SColData *pColData = &aColData[iColData];
int32_t iTColumn = 1;
STColumn *pTColumn = &pSchema->columns[iTColumn];
while (pColData) {
if (pTColumn) {
if (pTColumn->colId == pColData->cid) { // NULL
if (flag == 0) {
code = tColDataAppendValueImpl[pColData->flag][CV_FLAG_NULL](pColData, NULL, 0);
} else {
code = tColDataUpdateValueImpl[pColData->flag][CV_FLAG_NULL](pColData, NULL, 0, flag > 0);
}
if (code) goto _exit;
pColData = (++iColData < nColData) ? &aColData[iColData] : NULL;
pTColumn = (++iTColumn < pSchema->numOfCols) ? &pSchema->columns[iTColumn] : NULL;
} else if (pTColumn->colId > pColData->cid) { // NONE
if (flag == 0 && (code = tColDataAppendValueImpl[pColData->flag][CV_FLAG_NONE](pColData, NULL, 0))) goto _exit;
pColData = (++iColData < nColData) ? &aColData[iColData] : NULL;
} else {
pTColumn = (++iTColumn < pSchema->numOfCols) ? &pSchema->columns[iTColumn] : NULL;
}
} else { // NONE
if (flag == 0 && (code = tColDataAppendValueImpl[pColData->flag][CV_FLAG_NONE](pColData, NULL, 0))) goto _exit;
pColData = (++iColData < nColData) ? &aColData[iColData] : NULL;
}
}
_exit:
return code;
}
static int32_t tRowTupleUpsertColData(SRow *pRow, STSchema *pTSchema, SColData *aColData, int32_t nColData,
int32_t flag) {
int32_t code = 0;
int32_t iColData = 0;
SColData *pColData = &aColData[iColData];
int32_t iTColumn = 1;
STColumn *pTColumn = &pTSchema->columns[iTColumn];
uint8_t *pb = NULL, *pf = NULL, *pv = NULL;
switch (pRow->flag) {
case HAS_VALUE:
pf = pRow->data;
pv = pf + pTSchema->flen;
break;
case (HAS_NULL | HAS_NONE):
pb = pRow->data;
break;
case (HAS_VALUE | HAS_NONE):
case (HAS_VALUE | HAS_NULL):
pb = pRow->data;
pf = pb + BIT1_SIZE(pTSchema->numOfCols - 1);
pv = pf + pTSchema->flen;
break;
case (HAS_VALUE | HAS_NULL | HAS_NONE):
pb = pRow->data;
pf = pb + BIT2_SIZE(pTSchema->numOfCols - 1);
pv = pf + pTSchema->flen;
break;
default:
ASSERTS(0, "Invalid row flag");
return TSDB_CODE_INVALID_DATA_FMT;
}
while (pColData) {
if (pTColumn) {
if (pTColumn->colId == pColData->cid) {
ASSERT(pTColumn->type == pColData->type);
if (pb) {
uint8_t bv;
switch (pRow->flag) {
case (HAS_NULL | HAS_NONE):
bv = GET_BIT1(pb, iTColumn - 1);
break;
case (HAS_VALUE | HAS_NONE):
bv = GET_BIT1(pb, iTColumn - 1);
if (bv) bv++;
break;
case (HAS_VALUE | HAS_NULL):
bv = GET_BIT1(pb, iTColumn - 1) + 1;
break;
case (HAS_VALUE | HAS_NULL | HAS_NONE):
bv = GET_BIT2(pb, iTColumn - 1);
break;
default:
ASSERTS(0, "Invalid row flag");
return TSDB_CODE_INVALID_DATA_FMT;
}
if (bv == BIT_FLG_NONE) {
if (flag == 0 && (code = tColDataAppendValueImpl[pColData->flag][CV_FLAG_NONE](pColData, NULL, 0)))
goto _exit;
goto _continue;
} else if (bv == BIT_FLG_NULL) {
if (flag == 0) {
code = tColDataAppendValueImpl[pColData->flag][CV_FLAG_NULL](pColData, NULL, 0);
} else {
code = tColDataUpdateValueImpl[pColData->flag][CV_FLAG_NULL](pColData, NULL, 0, flag > 0);
}
if (code) goto _exit;
goto _continue;
}
}
if (IS_VAR_DATA_TYPE(pColData->type)) {
uint8_t *pData = pv + *(int32_t *)(pf + pTColumn->offset);
uint32_t nData;
pData += tGetU32v(pData, &nData);
if (flag == 0) {
code = tColDataAppendValueImpl[pColData->flag][CV_FLAG_VALUE](pColData, pData, nData);
} else {
code = tColDataUpdateValueImpl[pColData->flag][CV_FLAG_VALUE](pColData, pData, nData, flag > 0);
}
if (code) goto _exit;
} else {
if (flag == 0) {
code = tColDataAppendValueImpl[pColData->flag][CV_FLAG_VALUE](pColData, pf + pTColumn->offset,
TYPE_BYTES[pColData->type]);
} else {
code = tColDataUpdateValueImpl[pColData->flag][CV_FLAG_VALUE](pColData, pf + pTColumn->offset,
TYPE_BYTES[pColData->type], flag > 0);
}
if (code) goto _exit;
}
_continue:
pColData = (++iColData < nColData) ? &aColData[iColData] : NULL;
pTColumn = (++iTColumn < pTSchema->numOfCols) ? &pTSchema->columns[iTColumn] : NULL;
} else if (pTColumn->colId > pColData->cid) { // NONE
if (flag == 0 && (code = tColDataAppendValueImpl[pColData->flag][CV_FLAG_NONE](pColData, NULL, 0))) goto _exit;
pColData = (++iColData < nColData) ? &aColData[iColData] : NULL;
} else {
pTColumn = (++iTColumn < pTSchema->numOfCols) ? &pTSchema->columns[iTColumn] : NULL;
}
} else {
if (flag == 0 && (code = tColDataAppendValueImpl[pColData->flag][CV_FLAG_NONE](pColData, NULL, 0))) goto _exit;
pColData = (++iColData < nColData) ? &aColData[iColData] : NULL;
}
}
_exit:
return code;
}
static int32_t tRowKVUpsertColData(SRow *pRow, STSchema *pTSchema, SColData *aColData, int32_t nColData, int32_t flag) {
int32_t code = 0;
SKVIdx *pKVIdx = (SKVIdx *)pRow->data;
uint8_t *pv = NULL;
int32_t iColData = 0;
SColData *pColData = &aColData[iColData];
int32_t iTColumn = 1;
STColumn *pTColumn = &pTSchema->columns[iTColumn];
int32_t iCol = 0;
if (pRow->flag & KV_FLG_LIT) {
pv = pKVIdx->idx + pKVIdx->nCol;
} else if (pRow->flag & KV_FLG_MID) {
pv = pKVIdx->idx + (pKVIdx->nCol << 1);
} else if (pRow->flag & KV_FLG_BIG) {
pv = pKVIdx->idx + (pKVIdx->nCol << 2);
} else {
ASSERT(0);
}
while (pColData) {
if (pTColumn) {
if (pTColumn->colId == pColData->cid) {
while (iCol < pKVIdx->nCol) {
uint8_t *pData;
if (pRow->flag & KV_FLG_LIT) {
pData = pv + ((uint8_t *)pKVIdx->idx)[iCol];
} else if (pRow->flag & KV_FLG_MID) {
pData = pv + ((uint16_t *)pKVIdx->idx)[iCol];
} else if (pRow->flag & KV_FLG_BIG) {
pData = pv + ((uint32_t *)pKVIdx->idx)[iCol];
} else {
ASSERTS(0, "Invalid KV row format");
return TSDB_CODE_INVALID_DATA_FMT;
}
int16_t cid;
pData += tGetI16v(pData, &cid);
if (TABS(cid) == pTColumn->colId) {
if (cid < 0) {
if (flag == 0) {
code = tColDataAppendValueImpl[pColData->flag][CV_FLAG_NULL](pColData, NULL, 0);
} else {
code = tColDataUpdateValueImpl[pColData->flag][CV_FLAG_NULL](pColData, NULL, 0, flag > 0);
}
if (code) goto _exit;
} else {
uint32_t nData;
if (IS_VAR_DATA_TYPE(pTColumn->type)) {
pData += tGetU32v(pData, &nData);
} else {
nData = 0;
}
if (flag == 0) {
code = tColDataAppendValueImpl[pColData->flag][CV_FLAG_VALUE](pColData, pData, nData);
} else {
code = tColDataUpdateValueImpl[pColData->flag][CV_FLAG_VALUE](pColData, pData, nData, flag > 0);
}
if (code) goto _exit;
}
iCol++;
goto _continue;
} else if (TABS(cid) > pTColumn->colId) { // NONE
break;
} else {
iCol++;
}
}
if (flag == 0 && (code = tColDataAppendValueImpl[pColData->flag][CV_FLAG_NONE](pColData, NULL, 0))) goto _exit;
_continue:
pColData = (++iColData < nColData) ? &aColData[iColData] : NULL;
pTColumn = (++iTColumn < pTSchema->numOfCols) ? &pTSchema->columns[iTColumn] : NULL;
} else if (pTColumn->colId > pColData->cid) {
if (flag == 0 && (code = tColDataAppendValueImpl[pColData->flag][CV_FLAG_NONE](pColData, NULL, 0))) goto _exit;
pColData = (++iColData < nColData) ? &aColData[iColData] : NULL;
} else {
pTColumn = (++iTColumn < pTSchema->numOfCols) ? &pTSchema->columns[iTColumn] : NULL;
}
} else {
if (flag == 0 && (code = tColDataAppendValueImpl[pColData->flag][CV_FLAG_NONE](pColData, NULL, 0))) goto _exit;
pColData = (++iColData < nColData) ? &aColData[iColData] : NULL;
}
}
_exit:
return code;
}
/* flag > 0: forward update
* flag == 0: append
* flag < 0: backward update
*/
int32_t tRowUpsertColData(SRow *pRow, STSchema *pTSchema, SColData *aColData, int32_t nColData, int32_t flag) {
ASSERT(pRow->sver == pTSchema->version);
ASSERT(nColData > 0);
if (pRow->flag == HAS_NONE) {
return tRowNoneUpsertColData(aColData, nColData, flag);
} else if (pRow->flag == HAS_NULL) {
return tRowNullUpsertColData(aColData, nColData, pTSchema, flag);
} else if (pRow->flag >> 4) { // KV row
return tRowKVUpsertColData(pRow, pTSchema, aColData, nColData, flag);
} else { // TUPLE row
return tRowTupleUpsertColData(pRow, pTSchema, aColData, nColData, flag);
}
}
// STag ========================================
static int tTagValCmprFn(const void *p1, const void *p2) {
if (((STagVal *)p1)->cid < ((STagVal *)p2)->cid) {
return -1;
} else if (((STagVal *)p1)->cid > ((STagVal *)p2)->cid) {
return 1;
}
return 0;
}
static int tTagValJsonCmprFn(const void *p1, const void *p2) {
return strcmp(((STagVal *)p1)[0].pKey, ((STagVal *)p2)[0].pKey);
}
static void debugPrintTagVal(int8_t type, const void *val, int32_t vlen, const char *tag, int32_t ln) {
switch (type) {
case TSDB_DATA_TYPE_VARBINARY:
case TSDB_DATA_TYPE_JSON:
case TSDB_DATA_TYPE_VARCHAR:
case TSDB_DATA_TYPE_NCHAR:
case TSDB_DATA_TYPE_GEOMETRY: {
char tmpVal[32] = {0};
strncpy(tmpVal, val, vlen > 31 ? 31 : vlen);
printf("%s:%d type:%d vlen:%d, val:\"%s\"\n", tag, ln, (int32_t)type, vlen, tmpVal);
} break;
case TSDB_DATA_TYPE_FLOAT:
printf("%s:%d type:%d vlen:%d, val:%f\n", tag, ln, (int32_t)type, vlen, *(float *)val);
break;
case TSDB_DATA_TYPE_DOUBLE:
printf("%s:%d type:%d vlen:%d, val:%lf\n", tag, ln, (int32_t)type, vlen, *(double *)val);
break;
case TSDB_DATA_TYPE_BOOL:
printf("%s:%d type:%d vlen:%d, val:%" PRIu8 "\n", tag, ln, (int32_t)type, vlen, *(uint8_t *)val);
break;
case TSDB_DATA_TYPE_TINYINT:
printf("%s:%d type:%d vlen:%d, val:%" PRIi8 "\n", tag, ln, (int32_t)type, vlen, *(int8_t *)val);
break;
case TSDB_DATA_TYPE_SMALLINT:
printf("%s:%d type:%d vlen:%d, val:%" PRIi16 "\n", tag, ln, (int32_t)type, vlen, *(int16_t *)val);
break;
case TSDB_DATA_TYPE_INT:
printf("%s:%d type:%d vlen:%d, val:%" PRIi32 "\n", tag, ln, (int32_t)type, vlen, *(int32_t *)val);
break;
case TSDB_DATA_TYPE_BIGINT:
printf("%s:%d type:%d vlen:%d, val:%" PRIi64 "\n", tag, ln, (int32_t)type, vlen, *(int64_t *)val);
break;
case TSDB_DATA_TYPE_TIMESTAMP:
printf("%s:%d type:%d vlen:%d, val:%" PRIi64 "\n", tag, ln, (int32_t)type, vlen, *(int64_t *)val);
break;
case TSDB_DATA_TYPE_UTINYINT:
printf("%s:%d type:%d vlen:%d, val:%" PRIu8 "\n", tag, ln, (int32_t)type, vlen, *(uint8_t *)val);
break;
case TSDB_DATA_TYPE_USMALLINT:
printf("%s:%d type:%d vlen:%d, val:%" PRIu16 "\n", tag, ln, (int32_t)type, vlen, *(uint16_t *)val);
break;
case TSDB_DATA_TYPE_UINT:
printf("%s:%d type:%d vlen:%d, val:%" PRIu32 "\n", tag, ln, (int32_t)type, vlen, *(uint32_t *)val);
break;
case TSDB_DATA_TYPE_UBIGINT:
printf("%s:%d type:%d vlen:%d, val:%" PRIu64 "\n", tag, ln, (int32_t)type, vlen, *(uint64_t *)val);
break;
case TSDB_DATA_TYPE_NULL:
printf("%s:%d type:%d vlen:%d, val:%" PRIi8 "\n", tag, ln, (int32_t)type, vlen, *(int8_t *)val);
break;
default:
ASSERT(0);
break;
}
}
void debugPrintSTag(STag *pTag, const char *tag, int32_t ln) {
int8_t isJson = pTag->flags & TD_TAG_JSON;
int8_t isLarge = pTag->flags & TD_TAG_LARGE;
uint8_t *p = NULL;
int16_t offset = 0;
if (isLarge) {
p = (uint8_t *)&((int16_t *)pTag->idx)[pTag->nTag];
} else {
p = (uint8_t *)&pTag->idx[pTag->nTag];
}
printf("%s:%d >>> STAG === %s:%s, len: %d, nTag: %d, sver:%d\n", tag, ln, isJson ? "json" : "normal",
isLarge ? "large" : "small", (int32_t)pTag->len, (int32_t)pTag->nTag, pTag->ver);
for (uint16_t n = 0; n < pTag->nTag; ++n) {
if (isLarge) {
offset = ((int16_t *)pTag->idx)[n];
} else {
offset = pTag->idx[n];
}
STagVal tagVal = {0};
if (isJson) {
tagVal.pKey = (char *)POINTER_SHIFT(p, offset);
} else {
tagVal.cid = *(int16_t *)POINTER_SHIFT(p, offset);
}
printf("%s:%d loop[%d-%d] offset=%d\n", __func__, __LINE__, (int32_t)pTag->nTag, (int32_t)n, (int32_t)offset);
tGetTagVal(p + offset, &tagVal, isJson);
if (IS_VAR_DATA_TYPE(tagVal.type)) {
debugPrintTagVal(tagVal.type, tagVal.pData, tagVal.nData, __func__, __LINE__);
} else {
debugPrintTagVal(tagVal.type, &tagVal.i64, tDataTypes[tagVal.type].bytes, __func__, __LINE__);
}
}
printf("\n");
}
static int32_t tPutTagVal(uint8_t *p, STagVal *pTagVal, int8_t isJson) {
int32_t n = 0;
// key
if (isJson) {
n += tPutCStr(p ? p + n : p, pTagVal->pKey);
} else {
n += tPutI16v(p ? p + n : p, pTagVal->cid);
}
// type
n += tPutI8(p ? p + n : p, pTagVal->type);
// value
if (IS_VAR_DATA_TYPE(pTagVal->type)) {
n += tPutBinary(p ? p + n : p, pTagVal->pData, pTagVal->nData);
} else {
p = p ? p + n : p;
n += tDataTypes[pTagVal->type].bytes;
if (p) memcpy(p, &(pTagVal->i64), tDataTypes[pTagVal->type].bytes);
}
return n;
}
static int32_t tGetTagVal(uint8_t *p, STagVal *pTagVal, int8_t isJson) {
int32_t n = 0;
// key
if (isJson) {
n += tGetCStr(p + n, &pTagVal->pKey);
} else {
n += tGetI16v(p + n, &pTagVal->cid);
}
// type
n += tGetI8(p + n, &pTagVal->type);
// value
if (IS_VAR_DATA_TYPE(pTagVal->type)) {
n += tGetBinary(p + n, &pTagVal->pData, &pTagVal->nData);
} else {
memcpy(&(pTagVal->i64), p + n, tDataTypes[pTagVal->type].bytes);
n += tDataTypes[pTagVal->type].bytes;
}
return n;
}
bool tTagIsJson(const void *pTag) { return (((const STag *)pTag)->flags & TD_TAG_JSON); }
bool tTagIsJsonNull(void *data) {
STag *pTag = (STag *)data;
int8_t isJson = tTagIsJson(pTag);
if (!isJson) return false;
return ((STag *)data)->nTag == 0;
}
int32_t tTagNew(SArray *pArray, int32_t version, int8_t isJson, STag **ppTag) {
int32_t code = 0;
uint8_t *p = NULL;
int16_t n = 0;
int16_t nTag = taosArrayGetSize(pArray);
int32_t szTag = 0;
int8_t isLarge = 0;
// sort
if (isJson) {
taosSort(pArray->pData, nTag, sizeof(STagVal), tTagValJsonCmprFn);
} else {
taosSort(pArray->pData, nTag, sizeof(STagVal), tTagValCmprFn);
}
// get size
for (int16_t iTag = 0; iTag < nTag; iTag++) {
szTag += tPutTagVal(NULL, (STagVal *)taosArrayGet(pArray, iTag), isJson);
}
if (szTag <= INT8_MAX) {
szTag = szTag + sizeof(STag) + sizeof(int8_t) * nTag;
} else {
szTag = szTag + sizeof(STag) + sizeof(int16_t) * nTag;
isLarge = 1;
}
ASSERT(szTag <= INT16_MAX);
// build tag
(*ppTag) = (STag *)taosMemoryCalloc(szTag, 1);
if ((*ppTag) == NULL) {
code = TSDB_CODE_OUT_OF_MEMORY;
goto _err;
}
(*ppTag)->flags = 0;
if (isJson) {
(*ppTag)->flags |= TD_TAG_JSON;
}
if (isLarge) {
(*ppTag)->flags |= TD_TAG_LARGE;
}
(*ppTag)->len = szTag;
(*ppTag)->nTag = nTag;
(*ppTag)->ver = version;
if (isLarge) {
p = (uint8_t *)&((int16_t *)(*ppTag)->idx)[nTag];
} else {
p = (uint8_t *)&(*ppTag)->idx[nTag];
}
n = 0;
for (int16_t iTag = 0; iTag < nTag; iTag++) {
if (isLarge) {
((int16_t *)(*ppTag)->idx)[iTag] = n;
} else {
(*ppTag)->idx[iTag] = n;
}
n += tPutTagVal(p + n, (STagVal *)taosArrayGet(pArray, iTag), isJson);
}
#ifdef TD_DEBUG_PRINT_TAG
debugPrintSTag(*ppTag, __func__, __LINE__);
#endif
return code;
_err:
return code;
}
void tTagFree(STag *pTag) {
if (pTag) taosMemoryFree(pTag);
}
char *tTagValToData(const STagVal *value, bool isJson) {
if (!value) {
return NULL;
}
char *data = NULL;
int8_t typeBytes = 0;
if (isJson) {
typeBytes = CHAR_BYTES;
}
if (IS_VAR_DATA_TYPE(value->type)) {
data = taosMemoryCalloc(1, typeBytes + VARSTR_HEADER_SIZE + value->nData);
if (data == NULL) {
return NULL;
}
if (isJson) {
*data = value->type;
}
varDataLen(data + typeBytes) = value->nData;
memcpy(varDataVal(data + typeBytes), value->pData, value->nData);
} else {
data = ((char *)&(value->i64)) - typeBytes; // json with type
}
return data;
}
bool tTagGet(const STag *pTag, STagVal *pTagVal) {
if (!pTag || !pTagVal) {
return false;
}
int16_t lidx = 0;
int16_t ridx = pTag->nTag - 1;
int16_t midx;
uint8_t *p;
int8_t isJson = pTag->flags & TD_TAG_JSON;
int8_t isLarge = pTag->flags & TD_TAG_LARGE;
int16_t offset;
STagVal tv;
int c;
if (isLarge) {
p = (uint8_t *)&((int16_t *)pTag->idx)[pTag->nTag];
} else {
p = (uint8_t *)&pTag->idx[pTag->nTag];
}
pTagVal->type = TSDB_DATA_TYPE_NULL;
pTagVal->pData = NULL;
pTagVal->nData = 0;
while (lidx <= ridx) {
midx = (lidx + ridx) / 2;
if (isLarge) {
offset = ((int16_t *)pTag->idx)[midx];
} else {
offset = pTag->idx[midx];
}
tGetTagVal(p + offset, &tv, isJson);
if (isJson) {
c = tTagValJsonCmprFn(pTagVal, &tv);
} else {
c = tTagValCmprFn(pTagVal, &tv);
}
if (c < 0) {
ridx = midx - 1;
} else if (c > 0) {
lidx = midx + 1;
} else {
memcpy(pTagVal, &tv, sizeof(tv));
return true;
}
}
return false;
}
int32_t tEncodeTag(SEncoder *pEncoder, const STag *pTag) {
return tEncodeBinary(pEncoder, (const uint8_t *)pTag, pTag->len);
}
int32_t tDecodeTag(SDecoder *pDecoder, STag **ppTag) { return tDecodeBinary(pDecoder, (uint8_t **)ppTag, NULL); }
int32_t tTagToValArray(const STag *pTag, SArray **ppArray) {
int32_t code = 0;
uint8_t *p = NULL;
STagVal tv = {0};
int8_t isLarge = pTag->flags & TD_TAG_LARGE;
int16_t offset = 0;
if (isLarge) {
p = (uint8_t *)&((int16_t *)pTag->idx)[pTag->nTag];
} else {
p = (uint8_t *)&pTag->idx[pTag->nTag];
}
(*ppArray) = taosArrayInit(pTag->nTag + 1, sizeof(STagVal));
if (*ppArray == NULL) {
code = TSDB_CODE_OUT_OF_MEMORY;
goto _err;
}
for (int16_t iTag = 0; iTag < pTag->nTag; iTag++) {
if (isLarge) {
offset = ((int16_t *)pTag->idx)[iTag];
} else {
offset = pTag->idx[iTag];
}
tGetTagVal(p + offset, &tv, pTag->flags & TD_TAG_JSON);
taosArrayPush(*ppArray, &tv);
}
return code;
_err:
return code;
}
void tTagSetCid(const STag *pTag, int16_t iTag, int16_t cid) {
uint8_t *p = NULL;
int8_t isLarge = pTag->flags & TD_TAG_LARGE;
int16_t offset = 0;
if (isLarge) {
p = (uint8_t *)&((int16_t *)pTag->idx)[pTag->nTag];
} else {
p = (uint8_t *)&pTag->idx[pTag->nTag];
}
if (isLarge) {
offset = ((int16_t *)pTag->idx)[iTag];
} else {
offset = pTag->idx[iTag];
}
tPutI16v(p + offset, cid);
}
// STSchema ========================================
STSchema *tBuildTSchema(SSchema *aSchema, int32_t numOfCols, int32_t version) {
STSchema *pTSchema = taosMemoryCalloc(1, sizeof(STSchema) + sizeof(STColumn) * numOfCols);
if (pTSchema == NULL) {
return NULL;
}
pTSchema->numOfCols = numOfCols;
pTSchema->version = version;
// timestamp column
ASSERT(aSchema[0].type == TSDB_DATA_TYPE_TIMESTAMP);
ASSERT(aSchema[0].colId == PRIMARYKEY_TIMESTAMP_COL_ID);
pTSchema->columns[0].colId = aSchema[0].colId;
pTSchema->columns[0].type = aSchema[0].type;
pTSchema->columns[0].flags = aSchema[0].flags;
pTSchema->columns[0].bytes = TYPE_BYTES[aSchema[0].type];
pTSchema->columns[0].offset = -1;
// other columns
for (int32_t iCol = 1; iCol < numOfCols; iCol++) {
SSchema *pSchema = &aSchema[iCol];
STColumn *pTColumn = &pTSchema->columns[iCol];
pTColumn->colId = pSchema->colId;
pTColumn->type = pSchema->type;
pTColumn->flags = pSchema->flags;
pTColumn->offset = pTSchema->flen;
if (IS_VAR_DATA_TYPE(pSchema->type)) {
pTColumn->bytes = pSchema->bytes;
pTSchema->tlen += (TYPE_BYTES[pSchema->type] + pSchema->bytes); // todo: remove
} else {
pTColumn->bytes = TYPE_BYTES[pSchema->type];
pTSchema->tlen += TYPE_BYTES[pSchema->type]; // todo: remove
}
pTSchema->flen += TYPE_BYTES[pTColumn->type];
}
#if 1 // todo : remove this
pTSchema->tlen += (int32_t)TD_BITMAP_BYTES(numOfCols);
#endif
return pTSchema;
}
// SColData ========================================
void tColDataDestroy(void *ph) {
if (ph) {
SColData *pColData = (SColData *)ph;
tFree(pColData->pBitMap);
tFree(pColData->aOffset);
tFree(pColData->pData);
}
}
void tColDataInit(SColData *pColData, int16_t cid, int8_t type, int8_t smaOn) {
pColData->cid = cid;
pColData->type = type;
pColData->smaOn = smaOn;
tColDataClear(pColData);
}
void tColDataClear(SColData *pColData) {
pColData->numOfNone = 0;
pColData->numOfNull = 0;
pColData->numOfValue = 0;
pColData->nVal = 0;
pColData->flag = 0;
pColData->nData = 0;
}
void tColDataDeepClear(SColData *pColData) {
pColData->pBitMap = NULL;
pColData->aOffset = NULL;
pColData->pData = NULL;
tColDataClear(pColData);
}
static FORCE_INLINE int32_t tColDataPutValue(SColData *pColData, uint8_t *pData, uint32_t nData) {
int32_t code = 0;
if (IS_VAR_DATA_TYPE(pColData->type)) {
code = tRealloc((uint8_t **)(&pColData->aOffset), ((int64_t)(pColData->nVal + 1)) << 2);
if (code) goto _exit;
pColData->aOffset[pColData->nVal] = pColData->nData;
if (nData) {
code = tRealloc(&pColData->pData, pColData->nData + nData);
if (code) goto _exit;
memcpy(pColData->pData + pColData->nData, pData, nData);
pColData->nData += nData;
}
} else {
ASSERT(pColData->nData == tDataTypes[pColData->type].bytes * pColData->nVal);
code = tRealloc(&pColData->pData, pColData->nData + tDataTypes[pColData->type].bytes);
if (code) goto _exit;
if (pData) {
memcpy(pColData->pData + pColData->nData, pData, TYPE_BYTES[pColData->type]);
} else {
memset(pColData->pData + pColData->nData, 0, TYPE_BYTES[pColData->type]);
}
pColData->nData += tDataTypes[pColData->type].bytes;
}
pColData->nVal++;
_exit:
return code;
}
static FORCE_INLINE int32_t tColDataAppendValue00(SColData *pColData, uint8_t *pData, uint32_t nData) {
pColData->flag = HAS_VALUE;
pColData->numOfValue++;
return tColDataPutValue(pColData, pData, nData);
}
static FORCE_INLINE int32_t tColDataAppendValue01(SColData *pColData, uint8_t *pData, uint32_t nData) {
pColData->flag = HAS_NONE;
pColData->numOfNone++;
pColData->nVal++;
return 0;
}
static FORCE_INLINE int32_t tColDataAppendValue02(SColData *pColData, uint8_t *pData, uint32_t nData) {
pColData->flag = HAS_NULL;
pColData->numOfNull++;
pColData->nVal++;
return 0;
}
static FORCE_INLINE int32_t tColDataAppendValue10(SColData *pColData, uint8_t *pData, uint32_t nData) {
int32_t code = 0;
int32_t nBit = BIT1_SIZE(pColData->nVal + 1);
code = tRealloc(&pColData->pBitMap, nBit);
if (code) return code;
memset(pColData->pBitMap, 0, nBit);
SET_BIT1_EX(pColData->pBitMap, pColData->nVal, 1);
pColData->flag |= HAS_VALUE;
pColData->numOfValue++;
if (pColData->nVal) {
if (IS_VAR_DATA_TYPE(pColData->type)) {
int32_t nOffset = sizeof(int32_t) * pColData->nVal;
code = tRealloc((uint8_t **)(&pColData->aOffset), nOffset);
if (code) return code;
memset(pColData->aOffset, 0, nOffset);
} else {
pColData->nData = tDataTypes[pColData->type].bytes * pColData->nVal;
code = tRealloc(&pColData->pData, pColData->nData);
if (code) return code;
memset(pColData->pData, 0, pColData->nData);
}
}
return tColDataPutValue(pColData, pData, nData);
}
static FORCE_INLINE int32_t tColDataAppendValue11(SColData *pColData, uint8_t *pData, uint32_t nData) {
pColData->nVal++;
pColData->numOfNone++;
return 0;
}
static FORCE_INLINE int32_t tColDataAppendValue12(SColData *pColData, uint8_t *pData, uint32_t nData) {
int32_t code = 0;
int32_t nBit = BIT1_SIZE(pColData->nVal + 1);
code = tRealloc(&pColData->pBitMap, nBit);
if (code) return code;
memset(pColData->pBitMap, 0, nBit);
SET_BIT1_EX(pColData->pBitMap, pColData->nVal, 1);
pColData->flag |= HAS_NULL;
pColData->numOfNull++;
pColData->nVal++;
return code;
}
static FORCE_INLINE int32_t tColDataAppendValue20(SColData *pColData, uint8_t *pData, uint32_t nData) {
int32_t code = 0;
int32_t nBit = BIT1_SIZE(pColData->nVal + 1);
code = tRealloc(&pColData->pBitMap, nBit);
if (code) return code;
memset(pColData->pBitMap, 0, nBit);
SET_BIT1_EX(pColData->pBitMap, pColData->nVal, 1);
pColData->flag |= HAS_VALUE;
pColData->numOfValue++;
if (pColData->nVal) {
if (IS_VAR_DATA_TYPE(pColData->type)) {
int32_t nOffset = sizeof(int32_t) * pColData->nVal;
code = tRealloc((uint8_t **)(&pColData->aOffset), nOffset);
if (code) return code;
memset(pColData->aOffset, 0, nOffset);
} else {
pColData->nData = tDataTypes[pColData->type].bytes * pColData->nVal;
code = tRealloc(&pColData->pData, pColData->nData);
if (code) return code;
memset(pColData->pData, 0, pColData->nData);
}
}
return tColDataPutValue(pColData, pData, nData);
}
static FORCE_INLINE int32_t tColDataAppendValue21(SColData *pColData, uint8_t *pData, uint32_t nData) {
int32_t code = 0;
int32_t nBit = BIT1_SIZE(pColData->nVal + 1);
code = tRealloc(&pColData->pBitMap, nBit);
if (code) return code;
memset(pColData->pBitMap, 255, nBit);
SET_BIT1_EX(pColData->pBitMap, pColData->nVal, 0);
pColData->flag |= HAS_NONE;
pColData->numOfNone++;
pColData->nVal++;
return code;
}
static FORCE_INLINE int32_t tColDataAppendValue22(SColData *pColData, uint8_t *pData, uint32_t nData) {
pColData->nVal++;
pColData->numOfNull++;
return 0;
}
static FORCE_INLINE int32_t tColDataAppendValue30(SColData *pColData, uint8_t *pData, uint32_t nData) {
int32_t code = 0;
pColData->flag |= HAS_VALUE;
pColData->numOfValue++;
uint8_t *pBitMap = NULL;
code = tRealloc(&pBitMap, BIT2_SIZE(pColData->nVal + 1));
if (code) return code;
for (int32_t iVal = 0; iVal < pColData->nVal; iVal++) {
SET_BIT2_EX(pBitMap, iVal, GET_BIT1(pColData->pBitMap, iVal));
}
SET_BIT2_EX(pBitMap, pColData->nVal, 2);
tFree(pColData->pBitMap);
pColData->pBitMap = pBitMap;
if (pColData->nVal) {
if (IS_VAR_DATA_TYPE(pColData->type)) {
int32_t nOffset = sizeof(int32_t) * pColData->nVal;
code = tRealloc((uint8_t **)(&pColData->aOffset), nOffset);
if (code) return code;
memset(pColData->aOffset, 0, nOffset);
} else {
pColData->nData = tDataTypes[pColData->type].bytes * pColData->nVal;
code = tRealloc(&pColData->pData, pColData->nData);
if (code) return code;
memset(pColData->pData, 0, pColData->nData);
}
}
return tColDataPutValue(pColData, pData, nData);
}
static FORCE_INLINE int32_t tColDataAppendValue31(SColData *pColData, uint8_t *pData, uint32_t nData) {
int32_t code = 0;
code = tRealloc(&pColData->pBitMap, BIT1_SIZE(pColData->nVal + 1));
if (code) return code;
SET_BIT1_EX(pColData->pBitMap, pColData->nVal, 0);
pColData->numOfNone++;
pColData->nVal++;
return code;
}
static FORCE_INLINE int32_t tColDataAppendValue32(SColData *pColData, uint8_t *pData, uint32_t nData) {
int32_t code = 0;
code = tRealloc(&pColData->pBitMap, BIT1_SIZE(pColData->nVal + 1));
if (code) return code;
SET_BIT1_EX(pColData->pBitMap, pColData->nVal, 1);
pColData->numOfNull++;
pColData->nVal++;
return code;
}
static FORCE_INLINE int32_t tColDataAppendValue40(SColData *pColData, uint8_t *pData, uint32_t nData) {
pColData->numOfValue++;
return tColDataPutValue(pColData, pData, nData);
}
static FORCE_INLINE int32_t tColDataAppendValue41(SColData *pColData, uint8_t *pData, uint32_t nData) {
int32_t code = 0;
pColData->flag |= HAS_NONE;
pColData->numOfNone++;
int32_t nBit = BIT1_SIZE(pColData->nVal + 1);
code = tRealloc(&pColData->pBitMap, nBit);
if (code) return code;
memset(pColData->pBitMap, 255, nBit);
SET_BIT1_EX(pColData->pBitMap, pColData->nVal, 0);
return tColDataPutValue(pColData, NULL, 0);
}
static FORCE_INLINE int32_t tColDataAppendValue42(SColData *pColData, uint8_t *pData, uint32_t nData) {
int32_t code = 0;
pColData->flag |= HAS_NULL;
pColData->numOfNull++;
int32_t nBit = BIT1_SIZE(pColData->nVal + 1);
code = tRealloc(&pColData->pBitMap, nBit);
if (code) return code;
memset(pColData->pBitMap, 255, nBit);
SET_BIT1_EX(pColData->pBitMap, pColData->nVal, 0);
return tColDataPutValue(pColData, NULL, 0);
}
static FORCE_INLINE int32_t tColDataAppendValue50(SColData *pColData, uint8_t *pData, uint32_t nData) {
int32_t code = 0;
code = tRealloc(&pColData->pBitMap, BIT1_SIZE(pColData->nVal + 1));
if (code) return code;
SET_BIT1_EX(pColData->pBitMap, pColData->nVal, 1);
pColData->numOfValue++;
return tColDataPutValue(pColData, pData, nData);
}
static FORCE_INLINE int32_t tColDataAppendValue51(SColData *pColData, uint8_t *pData, uint32_t nData) {
int32_t code = 0;
code = tRealloc(&pColData->pBitMap, BIT1_SIZE(pColData->nVal + 1));
if (code) return code;
SET_BIT1_EX(pColData->pBitMap, pColData->nVal, 0);
pColData->numOfNone++;
return tColDataPutValue(pColData, NULL, 0);
}
static FORCE_INLINE int32_t tColDataAppendValue52(SColData *pColData, uint8_t *pData, uint32_t nData) {
int32_t code = 0;
pColData->flag |= HAS_NULL;
pColData->numOfNull++;
uint8_t *pBitMap = NULL;
code = tRealloc(&pBitMap, BIT2_SIZE(pColData->nVal + 1));
if (code) return code;
for (int32_t iVal = 0; iVal < pColData->nVal; iVal++) {
SET_BIT2_EX(pBitMap, iVal, GET_BIT1(pColData->pBitMap, iVal) ? 2 : 0);
}
SET_BIT2_EX(pBitMap, pColData->nVal, 1);
tFree(pColData->pBitMap);
pColData->pBitMap = pBitMap;
return tColDataPutValue(pColData, NULL, 0);
}
static FORCE_INLINE int32_t tColDataAppendValue60(SColData *pColData, uint8_t *pData, uint32_t nData) {
int32_t code = 0;
code = tRealloc(&pColData->pBitMap, BIT1_SIZE(pColData->nVal + 1));
if (code) return code;
SET_BIT1_EX(pColData->pBitMap, pColData->nVal, 1);
pColData->numOfValue++;
return tColDataPutValue(pColData, pData, nData);
}
static FORCE_INLINE int32_t tColDataAppendValue61(SColData *pColData, uint8_t *pData, uint32_t nData) {
int32_t code = 0;
pColData->flag |= HAS_NONE;
pColData->numOfNone++;
uint8_t *pBitMap = NULL;
code = tRealloc(&pBitMap, BIT2_SIZE(pColData->nVal + 1));
if (code) return code;
for (int32_t iVal = 0; iVal < pColData->nVal; iVal++) {
SET_BIT2_EX(pBitMap, iVal, GET_BIT1(pColData->pBitMap, iVal) ? 2 : 1);
}
SET_BIT2_EX(pBitMap, pColData->nVal, 0);
tFree(pColData->pBitMap);
pColData->pBitMap = pBitMap;
return tColDataPutValue(pColData, NULL, 0);
}
static FORCE_INLINE int32_t tColDataAppendValue62(SColData *pColData, uint8_t *pData, uint32_t nData) {
int32_t code = 0;
code = tRealloc(&pColData->pBitMap, BIT1_SIZE(pColData->nVal + 1));
if (code) return code;
SET_BIT1_EX(pColData->pBitMap, pColData->nVal, 0);
pColData->numOfNull++;
return tColDataPutValue(pColData, NULL, 0);
}
static FORCE_INLINE int32_t tColDataAppendValue70(SColData *pColData, uint8_t *pData, uint32_t nData) {
int32_t code = 0;
code = tRealloc(&pColData->pBitMap, BIT2_SIZE(pColData->nVal + 1));
if (code) return code;
SET_BIT2_EX(pColData->pBitMap, pColData->nVal, 2);
pColData->numOfValue++;
return tColDataPutValue(pColData, pData, nData);
}
static FORCE_INLINE int32_t tColDataAppendValue71(SColData *pColData, uint8_t *pData, uint32_t nData) {
int32_t code = 0;
code = tRealloc(&pColData->pBitMap, BIT2_SIZE(pColData->nVal + 1));
if (code) return code;
SET_BIT2_EX(pColData->pBitMap, pColData->nVal, 0);
pColData->numOfNone++;
return tColDataPutValue(pColData, NULL, 0);
}
static FORCE_INLINE int32_t tColDataAppendValue72(SColData *pColData, uint8_t *pData, uint32_t nData) {
int32_t code = 0;
code = tRealloc(&pColData->pBitMap, BIT2_SIZE(pColData->nVal + 1));
if (code) return code;
SET_BIT2_EX(pColData->pBitMap, pColData->nVal, 1);
pColData->numOfNull++;
return tColDataPutValue(pColData, NULL, 0);
}
static int32_t (*tColDataAppendValueImpl[8][3])(SColData *pColData, uint8_t *pData, uint32_t nData) = {
{tColDataAppendValue00, tColDataAppendValue01, tColDataAppendValue02}, // 0
{tColDataAppendValue10, tColDataAppendValue11, tColDataAppendValue12}, // HAS_NONE
{tColDataAppendValue20, tColDataAppendValue21, tColDataAppendValue22}, // HAS_NULL
{tColDataAppendValue30, tColDataAppendValue31, tColDataAppendValue32}, // HAS_NULL|HAS_NONE
{tColDataAppendValue40, tColDataAppendValue41, tColDataAppendValue42}, // HAS_VALUE
{tColDataAppendValue50, tColDataAppendValue51, tColDataAppendValue52}, // HAS_VALUE|HAS_NONE
{tColDataAppendValue60, tColDataAppendValue61, tColDataAppendValue62}, // HAS_VALUE|HAS_NULL
{tColDataAppendValue70, tColDataAppendValue71, tColDataAppendValue72}, // HAS_VALUE|HAS_NULL|HAS_NONE
// VALUE NONE NULL
};
int32_t tColDataAppendValue(SColData *pColData, SColVal *pColVal) {
ASSERT(pColData->cid == pColVal->cid && pColData->type == pColVal->type);
return tColDataAppendValueImpl[pColData->flag][pColVal->flag](
pColData, IS_VAR_DATA_TYPE(pColData->type) ? pColVal->value.pData : (uint8_t *)&pColVal->value.val,
pColVal->value.nData);
}
static FORCE_INLINE int32_t tColDataUpdateValue10(SColData *pColData, uint8_t *pData, uint32_t nData, bool forward) {
pColData->numOfNone--;
pColData->nVal--;
if (pColData->numOfNone) {
return tColDataAppendValue10(pColData, pData, nData);
} else {
pColData->flag = 0;
return tColDataAppendValue00(pColData, pData, nData);
}
}
static FORCE_INLINE int32_t tColDataUpdateValue12(SColData *pColData, uint8_t *pData, uint32_t nData, bool forward) {
pColData->numOfNone--;
pColData->nVal--;
if (pColData->numOfNone) {
return tColDataAppendValue12(pColData, pData, nData);
} else {
pColData->flag = 0;
return tColDataAppendValue02(pColData, pData, nData);
}
return 0;
}
static FORCE_INLINE int32_t tColDataUpdateValue20(SColData *pColData, uint8_t *pData, uint32_t nData, bool forward) {
if (forward) {
pColData->numOfNull--;
pColData->nVal--;
if (pColData->numOfNull) {
return tColDataAppendValue20(pColData, pData, nData);
} else {
pColData->flag = 0;
return tColDataAppendValue00(pColData, pData, nData);
}
}
return 0;
}
static FORCE_INLINE int32_t tColDataUpdateValue30(SColData *pColData, uint8_t *pData, uint32_t nData, bool forward) {
if (GET_BIT1(pColData->pBitMap, pColData->nVal - 1) == 0) { // NONE ==> VALUE
pColData->numOfNone--;
pColData->nVal--;
if (pColData->numOfNone) {
return tColDataAppendValue30(pColData, pData, nData);
} else {
pColData->flag = HAS_NULL;
return tColDataAppendValue20(pColData, pData, nData);
}
} else if (forward) { // NULL ==> VALUE
pColData->numOfNull--;
pColData->nVal--;
if (pColData->numOfNull) {
return tColDataAppendValue30(pColData, pData, nData);
} else {
pColData->flag = HAS_NONE;
return tColDataAppendValue10(pColData, pData, nData);
}
}
return 0;
}
static FORCE_INLINE int32_t tColDataUpdateValue32(SColData *pColData, uint8_t *pData, uint32_t nData, bool forward) {
if (GET_BIT1(pColData->pBitMap, pColData->nVal - 1) == 0) { // NONE ==> NULL
pColData->numOfNone--;
pColData->numOfNull++;
if (pColData->numOfNone) {
SET_BIT1(pColData->pBitMap, pColData->nVal - 1, 1);
} else {
pColData->flag = HAS_NULL;
}
}
return 0;
}
static FORCE_INLINE int32_t tColDataUpdateValue40(SColData *pColData, uint8_t *pData, uint32_t nData, bool forward) {
if (forward) { // VALUE ==> VALUE
pColData->nVal--;
if (IS_VAR_DATA_TYPE(pColData->type)) {
pColData->nData = pColData->aOffset[pColData->nVal];
} else {
pColData->nData -= TYPE_BYTES[pColData->type];
}
return tColDataPutValue(pColData, pData, nData);
}
return 0;
}
static FORCE_INLINE int32_t tColDataUpdateValue42(SColData *pColData, uint8_t *pData, uint32_t nData, bool forward) {
if (forward) { // VALUE ==> NULL
pColData->numOfValue--;
pColData->nVal--;
if (pColData->numOfValue) {
if (IS_VAR_DATA_TYPE(pColData->type)) {
pColData->nData = pColData->aOffset[pColData->nVal];
} else {
pColData->nData -= TYPE_BYTES[pColData->type];
}
return tColDataAppendValue42(pColData, pData, nData);
} else {
pColData->flag = 0;
pColData->nData = 0;
return tColDataAppendValue02(pColData, pData, nData);
}
}
return 0;
}
static FORCE_INLINE int32_t tColDataUpdateValue50(SColData *pColData, uint8_t *pData, uint32_t nData, bool forward) {
if (GET_BIT1(pColData->pBitMap, pColData->nVal - 1) == 0) { // NONE ==> VALUE
pColData->numOfNone--;
pColData->nVal--;
if (!IS_VAR_DATA_TYPE(pColData->type)) {
pColData->nData -= TYPE_BYTES[pColData->type];
}
if (pColData->numOfNone) {
return tColDataAppendValue50(pColData, pData, nData);
} else {
pColData->flag = HAS_VALUE;
return tColDataAppendValue40(pColData, pData, nData);
}
} else if (forward) { // VALUE ==> VALUE
pColData->nVal--;
if (IS_VAR_DATA_TYPE(pColData->type)) {
pColData->nData = pColData->aOffset[pColData->nVal];
} else {
pColData->nData -= TYPE_BYTES[pColData->type];
}
return tColDataPutValue(pColData, pData, nData);
}
return 0;
}
static FORCE_INLINE int32_t tColDataUpdateValue52(SColData *pColData, uint8_t *pData, uint32_t nData, bool forward) {
if (GET_BIT1(pColData->pBitMap, pColData->nVal - 1) == 0) { // NONE ==> NULL
pColData->numOfNone--;
pColData->nVal--;
if (!IS_VAR_DATA_TYPE(pColData->type)) {
pColData->nData -= TYPE_BYTES[pColData->type];
}
if (pColData->numOfNone) {
return tColDataAppendValue52(pColData, pData, nData);
} else {
pColData->flag = HAS_VALUE;
return tColDataAppendValue42(pColData, pData, nData);
}
} else if (forward) { // VALUE ==> NULL
pColData->numOfValue--;
pColData->nVal--;
if (pColData->numOfValue) {
if (IS_VAR_DATA_TYPE(pColData->type)) {
pColData->nData = pColData->aOffset[pColData->nVal];
} else {
pColData->nData -= TYPE_BYTES[pColData->type];
}
return tColDataAppendValue52(pColData, pData, nData);
} else {
pColData->flag = HAS_NONE;
pColData->nData = 0;
return tColDataAppendValue12(pColData, pData, nData);
}
}
return 0;
}
static FORCE_INLINE int32_t tColDataUpdateValue60(SColData *pColData, uint8_t *pData, uint32_t nData, bool forward) {
if (forward) {
if (GET_BIT1(pColData->pBitMap, pColData->nVal - 1) == 0) { // NULL ==> VALUE
pColData->numOfNull--;
pColData->nVal--;
if (!IS_VAR_DATA_TYPE(pColData->type)) {
pColData->nData -= TYPE_BYTES[pColData->type];
}
if (pColData->numOfNull) {
return tColDataAppendValue60(pColData, pData, nData);
} else {
pColData->flag = HAS_VALUE;
return tColDataAppendValue40(pColData, pData, nData);
}
} else { // VALUE ==> VALUE
pColData->nVal--;
if (IS_VAR_DATA_TYPE(pColData->type)) {
pColData->nData = pColData->aOffset[pColData->nVal];
} else {
pColData->nData -= TYPE_BYTES[pColData->type];
}
return tColDataPutValue(pColData, pData, nData);
}
}
return 0;
}
static FORCE_INLINE int32_t tColDataUpdateValue62(SColData *pColData, uint8_t *pData, uint32_t nData, bool forward) {
if (forward && (GET_BIT1(pColData->pBitMap, pColData->nVal - 1) == 1)) { // VALUE ==> NULL
pColData->numOfValue--;
pColData->nVal--;
if (pColData->numOfValue) {
if (IS_VAR_DATA_TYPE(pColData->type)) {
pColData->nData = pColData->aOffset[pColData->nVal];
} else {
pColData->nData -= TYPE_BYTES[pColData->type];
}
return tColDataAppendValue62(pColData, pData, nData);
} else {
pColData->flag = HAS_NULL;
pColData->nData = 0;
return tColDataAppendValue20(pColData, pData, nData);
}
}
return 0;
}
static FORCE_INLINE int32_t tColDataUpdateValue70(SColData *pColData, uint8_t *pData, uint32_t nData, bool forward) {
int32_t code = 0;
uint8_t bv = GET_BIT2(pColData->pBitMap, pColData->nVal - 1);
if (bv == 0) { // NONE ==> VALUE
pColData->numOfNone--;
pColData->nVal--;
if (!IS_VAR_DATA_TYPE(pColData->type)) {
pColData->nData -= TYPE_BYTES[pColData->type];
}
if (pColData->numOfNone) {
return tColDataAppendValue70(pColData, pData, nData);
} else {
for (int32_t iVal = 0; iVal < pColData->nVal; ++iVal) {
SET_BIT1(pColData->pBitMap, iVal, GET_BIT2(pColData->pBitMap, iVal) - 1);
}
pColData->flag = (HAS_VALUE | HAS_NULL);
return tColDataAppendValue60(pColData, pData, nData);
}
} else if (bv == 1) { // NULL ==> VALUE
if (forward) {
pColData->numOfNull--;
pColData->nVal--;
if (!IS_VAR_DATA_TYPE(pColData->type)) {
pColData->nData -= TYPE_BYTES[pColData->type];
}
if (pColData->numOfNull) {
return tColDataAppendValue70(pColData, pData, nData);
} else {
for (int32_t iVal = 0; iVal < pColData->nVal; ++iVal) {
SET_BIT1(pColData->pBitMap, iVal, GET_BIT2(pColData->pBitMap, iVal) ? 1 : 0);
}
pColData->flag = (HAS_VALUE | HAS_NONE);
return tColDataAppendValue50(pColData, pData, nData);
}
}
} else if (bv == 2) { // VALUE ==> VALUE
if (forward) {
pColData->nVal--;
if (IS_VAR_DATA_TYPE(pColData->type)) {
pColData->nData = pColData->aOffset[pColData->nVal];
} else {
pColData->nData -= TYPE_BYTES[pColData->type];
}
return tColDataPutValue(pColData, pData, nData);
}
} else {
ASSERT(0);
}
return 0;
}
static int32_t tColDataUpdateValue72(SColData *pColData, uint8_t *pData, uint32_t nData, bool forward) {
uint8_t bv = GET_BIT2(pColData->pBitMap, pColData->nVal - 1);
if (bv == 0) { // NONE ==> NULL
pColData->numOfNone--;
pColData->nVal--;
if (!IS_VAR_DATA_TYPE(pColData->type)) {
pColData->nData -= TYPE_BYTES[pColData->type];
}
if (pColData->numOfNone) {
return tColDataAppendValue72(pColData, pData, nData);
} else {
for (int32_t iVal = 0; iVal < pColData->nVal; ++iVal) {
SET_BIT1(pColData->pBitMap, iVal, GET_BIT2(pColData->pBitMap, iVal) - 1);
}
pColData->flag = (HAS_VALUE | HAS_NULL);
return tColDataAppendValue62(pColData, pData, nData);
}
} else if (bv == 2 && forward) { // VALUE ==> NULL
pColData->numOfValue--;
pColData->nVal--;
if (pColData->numOfValue) {
if (IS_STR_DATA_TYPE(pColData->type)) {
pColData->nData = pColData->aOffset[pColData->nVal];
} else {
pColData->nData -= TYPE_BYTES[pColData->type];
}
return tColDataAppendValue72(pColData, pData, nData);
} else {
for (int32_t iVal = 0; iVal < pColData->nVal; ++iVal) {
SET_BIT1(pColData->pBitMap, iVal, GET_BIT2(pColData->pBitMap, iVal));
}
pColData->flag = (HAS_NULL | HAS_NONE);
pColData->nData = 0;
return tColDataAppendValue32(pColData, pData, nData);
}
}
return 0;
}
static FORCE_INLINE int32_t tColDataUpdateNothing(SColData *pColData, uint8_t *pData, uint32_t nData, bool forward) {
return 0;
}
static int32_t (*tColDataUpdateValueImpl[8][3])(SColData *pColData, uint8_t *pData, uint32_t nData, bool forward) = {
{NULL, NULL, NULL}, // 0
{tColDataUpdateValue10, tColDataUpdateNothing, tColDataUpdateValue12}, // HAS_NONE
{tColDataUpdateValue20, tColDataUpdateNothing, tColDataUpdateNothing}, // HAS_NULL
{tColDataUpdateValue30, tColDataUpdateNothing, tColDataUpdateValue32}, // HAS_NULL|HAS_NONE
{tColDataUpdateValue40, tColDataUpdateNothing, tColDataUpdateValue42}, // HAS_VALUE
{tColDataUpdateValue50, tColDataUpdateNothing, tColDataUpdateValue52}, // HAS_VALUE|HAS_NONE
{tColDataUpdateValue60, tColDataUpdateNothing, tColDataUpdateValue62}, // HAS_VALUE|HAS_NULL
{tColDataUpdateValue70, tColDataUpdateNothing, tColDataUpdateValue72}, // HAS_VALUE|HAS_NULL|HAS_NONE
// VALUE NONE NULL
};
int32_t tColDataUpdateValue(SColData *pColData, SColVal *pColVal, bool forward) {
ASSERT(pColData->cid == pColVal->cid && pColData->type == pColVal->type);
ASSERT(pColData->nVal > 0);
if (tColDataUpdateValueImpl[pColData->flag][pColVal->flag] == NULL) return 0;
return tColDataUpdateValueImpl[pColData->flag][pColVal->flag](
pColData, IS_VAR_DATA_TYPE(pColData->type) ? pColVal->value.pData : (uint8_t *)&pColVal->value.val,
pColVal->value.nData, forward);
}
static FORCE_INLINE void tColDataGetValue1(SColData *pColData, int32_t iVal, SColVal *pColVal) { // HAS_NONE
*pColVal = COL_VAL_NONE(pColData->cid, pColData->type);
}
static FORCE_INLINE void tColDataGetValue2(SColData *pColData, int32_t iVal, SColVal *pColVal) { // HAS_NULL
*pColVal = COL_VAL_NULL(pColData->cid, pColData->type);
}
static FORCE_INLINE void tColDataGetValue3(SColData *pColData, int32_t iVal,
SColVal *pColVal) { // HAS_NULL|HAS_NONE
switch (GET_BIT1(pColData->pBitMap, iVal)) {
case 0:
*pColVal = COL_VAL_NONE(pColData->cid, pColData->type);
break;
case 1:
*pColVal = COL_VAL_NULL(pColData->cid, pColData->type);
break;
default:
ASSERT(0);
}
}
static FORCE_INLINE void tColDataGetValue4(SColData *pColData, int32_t iVal, SColVal *pColVal) { // HAS_VALUE
SValue value;
if (IS_VAR_DATA_TYPE(pColData->type)) {
if (iVal + 1 < pColData->nVal) {
value.nData = pColData->aOffset[iVal + 1] - pColData->aOffset[iVal];
} else {
value.nData = pColData->nData - pColData->aOffset[iVal];
}
value.pData = pColData->pData + pColData->aOffset[iVal];
} else {
memcpy(&value.val, pColData->pData + tDataTypes[pColData->type].bytes * iVal, tDataTypes[pColData->type].bytes);
}
*pColVal = COL_VAL_VALUE(pColData->cid, pColData->type, value);
}
static FORCE_INLINE void tColDataGetValue5(SColData *pColData, int32_t iVal,
SColVal *pColVal) { // HAS_VALUE|HAS_NONE
switch (GET_BIT1(pColData->pBitMap, iVal)) {
case 0:
*pColVal = COL_VAL_NONE(pColData->cid, pColData->type);
break;
case 1:
tColDataGetValue4(pColData, iVal, pColVal);
break;
default:
ASSERT(0);
}
}
static FORCE_INLINE void tColDataGetValue6(SColData *pColData, int32_t iVal,
SColVal *pColVal) { // HAS_VALUE|HAS_NULL
switch (GET_BIT1(pColData->pBitMap, iVal)) {
case 0:
*pColVal = COL_VAL_NULL(pColData->cid, pColData->type);
break;
case 1:
tColDataGetValue4(pColData, iVal, pColVal);
break;
default:
ASSERT(0);
}
}
static FORCE_INLINE void tColDataGetValue7(SColData *pColData, int32_t iVal,
SColVal *pColVal) { // HAS_VALUE|HAS_NULL|HAS_NONE
switch (GET_BIT2(pColData->pBitMap, iVal)) {
case 0:
*pColVal = COL_VAL_NONE(pColData->cid, pColData->type);
break;
case 1:
*pColVal = COL_VAL_NULL(pColData->cid, pColData->type);
break;
case 2:
tColDataGetValue4(pColData, iVal, pColVal);
break;
default:
ASSERT(0);
}
}
static void (*tColDataGetValueImpl[])(SColData *pColData, int32_t iVal, SColVal *pColVal) = {
NULL, // 0
tColDataGetValue1, // HAS_NONE
tColDataGetValue2, // HAS_NULL
tColDataGetValue3, // HAS_NULL | HAS_NONE
tColDataGetValue4, // HAS_VALUE
tColDataGetValue5, // HAS_VALUE | HAS_NONE
tColDataGetValue6, // HAS_VALUE | HAS_NULL
tColDataGetValue7 // HAS_VALUE | HAS_NULL | HAS_NONE
};
void tColDataGetValue(SColData *pColData, int32_t iVal, SColVal *pColVal) {
ASSERT(iVal >= 0 && iVal < pColData->nVal && pColData->flag);
tColDataGetValueImpl[pColData->flag](pColData, iVal, pColVal);
}
uint8_t tColDataGetBitValue(const SColData *pColData, int32_t iVal) {
switch (pColData->flag) {
case HAS_NONE:
return 0;
case HAS_NULL:
return 1;
case (HAS_NULL | HAS_NONE):
return GET_BIT1(pColData->pBitMap, iVal);
case HAS_VALUE:
return 2;
case (HAS_VALUE | HAS_NONE):
return (GET_BIT1(pColData->pBitMap, iVal)) ? 2 : 0;
case (HAS_VALUE | HAS_NULL):
return GET_BIT1(pColData->pBitMap, iVal) + 1;
case (HAS_VALUE | HAS_NULL | HAS_NONE):
return GET_BIT2(pColData->pBitMap, iVal);
default:
ASSERTS(0, "not possible");
return 0;
}
}
int32_t tColDataCopy(SColData *pColDataFrom, SColData *pColData, xMallocFn xMalloc, void *arg) {
int32_t code = 0;
*pColData = *pColDataFrom;
// bitmap
switch (pColData->flag) {
case (HAS_NULL | HAS_NONE):
case (HAS_VALUE | HAS_NONE):
case (HAS_VALUE | HAS_NULL):
pColData->pBitMap = xMalloc(arg, BIT1_SIZE(pColData->nVal));
if (pColData->pBitMap == NULL) {
code = TSDB_CODE_OUT_OF_MEMORY;
goto _exit;
}
memcpy(pColData->pBitMap, pColDataFrom->pBitMap, BIT1_SIZE(pColData->nVal));
break;
case (HAS_VALUE | HAS_NULL | HAS_NONE):
pColData->pBitMap = xMalloc(arg, BIT2_SIZE(pColData->nVal));
if (pColData->pBitMap == NULL) {
code = TSDB_CODE_OUT_OF_MEMORY;
goto _exit;
}
memcpy(pColData->pBitMap, pColDataFrom->pBitMap, BIT2_SIZE(pColData->nVal));
break;
default:
pColData->pBitMap = NULL;
break;
}
// offset
if (IS_VAR_DATA_TYPE(pColData->type) && (pColData->flag & HAS_VALUE)) {
pColData->aOffset = xMalloc(arg, pColData->nVal << 2);
if (pColData->aOffset == NULL) {
code = TSDB_CODE_OUT_OF_MEMORY;
goto _exit;
}
memcpy(pColData->aOffset, pColDataFrom->aOffset, pColData->nVal << 2);
} else {
pColData->aOffset = NULL;
}
// value
if (pColData->nData) {
pColData->pData = xMalloc(arg, pColData->nData);
if (pColData->pData == NULL) {
code = TSDB_CODE_OUT_OF_MEMORY;
goto _exit;
}
memcpy(pColData->pData, pColDataFrom->pData, pColData->nData);
} else {
pColData->pData = NULL;
}
_exit:
return code;
}
int32_t tColDataAddValueByDataBlock(SColData *pColData, int8_t type, int32_t bytes, int32_t nRows, char *lengthOrbitmap,
char *data) {
int32_t code = 0;
if (data == NULL) {
for (int32_t i = 0; i < nRows; ++i) {
code = tColDataAppendValueImpl[pColData->flag][CV_FLAG_NONE](pColData, NULL, 0);
}
goto _exit;
}
if (IS_VAR_DATA_TYPE(type)) { // var-length data type
for (int32_t i = 0; i < nRows; ++i) {
int32_t offset = *((int32_t *)lengthOrbitmap + i);
if (offset == -1) {
code = tColDataAppendValueImpl[pColData->flag][CV_FLAG_NULL](pColData, NULL, 0);
if (code) goto _exit;
} else {
if (varDataTLen(data + offset) > bytes) {
uError("var data length invalid, varDataTLen(data + offset):%d <= bytes:%d", (int)varDataTLen(data + offset),
bytes);
code = TSDB_CODE_PAR_VALUE_TOO_LONG;
goto _exit;
}
code = tColDataAppendValueImpl[pColData->flag][CV_FLAG_VALUE](pColData, (uint8_t *)varDataVal(data + offset),
varDataLen(data + offset));
}
}
} else { // fixed-length data type
bool allValue = true;
bool allNull = true;
for (int32_t i = 0; i < nRows; ++i) {
if (!colDataIsNull_f(lengthOrbitmap, i)) {
allNull = false;
} else {
allValue = false;
}
}
if (allValue) {
// optimize (todo)
for (int32_t i = 0; i < nRows; ++i) {
code = tColDataAppendValueImpl[pColData->flag][CV_FLAG_VALUE](pColData, (uint8_t *)data + bytes * i, bytes);
}
} else if (allNull) {
// optimize (todo)
for (int32_t i = 0; i < nRows; ++i) {
code = tColDataAppendValueImpl[pColData->flag][CV_FLAG_NULL](pColData, NULL, 0);
if (code) goto _exit;
}
} else {
for (int32_t i = 0; i < nRows; ++i) {
if (colDataIsNull_f(lengthOrbitmap, i)) {
code = tColDataAppendValueImpl[pColData->flag][CV_FLAG_NULL](pColData, NULL, 0);
if (code) goto _exit;
} else {
code = tColDataAppendValueImpl[pColData->flag][CV_FLAG_VALUE](pColData, (uint8_t *)data + bytes * i, bytes);
}
}
}
}
_exit:
return code;
}
int32_t tColDataAddValueByBind(SColData *pColData, TAOS_MULTI_BIND *pBind, int32_t buffMaxLen) {
int32_t code = 0;
if (!(pBind->num == 1 && pBind->is_null && *pBind->is_null)) {
ASSERT(pColData->type == pBind->buffer_type);
}
if (IS_VAR_DATA_TYPE(pColData->type)) { // var-length data type
for (int32_t i = 0; i < pBind->num; ++i) {
if (pBind->is_null && pBind->is_null[i]) {
code = tColDataAppendValueImpl[pColData->flag][CV_FLAG_NULL](pColData, NULL, 0);
if (code) goto _exit;
} else if (pBind->length[i] > buffMaxLen) {
uError("var data length too big, len:%d, max:%d", pBind->length[i], buffMaxLen);
return TSDB_CODE_INVALID_PARA;
} else {
code = tColDataAppendValueImpl[pColData->flag][CV_FLAG_VALUE](
pColData, (uint8_t *)pBind->buffer + pBind->buffer_length * i, pBind->length[i]);
}
}
} else { // fixed-length data type
bool allValue;
bool allNull;
if (pBind->is_null) {
bool same = (memcmp(pBind->is_null, pBind->is_null + 1, pBind->num - 1) == 0);
allNull = (same && pBind->is_null[0] != 0);
allValue = (same && pBind->is_null[0] == 0);
} else {
allNull = false;
allValue = true;
}
if (allValue) {
// optimize (todo)
for (int32_t i = 0; i < pBind->num; ++i) {
code = tColDataAppendValueImpl[pColData->flag][CV_FLAG_VALUE](
pColData, (uint8_t *)pBind->buffer + TYPE_BYTES[pColData->type] * i, pBind->buffer_length);
}
} else if (allNull) {
// optimize (todo)
for (int32_t i = 0; i < pBind->num; ++i) {
code = tColDataAppendValueImpl[pColData->flag][CV_FLAG_NULL](pColData, NULL, 0);
if (code) goto _exit;
}
} else {
for (int32_t i = 0; i < pBind->num; ++i) {
if (pBind->is_null[i]) {
code = tColDataAppendValueImpl[pColData->flag][CV_FLAG_NULL](pColData, NULL, 0);
if (code) goto _exit;
} else {
code = tColDataAppendValueImpl[pColData->flag][CV_FLAG_VALUE](
pColData, (uint8_t *)pBind->buffer + TYPE_BYTES[pColData->type] * i, pBind->buffer_length);
}
}
}
}
_exit:
return code;
}
static int32_t tColDataSwapValue(SColData *pColData, int32_t i, int32_t j) {
int32_t code = 0;
if (IS_VAR_DATA_TYPE(pColData->type)) {
int32_t nData1 = pColData->aOffset[i + 1] - pColData->aOffset[i];
int32_t nData2 = (j < pColData->nVal - 1) ? pColData->aOffset[j + 1] - pColData->aOffset[j]
: pColData->nData - pColData->aOffset[j];
uint8_t *pData = taosMemoryMalloc(TMAX(nData1, nData2));
if (pData == NULL) {
code = TSDB_CODE_OUT_OF_MEMORY;
goto _exit;
}
if (nData1 > nData2) {
memcpy(pData, pColData->pData + pColData->aOffset[i], nData1);
memcpy(pColData->pData + pColData->aOffset[i], pColData->pData + pColData->aOffset[j], nData2);
// memmove(pColData->pData + pColData->aOffset[i] + nData2, pColData->pData + pColData->aOffset[i] + nData1,
// pColData->aOffset[j] - pColData->aOffset[i + 1]);
memmove(pColData->pData + pColData->aOffset[i] + nData2, pColData->pData + pColData->aOffset[i + 1],
pColData->aOffset[j] - pColData->aOffset[i + 1]);
memcpy(pColData->pData + pColData->aOffset[j] + nData2 - nData1, pData, nData1);
} else {
memcpy(pData, pColData->pData + pColData->aOffset[j], nData2);
memcpy(pColData->pData + pColData->aOffset[j] + nData2 - nData1, pColData->pData + pColData->aOffset[i], nData1);
// memmove(pColData->pData + pColData->aOffset[j] + nData2 - nData1, pColData->pData + pColData->aOffset[i] +
// nData1,
// pColData->aOffset[j] - pColData->aOffset[i + 1]);
memmove(pColData->pData + pColData->aOffset[i] + nData2, pColData->pData + pColData->aOffset[i + 1],
pColData->aOffset[j] - pColData->aOffset[i + 1]);
memcpy(pColData->pData + pColData->aOffset[i], pData, nData2);
}
for (int32_t k = i + 1; k <= j; ++k) {
pColData->aOffset[k] = pColData->aOffset[k] + nData2 - nData1;
}
taosMemoryFree(pData);
} else {
uint64_t val;
memcpy(&val, &pColData->pData[TYPE_BYTES[pColData->type] * i], TYPE_BYTES[pColData->type]);
memcpy(&pColData->pData[TYPE_BYTES[pColData->type] * i], &pColData->pData[TYPE_BYTES[pColData->type] * j],
TYPE_BYTES[pColData->type]);
memcpy(&pColData->pData[TYPE_BYTES[pColData->type] * j], &val, TYPE_BYTES[pColData->type]);
}
_exit:
return code;
}
static void tColDataSwap(SColData *pColData, int32_t i, int32_t j) {
ASSERT(i < j);
ASSERT(j < pColData->nVal);
switch (pColData->flag) {
case HAS_NONE:
case HAS_NULL:
break;
case (HAS_NULL | HAS_NONE): {
uint8_t bv = GET_BIT1(pColData->pBitMap, i);
SET_BIT1(pColData->pBitMap, i, GET_BIT1(pColData->pBitMap, j));
SET_BIT1(pColData->pBitMap, j, bv);
} break;
case HAS_VALUE: {
tColDataSwapValue(pColData, i, j);
} break;
case (HAS_VALUE | HAS_NONE):
case (HAS_VALUE | HAS_NULL): {
uint8_t bv = GET_BIT1(pColData->pBitMap, i);
SET_BIT1(pColData->pBitMap, i, GET_BIT1(pColData->pBitMap, j));
SET_BIT1(pColData->pBitMap, j, bv);
tColDataSwapValue(pColData, i, j);
} break;
case (HAS_VALUE | HAS_NULL | HAS_NONE): {
uint8_t bv = GET_BIT2(pColData->pBitMap, i);
SET_BIT2(pColData->pBitMap, i, GET_BIT2(pColData->pBitMap, j));
SET_BIT2(pColData->pBitMap, j, bv);
tColDataSwapValue(pColData, i, j);
} break;
default:
ASSERT(0);
break;
}
}
static int32_t tColDataCopyRowCell(SColData *pFromColData, int32_t iFromRow, SColData *pToColData, int32_t iToRow) {
int32_t code = TSDB_CODE_SUCCESS;
if (IS_VAR_DATA_TYPE(pToColData->type)) {
int32_t nData = (iFromRow < pFromColData->nVal - 1)
? pFromColData->aOffset[iFromRow + 1] - pFromColData->aOffset[iFromRow]
: pFromColData->nData - pFromColData->aOffset[iFromRow];
if (iToRow == 0) {
pToColData->aOffset[iToRow] = 0;
}
if (iToRow < pToColData->nVal - 1) {
pToColData->aOffset[iToRow + 1] = pToColData->aOffset[iToRow] + nData;
}
memcpy(pToColData->pData + pToColData->aOffset[iToRow], pFromColData->pData + pFromColData->aOffset[iFromRow],
nData);
} else {
memcpy(&pToColData->pData[TYPE_BYTES[pToColData->type] * iToRow],
&pFromColData->pData[TYPE_BYTES[pToColData->type] * iFromRow], TYPE_BYTES[pToColData->type]);
}
return code;
}
static int32_t tColDataCopyRowSingleCol(SColData *pFromColData, int32_t iFromRow, SColData *pToColData,
int32_t iToRow) {
int32_t code = TSDB_CODE_SUCCESS;
switch (pFromColData->flag) {
case HAS_NONE:
case HAS_NULL:
break;
case (HAS_NULL | HAS_NONE): {
SET_BIT1(pToColData->pBitMap, iToRow, GET_BIT1(pFromColData->pBitMap, iFromRow));
} break;
case HAS_VALUE: {
tColDataCopyRowCell(pFromColData, iFromRow, pToColData, iToRow);
} break;
case (HAS_VALUE | HAS_NONE):
case (HAS_VALUE | HAS_NULL): {
SET_BIT1(pToColData->pBitMap, iToRow, GET_BIT1(pFromColData->pBitMap, iFromRow));
tColDataCopyRowCell(pFromColData, iFromRow, pToColData, iToRow);
} break;
case (HAS_VALUE | HAS_NULL | HAS_NONE): {
SET_BIT2(pToColData->pBitMap, iToRow, GET_BIT2(pFromColData->pBitMap, iFromRow));
tColDataCopyRowCell(pFromColData, iFromRow, pToColData, iToRow);
} break;
default:
return -1;
}
return code;
}
static int32_t tColDataCopyRow(SColData *aFromColData, int32_t iFromRow, SColData *aToColData, int32_t iToRow,
int32_t nColData) {
int32_t code = TSDB_CODE_SUCCESS;
for (int32_t i = 0; i < nColData; i++) {
code = tColDataCopyRowSingleCol(&aFromColData[i], iFromRow, &aToColData[i], iToRow);
if (code != TSDB_CODE_SUCCESS) {
return code;
}
}
return code;
}
static int32_t tColDataCopyRowAppend(SColData *aFromColData, int32_t iFromRow, SColData *aToColData, int32_t nColData) {
int32_t code = TSDB_CODE_SUCCESS;
for (int32_t i = 0; i < nColData; i++) {
SColVal cv = {0};
tColDataGetValue(&aFromColData[i], iFromRow, &cv);
code = tColDataAppendValue(&aToColData[i], &cv);
if (code != TSDB_CODE_SUCCESS) {
return code;
}
}
return code;
}
static int32_t tColDataMergeSortMerge(SColData *aColData, int32_t start, int32_t mid, int32_t end, int32_t nColData) {
SColData *aDstColData = NULL;
TSKEY *aKey = (TSKEY *)aColData[0].pData;
int32_t i = start, j = mid + 1, k = 0;
if (end > start) {
aDstColData = taosMemoryCalloc(1, sizeof(SColData) * nColData);
for (int c = 0; c < nColData; ++c) {
tColDataInit(&aDstColData[c], aColData[c].cid, aColData[c].type, aColData[c].smaOn);
}
if (aDstColData == NULL) {
return TSDB_CODE_OUT_OF_MEMORY;
}
/*
for (int32_t i = 0; i < nColData; i++) {
tColDataCopy(&aColData[i], &aDstColData[i], tColDataDefaultMalloc, NULL);
}
*/
}
while (i <= mid && j <= end) {
if (aKey[i] <= aKey[j]) {
// tColDataCopyRow(aColData, i++, aDstColData, k++);
tColDataCopyRowAppend(aColData, i++, aDstColData, nColData);
} else {
// tColDataCopyRow(aColData, j++, aDstColData, k++);
tColDataCopyRowAppend(aColData, j++, aDstColData, nColData);
}
}
while (i <= mid) {
// tColDataCopyRow(aColData, i++, aDstColData, k++);
tColDataCopyRowAppend(aColData, i++, aDstColData, nColData);
}
while (j <= end) {
// tColDataCopyRow(aColData, j++, aDstColData, k++);
tColDataCopyRowAppend(aColData, j++, aDstColData, nColData);
}
for (i = start, k = 0; i <= end; ++i, ++k) {
tColDataCopyRow(aDstColData, k, aColData, i, nColData);
}
if (aDstColData) {
for (int32_t i = 0; i < nColData; i++) {
tColDataDestroy(&aDstColData[i]);
}
taosMemoryFree(aDstColData);
}
return TSDB_CODE_SUCCESS;
}
static int32_t tColDataMergeSort(SColData *aColData, int32_t start, int32_t end, int32_t nColData) {
int32_t ret = TSDB_CODE_SUCCESS;
int32_t mid;
if (start >= end) {
return TSDB_CODE_SUCCESS;
}
mid = (start + end) / 2;
ret = tColDataMergeSort(aColData, start, mid, nColData);
if (ret != TSDB_CODE_SUCCESS) {
return ret;
}
ret = tColDataMergeSort(aColData, mid + 1, end, nColData);
if (ret != TSDB_CODE_SUCCESS) {
return ret;
}
return tColDataMergeSortMerge(aColData, start, mid, end, nColData);
}
static int32_t tColDataSort(SColData *aColData, int32_t nColData) {
int32_t nVal = aColData[0].nVal;
if (nVal < 2) return TSDB_CODE_SUCCESS;
return tColDataMergeSort(aColData, 0, nVal - 1, nColData);
}
static void tColDataMergeImpl(SColData *pColData, int32_t iStart, int32_t iEnd /* not included */) {
switch (pColData->flag) {
case HAS_NONE:
case HAS_NULL: {
pColData->nVal -= (iEnd - iStart - 1);
} break;
case (HAS_NULL | HAS_NONE): {
if (GET_BIT1(pColData->pBitMap, iStart) == 0) {
for (int32_t i = iStart + 1; i < iEnd; ++i) {
if (GET_BIT1(pColData->pBitMap, i) == 1) {
SET_BIT1(pColData->pBitMap, iStart, 1);
break;
}
}
}
for (int32_t i = iEnd, j = iStart + 1; i < pColData->nVal; ++i, ++j) {
SET_BIT1(pColData->pBitMap, j, GET_BIT1(pColData->pBitMap, i));
}
pColData->nVal -= (iEnd - iStart - 1);
uint8_t flag = 0;
for (int32_t i = 0; i < pColData->nVal; ++i) {
uint8_t bv = GET_BIT1(pColData->pBitMap, i);
if (bv == BIT_FLG_NONE) {
flag |= HAS_NONE;
} else if (bv == BIT_FLG_NULL) {
flag |= HAS_NULL;
} else {
ASSERT(0);
}
if (flag == pColData->flag) break;
}
pColData->flag = flag;
} break;
case HAS_VALUE: {
if (IS_VAR_DATA_TYPE(pColData->type)) {
int32_t nDiff = pColData->aOffset[iEnd - 1] - pColData->aOffset[iStart];
memmove(pColData->pData + pColData->aOffset[iStart], pColData->pData + pColData->aOffset[iEnd - 1],
pColData->nData - pColData->aOffset[iEnd - 1]);
pColData->nData -= nDiff;
for (int32_t i = iEnd, j = iStart + 1; i < pColData->nVal; ++i, ++j) {
pColData->aOffset[j] = pColData->aOffset[i] - nDiff;
}
} else {
memmove(pColData->pData + TYPE_BYTES[pColData->type] * iStart,
pColData->pData + TYPE_BYTES[pColData->type] * (iEnd - 1),
TYPE_BYTES[pColData->type] * (pColData->nVal - iEnd + 1));
pColData->nData -= (TYPE_BYTES[pColData->type] * (iEnd - iStart - 1));
}
pColData->nVal -= (iEnd - iStart - 1);
} break;
case (HAS_VALUE | HAS_NONE): {
uint8_t bv;
int32_t iv;
for (int32_t i = iEnd - 1; i >= iStart; --i) {
bv = GET_BIT1(pColData->pBitMap, i);
if (bv) {
iv = i;
break;
}
}
if (bv) { // has a value
if (IS_VAR_DATA_TYPE(pColData->type)) {
if (iv != iStart) {
memmove(&pColData->pData[pColData->aOffset[iStart]], &pColData->pData[pColData->aOffset[iv]],
iv < (pColData->nVal - 1) ? pColData->aOffset[iv + 1] - pColData->aOffset[iv]
: pColData->nData - pColData->aOffset[iv]);
}
// TODO
ASSERT(0);
} else {
if (iv != iStart) {
memcpy(&pColData->pData[TYPE_BYTES[pColData->type] * iStart],
&pColData->pData[TYPE_BYTES[pColData->type] * iv], TYPE_BYTES[pColData->type]);
}
memmove(&pColData->pData[TYPE_BYTES[pColData->type] * (iStart + 1)],
&pColData->pData[TYPE_BYTES[pColData->type] * iEnd],
TYPE_BYTES[pColData->type] * (iEnd - iStart - 1));
pColData->nData -= (TYPE_BYTES[pColData->type] * (iEnd - iStart - 1));
}
SET_BIT1(pColData->pBitMap, iStart, 1);
for (int32_t i = iEnd, j = iStart + 1; i < pColData->nVal; ++i, ++j) {
SET_BIT1(pColData->pBitMap, j, GET_BIT1(pColData->pBitMap, i));
}
uint8_t flag = HAS_VALUE;
for (int32_t i = 0; i < pColData->nVal - (iEnd - iStart - 1); ++i) {
if (GET_BIT1(pColData->pBitMap, i) == 0) {
flag |= HAS_NONE;
}
if (flag == pColData->flag) break;
}
pColData->flag = flag;
} else { // all NONE
if (IS_VAR_DATA_TYPE(pColData->type)) {
int32_t nDiff = pColData->aOffset[iEnd - 1] - pColData->aOffset[iStart];
memmove(&pColData->pData[pColData->aOffset[iStart]], &pColData->pData[pColData->aOffset[iEnd - 1]],
pColData->nData - pColData->aOffset[iEnd - 1]);
pColData->nData -= nDiff;
for (int32_t i = iEnd, j = iStart + 1; i < pColData->nVal; ++i, ++j) {
pColData->aOffset[j] = pColData->aOffset[i] - nDiff;
}
} else {
memmove(pColData->pData + TYPE_BYTES[pColData->type] * (iStart + 1),
pColData->pData + TYPE_BYTES[pColData->type] * iEnd,
TYPE_BYTES[pColData->type] * (pColData->nVal - iEnd + 1));
pColData->nData -= (TYPE_BYTES[pColData->type] * (iEnd - iStart - 1));
}
for (int32_t i = iEnd, j = iStart + 1; i < pColData->nVal; ++i, ++j) {
SET_BIT1(pColData->pBitMap, j, GET_BIT1(pColData->pBitMap, i));
}
}
pColData->nVal -= (iEnd - iStart - 1);
} break;
case (HAS_VALUE | HAS_NULL): {
if (IS_VAR_DATA_TYPE(pColData->type)) {
int32_t nDiff = pColData->aOffset[iEnd - 1] - pColData->aOffset[iStart];
memmove(pColData->pData + pColData->aOffset[iStart], pColData->pData + pColData->aOffset[iEnd - 1],
pColData->nData - pColData->aOffset[iEnd - 1]);
pColData->nData -= nDiff;
for (int32_t i = iEnd, j = iStart + 1; i < pColData->nVal; ++i, ++j) {
pColData->aOffset[j] = pColData->aOffset[i] - nDiff;
}
} else {
memmove(pColData->pData + TYPE_BYTES[pColData->type] * iStart,
pColData->pData + TYPE_BYTES[pColData->type] * (iEnd - 1),
TYPE_BYTES[pColData->type] * (pColData->nVal - iEnd + 1));
pColData->nData -= (TYPE_BYTES[pColData->type] * (iEnd - iStart - 1));
}
for (int32_t i = iEnd - 1, j = iStart; i < pColData->nVal; ++i, ++j) {
SET_BIT1(pColData->pBitMap, j, GET_BIT1(pColData->pBitMap, i));
}
pColData->nVal -= (iEnd - iStart - 1);
uint8_t flag = 0;
for (int32_t i = 0; i < pColData->nVal; ++i) {
if (GET_BIT1(pColData->pBitMap, i)) {
flag |= HAS_VALUE;
} else {
flag |= HAS_NULL;
}
if (flag == pColData->flag) break;
}
pColData->flag = flag;
} break;
case (HAS_VALUE | HAS_NULL | HAS_NONE): {
uint8_t bv;
int32_t iv;
for (int32_t i = iEnd - 1; i >= iStart; --i) {
bv = GET_BIT2(pColData->pBitMap, i);
if (bv) {
iv = i;
break;
}
}
if (bv) {
// TODO
ASSERT(0);
} else { // ALL NONE
if (IS_VAR_DATA_TYPE(pColData->type)) {
// TODO
ASSERT(0);
} else {
memmove(pColData->pData + TYPE_BYTES[pColData->type] * (iStart + 1),
pColData->pData + TYPE_BYTES[pColData->type] * iEnd,
TYPE_BYTES[pColData->type] * (pColData->nVal - iEnd));
pColData->nData -= (TYPE_BYTES[pColData->type] * (iEnd - iStart - 1));
}
for (int32_t i = iEnd, j = iStart + 1; i < pColData->nVal; ++i, ++j) {
SET_BIT2(pColData->pBitMap, j, GET_BIT2(pColData->pBitMap, i));
}
}
pColData->nVal -= (iEnd - iStart - 1);
} break;
default:
ASSERT(0);
break;
}
}
static void tColDataMerge(SColData *aColData, int32_t nColData) {
int32_t iStart = 0;
for (;;) {
if (iStart >= aColData[0].nVal - 1) break;
int32_t iEnd = iStart + 1;
while (iEnd < aColData[0].nVal) {
if (((TSKEY *)aColData[0].pData)[iEnd] != ((TSKEY *)aColData[0].pData)[iStart]) break;
iEnd++;
}
if (iEnd - iStart > 1) {
for (int32_t i = 0; i < nColData; i++) {
tColDataMergeImpl(&aColData[i], iStart, iEnd);
}
}
iStart++;
}
}
void tColDataSortMerge(SArray *colDataArr) {
int32_t nColData = TARRAY_SIZE(colDataArr);
SColData *aColData = (SColData *)TARRAY_DATA(colDataArr);
if (aColData[0].nVal <= 1) goto _exit;
ASSERT(aColData[0].type == TSDB_DATA_TYPE_TIMESTAMP);
ASSERT(aColData[0].cid == PRIMARYKEY_TIMESTAMP_COL_ID);
ASSERT(aColData[0].flag == HAS_VALUE);
int8_t doSort = 0;
int8_t doMerge = 0;
// scan -------
TSKEY *aKey = (TSKEY *)aColData[0].pData;
for (int32_t iVal = 1; iVal < aColData[0].nVal; ++iVal) {
if (aKey[iVal] > aKey[iVal - 1]) {
continue;
} else if (aKey[iVal] < aKey[iVal - 1]) {
doSort = 1;
break;
} else {
doMerge = 1;
}
}
// sort -------
if (doSort) {
tColDataSort(aColData, nColData);
}
if (doMerge != 1) {
for (int32_t iVal = 1; iVal < aColData[0].nVal; ++iVal) {
if (aKey[iVal] == aKey[iVal - 1]) {
doMerge = 1;
break;
}
}
}
// merge -------
if (doMerge) {
tColDataMerge(aColData, nColData);
}
_exit:
return;
}
int32_t tPutColData(uint8_t *pBuf, SColData *pColData) {
int32_t n = 0;
n += tPutI16v(pBuf ? pBuf + n : NULL, pColData->cid);
n += tPutI8(pBuf ? pBuf + n : NULL, pColData->type);
n += tPutI32v(pBuf ? pBuf + n : NULL, pColData->nVal);
n += tPutI8(pBuf ? pBuf + n : NULL, pColData->flag);
// bitmap
switch (pColData->flag) {
case (HAS_NULL | HAS_NONE):
case (HAS_VALUE | HAS_NONE):
case (HAS_VALUE | HAS_NULL):
if (pBuf) memcpy(pBuf + n, pColData->pBitMap, BIT1_SIZE(pColData->nVal));
n += BIT1_SIZE(pColData->nVal);
break;
case (HAS_VALUE | HAS_NULL | HAS_NONE):
if (pBuf) memcpy(pBuf + n, pColData->pBitMap, BIT2_SIZE(pColData->nVal));
n += BIT2_SIZE(pColData->nVal);
break;
default:
break;
}
// value
if (pColData->flag & HAS_VALUE) {
if (IS_VAR_DATA_TYPE(pColData->type)) {
if (pBuf) memcpy(pBuf + n, pColData->aOffset, pColData->nVal << 2);
n += (pColData->nVal << 2);
n += tPutI32v(pBuf ? pBuf + n : NULL, pColData->nData);
if (pBuf) memcpy(pBuf + n, pColData->pData, pColData->nData);
n += pColData->nData;
} else {
if (pBuf) memcpy(pBuf + n, pColData->pData, pColData->nData);
n += pColData->nData;
}
}
return n;
}
int32_t tGetColData(uint8_t *pBuf, SColData *pColData) {
int32_t n = 0;
n += tGetI16v(pBuf + n, &pColData->cid);
n += tGetI8(pBuf + n, &pColData->type);
n += tGetI32v(pBuf + n, &pColData->nVal);
n += tGetI8(pBuf + n, &pColData->flag);
// bitmap
switch (pColData->flag) {
case (HAS_NULL | HAS_NONE):
case (HAS_VALUE | HAS_NONE):
case (HAS_VALUE | HAS_NULL):
pColData->pBitMap = pBuf + n;
n += BIT1_SIZE(pColData->nVal);
break;
case (HAS_VALUE | HAS_NULL | HAS_NONE):
pColData->pBitMap = pBuf + n;
n += BIT2_SIZE(pColData->nVal);
break;
default:
break;
}
// value
if (pColData->flag & HAS_VALUE) {
if (IS_VAR_DATA_TYPE(pColData->type)) {
pColData->aOffset = (int32_t *)(pBuf + n);
n += (pColData->nVal << 2);
n += tGetI32v(pBuf + n, &pColData->nData);
pColData->pData = pBuf + n;
n += pColData->nData;
} else {
pColData->pData = pBuf + n;
pColData->nData = TYPE_BYTES[pColData->type] * pColData->nVal;
n += pColData->nData;
}
}
return n;
}
#define CALC_SUM_MAX_MIN(SUM, MAX, MIN, VAL) \
do { \
(SUM) += (VAL); \
if ((MAX) < (VAL)) (MAX) = (VAL); \
if ((MIN) > (VAL)) (MIN) = (VAL); \
} while (0)
static FORCE_INLINE void tColDataCalcSMABool(SColData *pColData, int64_t *sum, int64_t *max, int64_t *min,
int16_t *numOfNull) {
*sum = 0;
*max = 0;
*min = 1;
*numOfNull = 0;
int8_t val;
if (HAS_VALUE == pColData->flag) {
for (int32_t iVal = 0; iVal < pColData->nVal; iVal++) {
val = ((int8_t *)pColData->pData)[iVal] ? 1 : 0;
CALC_SUM_MAX_MIN(*sum, *max, *min, val);
}
} else {
for (int32_t iVal = 0; iVal < pColData->nVal; iVal++) {
switch (tColDataGetBitValue(pColData, iVal)) {
case 0:
case 1:
(*numOfNull)++;
break;
case 2:
val = ((int8_t *)pColData->pData)[iVal] ? 1 : 0;
CALC_SUM_MAX_MIN(*sum, *max, *min, val);
break;
default:
ASSERT(0);
break;
}
}
}
}
static FORCE_INLINE void tColDataCalcSMATinyInt(SColData *pColData, int64_t *sum, int64_t *max, int64_t *min,
int16_t *numOfNull) {
*sum = 0;
*max = INT8_MIN;
*min = INT8_MAX;
*numOfNull = 0;
int8_t val;
if (HAS_VALUE == pColData->flag) {
for (int32_t iVal = 0; iVal < pColData->nVal; iVal++) {
val = ((int8_t *)pColData->pData)[iVal];
CALC_SUM_MAX_MIN(*sum, *max, *min, val);
}
} else {
for (int32_t iVal = 0; iVal < pColData->nVal; iVal++) {
switch (tColDataGetBitValue(pColData, iVal)) {
case 0:
case 1:
(*numOfNull)++;
break;
case 2:
val = ((int8_t *)pColData->pData)[iVal];
CALC_SUM_MAX_MIN(*sum, *max, *min, val);
break;
default:
ASSERT(0);
break;
}
}
}
}
static FORCE_INLINE void tColDataCalcSMATinySmallInt(SColData *pColData, int64_t *sum, int64_t *max, int64_t *min,
int16_t *numOfNull) {
*sum = 0;
*max = INT16_MIN;
*min = INT16_MAX;
*numOfNull = 0;
int16_t val;
if (HAS_VALUE == pColData->flag) {
for (int32_t iVal = 0; iVal < pColData->nVal; iVal++) {
val = ((int16_t *)pColData->pData)[iVal];
CALC_SUM_MAX_MIN(*sum, *max, *min, val);
}
} else {
for (int32_t iVal = 0; iVal < pColData->nVal; iVal++) {
switch (tColDataGetBitValue(pColData, iVal)) {
case 0:
case 1:
(*numOfNull)++;
break;
case 2:
val = ((int16_t *)pColData->pData)[iVal];
CALC_SUM_MAX_MIN(*sum, *max, *min, val);
break;
default:
ASSERT(0);
break;
}
}
}
}
static FORCE_INLINE void tColDataCalcSMAInt(SColData *pColData, int64_t *sum, int64_t *max, int64_t *min,
int16_t *numOfNull) {
*sum = 0;
*max = INT32_MIN;
*min = INT32_MAX;
*numOfNull = 0;
int32_t val;
if (HAS_VALUE == pColData->flag) {
for (int32_t iVal = 0; iVal < pColData->nVal; iVal++) {
val = ((int32_t *)pColData->pData)[iVal];
CALC_SUM_MAX_MIN(*sum, *max, *min, val);
}
} else {
for (int32_t iVal = 0; iVal < pColData->nVal; iVal++) {
switch (tColDataGetBitValue(pColData, iVal)) {
case 0:
case 1:
(*numOfNull)++;
break;
case 2:
val = ((int32_t *)pColData->pData)[iVal];
CALC_SUM_MAX_MIN(*sum, *max, *min, val);
break;
default:
ASSERT(0);
break;
}
}
}
}
static FORCE_INLINE void tColDataCalcSMABigInt(SColData *pColData, int64_t *sum, int64_t *max, int64_t *min,
int16_t *numOfNull) {
*sum = 0;
*max = INT64_MIN;
*min = INT64_MAX;
*numOfNull = 0;
int64_t val;
if (HAS_VALUE == pColData->flag) {
for (int32_t iVal = 0; iVal < pColData->nVal; iVal++) {
val = ((int64_t *)pColData->pData)[iVal];
CALC_SUM_MAX_MIN(*sum, *max, *min, val);
}
} else {
for (int32_t iVal = 0; iVal < pColData->nVal; iVal++) {
switch (tColDataGetBitValue(pColData, iVal)) {
case 0:
case 1:
(*numOfNull)++;
break;
case 2:
val = ((int64_t *)pColData->pData)[iVal];
CALC_SUM_MAX_MIN(*sum, *max, *min, val);
break;
default:
ASSERT(0);
break;
}
}
}
}
static FORCE_INLINE void tColDataCalcSMAFloat(SColData *pColData, int64_t *sum, int64_t *max, int64_t *min,
int16_t *numOfNull) {
*(double *)sum = 0;
*(double *)max = -FLT_MAX;
*(double *)min = FLT_MAX;
*numOfNull = 0;
float val;
if (HAS_VALUE == pColData->flag) {
for (int32_t iVal = 0; iVal < pColData->nVal; iVal++) {
val = ((float *)pColData->pData)[iVal];
CALC_SUM_MAX_MIN(*(double *)sum, *(double *)max, *(double *)min, val);
}
} else {
for (int32_t iVal = 0; iVal < pColData->nVal; iVal++) {
switch (tColDataGetBitValue(pColData, iVal)) {
case 0:
case 1:
(*numOfNull)++;
break;
case 2:
val = ((float *)pColData->pData)[iVal];
CALC_SUM_MAX_MIN(*(double *)sum, *(double *)max, *(double *)min, val);
break;
default:
ASSERT(0);
break;
}
}
}
}
static FORCE_INLINE void tColDataCalcSMADouble(SColData *pColData, int64_t *sum, int64_t *max, int64_t *min,
int16_t *numOfNull) {
*(double *)sum = 0;
*(double *)max = -DBL_MAX;
*(double *)min = DBL_MAX;
*numOfNull = 0;
double val;
if (HAS_VALUE == pColData->flag) {
for (int32_t iVal = 0; iVal < pColData->nVal; iVal++) {
val = ((double *)pColData->pData)[iVal];
CALC_SUM_MAX_MIN(*(double *)sum, *(double *)max, *(double *)min, val);
}
} else {
for (int32_t iVal = 0; iVal < pColData->nVal; iVal++) {
switch (tColDataGetBitValue(pColData, iVal)) {
case 0:
case 1:
(*numOfNull)++;
break;
case 2:
val = ((double *)pColData->pData)[iVal];
CALC_SUM_MAX_MIN(*(double *)sum, *(double *)max, *(double *)min, val);
break;
default:
ASSERT(0);
break;
}
}
}
}
static FORCE_INLINE void tColDataCalcSMAUTinyInt(SColData *pColData, int64_t *sum, int64_t *max, int64_t *min,
int16_t *numOfNull) {
*(uint64_t *)sum = 0;
*(uint64_t *)max = 0;
*(uint64_t *)min = UINT8_MAX;
*numOfNull = 0;
uint8_t val;
if (HAS_VALUE == pColData->flag) {
for (int32_t iVal = 0; iVal < pColData->nVal; iVal++) {
val = ((uint8_t *)pColData->pData)[iVal];
CALC_SUM_MAX_MIN(*(uint64_t *)sum, *(uint64_t *)max, *(uint64_t *)min, val);
}
} else {
for (int32_t iVal = 0; iVal < pColData->nVal; iVal++) {
switch (tColDataGetBitValue(pColData, iVal)) {
case 0:
case 1:
(*numOfNull)++;
break;
case 2:
val = ((uint8_t *)pColData->pData)[iVal];
CALC_SUM_MAX_MIN(*(uint64_t *)sum, *(uint64_t *)max, *(uint64_t *)min, val);
break;
default:
ASSERT(0);
break;
}
}
}
}
static FORCE_INLINE void tColDataCalcSMATinyUSmallInt(SColData *pColData, int64_t *sum, int64_t *max, int64_t *min,
int16_t *numOfNull) {
*(uint64_t *)sum = 0;
*(uint64_t *)max = 0;
*(uint64_t *)min = UINT16_MAX;
*numOfNull = 0;
uint16_t val;
if (HAS_VALUE == pColData->flag) {
for (int32_t iVal = 0; iVal < pColData->nVal; iVal++) {
val = ((uint16_t *)pColData->pData)[iVal];
CALC_SUM_MAX_MIN(*(uint64_t *)sum, *(uint64_t *)max, *(uint64_t *)min, val);
}
} else {
for (int32_t iVal = 0; iVal < pColData->nVal; iVal++) {
switch (tColDataGetBitValue(pColData, iVal)) {
case 0:
case 1:
(*numOfNull)++;
break;
case 2:
val = ((uint16_t *)pColData->pData)[iVal];
CALC_SUM_MAX_MIN(*(uint64_t *)sum, *(uint64_t *)max, *(uint64_t *)min, val);
break;
default:
ASSERT(0);
break;
}
}
}
}
static FORCE_INLINE void tColDataCalcSMAUInt(SColData *pColData, int64_t *sum, int64_t *max, int64_t *min,
int16_t *numOfNull) {
*(uint64_t *)sum = 0;
*(uint64_t *)max = 0;
*(uint64_t *)min = UINT32_MAX;
*numOfNull = 0;
uint32_t val;
if (HAS_VALUE == pColData->flag) {
for (int32_t iVal = 0; iVal < pColData->nVal; iVal++) {
val = ((uint32_t *)pColData->pData)[iVal];
CALC_SUM_MAX_MIN(*(uint64_t *)sum, *(uint64_t *)max, *(uint64_t *)min, val);
}
} else {
for (int32_t iVal = 0; iVal < pColData->nVal; iVal++) {
switch (tColDataGetBitValue(pColData, iVal)) {
case 0:
case 1:
(*numOfNull)++;
break;
case 2:
val = ((uint32_t *)pColData->pData)[iVal];
CALC_SUM_MAX_MIN(*(uint64_t *)sum, *(uint64_t *)max, *(uint64_t *)min, val);
break;
default:
ASSERT(0);
break;
}
}
}
}
static FORCE_INLINE void tColDataCalcSMAUBigInt(SColData *pColData, int64_t *sum, int64_t *max, int64_t *min,
int16_t *numOfNull) {
*(uint64_t *)sum = 0;
*(uint64_t *)max = 0;
*(uint64_t *)min = UINT64_MAX;
*numOfNull = 0;
uint64_t val;
if (HAS_VALUE == pColData->flag) {
for (int32_t iVal = 0; iVal < pColData->nVal; iVal++) {
val = ((uint64_t *)pColData->pData)[iVal];
CALC_SUM_MAX_MIN(*(uint64_t *)sum, *(uint64_t *)max, *(uint64_t *)min, val);
}
} else {
for (int32_t iVal = 0; iVal < pColData->nVal; iVal++) {
switch (tColDataGetBitValue(pColData, iVal)) {
case 0:
case 1:
(*numOfNull)++;
break;
case 2:
val = ((uint64_t *)pColData->pData)[iVal];
CALC_SUM_MAX_MIN(*(uint64_t *)sum, *(uint64_t *)max, *(uint64_t *)min, val);
break;
default:
ASSERT(0);
break;
}
}
}
}
static FORCE_INLINE void tColDataCalcSMAVarType(SColData *pColData, int64_t *sum, int64_t *max, int64_t *min,
int16_t *numOfNull) {
*(uint64_t *)sum = 0;
*(uint64_t *)max = 0;
*(uint64_t *)min = 0;
*numOfNull = 0;
switch (pColData->flag) {
case HAS_NONE:
case HAS_NULL:
case (HAS_NONE | HAS_NULL):
*numOfNull = pColData->nVal;
break;
case HAS_VALUE:
*numOfNull = 0;
break;
case (HAS_VALUE | HAS_NULL):
case (HAS_VALUE | HAS_NONE):
for (int32_t iVal = 0; iVal < pColData->nVal; iVal++) {
if (GET_BIT1(pColData->pBitMap, iVal) == 0) {
(*numOfNull)++;
}
}
break;
case (HAS_VALUE | HAS_NONE | HAS_NULL):
for (int32_t iVal = 0; iVal < pColData->nVal; iVal++) {
if (GET_BIT2(pColData->pBitMap, iVal) != 2) {
(*numOfNull)++;
}
}
break;
default:
ASSERT(0);
break;
}
}
void (*tColDataCalcSMA[])(SColData *pColData, int64_t *sum, int64_t *max, int64_t *min, int16_t *numOfNull) = {
NULL,
tColDataCalcSMABool, // TSDB_DATA_TYPE_BOOL
tColDataCalcSMATinyInt, // TSDB_DATA_TYPE_TINYINT
tColDataCalcSMATinySmallInt, // TSDB_DATA_TYPE_SMALLINT
tColDataCalcSMAInt, // TSDB_DATA_TYPE_INT
tColDataCalcSMABigInt, // TSDB_DATA_TYPE_BIGINT
tColDataCalcSMAFloat, // TSDB_DATA_TYPE_FLOAT
tColDataCalcSMADouble, // TSDB_DATA_TYPE_DOUBLE
tColDataCalcSMAVarType, // TSDB_DATA_TYPE_VARCHAR
tColDataCalcSMABigInt, // TSDB_DATA_TYPE_TIMESTAMP
tColDataCalcSMAVarType, // TSDB_DATA_TYPE_NCHAR
tColDataCalcSMAUTinyInt, // TSDB_DATA_TYPE_UTINYINT
tColDataCalcSMATinyUSmallInt, // TSDB_DATA_TYPE_USMALLINT
tColDataCalcSMAUInt, // TSDB_DATA_TYPE_UINT
tColDataCalcSMAUBigInt, // TSDB_DATA_TYPE_UBIGINT
tColDataCalcSMAVarType, // TSDB_DATA_TYPE_JSON
NULL, // TSDB_DATA_TYPE_VARBINARY
NULL, // TSDB_DATA_TYPE_DECIMAL
NULL, // TSDB_DATA_TYPE_BLOB
NULL, // TSDB_DATA_TYPE_MEDIUMBLOB
tColDataCalcSMAVarType // TSDB_DATA_TYPE_GEOMETRY
};