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

4582 lines
142 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 "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);
// ================================
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)0x40)
#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;
uint8_t idx[]; // uint8_t * | uint16_t * | uint32_t *
} SKVIdx;
#pragma pack(pop)
#define ROW_SET_BITMAP(PB, FLAG, IDX, VAL) \
do { \
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: \
break; \
} \
} while (0)
static int32_t tPutPrimaryKeyIndex(uint8_t *p, const SPrimaryKeyIndex *index) {
int32_t n = 0;
n += tPutI8(p ? p + n : p, index->type);
n += tPutU32v(p ? p + n : p, index->offset);
return n;
}
static int32_t tGetPrimaryKeyIndex(uint8_t *p, SPrimaryKeyIndex *index) {
int32_t n = 0;
n += tGetI8(p + n, &index->type);
n += tGetU32v(p + n, &index->offset);
return n;
}
typedef struct {
int32_t numOfNone;
int32_t numOfNull;
int32_t numOfValue;
int32_t numOfPKs;
int8_t flag;
// tuple
int8_t tupleFlag;
SPrimaryKeyIndex tupleIndices[TD_MAX_PK_COLS];
int32_t tuplePKSize; // primary key size
int32_t tupleBitmapSize; // bitmap size
int32_t tupleFixedSize; // fixed part size
int32_t tupleVarSize; // var part size
int32_t tupleRowSize;
// key-value
int8_t kvFlag;
SPrimaryKeyIndex kvIndices[TD_MAX_PK_COLS];
int32_t kvMaxOffset;
int32_t kvPKSize; // primary key size
int32_t kvIndexSize; // offset array size
int32_t kvPayloadSize; // payload size
int32_t kvRowSize;
} SRowBuildScanInfo;
static FORCE_INLINE int32_t tRowBuildScanAddNone(SRowBuildScanInfo *sinfo, const STColumn *pTColumn) {
if ((pTColumn->flags & COL_IS_KEY)) return TSDB_CODE_PAR_PRIMARY_KEY_IS_NONE;
sinfo->numOfNone++;
return 0;
}
static FORCE_INLINE int32_t tRowBuildScanAddNull(SRowBuildScanInfo *sinfo, const STColumn *pTColumn) {
if ((pTColumn->flags & COL_IS_KEY)) return TSDB_CODE_PAR_PRIMARY_KEY_IS_NULL;
sinfo->numOfNull++;
sinfo->kvMaxOffset = sinfo->kvPayloadSize;
sinfo->kvPayloadSize += tPutI16v(NULL, -pTColumn->colId);
return 0;
}
static FORCE_INLINE void tRowBuildScanAddValue(SRowBuildScanInfo *sinfo, SColVal *colVal, const STColumn *pTColumn) {
bool isPK = ((pTColumn->flags & COL_IS_KEY) != 0);
if (isPK) {
sinfo->tupleIndices[sinfo->numOfPKs].type = colVal->value.type;
sinfo->tupleIndices[sinfo->numOfPKs].offset =
IS_VAR_DATA_TYPE(pTColumn->type) ? sinfo->tupleVarSize + sinfo->tupleFixedSize : pTColumn->offset;
sinfo->kvIndices[sinfo->numOfPKs].type = colVal->value.type;
sinfo->kvIndices[sinfo->numOfPKs].offset = sinfo->kvPayloadSize;
sinfo->numOfPKs++;
}
sinfo->kvMaxOffset = sinfo->kvPayloadSize;
if (IS_VAR_DATA_TYPE(colVal->value.type)) {
sinfo->tupleVarSize += tPutU32v(NULL, colVal->value.nData) // size
+ colVal->value.nData; // value
sinfo->kvPayloadSize += tPutI16v(NULL, colVal->cid) // colId
+ tPutU32v(NULL, colVal->value.nData) // size
+ colVal->value.nData; // value
} else {
sinfo->kvPayloadSize += tPutI16v(NULL, colVal->cid) // colId
+ tDataTypes[colVal->value.type].bytes; // value
}
sinfo->numOfValue++;
}
static int32_t tRowBuildScan(SArray *colVals, const STSchema *schema, SRowBuildScanInfo *sinfo) {
int32_t code = 0;
int32_t colValIndex = 1;
int32_t numOfColVals = TARRAY_SIZE(colVals);
SColVal *colValArray = (SColVal *)TARRAY_DATA(colVals);
if (!(numOfColVals > 0)) {
return TSDB_CODE_INVALID_PARA;
}
if (!(colValArray[0].cid == PRIMARYKEY_TIMESTAMP_COL_ID)) {
return TSDB_CODE_INVALID_PARA;
}
if (!(colValArray[0].value.type == TSDB_DATA_TYPE_TIMESTAMP)) {
return TSDB_CODE_INVALID_PARA;
}
*sinfo = (SRowBuildScanInfo){
.tupleFixedSize = schema->flen,
};
// loop scan
for (int32_t i = 1; i < schema->numOfCols; i++) {
for (;;) {
if (colValIndex >= numOfColVals) {
if ((code = tRowBuildScanAddNone(sinfo, schema->columns + i))) goto _exit;
break;
}
if (colValArray[colValIndex].cid == schema->columns[i].colId) {
if (!(colValArray[colValIndex].value.type == schema->columns[i].type)) {
code = TSDB_CODE_INVALID_PARA;
goto _exit;
}
if (COL_VAL_IS_VALUE(&colValArray[colValIndex])) {
tRowBuildScanAddValue(sinfo, &colValArray[colValIndex], schema->columns + i);
} else if (COL_VAL_IS_NULL(&colValArray[colValIndex])) {
if ((code = tRowBuildScanAddNull(sinfo, schema->columns + i))) goto _exit;
} else if (COL_VAL_IS_NONE(&colValArray[colValIndex])) {
if ((code = tRowBuildScanAddNone(sinfo, schema->columns + i))) goto _exit;
}
colValIndex++;
break;
} else if (colValArray[colValIndex].cid > schema->columns[i].colId) {
if ((code = tRowBuildScanAddNone(sinfo, schema->columns + i))) goto _exit;
break;
} else { // skip useless value
colValIndex++;
}
}
}
if (sinfo->numOfNone) {
sinfo->flag |= HAS_NONE;
}
if (sinfo->numOfNull) {
sinfo->flag |= HAS_NULL;
}
if (sinfo->numOfValue) {
sinfo->flag |= HAS_VALUE;
}
// Tuple
sinfo->tupleFlag = sinfo->flag;
switch (sinfo->flag) {
case HAS_NONE:
case HAS_NULL:
sinfo->tupleBitmapSize = 0;
sinfo->tupleFixedSize = 0;
break;
case HAS_VALUE:
sinfo->tupleBitmapSize = 0;
sinfo->tupleFixedSize = schema->flen;
break;
case (HAS_NONE | HAS_NULL):
sinfo->tupleBitmapSize = BIT1_SIZE(schema->numOfCols - 1);
sinfo->tupleFixedSize = 0;
break;
case (HAS_NONE | HAS_VALUE):
case (HAS_NULL | HAS_VALUE):
sinfo->tupleBitmapSize = BIT1_SIZE(schema->numOfCols - 1);
sinfo->tupleFixedSize = schema->flen;
break;
case (HAS_NONE | HAS_NULL | HAS_VALUE):
sinfo->tupleBitmapSize = BIT2_SIZE(schema->numOfCols - 1);
sinfo->tupleFixedSize = schema->flen;
break;
}
for (int32_t i = 0; i < sinfo->numOfPKs; i++) {
sinfo->tupleIndices[i].offset += sinfo->tupleBitmapSize;
sinfo->tuplePKSize += tPutPrimaryKeyIndex(NULL, sinfo->tupleIndices + i);
}
sinfo->tupleRowSize = sizeof(SRow) // SRow
+ sinfo->tuplePKSize // primary keys
+ sinfo->tupleBitmapSize // bitmap
+ sinfo->tupleFixedSize // fixed part
+ sinfo->tupleVarSize; // var part
// Key-Value
if (sinfo->kvMaxOffset <= UINT8_MAX) {
sinfo->kvFlag = (KV_FLG_LIT | sinfo->flag);
sinfo->kvIndexSize = sizeof(SKVIdx) + (sinfo->numOfNull + sinfo->numOfValue) * sizeof(uint8_t);
} else if (sinfo->kvMaxOffset <= UINT16_MAX) {
sinfo->kvFlag = (KV_FLG_MID | sinfo->flag);
sinfo->kvIndexSize = sizeof(SKVIdx) + (sinfo->numOfNull + sinfo->numOfValue) * sizeof(uint16_t);
} else {
sinfo->kvFlag = (KV_FLG_BIG | sinfo->flag);
sinfo->kvIndexSize = sizeof(SKVIdx) + (sinfo->numOfNull + sinfo->numOfValue) * sizeof(uint32_t);
}
for (int32_t i = 0; i < sinfo->numOfPKs; i++) {
sinfo->kvIndices[i].offset += sinfo->kvIndexSize;
sinfo->kvPKSize += tPutPrimaryKeyIndex(NULL, sinfo->kvIndices + i);
}
sinfo->kvRowSize = sizeof(SRow) // SRow
+ sinfo->kvPKSize // primary keys
+ sinfo->kvIndexSize // index array
+ sinfo->kvPayloadSize; // payload
_exit:
return code;
}
static int32_t tRowBuildTupleRow(SArray *aColVal, const SRowBuildScanInfo *sinfo, const STSchema *schema,
SRow **ppRow) {
SColVal *colValArray = (SColVal *)TARRAY_DATA(aColVal);
*ppRow = (SRow *)taosMemoryCalloc(1, sinfo->tupleRowSize);
if (*ppRow == NULL) {
return terrno;
}
(*ppRow)->flag = sinfo->tupleFlag;
(*ppRow)->numOfPKs = sinfo->numOfPKs;
(*ppRow)->sver = schema->version;
(*ppRow)->len = sinfo->tupleRowSize;
(*ppRow)->ts = colValArray[0].value.val;
if (sinfo->tupleFlag == HAS_NONE || sinfo->tupleFlag == HAS_NULL) {
return 0;
}
uint8_t *primaryKeys = (*ppRow)->data;
uint8_t *bitmap = primaryKeys + sinfo->tuplePKSize;
uint8_t *fixed = bitmap + sinfo->tupleBitmapSize;
uint8_t *varlen = fixed + sinfo->tupleFixedSize;
// primary keys
for (int32_t i = 0; i < sinfo->numOfPKs; i++) {
primaryKeys += tPutPrimaryKeyIndex(primaryKeys, sinfo->tupleIndices + i);
}
// bitmap + fixed + varlen
int32_t numOfColVals = TARRAY_SIZE(aColVal);
int32_t colValIndex = 1;
for (int32_t i = 1; i < schema->numOfCols; i++) {
for (;;) {
if (colValIndex >= numOfColVals) { // NONE
ROW_SET_BITMAP(bitmap, sinfo->tupleFlag, i - 1, BIT_FLG_NONE);
break;
}
if (colValArray[colValIndex].cid == schema->columns[i].colId) {
if (COL_VAL_IS_VALUE(&colValArray[colValIndex])) { // value
ROW_SET_BITMAP(bitmap, sinfo->tupleFlag, i - 1, BIT_FLG_VALUE);
if (IS_VAR_DATA_TYPE(schema->columns[i].type)) {
*(int32_t *)(fixed + schema->columns[i].offset) = varlen - fixed - sinfo->tupleFixedSize;
varlen += tPutU32v(varlen, colValArray[colValIndex].value.nData);
if (colValArray[colValIndex].value.nData) {
(void)memcpy(varlen, colValArray[colValIndex].value.pData, colValArray[colValIndex].value.nData);
varlen += colValArray[colValIndex].value.nData;
}
} else {
(void)memcpy(fixed + schema->columns[i].offset, &colValArray[colValIndex].value.val,
tDataTypes[schema->columns[i].type].bytes);
}
} else if (COL_VAL_IS_NULL(&colValArray[colValIndex])) { // NULL
ROW_SET_BITMAP(bitmap, sinfo->tupleFlag, i - 1, BIT_FLG_NULL);
} else if (COL_VAL_IS_NONE(&colValArray[colValIndex])) { // NONE
ROW_SET_BITMAP(bitmap, sinfo->tupleFlag, i - 1, BIT_FLG_NONE);
}
colValIndex++;
break;
} else if (colValArray[colValIndex].cid > schema->columns[i].colId) { // NONE
ROW_SET_BITMAP(bitmap, sinfo->tupleFlag, i - 1, BIT_FLG_NONE);
break;
} else {
colValIndex++;
}
}
}
return 0;
}
static FORCE_INLINE void tRowBuildKVRowSetIndex(uint8_t flag, SKVIdx *indices, uint32_t offset) {
if (flag & KV_FLG_LIT) {
((uint8_t *)indices->idx)[indices->nCol] = (uint8_t)offset;
} else if (flag & KV_FLG_MID) {
((uint16_t *)indices->idx)[indices->nCol] = (uint16_t)offset;
} else {
((uint32_t *)indices->idx)[indices->nCol] = (uint32_t)offset;
}
indices->nCol++;
}
static int32_t tRowBuildKVRow(SArray *aColVal, const SRowBuildScanInfo *sinfo, const STSchema *schema, SRow **ppRow) {
SColVal *colValArray = (SColVal *)TARRAY_DATA(aColVal);
*ppRow = (SRow *)taosMemoryCalloc(1, sinfo->kvRowSize);
if (*ppRow == NULL) {
return terrno;
}
(*ppRow)->flag = sinfo->kvFlag;
(*ppRow)->numOfPKs = sinfo->numOfPKs;
(*ppRow)->sver = schema->version;
(*ppRow)->len = sinfo->kvRowSize;
(*ppRow)->ts = colValArray[0].value.val;
if (!(sinfo->flag != HAS_NONE && sinfo->flag != HAS_NULL)) {
return TSDB_CODE_INVALID_PARA;
}
uint8_t *primaryKeys = (*ppRow)->data;
SKVIdx *indices = (SKVIdx *)(primaryKeys + sinfo->kvPKSize);
uint8_t *payload = primaryKeys + sinfo->kvPKSize + sinfo->kvIndexSize;
uint32_t payloadSize = 0;
// primary keys
for (int32_t i = 0; i < sinfo->numOfPKs; i++) {
primaryKeys += tPutPrimaryKeyIndex(primaryKeys, sinfo->kvIndices + i);
}
int32_t numOfColVals = TARRAY_SIZE(aColVal);
int32_t colValIndex = 1;
for (int32_t i = 1; i < schema->numOfCols; i++) {
for (;;) {
if (colValIndex >= numOfColVals) { // NONE
break;
}
if (colValArray[colValIndex].cid == schema->columns[i].colId) {
if (COL_VAL_IS_VALUE(&colValArray[colValIndex])) { // value
tRowBuildKVRowSetIndex(sinfo->kvFlag, indices, payloadSize);
if (IS_VAR_DATA_TYPE(schema->columns[i].type)) {
payloadSize += tPutI16v(payload + payloadSize, colValArray[colValIndex].cid);
payloadSize += tPutU32v(payload + payloadSize, colValArray[colValIndex].value.nData);
if (colValArray[colValIndex].value.nData > 0) {
(void)memcpy(payload + payloadSize, colValArray[colValIndex].value.pData,
colValArray[colValIndex].value.nData);
}
payloadSize += colValArray[colValIndex].value.nData;
} else {
payloadSize += tPutI16v(payload + payloadSize, colValArray[colValIndex].cid);
(void)memcpy(payload + payloadSize, &colValArray[colValIndex].value.val,
tDataTypes[schema->columns[i].type].bytes);
payloadSize += tDataTypes[schema->columns[i].type].bytes;
}
} else if (COL_VAL_IS_NULL(&colValArray[colValIndex])) { // NULL
tRowBuildKVRowSetIndex(sinfo->kvFlag, indices, payloadSize);
payloadSize += tPutI16v(payload + payloadSize, -schema->columns[i].colId);
}
colValIndex++;
break;
} else if (colValArray[colValIndex].cid > schema->columns[i].colId) { // NONE
break;
} else {
colValIndex++;
}
}
}
return 0;
}
int32_t tRowBuild(SArray *aColVal, const STSchema *pTSchema, SRow **ppRow) {
int32_t code;
SRowBuildScanInfo sinfo;
code = tRowBuildScan(aColVal, pTSchema, &sinfo);
if (code) return code;
if (sinfo.tupleRowSize <= sinfo.kvRowSize) {
code = tRowBuildTupleRow(aColVal, &sinfo, pTSchema, ppRow);
} else {
code = tRowBuildKVRow(aColVal, &sinfo, pTSchema, ppRow);
}
return code;
}
static int32_t tBindInfoCompare(const void *p1, const void *p2, const void *param) {
if (((SBindInfo *)p1)->columnId < ((SBindInfo *)p2)->columnId) {
return -1;
} else if (((SBindInfo *)p1)->columnId > ((SBindInfo *)p2)->columnId) {
return 1;
}
return 0;
}
/* build rows to `rowArray` from bind
* `infos` is the bind information array
* `numOfInfos` is the number of bind information
* `infoSorted` is whether the bind information is sorted by column id
* `pTSchema` is the schema of the table
* `rowArray` is the array to store the rows
*/
int32_t tRowBuildFromBind(SBindInfo *infos, int32_t numOfInfos, bool infoSorted, const STSchema *pTSchema,
SArray *rowArray) {
if (infos == NULL || numOfInfos <= 0 || numOfInfos > pTSchema->numOfCols || pTSchema == NULL || rowArray == NULL) {
return TSDB_CODE_INVALID_PARA;
}
if (!infoSorted) {
taosqsort_r(infos, numOfInfos, sizeof(SBindInfo), NULL, tBindInfoCompare);
}
int32_t code = 0;
int32_t numOfRows = infos[0].bind->num;
SArray *colValArray;
SColVal colVal;
if ((colValArray = taosArrayInit(numOfInfos, sizeof(SColVal))) == NULL) {
return terrno;
}
for (int32_t iRow = 0; iRow < numOfRows; iRow++) {
taosArrayClear(colValArray);
for (int32_t iInfo = 0; iInfo < numOfInfos; iInfo++) {
if (infos[iInfo].bind->is_null && infos[iInfo].bind->is_null[iRow]) {
colVal = COL_VAL_NULL(infos[iInfo].columnId, infos[iInfo].type);
} else {
SValue value = {
.type = infos[iInfo].type,
};
if (IS_VAR_DATA_TYPE(infos[iInfo].type)) {
value.nData = infos[iInfo].bind->length[iRow];
if (value.nData > pTSchema->columns[iInfo].bytes - VARSTR_HEADER_SIZE) {
code = TSDB_CODE_INVALID_PARA;
goto _exit;
}
value.pData = (uint8_t *)infos[iInfo].bind->buffer + infos[iInfo].bind->buffer_length * iRow;
} else {
(void)memcpy(&value.val, (uint8_t *)infos[iInfo].bind->buffer + infos[iInfo].bind->buffer_length * iRow,
infos[iInfo].bind->buffer_length);
}
colVal = COL_VAL_VALUE(infos[iInfo].columnId, value);
}
if (taosArrayPush(colValArray, &colVal) == NULL) {
code = terrno;
goto _exit;
}
}
SRow *row;
if ((code = tRowBuild(colValArray, pTSchema, &row))) {
goto _exit;
}
if ((taosArrayPush(rowArray, &row)) == NULL) {
code = terrno;
goto _exit;
}
}
_exit:
taosArrayDestroy(colValArray);
return code;
}
int32_t tRowGet(SRow *pRow, STSchema *pTSchema, int32_t iCol, SColVal *pColVal) {
if (!(iCol < pTSchema->numOfCols)) return TSDB_CODE_INVALID_PARA;
if (!(pRow->sver == pTSchema->version)) return TSDB_CODE_INVALID_PARA;
STColumn *pTColumn = pTSchema->columns + iCol;
if (iCol == 0) {
pColVal->cid = pTColumn->colId;
pColVal->value.type = pTColumn->type;
pColVal->flag = CV_FLAG_VALUE;
(void)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;
}
SPrimaryKeyIndex index;
uint8_t *data = pRow->data;
for (int32_t i = 0; i < pRow->numOfPKs; i++) {
data += tGetPrimaryKeyIndex(data, &index);
}
if (pRow->flag >> 4) { // KV Row
SKVIdx *pIdx = (SKVIdx *)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->value.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 {
(void)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
uint8_t *bitmap = data;
uint8_t *fixed;
uint8_t *varlen;
uint8_t bit;
if (pRow->flag == HAS_VALUE) {
fixed = bitmap;
bit = BIT_FLG_VALUE;
} else if (pRow->flag == (HAS_NONE | HAS_NULL | HAS_VALUE)) {
fixed = BIT2_SIZE(pTSchema->numOfCols - 1) + bitmap;
bit = GET_BIT2(bitmap, iCol - 1);
} else {
fixed = BIT1_SIZE(pTSchema->numOfCols - 1) + bitmap;
bit = GET_BIT1(bitmap, iCol - 1);
if (pRow->flag == (HAS_NONE | HAS_VALUE)) {
if (bit) bit++;
} else if (pRow->flag == (HAS_NULL | HAS_VALUE)) {
bit++;
}
}
varlen = fixed + pTSchema->flen;
if (bit == BIT_FLG_NONE) {
*pColVal = COL_VAL_NONE(pTColumn->colId, pTColumn->type);
return 0;
} else if (bit == BIT_FLG_NULL) {
*pColVal = COL_VAL_NULL(pTColumn->colId, pTColumn->type);
return 0;
}
pColVal->cid = pTColumn->colId;
pColVal->value.type = pTColumn->type;
pColVal->flag = CV_FLAG_VALUE;
if (IS_VAR_DATA_TYPE(pTColumn->type)) {
pColVal->value.pData = varlen + *(int32_t *)(fixed + pTColumn->offset);
pColVal->value.pData += tGetU32v(pColVal->value.pData, &pColVal->value.nData);
} else {
(void)memcpy(&pColVal->value.val, fixed + 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) {
SRowKey key1, key2;
tRowGetKey(*(SRow **)p1, &key1);
tRowGetKey(*(SRow **)p2, &key2);
return tRowKeyCompare(&key1, &key2);
}
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 = terrno;
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 = terrno;
goto _exit;
}
for (int32_t iCol = 0; iCol < pTSchema->numOfCols; iCol++) {
SColVal *pColVal = NULL;
for (int32_t iRow = nRow - 1; iRow >= 0; --iRow) {
SColVal *pColValT = tRowIterNext(aIter[iRow]);
while (pColValT->cid < pTSchema->columns[iCol].colId) {
pColValT = tRowIterNext(aIter[iRow]);
}
// todo: take strategy according to the flag
if (COL_VAL_IS_VALUE(pColValT)) {
pColVal = pColValT;
break;
} else if (COL_VAL_IS_NULL(pColValT)) {
if (pColVal == NULL) {
pColVal = pColValT;
}
}
}
if (pColVal) {
if (taosArrayPush(aColVal, pColVal) == NULL) {
code = terrno;
goto _exit;
}
}
}
// build
code = tRowBuild(aColVal, pTSchema, &pRow);
if (code) goto _exit;
taosArrayRemoveBatch(aRowP, iStart, nRow, (FDelete)tRowPDestroy);
if (taosArrayInsert(aRowP, iStart, &pRow) == NULL) {
code = terrno;
goto _exit;
}
_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) {
SRowKey key1;
SRow *row1 = (SRow *)taosArrayGetP(aRowP, iStart);
tRowGetKey(row1, &key1);
int32_t iEnd = iStart + 1;
while (iEnd < aRowP->size) {
SRowKey key2;
SRow *row2 = (SRow *)taosArrayGetP(aRowP, iEnd);
tRowGetKey(row2, &key2);
if (tRowKeyCompare(&key1, &key2) != 0) 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) {
if (!(pRow->sver == pTSchema->version)) return TSDB_CODE_INVALID_PARA;
int32_t code = 0;
SRowIter *pIter = taosMemoryCalloc(1, sizeof(*pIter));
if (pIter == NULL) {
code = terrno;
goto _exit;
}
pIter->pRow = pRow;
pIter->pTSchema = pTSchema;
pIter->iTColumn = 0;
if (pRow->flag == HAS_NONE || pRow->flag == HAS_NULL) goto _exit;
uint8_t *data = pRow->data;
SPrimaryKeyIndex index;
for (int32_t i = 0; i < pRow->numOfPKs; i++) {
data += tGetPrimaryKeyIndex(data, &index);
}
if (pRow->flag >> 4) {
pIter->iCol = 0;
pIter->pIdx = (SKVIdx *)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 = data;
break;
case HAS_VALUE:
pIter->pf = data;
pIter->pv = pIter->pf + pTSchema->flen;
break;
case (HAS_VALUE | HAS_NONE):
case (HAS_VALUE | HAS_NULL):
pIter->pb = data;
pIter->pf = data + BIT1_SIZE(pTSchema->numOfCols - 1);
pIter->pv = pIter->pf + pTSchema->flen;
break;
case (HAS_VALUE | HAS_NULL | HAS_NONE):
pIter->pb = data;
pIter->pf = data + BIT2_SIZE(pTSchema->numOfCols - 1);
pIter->pv = pIter->pf + pTSchema->flen;
break;
default:
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.value.type = pTColumn->type;
pIter->cv.flag = CV_FLAG_VALUE;
(void)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.value.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 {
(void)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 {
uError("unexpected column id %d, %d", cid, pTColumn->colId);
goto _exit;
}
} 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:
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.value.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 {
(void)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;
SPrimaryKeyIndex index;
uint8_t *data = pRow->data;
for (int32_t i = 0; i < pRow->numOfPKs; i++) {
data += tGetPrimaryKeyIndex(data, &index);
}
switch (pRow->flag) {
case HAS_VALUE:
pf = data; // TODO: fix here
pv = pf + pTSchema->flen;
break;
case (HAS_NULL | HAS_NONE):
pb = data;
break;
case (HAS_VALUE | HAS_NONE):
case (HAS_VALUE | HAS_NULL):
pb = data;
pf = pb + BIT1_SIZE(pTSchema->numOfCols - 1);
pv = pf + pTSchema->flen;
break;
case (HAS_VALUE | HAS_NULL | HAS_NONE):
pb = data;
pf = pb + BIT2_SIZE(pTSchema->numOfCols - 1);
pv = pf + pTSchema->flen;
break;
default:
return TSDB_CODE_INVALID_DATA_FMT;
}
while (pColData) {
if (pTColumn) {
if (pTColumn->colId == pColData->cid) {
if (!(pTColumn->type == pColData->type)) {
return TSDB_CODE_INVALID_PARA;
}
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:
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;
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;
// primary keys
uint8_t *data = pRow->data;
SPrimaryKeyIndex index;
for (int32_t i = 0; i < pRow->numOfPKs; i++) {
data += tGetPrimaryKeyIndex(data, &index);
}
SKVIdx *pKVIdx = (SKVIdx *)data;
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 {
return TSDB_CODE_INVALID_PARA;
}
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 {
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) {
if (!(pRow->sver == pTSchema->version)) return TSDB_CODE_INVALID_PARA;
if (!(nColData > 0)) return TSDB_CODE_INVALID_PARA;
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);
}
}
void tRowGetPrimaryKey(SRow *row, SRowKey *key) {
key->numOfPKs = row->numOfPKs;
if (key->numOfPKs == 0) {
return;
}
SPrimaryKeyIndex indices[TD_MAX_PK_COLS];
uint8_t *data = row->data;
for (int32_t i = 0; i < row->numOfPKs; i++) {
data += tGetPrimaryKeyIndex(data, &indices[i]);
}
// primary keys
for (int32_t i = 0; i < row->numOfPKs; i++) {
key->pks[i].type = indices[i].type;
uint8_t *tdata = data + indices[i].offset;
if (row->flag >> 4) {
tdata += tGetI16v(tdata, NULL);
}
if (IS_VAR_DATA_TYPE(indices[i].type)) {
key->pks[i].pData = tdata;
key->pks[i].pData += tGetU32v(key->pks[i].pData, &key->pks[i].nData);
} else {
(void)memcpy(&key->pks[i].val, tdata, tDataTypes[indices[i].type].bytes);
}
}
}
#define T_COMPARE_SCALAR_VALUE(TYPE, V1, V2) \
do { \
if (*(TYPE *)(V1) < *(TYPE *)(V2)) { \
return -1; \
} else if (*(TYPE *)(V1) > *(TYPE *)(V2)) { \
return 1; \
} else { \
return 0; \
} \
} while (0)
int32_t tValueCompare(const SValue *tv1, const SValue *tv2) {
switch (tv1->type) {
case TSDB_DATA_TYPE_BOOL:
case TSDB_DATA_TYPE_TINYINT:
T_COMPARE_SCALAR_VALUE(int8_t, &tv1->val, &tv2->val);
case TSDB_DATA_TYPE_SMALLINT:
T_COMPARE_SCALAR_VALUE(int16_t, &tv1->val, &tv2->val);
case TSDB_DATA_TYPE_INT:
T_COMPARE_SCALAR_VALUE(int32_t, &tv1->val, &tv2->val);
case TSDB_DATA_TYPE_BIGINT:
case TSDB_DATA_TYPE_TIMESTAMP:
T_COMPARE_SCALAR_VALUE(int64_t, &tv1->val, &tv2->val);
case TSDB_DATA_TYPE_FLOAT:
T_COMPARE_SCALAR_VALUE(float, &tv1->val, &tv2->val);
case TSDB_DATA_TYPE_DOUBLE:
T_COMPARE_SCALAR_VALUE(double, &tv1->val, &tv2->val);
case TSDB_DATA_TYPE_UTINYINT:
T_COMPARE_SCALAR_VALUE(uint8_t, &tv1->val, &tv2->val);
case TSDB_DATA_TYPE_USMALLINT:
T_COMPARE_SCALAR_VALUE(uint16_t, &tv1->val, &tv2->val);
case TSDB_DATA_TYPE_UINT:
T_COMPARE_SCALAR_VALUE(uint32_t, &tv1->val, &tv2->val);
case TSDB_DATA_TYPE_UBIGINT:
T_COMPARE_SCALAR_VALUE(uint64_t, &tv1->val, &tv2->val);
case TSDB_DATA_TYPE_GEOMETRY:
case TSDB_DATA_TYPE_BINARY: {
int32_t ret = strncmp((const char *)tv1->pData, (const char *)tv2->pData, TMIN(tv1->nData, tv2->nData));
return ret ? ret : (tv1->nData < tv2->nData ? -1 : (tv1->nData > tv2->nData ? 1 : 0));
}
case TSDB_DATA_TYPE_NCHAR: {
int32_t ret = tasoUcs4Compare((TdUcs4 *)tv1->pData, (TdUcs4 *)tv2->pData,
tv1->nData < tv2->nData ? tv1->nData : tv2->nData);
return ret ? ret : (tv1->nData < tv2->nData ? -1 : (tv1->nData > tv2->nData ? 1 : 0));
}
case TSDB_DATA_TYPE_VARBINARY: {
int32_t ret = memcmp(tv1->pData, tv2->pData, tv1->nData < tv2->nData ? tv1->nData : tv2->nData);
return ret ? ret : (tv1->nData < tv2->nData ? -1 : (tv1->nData > tv2->nData ? 1 : 0));
}
default:
break;
}
return 0;
}
// NOTE:
// set key->numOfPKs to 0 as the smallest key with ts
// set key->numOfPKs to (TD_MAX_PK_COLS + 1) as the largest key with ts
FORCE_INLINE int32_t tRowKeyCompare(const SRowKey *key1, const SRowKey *key2) {
if (key1->ts < key2->ts) {
return -1;
} else if (key1->ts > key2->ts) {
return 1;
}
if (key1->numOfPKs == key2->numOfPKs) {
for (uint8_t iKey = 0; iKey < key1->numOfPKs; iKey++) {
int32_t ret = tValueCompare(&key1->pks[iKey], &key2->pks[iKey]);
if (ret) return ret;
}
} else if (key1->numOfPKs < key2->numOfPKs) {
return -1;
} else {
return 1;
}
return 0;
}
void tRowKeyAssign(SRowKey *pDst, SRowKey *pSrc) {
pDst->ts = pSrc->ts;
pDst->numOfPKs = pSrc->numOfPKs;
if (pSrc->numOfPKs > 0) {
for (int32_t i = 0; i < pSrc->numOfPKs; ++i) {
SValue *pVal = &pDst->pks[i];
pVal->type = pSrc->pks[i].type;
if (IS_NUMERIC_TYPE(pVal->type)) {
pVal->val = pSrc->pks[i].val;
} else {
pVal->nData = pSrc->pks[i].nData;
(void)memcpy(pVal->pData, pSrc->pks[i].pData, pVal->nData);
}
}
}
}
// 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);
}
#ifdef TD_DEBUG_PRINT_TAG
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:
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");
}
#endif
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) (void)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 {
(void)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;
}
// build tag
(*ppTag) = (STag *)taosMemoryCalloc(szTag, 1);
if ((*ppTag) == NULL) {
code = terrno;
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;
(void)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];
}
int32_t nt = 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 {
(void)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 = terrno;
goto _err;
}
for (int16_t iTag = 0; iTag < pTag->nTag; iTag++) {
if (isLarge) {
offset = ((int16_t *)pTag->idx)[iTag];
} else {
offset = pTag->idx[iTag];
}
int32_t nt = tGetTagVal(p + offset, &tv, pTag->flags & TD_TAG_JSON);
if (taosArrayPush(*ppArray, &tv) == NULL) {
code = terrno;
goto _err;
}
}
return code;
_err:
return code;
}
// STSchema ========================================
STSchema *tBuildTSchema(SSchema *aSchema, int32_t numOfCols, int32_t version) {
STSchema *pTSchema = taosMemoryCalloc(1, sizeof(STSchema) + sizeof(STColumn) * numOfCols);
if (pTSchema == NULL) {
terrno = TSDB_CODE_OUT_OF_MEMORY;
return NULL;
}
pTSchema->numOfCols = numOfCols;
pTSchema->version = version;
// timestamp column
if (!(aSchema[0].type == TSDB_DATA_TYPE_TIMESTAMP)) {
terrno = TSDB_CODE_INVALID_PARA;
return NULL;
}
if (!(aSchema[0].colId == PRIMARYKEY_TIMESTAMP_COL_ID)) {
terrno = TSDB_CODE_INVALID_PARA;
return NULL;
}
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;
}
static int32_t tTColumnCompare(const void *p1, const void *p2) {
if (((STColumn *)p1)->colId < ((STColumn *)p2)->colId) {
return -1;
} else if (((STColumn *)p1)->colId > ((STColumn *)p2)->colId) {
return 1;
}
return 0;
}
const STColumn *tTSchemaSearchColumn(const STSchema *pTSchema, int16_t cid) {
STColumn tcol = {
.colId = cid,
};
return taosbsearch(&tcol, pTSchema->columns, pTSchema->numOfCols, sizeof(STColumn), tTColumnCompare, TD_EQ);
}
// 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 cflag) {
pColData->cid = cid;
pColData->type = type;
pColData->cflag = cflag;
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;
(void)memcpy(pColData->pData + pColData->nData, pData, nData);
pColData->nData += nData;
}
} else {
if (!(pColData->nData == tDataTypes[pColData->type].bytes * pColData->nVal)) {
return TSDB_CODE_INVALID_PARA;
}
code = tRealloc(&pColData->pData, pColData->nData + tDataTypes[pColData->type].bytes);
if (code) goto _exit;
if (pData) {
(void)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) {
if (!(pColData->cid == pColVal->cid && pColData->type == pColVal->value.type)) {
return TSDB_CODE_INVALID_PARA;
}
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 {
return TSDB_CODE_INVALID_PARA;
}
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_VAR_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) {
if (!(pColData->cid == pColVal->cid && pColData->type == pColVal->value.type)) return TSDB_CODE_INVALID_PARA;
if (!(pColData->nVal > 0)) return TSDB_CODE_INVALID_PARA;
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:
break;
}
}
static FORCE_INLINE void tColDataGetValue4(SColData *pColData, int32_t iVal, SColVal *pColVal) { // HAS_VALUE
SValue value = {.type = pColData->type};
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 {
(void)memcpy(&value.val, pColData->pData + tDataTypes[pColData->type].bytes * iVal,
tDataTypes[pColData->type].bytes);
}
*pColVal = COL_VAL_VALUE(pColData->cid, 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:
break;
}
}
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:
break;
}
}
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:
break;
}
}
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) {
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:
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;
}
(void)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;
}
(void)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;
}
(void)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;
}
(void)memcpy(pColData->pData, pColDataFrom->pData, pColData->nData);
} else {
pColData->pData = NULL;
}
_exit:
return code;
}
int32_t tColDataCompress(SColData *colData, SColDataCompressInfo *info, SBuffer *output, SBuffer *assist) {
int32_t code;
SBuffer local;
if (!(colData->nVal > 0)) {
return TSDB_CODE_INVALID_PARA;
}
(*info) = (SColDataCompressInfo){
.cmprAlg = info->cmprAlg,
.columnFlag = colData->cflag,
.flag = colData->flag,
.dataType = colData->type,
.columnId = colData->cid,
.numOfData = colData->nVal,
};
if (colData->flag == HAS_NONE || colData->flag == HAS_NULL) {
return 0;
}
tBufferInit(&local);
if (assist == NULL) {
assist = &local;
}
// bitmap
if (colData->flag != HAS_VALUE) {
if (colData->flag == (HAS_NONE | HAS_NULL | HAS_VALUE)) {
info->bitmapOriginalSize = BIT2_SIZE(colData->nVal);
} else {
info->bitmapOriginalSize = BIT1_SIZE(colData->nVal);
}
SCompressInfo cinfo = {
.dataType = TSDB_DATA_TYPE_TINYINT,
.cmprAlg = info->cmprAlg,
.originalSize = info->bitmapOriginalSize,
};
code = tCompressDataToBuffer(colData->pBitMap, &cinfo, output, assist);
if (code) {
tBufferDestroy(&local);
return code;
}
info->bitmapCompressedSize = cinfo.compressedSize;
}
if (colData->flag == (HAS_NONE | HAS_NULL)) {
tBufferDestroy(&local);
return 0;
}
// offset
if (IS_VAR_DATA_TYPE(colData->type)) {
info->offsetOriginalSize = sizeof(int32_t) * info->numOfData;
SCompressInfo cinfo = {
.dataType = TSDB_DATA_TYPE_INT,
.cmprAlg = info->cmprAlg,
.originalSize = info->offsetOriginalSize,
};
code = tCompressDataToBuffer(colData->aOffset, &cinfo, output, assist);
if (code) {
tBufferDestroy(&local);
return code;
}
info->offsetCompressedSize = cinfo.compressedSize;
}
// data
if (colData->nData > 0) {
info->dataOriginalSize = colData->nData;
SCompressInfo cinfo = {
.dataType = colData->type,
.cmprAlg = info->cmprAlg,
.originalSize = info->dataOriginalSize,
};
code = tCompressDataToBuffer(colData->pData, &cinfo, output, assist);
if (code) {
tBufferDestroy(&local);
return code;
}
info->dataCompressedSize = cinfo.compressedSize;
}
tBufferDestroy(&local);
return 0;
}
int32_t tColDataDecompress(void *input, SColDataCompressInfo *info, SColData *colData, SBuffer *assist) {
int32_t code;
SBuffer local;
uint8_t *data = (uint8_t *)input;
tBufferInit(&local);
if (assist == NULL) {
assist = &local;
}
tColDataClear(colData);
colData->cid = info->columnId;
colData->type = info->dataType;
colData->cflag = info->columnFlag;
colData->nVal = info->numOfData;
colData->flag = info->flag;
if (info->flag == HAS_NONE || info->flag == HAS_NULL) {
goto _exit;
}
// bitmap
if (info->bitmapOriginalSize > 0) {
SCompressInfo cinfo = {
.dataType = TSDB_DATA_TYPE_TINYINT,
.cmprAlg = info->cmprAlg,
.originalSize = info->bitmapOriginalSize,
.compressedSize = info->bitmapCompressedSize,
};
code = tRealloc(&colData->pBitMap, cinfo.originalSize);
if (code) {
tBufferDestroy(&local);
return code;
}
code = tDecompressData(data, &cinfo, colData->pBitMap, cinfo.originalSize, assist);
if (code) {
tBufferDestroy(&local);
return code;
}
data += cinfo.compressedSize;
}
if (info->flag == (HAS_NONE | HAS_NULL)) {
goto _exit;
}
// offset
if (info->offsetOriginalSize > 0) {
SCompressInfo cinfo = {
.cmprAlg = info->cmprAlg,
.dataType = TSDB_DATA_TYPE_INT,
.originalSize = info->offsetOriginalSize,
.compressedSize = info->offsetCompressedSize,
};
code = tRealloc((uint8_t **)&colData->aOffset, cinfo.originalSize);
if (code) {
tBufferDestroy(&local);
return code;
}
code = tDecompressData(data, &cinfo, colData->aOffset, cinfo.originalSize, assist);
if (code) {
tBufferDestroy(&local);
return code;
}
data += cinfo.compressedSize;
}
// data
if (info->dataOriginalSize > 0) {
colData->nData = info->dataOriginalSize;
SCompressInfo cinfo = {
.cmprAlg = info->cmprAlg,
.dataType = colData->type,
.originalSize = info->dataOriginalSize,
.compressedSize = info->dataCompressedSize,
};
code = tRealloc((uint8_t **)&colData->pData, cinfo.originalSize);
if (code) {
tBufferDestroy(&local);
return code;
}
code = tDecompressData(data, &cinfo, colData->pData, cinfo.originalSize, assist);
if (code) {
tBufferDestroy(&local);
return code;
}
data += cinfo.compressedSize;
}
_exit:
switch (colData->flag) {
case HAS_NONE:
colData->numOfNone = colData->nVal;
break;
case HAS_NULL:
colData->numOfNull = colData->nVal;
break;
case HAS_VALUE:
colData->numOfValue = colData->nVal;
break;
default:
for (int32_t i = 0; i < colData->nVal; i++) {
uint8_t bitValue = tColDataGetBitValue(colData, i);
if (bitValue == 0) {
colData->numOfNone++;
} else if (bitValue == 1) {
colData->numOfNull++;
} else {
colData->numOfValue++;
}
}
}
tBufferDestroy(&local);
return 0;
}
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) {
if (pColData->cflag & COL_IS_KEY) {
code = TSDB_CODE_PAR_PRIMARY_KEY_IS_NULL;
} else {
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) {
if (pColData->cflag & COL_IS_KEY) {
code = TSDB_CODE_PAR_PRIMARY_KEY_IS_NULL;
goto _exit;
}
if ((code = tColDataAppendValueImpl[pColData->flag][CV_FLAG_NULL](pColData, NULL, 0))) {
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 ((pColData->cflag & COL_IS_KEY) && !allValue) {
code = TSDB_CODE_PAR_PRIMARY_KEY_IS_NULL;
goto _exit;
}
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)) {
if (!(pColData->type == pBind->buffer_type)) {
return TSDB_CODE_INVALID_PARA;
}
}
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]) {
if (pColData->cflag & COL_IS_KEY) {
code = TSDB_CODE_PAR_PRIMARY_KEY_IS_NULL;
goto _exit;
}
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 ((pColData->cflag & COL_IS_KEY) && !allValue) {
code = TSDB_CODE_PAR_PRIMARY_KEY_IS_NULL;
goto _exit;
}
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;
}
int32_t tColDataAddValueByBind2(SColData *pColData, TAOS_STMT2_BIND *pBind, int32_t buffMaxLen) {
int32_t code = 0;
if (!(pBind->num == 1 && pBind->is_null && *pBind->is_null)) {
if (!(pColData->type == pBind->buffer_type)) {
return TSDB_CODE_INVALID_PARA;
}
}
if (IS_VAR_DATA_TYPE(pColData->type)) { // var-length data type
uint8_t *buf = pBind->buffer;
for (int32_t i = 0; i < pBind->num; ++i) {
if (pBind->is_null && pBind->is_null[i]) {
if (pColData->cflag & COL_IS_KEY) {
code = TSDB_CODE_PAR_PRIMARY_KEY_IS_NULL;
goto _exit;
}
if (pBind->is_null[i] == 1) {
code = tColDataAppendValueImpl[pColData->flag][CV_FLAG_NULL](pColData, NULL, 0);
if (code) goto _exit;
} else {
code = tColDataAppendValueImpl[pColData->flag][CV_FLAG_NONE](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, buf, pBind->length[i]);
buf += pBind->length[i];
}
}
} else { // fixed-length data type
bool allValue;
bool allNull;
bool allNone;
if (pBind->is_null) {
bool same = (memcmp(pBind->is_null, pBind->is_null + 1, pBind->num - 1) == 0);
allNull = (same && pBind->is_null[0] == 1);
allNone = (same && pBind->is_null[0] > 1);
allValue = (same && pBind->is_null[0] == 0);
} else {
allNull = false;
allNone = false;
allValue = true;
}
if ((pColData->cflag & COL_IS_KEY) && !allValue) {
code = TSDB_CODE_PAR_PRIMARY_KEY_IS_NULL;
goto _exit;
}
if (allValue) {
// optimize (todo)
for (int32_t i = 0; i < pBind->num; ++i) {
uint8_t *val = (uint8_t *)pBind->buffer + TYPE_BYTES[pColData->type] * i;
if (TSDB_DATA_TYPE_BOOL == pColData->type && *val > 1) {
*val = 1;
}
code = tColDataAppendValueImpl[pColData->flag][CV_FLAG_VALUE](pColData, val, TYPE_BYTES[pColData->type]);
}
} 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 if (allNone) {
// optimize (todo)
for (int32_t i = 0; i < pBind->num; ++i) {
code = tColDataAppendValueImpl[pColData->flag][CV_FLAG_NONE](pColData, NULL, 0);
if (code) goto _exit;
}
} else {
for (int32_t i = 0; i < pBind->num; ++i) {
if (pBind->is_null[i]) {
if (pBind->is_null[i] == 1) {
code = tColDataAppendValueImpl[pColData->flag][CV_FLAG_NULL](pColData, NULL, 0);
if (code) goto _exit;
} else {
code = tColDataAppendValueImpl[pColData->flag][CV_FLAG_NONE](pColData, NULL, 0);
if (code) goto _exit;
}
} else {
uint8_t *val = (uint8_t *)pBind->buffer + TYPE_BYTES[pColData->type] * i;
if (TSDB_DATA_TYPE_BOOL == pColData->type && *val > 1) {
*val = 1;
}
code = tColDataAppendValueImpl[pColData->flag][CV_FLAG_VALUE](pColData, val, TYPE_BYTES[pColData->type]);
}
}
}
}
_exit:
return code;
}
/* build rows to `rowArray` from bind
* `infos` is the bind information array
* `numOfInfos` is the number of bind information
* `infoSorted` is whether the bind information is sorted by column id
* `pTSchema` is the schema of the table
* `rowArray` is the array to store the rows
*/
int32_t tRowBuildFromBind2(SBindInfo2 *infos, int32_t numOfInfos, bool infoSorted, const STSchema *pTSchema,
SArray *rowArray) {
if (infos == NULL || numOfInfos <= 0 || numOfInfos > pTSchema->numOfCols || pTSchema == NULL || rowArray == NULL) {
return TSDB_CODE_INVALID_PARA;
}
if (!infoSorted) {
taosqsort_r(infos, numOfInfos, sizeof(SBindInfo), NULL, tBindInfoCompare);
}
int32_t code = 0;
int32_t numOfRows = infos[0].bind->num;
SArray *colValArray, *bufArray;
SColVal colVal;
if ((colValArray = taosArrayInit(numOfInfos, sizeof(SColVal))) == NULL) {
return terrno;
}
if ((bufArray = taosArrayInit(numOfInfos, sizeof(uint8_t *))) == NULL) {
taosArrayDestroy(colValArray);
return terrno;
}
for (int i = 0; i < numOfInfos; ++i) {
if (!taosArrayPush(bufArray, &infos[i].bind->buffer)) {
taosArrayDestroy(colValArray);
taosArrayDestroy(bufArray);
return terrno;
}
}
for (int32_t iRow = 0; iRow < numOfRows; iRow++) {
taosArrayClear(colValArray);
for (int32_t iInfo = 0; iInfo < numOfInfos; iInfo++) {
if (infos[iInfo].bind->is_null && infos[iInfo].bind->is_null[iRow]) {
if (infos[iInfo].bind->is_null[iRow] == 1) {
colVal = COL_VAL_NULL(infos[iInfo].columnId, infos[iInfo].type);
} else {
colVal = COL_VAL_NONE(infos[iInfo].columnId, infos[iInfo].type);
}
} else {
SValue value = {
.type = infos[iInfo].type,
};
if (IS_VAR_DATA_TYPE(infos[iInfo].type)) {
int32_t length = infos[iInfo].bind->length[iRow];
uint8_t **data = &((uint8_t **)TARRAY_DATA(bufArray))[iInfo];
value.nData = length;
if (value.nData > pTSchema->columns[iInfo].bytes - VARSTR_HEADER_SIZE) {
code = TSDB_CODE_INVALID_PARA;
goto _exit;
}
value.pData = *data;
*data += length;
// value.pData = (uint8_t *)infos[iInfo].bind->buffer + infos[iInfo].bind->buffer_length * iRow;
} else {
uint8_t *val = (uint8_t *)infos[iInfo].bind->buffer + infos[iInfo].bytes * iRow;
if (TSDB_DATA_TYPE_BOOL == value.type && *val > 1) {
*val = 1;
}
(void)memcpy(&value.val, val,
/*(uint8_t *)infos[iInfo].bind->buffer + infos[iInfo].bind->buffer_length * iRow,*/
infos[iInfo].bytes /*bind->buffer_length*/);
}
colVal = COL_VAL_VALUE(infos[iInfo].columnId, value);
}
if (taosArrayPush(colValArray, &colVal) == NULL) {
code = terrno;
goto _exit;
}
}
SRow *row;
if ((code = tRowBuild(colValArray, pTSchema, &row))) {
goto _exit;
}
if ((taosArrayPush(rowArray, &row)) == NULL) {
code = terrno;
goto _exit;
}
}
_exit:
taosArrayDestroy(colValArray);
taosArrayDestroy(bufArray);
return code;
}
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;
}
(void)memcpy(pToColData->pData + pToColData->aOffset[iToRow], pFromColData->pData + pFromColData->aOffset[iFromRow],
nData);
} else {
(void)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: {
TAOS_CHECK_RETURN(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));
TAOS_CHECK_RETURN(tColDataCopyRowCell(pFromColData, iFromRow, pToColData, iToRow));
} break;
case (HAS_VALUE | HAS_NULL | HAS_NONE): {
SET_BIT2(pToColData->pBitMap, iToRow, GET_BIT2(pFromColData->pBitMap, iFromRow));
TAOS_CHECK_RETURN(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;
}
void tColDataArrGetRowKey(SColData *aColData, int32_t nColData, int32_t iRow, SRowKey *key) {
SColVal cv;
key->ts = ((TSKEY *)aColData[0].pData)[iRow];
key->numOfPKs = 0;
for (int i = 1; i < nColData; i++) {
if (aColData[i].cflag & COL_IS_KEY) {
tColDataGetValue4(&aColData[i], iRow, &cv);
key->pks[key->numOfPKs++] = cv.value;
} else {
break;
}
}
}
static int32_t tColDataMergeSortMerge(SColData *aColData, int32_t start, int32_t mid, int32_t end, int32_t nColData) {
SColData *aDstColData = NULL;
int32_t i = start, j = mid + 1, k = 0;
SRowKey keyi, keyj;
if (end > start) {
aDstColData = taosMemoryCalloc(1, sizeof(SColData) * nColData);
if (aDstColData == NULL) {
return terrno;
}
for (int c = 0; c < nColData; ++c) {
tColDataInit(&aDstColData[c], aColData[c].cid, aColData[c].type, aColData[c].cflag);
}
}
tColDataArrGetRowKey(aColData, nColData, i, &keyi);
tColDataArrGetRowKey(aColData, nColData, j, &keyj);
while (i <= mid && j <= end) {
if (tRowKeyCompare(&keyi, &keyj) <= 0) {
TAOS_CHECK_RETURN(tColDataCopyRowAppend(aColData, i++, aDstColData, nColData));
tColDataArrGetRowKey(aColData, nColData, i, &keyi);
} else {
TAOS_CHECK_RETURN(tColDataCopyRowAppend(aColData, j++, aDstColData, nColData));
tColDataArrGetRowKey(aColData, nColData, j, &keyj);
}
}
while (i <= mid) {
TAOS_CHECK_RETURN(tColDataCopyRowAppend(aColData, i++, aDstColData, nColData));
}
while (j <= end) {
TAOS_CHECK_RETURN(tColDataCopyRowAppend(aColData, j++, aDstColData, nColData));
}
for (i = start, k = 0; i <= end; ++i, ++k) {
TAOS_CHECK_RETURN(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 int32_t tColDataMerge(SArray **colArr) {
int32_t code = 0;
SArray *src = *colArr;
SArray *dst = NULL;
dst = taosArrayInit(taosArrayGetSize(src), sizeof(SColData));
if (dst == NULL) {
return terrno;
}
for (int32_t i = 0; i < taosArrayGetSize(src); i++) {
SColData *srcCol = taosArrayGet(src, i);
SColData *dstCol = taosArrayReserve(dst, 1);
if (dstCol == NULL) {
code = terrno;
goto _exit;
}
tColDataInit(dstCol, srcCol->cid, srcCol->type, srcCol->cflag);
}
int32_t numRows = ((SColData *)TARRAY_DATA(src))->nVal;
SRowKey lastKey;
for (int32_t i = 0; i < numRows; i++) {
SRowKey key;
tColDataArrGetRowKey((SColData *)TARRAY_DATA(src), taosArrayGetSize(src), i, &key);
if (i == 0 || tRowKeyCompare(&key, &lastKey) != 0) { // append new row
for (int32_t j = 0; j < taosArrayGetSize(src); j++) {
SColData *srcCol = taosArrayGet(src, j);
SColData *dstCol = taosArrayGet(dst, j);
SColVal cv;
tColDataGetValue(srcCol, i, &cv);
code = tColDataAppendValue(dstCol, &cv);
if (code) {
goto _exit;
}
}
lastKey = key;
} else { // update existing row
for (int32_t j = 0; j < taosArrayGetSize(src); j++) {
SColData *srcCol = taosArrayGet(src, j);
SColData *dstCol = taosArrayGet(dst, j);
SColVal cv;
tColDataGetValue(srcCol, i, &cv);
code = tColDataUpdateValue(dstCol, &cv, true);
if (code) {
goto _exit;
}
}
}
}
_exit:
if (code) {
taosArrayDestroyEx(dst, tColDataDestroy);
} else {
taosArrayDestroyEx(src, tColDataDestroy);
*colArr = dst;
}
return code;
}
int32_t tColDataSortMerge(SArray **arr) {
SArray *colDataArr = *arr;
int32_t nColData = TARRAY_SIZE(colDataArr);
SColData *aColData = (SColData *)TARRAY_DATA(colDataArr);
if (!(aColData[0].type == TSDB_DATA_TYPE_TIMESTAMP)) {
return TSDB_CODE_INVALID_PARA;
}
if (!(aColData[0].cid == PRIMARYKEY_TIMESTAMP_COL_ID)) {
return TSDB_CODE_INVALID_PARA;
}
if (!(aColData[0].flag == HAS_VALUE)) {
return TSDB_CODE_INVALID_PARA;
}
if (aColData[0].nVal <= 1) goto _exit;
int8_t doSort = 0;
int8_t doMerge = 0;
// scan -------
SRowKey lastKey;
tColDataArrGetRowKey(aColData, nColData, 0, &lastKey);
for (int32_t iVal = 1; iVal < aColData[0].nVal; ++iVal) {
SRowKey key;
tColDataArrGetRowKey(aColData, nColData, iVal, &key);
int32_t c = tRowKeyCompare(&lastKey, &key);
if (c < 0) {
lastKey = key;
continue;
} else if (c > 0) {
doSort = 1;
break;
} else {
doMerge = 1;
}
}
// sort -------
if (doSort) {
TAOS_CHECK_RETURN(tColDataSort(aColData, nColData));
}
if (doMerge != 1) {
tColDataArrGetRowKey(aColData, nColData, 0, &lastKey);
for (int32_t iVal = 1; iVal < aColData[0].nVal; ++iVal) {
SRowKey key;
tColDataArrGetRowKey(aColData, nColData, iVal, &key);
int32_t c = tRowKeyCompare(&lastKey, &key);
if (c == 0) {
doMerge = 1;
break;
}
lastKey = key;
}
}
// merge -------
if (doMerge) {
int32_t code = tColDataMerge(arr);
if (code) return code;
}
_exit:
return 0;
}
static int32_t tPutColDataVersion0(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) (void)memcpy(pBuf + n, pColData->pBitMap, BIT1_SIZE(pColData->nVal));
n += BIT1_SIZE(pColData->nVal);
break;
case (HAS_VALUE | HAS_NULL | HAS_NONE):
if (pBuf) (void)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) (void)memcpy(pBuf + n, pColData->aOffset, pColData->nVal << 2);
n += (pColData->nVal << 2);
n += tPutI32v(pBuf ? pBuf + n : NULL, pColData->nData);
if (pBuf) (void)memcpy(pBuf + n, pColData->pData, pColData->nData);
n += pColData->nData;
} else {
if (pBuf) (void)memcpy(pBuf + n, pColData->pData, pColData->nData);
n += pColData->nData;
}
}
return n;
}
static int32_t tGetColDataVersion0(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;
}
}
pColData->cflag = 0;
return n;
}
static int32_t tPutColDataVersion1(uint8_t *pBuf, SColData *pColData) {
int32_t n = tPutColDataVersion0(pBuf, pColData);
n += tPutI8(pBuf ? pBuf + n : NULL, pColData->cflag);
return n;
}
static int32_t tGetColDataVersion1(uint8_t *pBuf, SColData *pColData) {
int32_t n = tGetColDataVersion0(pBuf, pColData);
n += tGetI8(pBuf ? pBuf + n : NULL, &pColData->cflag);
return n;
}
int32_t tPutColData(uint8_t version, uint8_t *pBuf, SColData *pColData) {
if (version == 0) {
return tPutColDataVersion0(pBuf, pColData);
} else if (version == 1) {
return tPutColDataVersion1(pBuf, pColData);
} else {
return TSDB_CODE_INVALID_PARA;
}
}
int32_t tGetColData(uint8_t version, uint8_t *pBuf, SColData *pColData) {
if (version == 0) {
return tGetColDataVersion0(pBuf, pColData);
} else if (version == 1) {
return tGetColDataVersion1(pBuf, pColData);
} else {
return TSDB_CODE_INVALID_PARA;
}
}
#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:
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:
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:
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:
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:
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:
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:
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:
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:
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:
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:
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:
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
tColDataCalcSMAVarType, // TSDB_DATA_TYPE_VARBINARY
tColDataCalcSMAVarType, // TSDB_DATA_TYPE_DECIMAL
tColDataCalcSMAVarType, // TSDB_DATA_TYPE_BLOB
NULL, // TSDB_DATA_TYPE_MEDIUMBLOB
tColDataCalcSMAVarType // TSDB_DATA_TYPE_GEOMETRY
};
// SValueColumn ================================
int32_t tValueColumnInit(SValueColumn *valCol) {
valCol->type = TSDB_DATA_TYPE_NULL;
valCol->numOfValues = 0;
tBufferInit(&valCol->data);
tBufferInit(&valCol->offsets);
return 0;
}
void tValueColumnDestroy(SValueColumn *valCol) {
valCol->type = TSDB_DATA_TYPE_NULL;
valCol->numOfValues = 0;
tBufferDestroy(&valCol->data);
tBufferDestroy(&valCol->offsets);
return;
}
void tValueColumnClear(SValueColumn *valCol) {
valCol->type = TSDB_DATA_TYPE_NULL;
valCol->numOfValues = 0;
tBufferClear(&valCol->data);
tBufferClear(&valCol->offsets);
return;
}
int32_t tValueColumnAppend(SValueColumn *valCol, const SValue *value) {
int32_t code;
if (valCol->numOfValues == 0) {
valCol->type = value->type;
}
if (!(value->type == valCol->type)) {
return TSDB_CODE_INVALID_PARA;
}
if (IS_VAR_DATA_TYPE(value->type)) {
if ((code = tBufferPutI32(&valCol->offsets, tBufferGetSize(&valCol->data)))) {
return code;
}
if ((code = tBufferPut(&valCol->data, value->pData, value->nData))) {
return code;
}
} else {
code = tBufferPut(&valCol->data, &value->val, tDataTypes[value->type].bytes);
if (code) return code;
}
valCol->numOfValues++;
return 0;
}
int32_t tValueColumnUpdate(SValueColumn *valCol, int32_t idx, const SValue *value) {
int32_t code;
if (idx < 0 || idx >= valCol->numOfValues) {
return TSDB_CODE_OUT_OF_RANGE;
}
if (IS_VAR_DATA_TYPE(valCol->type)) {
int32_t *offsets = (int32_t *)tBufferGetData(&valCol->offsets);
int32_t nextOffset = (idx == valCol->numOfValues - 1) ? tBufferGetSize(&valCol->data) : offsets[idx + 1];
int32_t oldDataSize = nextOffset - offsets[idx];
int32_t bytesAdded = value->nData - oldDataSize;
if (bytesAdded != 0) {
if ((code = tBufferEnsureCapacity(&valCol->data, tBufferGetSize(&valCol->data) + bytesAdded))) return code;
memmove(tBufferGetDataAt(&valCol->data, nextOffset + bytesAdded), tBufferGetDataAt(&valCol->data, nextOffset),
tBufferGetSize(&valCol->data) - nextOffset);
valCol->data.size += bytesAdded;
for (int32_t i = idx + 1; i < valCol->numOfValues; i++) {
offsets[i] += bytesAdded;
}
}
return tBufferPutAt(&valCol->data, offsets[idx], value->pData, value->nData);
} else {
return tBufferPutAt(&valCol->data, idx * tDataTypes[valCol->type].bytes, &value->val,
tDataTypes[valCol->type].bytes);
}
return 0;
}
int32_t tValueColumnGet(SValueColumn *valCol, int32_t idx, SValue *value) {
if (idx < 0 || idx >= valCol->numOfValues) {
return TSDB_CODE_OUT_OF_RANGE;
}
value->type = valCol->type;
if (IS_VAR_DATA_TYPE(value->type)) {
int32_t offset, nextOffset;
SBufferReader reader = BUFFER_READER_INITIALIZER(idx * sizeof(offset), &valCol->offsets);
TAOS_CHECK_RETURN(tBufferGetI32(&reader, &offset));
if (idx == valCol->numOfValues - 1) {
nextOffset = tBufferGetSize(&valCol->data);
} else {
TAOS_CHECK_RETURN(tBufferGetI32(&reader, &nextOffset));
}
value->nData = nextOffset - offset;
value->pData = (uint8_t *)tBufferGetDataAt(&valCol->data, offset);
} else {
SBufferReader reader = BUFFER_READER_INITIALIZER(idx * tDataTypes[value->type].bytes, &valCol->data);
TAOS_CHECK_RETURN(tBufferGet(&reader, tDataTypes[value->type].bytes, &value->val));
}
return 0;
}
int32_t tValueColumnCompress(SValueColumn *valCol, SValueColumnCompressInfo *info, SBuffer *output, SBuffer *assist) {
int32_t code;
if (!(valCol->numOfValues > 0)) {
return TSDB_CODE_INVALID_PARA;
}
(*info) = (SValueColumnCompressInfo){
.cmprAlg = info->cmprAlg,
.type = valCol->type,
};
// offset
if (IS_VAR_DATA_TYPE(valCol->type)) {
SCompressInfo cinfo = {
.cmprAlg = info->cmprAlg,
.dataType = TSDB_DATA_TYPE_INT,
.originalSize = valCol->offsets.size,
};
code = tCompressDataToBuffer(valCol->offsets.data, &cinfo, output, assist);
if (code) return code;
info->offsetOriginalSize = cinfo.originalSize;
info->offsetCompressedSize = cinfo.compressedSize;
}
// data
SCompressInfo cinfo = {
.cmprAlg = info->cmprAlg,
.dataType = valCol->type,
.originalSize = valCol->data.size,
};
code = tCompressDataToBuffer(valCol->data.data, &cinfo, output, assist);
if (code) return code;
info->dataOriginalSize = cinfo.originalSize;
info->dataCompressedSize = cinfo.compressedSize;
return 0;
}
int32_t tValueColumnDecompress(void *input, const SValueColumnCompressInfo *info, SValueColumn *valCol,
SBuffer *assist) {
int32_t code;
tValueColumnClear(valCol);
valCol->type = info->type;
// offset
if (IS_VAR_DATA_TYPE(valCol->type)) {
valCol->numOfValues = info->offsetOriginalSize / tDataTypes[TSDB_DATA_TYPE_INT].bytes;
SCompressInfo cinfo = {
.dataType = TSDB_DATA_TYPE_INT,
.cmprAlg = info->cmprAlg,
.originalSize = info->offsetOriginalSize,
.compressedSize = info->offsetCompressedSize,
};
code = tDecompressDataToBuffer(input, &cinfo, &valCol->offsets, assist);
if (code) {
return code;
}
} else {
valCol->numOfValues = info->dataOriginalSize / tDataTypes[valCol->type].bytes;
}
// data
SCompressInfo cinfo = {
.dataType = valCol->type,
.cmprAlg = info->cmprAlg,
.originalSize = info->dataOriginalSize,
.compressedSize = info->dataCompressedSize,
};
code = tDecompressDataToBuffer((char *)input + info->offsetCompressedSize, &cinfo, &valCol->data, assist);
if (code) {
return code;
}
return 0;
}
int32_t tValueColumnCompressInfoEncode(const SValueColumnCompressInfo *info, SBuffer *buffer) {
int32_t code;
uint8_t fmtVer = 0;
if ((code = tBufferPutU8(buffer, fmtVer))) return code;
if ((code = tBufferPutI8(buffer, info->cmprAlg))) return code;
if ((code = tBufferPutI8(buffer, info->type))) return code;
if (IS_VAR_DATA_TYPE(info->type)) {
if ((code = tBufferPutI32v(buffer, info->offsetOriginalSize))) return code;
if ((code = tBufferPutI32v(buffer, info->offsetCompressedSize))) return code;
}
if ((code = tBufferPutI32v(buffer, info->dataOriginalSize))) return code;
if ((code = tBufferPutI32v(buffer, info->dataCompressedSize))) return code;
return 0;
}
int32_t tValueColumnCompressInfoDecode(SBufferReader *reader, SValueColumnCompressInfo *info) {
int32_t code;
uint8_t fmtVer;
if ((code = tBufferGetU8(reader, &fmtVer))) return code;
if (fmtVer == 0) {
if ((code = tBufferGetI8(reader, &info->cmprAlg))) return code;
if ((code = tBufferGetI8(reader, &info->type))) return code;
if (IS_VAR_DATA_TYPE(info->type)) {
if ((code = tBufferGetI32v(reader, &info->offsetOriginalSize))) return code;
if ((code = tBufferGetI32v(reader, &info->offsetCompressedSize))) return code;
} else {
info->offsetOriginalSize = 0;
info->offsetCompressedSize = 0;
}
if ((code = tBufferGetI32v(reader, &info->dataOriginalSize))) return code;
if ((code = tBufferGetI32v(reader, &info->dataCompressedSize))) return code;
} else {
return TSDB_CODE_INVALID_PARA;
}
return 0;
}
int32_t tCompressData(void *input, // input
SCompressInfo *info, // compress info
void *output, // output
int32_t outputSize, // output size
SBuffer *buffer // assistant buffer provided by caller, can be NULL
) {
int32_t extraSizeNeeded;
int32_t code;
extraSizeNeeded = (info->cmprAlg == NO_COMPRESSION) ? info->originalSize : info->originalSize + COMP_OVERFLOW_BYTES;
if (!(outputSize >= extraSizeNeeded)) {
return TSDB_CODE_INVALID_PARA;
}
if (info->cmprAlg == NO_COMPRESSION) {
(void)memcpy(output, input, info->originalSize);
info->compressedSize = info->originalSize;
} else if (info->cmprAlg == ONE_STAGE_COMP || info->cmprAlg == TWO_STAGE_COMP) {
SBuffer local;
tBufferInit(&local);
if (buffer == NULL) {
buffer = &local;
}
if (info->cmprAlg == TWO_STAGE_COMP) {
code = tBufferEnsureCapacity(buffer, extraSizeNeeded);
if (code) {
tBufferDestroy(&local);
return code;
}
}
info->compressedSize = tDataTypes[info->dataType].compFunc( //
input, // input
info->originalSize, // input size
info->originalSize / tDataTypes[info->dataType].bytes, // number of elements
output, // output
outputSize, // output size
info->cmprAlg, // compression algorithm
buffer->data, // buffer
buffer->capacity // buffer size
);
if (info->compressedSize < 0) {
tBufferDestroy(&local);
return TSDB_CODE_COMPRESS_ERROR;
}
tBufferDestroy(&local);
} else {
DEFINE_VAR(info->cmprAlg)
if ((l1 == L1_UNKNOWN && l2 == L2_UNKNOWN) || (l1 == L1_DISABLED && l2 == L2_DISABLED)) {
(void)memcpy(output, input, info->originalSize);
info->compressedSize = info->originalSize;
return 0;
}
SBuffer local;
tBufferInit(&local);
if (buffer == NULL) {
buffer = &local;
}
code = tBufferEnsureCapacity(buffer, extraSizeNeeded);
info->compressedSize = tDataCompress[info->dataType].compFunc( //
input, // input
info->originalSize, // input size
info->originalSize / tDataTypes[info->dataType].bytes, // number of elements
output, // output
outputSize, // output size
info->cmprAlg, // compression algorithm
buffer->data, // buffer
buffer->capacity // buffer size
);
if (info->compressedSize < 0) {
tBufferDestroy(&local);
return TSDB_CODE_COMPRESS_ERROR;
}
tBufferDestroy(&local);
// new col compress
}
return 0;
}
int32_t tDecompressData(void *input, // input
const SCompressInfo *info, // compress info
void *output, // output
int32_t outputSize, // output size
SBuffer *buffer // assistant buffer provided by caller, can be NULL
) {
int32_t code;
if (!(outputSize >= info->originalSize)) {
return TSDB_CODE_INVALID_PARA;
}
if (info->cmprAlg == NO_COMPRESSION) {
if (!(info->compressedSize == info->originalSize)) {
return TSDB_CODE_INVALID_PARA;
}
(void)memcpy(output, input, info->compressedSize);
} else if (info->cmprAlg == ONE_STAGE_COMP || info->cmprAlg == TWO_STAGE_COMP) {
SBuffer local;
tBufferInit(&local);
if (buffer == NULL) {
buffer = &local;
}
if (info->cmprAlg == TWO_STAGE_COMP) {
code = tBufferEnsureCapacity(buffer, info->originalSize + COMP_OVERFLOW_BYTES);
if (code) {
tBufferDestroy(&local);
return code;
}
}
int32_t decompressedSize = tDataTypes[info->dataType].decompFunc(
input, // input
info->compressedSize, // inputSize
info->originalSize / tDataTypes[info->dataType].bytes, // number of elements
output, // output
outputSize, // output size
info->cmprAlg, // compression algorithm
buffer->data, // helper buffer
buffer->capacity // extra buffer size
);
if (decompressedSize < 0) {
tBufferDestroy(&local);
return TSDB_CODE_COMPRESS_ERROR;
}
if (!(decompressedSize == info->originalSize)) {
return TSDB_CODE_COMPRESS_ERROR;
}
tBufferDestroy(&local);
} else {
DEFINE_VAR(info->cmprAlg);
if (l1 == L1_DISABLED && l2 == L2_DISABLED) {
(void)memcpy(output, input, info->compressedSize);
return 0;
}
SBuffer local;
tBufferInit(&local);
if (buffer == NULL) {
buffer = &local;
}
code = tBufferEnsureCapacity(buffer, info->originalSize + COMP_OVERFLOW_BYTES);
if (code) {
return code;
}
int32_t decompressedSize = tDataCompress[info->dataType].decompFunc(
input, // input
info->compressedSize, // inputSize
info->originalSize / tDataTypes[info->dataType].bytes, // number of elements
output, // output
outputSize, // output size
info->cmprAlg, // compression algorithm
buffer->data, // helper buffer
buffer->capacity // extra buffer size
);
if (decompressedSize < 0) {
tBufferDestroy(&local);
return TSDB_CODE_COMPRESS_ERROR;
}
if (!(decompressedSize == info->originalSize)) {
return TSDB_CODE_COMPRESS_ERROR;
}
tBufferDestroy(&local);
}
return 0;
}
int32_t tCompressDataToBuffer(void *input, SCompressInfo *info, SBuffer *output, SBuffer *assist) {
int32_t code;
code = tBufferEnsureCapacity(output, output->size + info->originalSize + COMP_OVERFLOW_BYTES);
if (code) return code;
code = tCompressData(input, info, tBufferGetDataEnd(output), output->capacity - output->size, assist);
if (code) return code;
output->size += info->compressedSize;
return 0;
}
int32_t tDecompressDataToBuffer(void *input, SCompressInfo *info, SBuffer *output, SBuffer *assist) {
int32_t code;
code = tBufferEnsureCapacity(output, output->size + info->originalSize);
if (code) return code;
code = tDecompressData(input, info, tBufferGetDataEnd(output), output->capacity - output->size, assist);
if (code) return code;
output->size += info->originalSize;
return 0;
}