[TD-2339]<feature>: interpolation can be applied along with the time window.
This commit is contained in:
parent
d50054c732
commit
9dc0bf6c86
|
@ -2194,6 +2194,7 @@ int32_t addExprAndResultField(SSqlCmd* pCmd, SQueryInfo* pQueryInfo, int32_t col
|
||||||
if (getColumnIndexByName(pCmd, &pParamElem->pNode->colInfo, pQueryInfo, &index) != TSDB_CODE_SUCCESS) {
|
if (getColumnIndexByName(pCmd, &pParamElem->pNode->colInfo, pQueryInfo, &index) != TSDB_CODE_SUCCESS) {
|
||||||
return invalidSqlErrMsg(tscGetErrorMsgPayload(pCmd), msg3);
|
return invalidSqlErrMsg(tscGetErrorMsgPayload(pCmd), msg3);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (index.columnIndex == TSDB_TBNAME_COLUMN_INDEX) {
|
if (index.columnIndex == TSDB_TBNAME_COLUMN_INDEX) {
|
||||||
return invalidSqlErrMsg(tscGetErrorMsgPayload(pCmd), msg6);
|
return invalidSqlErrMsg(tscGetErrorMsgPayload(pCmd), msg6);
|
||||||
}
|
}
|
||||||
|
@ -4524,10 +4525,10 @@ int32_t parseFillClause(SSqlCmd* pCmd, SQueryInfo* pQueryInfo, SQuerySQL* pQuery
|
||||||
return invalidSqlErrMsg(tscGetErrorMsgPayload(pCmd), msg2);
|
return invalidSqlErrMsg(tscGetErrorMsgPayload(pCmd), msg2);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t size = tscNumOfFields(pQueryInfo);
|
size_t numOfFields = tscNumOfFields(pQueryInfo);
|
||||||
|
|
||||||
if (pQueryInfo->fillVal == NULL) {
|
if (pQueryInfo->fillVal == NULL) {
|
||||||
pQueryInfo->fillVal = calloc(size, sizeof(int64_t));
|
pQueryInfo->fillVal = calloc(numOfFields, sizeof(int64_t));
|
||||||
if (pQueryInfo->fillVal == NULL) {
|
if (pQueryInfo->fillVal == NULL) {
|
||||||
return TSDB_CODE_TSC_OUT_OF_MEMORY;
|
return TSDB_CODE_TSC_OUT_OF_MEMORY;
|
||||||
}
|
}
|
||||||
|
@ -4537,7 +4538,7 @@ int32_t parseFillClause(SSqlCmd* pCmd, SQueryInfo* pQueryInfo, SQuerySQL* pQuery
|
||||||
pQueryInfo->fillType = TSDB_FILL_NONE;
|
pQueryInfo->fillType = TSDB_FILL_NONE;
|
||||||
} else if (strncasecmp(pItem->pVar.pz, "null", 4) == 0 && pItem->pVar.nLen == 4) {
|
} else if (strncasecmp(pItem->pVar.pz, "null", 4) == 0 && pItem->pVar.nLen == 4) {
|
||||||
pQueryInfo->fillType = TSDB_FILL_NULL;
|
pQueryInfo->fillType = TSDB_FILL_NULL;
|
||||||
for (int32_t i = START_INTERPO_COL_IDX; i < size; ++i) {
|
for (int32_t i = START_INTERPO_COL_IDX; i < numOfFields; ++i) {
|
||||||
TAOS_FIELD* pField = tscFieldInfoGetField(&pQueryInfo->fieldsInfo, i);
|
TAOS_FIELD* pField = tscFieldInfoGetField(&pQueryInfo->fieldsInfo, i);
|
||||||
setNull((char*)&pQueryInfo->fillVal[i], pField->type, pField->bytes);
|
setNull((char*)&pQueryInfo->fillVal[i], pField->type, pField->bytes);
|
||||||
}
|
}
|
||||||
|
@ -4551,7 +4552,7 @@ int32_t parseFillClause(SSqlCmd* pCmd, SQueryInfo* pQueryInfo, SQuerySQL* pQuery
|
||||||
pQueryInfo->fillType = TSDB_FILL_SET_VALUE;
|
pQueryInfo->fillType = TSDB_FILL_SET_VALUE;
|
||||||
|
|
||||||
size_t num = taosArrayGetSize(pFillToken);
|
size_t num = taosArrayGetSize(pFillToken);
|
||||||
if (num == 1) {
|
if (num == 1) { // no actual value, return with error code
|
||||||
return invalidSqlErrMsg(tscGetErrorMsgPayload(pCmd), msg1);
|
return invalidSqlErrMsg(tscGetErrorMsgPayload(pCmd), msg1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4562,11 +4563,11 @@ int32_t parseFillClause(SSqlCmd* pCmd, SQueryInfo* pQueryInfo, SQuerySQL* pQuery
|
||||||
if (tscIsPointInterpQuery(pQueryInfo)) {
|
if (tscIsPointInterpQuery(pQueryInfo)) {
|
||||||
startPos = 0;
|
startPos = 0;
|
||||||
|
|
||||||
if (numOfFillVal > size) {
|
if (numOfFillVal > numOfFields) {
|
||||||
numOfFillVal = (int32_t)size;
|
numOfFillVal = (int32_t)numOfFields;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
numOfFillVal = (int16_t)((num > (int32_t)size) ? (int32_t)size : num);
|
numOfFillVal = (int16_t)((num > (int32_t)numOfFields) ? (int32_t)numOfFields : num);
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t j = 1;
|
int32_t j = 1;
|
||||||
|
@ -4586,10 +4587,10 @@ int32_t parseFillClause(SSqlCmd* pCmd, SQueryInfo* pQueryInfo, SQuerySQL* pQuery
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((num < size) || ((num - 1 < size) && (tscIsPointInterpQuery(pQueryInfo)))) {
|
if ((num < numOfFields) || ((num - 1 < numOfFields) && (tscIsPointInterpQuery(pQueryInfo)))) {
|
||||||
tVariantListItem* lastItem = taosArrayGetLast(pFillToken);
|
tVariantListItem* lastItem = taosArrayGetLast(pFillToken);
|
||||||
|
|
||||||
for (int32_t i = numOfFillVal; i < size; ++i) {
|
for (int32_t i = numOfFillVal; i < numOfFields; ++i) {
|
||||||
TAOS_FIELD* pField = tscFieldInfoGetField(&pQueryInfo->fieldsInfo, i);
|
TAOS_FIELD* pField = tscFieldInfoGetField(&pQueryInfo->fieldsInfo, i);
|
||||||
|
|
||||||
if (pField->type == TSDB_DATA_TYPE_BINARY || pField->type == TSDB_DATA_TYPE_NCHAR) {
|
if (pField->type == TSDB_DATA_TYPE_BINARY || pField->type == TSDB_DATA_TYPE_NCHAR) {
|
||||||
|
|
|
@ -114,6 +114,8 @@ void* tsdbGetTableTagVal(const void* pTable, int32_t colId, int16_t type, int16_
|
||||||
char* tsdbGetTableName(void *pTable);
|
char* tsdbGetTableName(void *pTable);
|
||||||
|
|
||||||
#define TSDB_TABLEID(_table) ((STableId*) (_table))
|
#define TSDB_TABLEID(_table) ((STableId*) (_table))
|
||||||
|
#define TSDB_PREV_ROW 0x1
|
||||||
|
#define TSDB_NEXT_ROW 0x2
|
||||||
|
|
||||||
STableCfg *tsdbCreateTableCfgFromMsg(SMDCreateTableMsg *pMsg);
|
STableCfg *tsdbCreateTableCfgFromMsg(SMDCreateTableMsg *pMsg);
|
||||||
|
|
||||||
|
@ -141,7 +143,6 @@ typedef struct {
|
||||||
int64_t tableTotalDataSize; // In bytes
|
int64_t tableTotalDataSize; // In bytes
|
||||||
int64_t tableTotalDiskSize; // In bytes
|
int64_t tableTotalDiskSize; // In bytes
|
||||||
} STableInfo;
|
} STableInfo;
|
||||||
STableInfo *tsdbGetTableInfo(TSDB_REPO_T *pRepo, STableId tid);
|
|
||||||
|
|
||||||
// -- FOR INSERT DATA
|
// -- FOR INSERT DATA
|
||||||
/**
|
/**
|
||||||
|
@ -163,6 +164,7 @@ typedef struct STsdbQueryCond {
|
||||||
int32_t order; // desc|asc order to iterate the data block
|
int32_t order; // desc|asc order to iterate the data block
|
||||||
int32_t numOfCols;
|
int32_t numOfCols;
|
||||||
SColumnInfo *colList;
|
SColumnInfo *colList;
|
||||||
|
bool loadExternalRows; // load external rows or not
|
||||||
} STsdbQueryCond;
|
} STsdbQueryCond;
|
||||||
|
|
||||||
typedef struct SMemRef {
|
typedef struct SMemRef {
|
||||||
|
@ -240,6 +242,8 @@ TsdbQueryHandleT tsdbQueryRowsInExternalWindow(TSDB_REPO_T *tsdb, STsdbQueryCond
|
||||||
*/
|
*/
|
||||||
bool tsdbNextDataBlock(TsdbQueryHandleT *pQueryHandle);
|
bool tsdbNextDataBlock(TsdbQueryHandleT *pQueryHandle);
|
||||||
|
|
||||||
|
SArray* tsdbGetExternalRow(TsdbQueryHandleT *pHandle, SMemRef* pMemRef, int16_t type);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get current data block information
|
* Get current data block information
|
||||||
*
|
*
|
||||||
|
|
|
@ -45,6 +45,7 @@ typedef struct tstr {
|
||||||
case TSDB_DATA_TYPE_USMALLINT: \
|
case TSDB_DATA_TYPE_USMALLINT: \
|
||||||
(_v) = (_finalType)GET_UINT16_VAL(_data); \
|
(_v) = (_finalType)GET_UINT16_VAL(_data); \
|
||||||
break; \
|
break; \
|
||||||
|
case TSDB_DATA_TYPE_TIMESTAMP:\
|
||||||
case TSDB_DATA_TYPE_BIGINT: \
|
case TSDB_DATA_TYPE_BIGINT: \
|
||||||
(_v) = (_finalType)(GET_INT64_VAL(_data)); \
|
(_v) = (_finalType)(GET_INT64_VAL(_data)); \
|
||||||
break; \
|
break; \
|
||||||
|
@ -66,6 +67,43 @@ typedef struct tstr {
|
||||||
} \
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
|
#define SET_TYPED_DATA(_v, _type, _data) \
|
||||||
|
do { \
|
||||||
|
switch (_type) { \
|
||||||
|
case TSDB_DATA_TYPE_BOOL: \
|
||||||
|
case TSDB_DATA_TYPE_TINYINT: \
|
||||||
|
*(int8_t *)(_v) = (_data); \
|
||||||
|
break; \
|
||||||
|
case TSDB_DATA_TYPE_UTINYINT: \
|
||||||
|
*(uint8_t *)(_v) = (_data); \
|
||||||
|
break; \
|
||||||
|
case TSDB_DATA_TYPE_SMALLINT: \
|
||||||
|
*(int16_t *)(_v) = (_data); \
|
||||||
|
break; \
|
||||||
|
case TSDB_DATA_TYPE_USMALLINT: \
|
||||||
|
*(uint16_t *)(_v) = (_data); \
|
||||||
|
break; \
|
||||||
|
case TSDB_DATA_TYPE_BIGINT: \
|
||||||
|
*(int64_t *)(_v) = (_data); \
|
||||||
|
break; \
|
||||||
|
case TSDB_DATA_TYPE_UBIGINT: \
|
||||||
|
*(uint64_t *)(_v) = (_data); \
|
||||||
|
break; \
|
||||||
|
case TSDB_DATA_TYPE_FLOAT: \
|
||||||
|
*(float *)(_v) = (_data); \
|
||||||
|
break; \
|
||||||
|
case TSDB_DATA_TYPE_DOUBLE: \
|
||||||
|
*(double *)(_v) = (_data); \
|
||||||
|
break; \
|
||||||
|
case TSDB_DATA_TYPE_UINT: \
|
||||||
|
*(uint32_t *)(_v) = (_data); \
|
||||||
|
break; \
|
||||||
|
default: \
|
||||||
|
*(int32_t *)(_v) = (_data); \
|
||||||
|
break; \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
#define IS_SIGNED_NUMERIC_TYPE(_t) ((_t) >= TSDB_DATA_TYPE_TINYINT && (_t) <= TSDB_DATA_TYPE_BIGINT)
|
#define IS_SIGNED_NUMERIC_TYPE(_t) ((_t) >= TSDB_DATA_TYPE_TINYINT && (_t) <= TSDB_DATA_TYPE_BIGINT)
|
||||||
#define IS_UNSIGNED_NUMERIC_TYPE(_t) ((_t) >= TSDB_DATA_TYPE_UTINYINT && (_t) <= TSDB_DATA_TYPE_UBIGINT)
|
#define IS_UNSIGNED_NUMERIC_TYPE(_t) ((_t) >= TSDB_DATA_TYPE_UTINYINT && (_t) <= TSDB_DATA_TYPE_UBIGINT)
|
||||||
#define IS_FLOAT_TYPE(_t) ((_t) == TSDB_DATA_TYPE_FLOAT || (_t) == TSDB_DATA_TYPE_DOUBLE)
|
#define IS_FLOAT_TYPE(_t) ((_t) == TSDB_DATA_TYPE_FLOAT || (_t) == TSDB_DATA_TYPE_DOUBLE)
|
||||||
|
|
|
@ -169,6 +169,7 @@ typedef struct SQuery {
|
||||||
int32_t pos;
|
int32_t pos;
|
||||||
tFilePage** sdata;
|
tFilePage** sdata;
|
||||||
STableQueryInfo* current;
|
STableQueryInfo* current;
|
||||||
|
int32_t numOfCheckedBlocks; // number of check data blocks
|
||||||
|
|
||||||
SOrderedPrjQueryInfo prjInfo; // limit value for each vgroup, only available in global order projection query.
|
SOrderedPrjQueryInfo prjInfo; // limit value for each vgroup, only available in global order projection query.
|
||||||
SSingleColumnFilterInfo* pFilterInfo;
|
SSingleColumnFilterInfo* pFilterInfo;
|
||||||
|
|
|
@ -86,7 +86,7 @@ bool taosFillHasMoreResults(SFillInfo* pFillInfo);
|
||||||
|
|
||||||
int64_t getNumOfResultsAfterFillGap(SFillInfo* pFillInfo, int64_t ekey, int32_t maxNumOfRows);
|
int64_t getNumOfResultsAfterFillGap(SFillInfo* pFillInfo, int64_t ekey, int32_t maxNumOfRows);
|
||||||
|
|
||||||
int32_t taosGetLinearInterpolationVal(int32_t type, SPoint *point1, SPoint *point2, SPoint *point);
|
int32_t taosGetLinearInterpolationVal(SPoint* point, int32_t outputType, SPoint* point1, SPoint* point2, int32_t inputType);
|
||||||
|
|
||||||
int64_t taosFillResultDataBlock(SFillInfo* pFillInfo, tFilePage** output, int32_t capacity);
|
int64_t taosFillResultDataBlock(SFillInfo* pFillInfo, tFilePage** output, int32_t capacity);
|
||||||
|
|
||||||
|
|
|
@ -153,7 +153,7 @@ typedef struct SResultRowCellInfo {
|
||||||
|
|
||||||
typedef struct SPoint1 {
|
typedef struct SPoint1 {
|
||||||
int64_t key;
|
int64_t key;
|
||||||
double val;
|
union{double val; char* ptr;};
|
||||||
} SPoint1;
|
} SPoint1;
|
||||||
|
|
||||||
#define GET_ROWCELL_INTERBUF(_c) ((void*) ((char*)(_c) + sizeof(SResultRowCellInfo)))
|
#define GET_ROWCELL_INTERBUF(_c) ((void*) ((char*)(_c) + sizeof(SResultRowCellInfo)))
|
||||||
|
|
|
@ -3776,89 +3776,67 @@ void twa_function_finalizer(SQLFunctionCtx *pCtx) {
|
||||||
*
|
*
|
||||||
* @param pCtx
|
* @param pCtx
|
||||||
*/
|
*/
|
||||||
static void interp_function(SQLFunctionCtx *pCtx) {
|
|
||||||
// at this point, the value is existed, return directly
|
|
||||||
SResultRowCellInfo *pResInfo = GET_RES_INFO(pCtx);
|
|
||||||
SInterpInfoDetail* pInfo = GET_ROWCELL_INTERBUF(pResInfo);
|
|
||||||
|
|
||||||
assert(pCtx->startOffset == 0);
|
static void interp_function_impl(SQLFunctionCtx *pCtx) {
|
||||||
|
int32_t type = pCtx->param[2].i64;
|
||||||
if (pCtx->size == 1) {
|
if (type == TSDB_FILL_NONE) {
|
||||||
char *pData = GET_INPUT_DATA_LIST(pCtx);
|
|
||||||
assignVal(pCtx->aOutputBuf, pData, pCtx->inputBytes, pCtx->inputType);
|
|
||||||
} else {
|
|
||||||
/*
|
|
||||||
* use interpolation to generate the result.
|
|
||||||
* Note: the result of primary timestamp column uses the timestamp specified by user in the query sql
|
|
||||||
*/
|
|
||||||
assert(pCtx->size == 2);
|
|
||||||
if (pInfo->type == TSDB_FILL_NONE) { // set no output result
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pInfo->primaryCol == 1) {
|
if (pCtx->inputType == TSDB_DATA_TYPE_TIMESTAMP) {
|
||||||
*(TSKEY *) pCtx->aOutputBuf = pInfo->ts;
|
*(TSKEY *) pCtx->aOutputBuf = pCtx->nStartQueryTimestamp;
|
||||||
} else {
|
} else {
|
||||||
if (pInfo->type == TSDB_FILL_NULL) {
|
if (pCtx->start.key == INT64_MIN) {
|
||||||
if (pCtx->outputType == TSDB_DATA_TYPE_BINARY || pCtx->outputType == TSDB_DATA_TYPE_NCHAR) {
|
assert(pCtx->end.key == INT64_MIN);
|
||||||
setVardataNull(pCtx->aOutputBuf, pCtx->outputType);
|
return;
|
||||||
} else {
|
|
||||||
setNull(pCtx->aOutputBuf, pCtx->outputType, pCtx->outputBytes);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SET_VAL(pCtx, pCtx->size, 1);
|
if (type == TSDB_FILL_NULL) {
|
||||||
} else if (pInfo->type == TSDB_FILL_SET_VALUE) {
|
setNull(pCtx->aOutputBuf, pCtx->outputType, pCtx->outputBytes);
|
||||||
|
} else if (type == TSDB_FILL_SET_VALUE) {
|
||||||
tVariantDump(&pCtx->param[1], pCtx->aOutputBuf, pCtx->inputType, true);
|
tVariantDump(&pCtx->param[1], pCtx->aOutputBuf, pCtx->inputType, true);
|
||||||
} else if (pInfo->type == TSDB_FILL_PREV) {
|
} else if (type == TSDB_FILL_PREV) {
|
||||||
char *data = GET_INPUT_DATA(pCtx, 0);
|
if (IS_NUMERIC_TYPE(pCtx->inputType) || pCtx->inputType == TSDB_DATA_TYPE_BOOL) {
|
||||||
assignVal(pCtx->aOutputBuf, data, pCtx->outputBytes, pCtx->outputType);
|
SET_TYPED_DATA(pCtx->aOutputBuf, pCtx->inputType, pCtx->start.val);
|
||||||
|
} else {
|
||||||
SET_VAL(pCtx, pCtx->size, 1);
|
assignVal(pCtx->aOutputBuf, pCtx->start.ptr, pCtx->outputBytes, pCtx->inputType);
|
||||||
} else if (pInfo->type == TSDB_FILL_LINEAR) {
|
}
|
||||||
char *data1 = GET_INPUT_DATA(pCtx, 0);
|
} else if (type == TSDB_FILL_LINEAR) {
|
||||||
char *data2 = GET_INPUT_DATA(pCtx, 1);
|
SPoint point1 = {.key = pCtx->start.key, .val = &pCtx->start.val};
|
||||||
|
SPoint point2 = {.key = pCtx->end.key, .val = &pCtx->end.val};
|
||||||
TSKEY key1 = pCtx->ptsList[0];
|
SPoint point = {.key = pCtx->nStartQueryTimestamp, .val = pCtx->aOutputBuf};
|
||||||
TSKEY key2 = pCtx->ptsList[1];
|
|
||||||
|
|
||||||
SPoint point1 = {.key = key1, .val = data1};
|
|
||||||
SPoint point2 = {.key = key2, .val = data2};
|
|
||||||
|
|
||||||
SPoint point = {.key = pInfo->ts, .val = pCtx->aOutputBuf};
|
|
||||||
|
|
||||||
int32_t srcType = pCtx->inputType;
|
int32_t srcType = pCtx->inputType;
|
||||||
if ((srcType >= TSDB_DATA_TYPE_TINYINT && srcType <= TSDB_DATA_TYPE_BIGINT) ||
|
if (IS_NUMERIC_TYPE(srcType)) { // TODO should find the not null data?
|
||||||
srcType == TSDB_DATA_TYPE_TIMESTAMP || srcType == TSDB_DATA_TYPE_DOUBLE) {
|
if (isNull((char *)&pCtx->start.val, srcType) || isNull((char *)&pCtx->end.val, srcType)) {
|
||||||
point1.val = data1;
|
|
||||||
point2.val = data2;
|
|
||||||
|
|
||||||
if (isNull(data1, srcType) || isNull(data2, srcType)) {
|
|
||||||
setNull(pCtx->aOutputBuf, srcType, pCtx->inputBytes);
|
setNull(pCtx->aOutputBuf, srcType, pCtx->inputBytes);
|
||||||
} else {
|
} else {
|
||||||
taosGetLinearInterpolationVal(pCtx->outputType, &point1, &point2, &point);
|
taosGetLinearInterpolationVal(&point, pCtx->outputType, &point1, &point2, TSDB_DATA_TYPE_DOUBLE);
|
||||||
}
|
}
|
||||||
} else if (srcType == TSDB_DATA_TYPE_FLOAT) {
|
|
||||||
point1.val = data1;
|
|
||||||
point2.val = data2;
|
|
||||||
|
|
||||||
if (isNull(data1, srcType) || isNull(data2, srcType)) {
|
|
||||||
setNull(pCtx->aOutputBuf, srcType, pCtx->inputBytes);
|
|
||||||
} else {
|
|
||||||
taosGetLinearInterpolationVal(pCtx->outputType, &point1, &point2, &point);
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
if (srcType == TSDB_DATA_TYPE_BINARY || srcType == TSDB_DATA_TYPE_NCHAR) {
|
|
||||||
setVardataNull(pCtx->aOutputBuf, pCtx->inputType);
|
|
||||||
} else {
|
} else {
|
||||||
setNull(pCtx->aOutputBuf, srcType, pCtx->inputBytes);
|
setNull(pCtx->aOutputBuf, srcType, pCtx->inputBytes);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
SET_VAL(pCtx, pCtx->size, 1);
|
SET_VAL(pCtx, 1, 1);
|
||||||
|
|
||||||
|
}
|
||||||
|
static void interp_function(SQLFunctionCtx *pCtx) {
|
||||||
|
// at this point, the value is existed, return directly
|
||||||
|
if (pCtx->size > 0) {
|
||||||
|
// impose the timestamp check
|
||||||
|
TSKEY key = GET_TS_DATA(pCtx, 0);
|
||||||
|
if (key == pCtx->nStartQueryTimestamp) {
|
||||||
|
char *pData = GET_INPUT_DATA(pCtx, 0);
|
||||||
|
assignVal(pCtx->aOutputBuf, pData, pCtx->inputBytes, pCtx->inputType);
|
||||||
|
SET_VAL(pCtx, 1, 1);
|
||||||
|
} else {
|
||||||
|
interp_function_impl(pCtx);
|
||||||
|
}
|
||||||
|
} else { //no qualified data rows and interpolation is required
|
||||||
|
interp_function_impl(pCtx);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool ts_comp_function_setup(SQLFunctionCtx *pCtx) {
|
static bool ts_comp_function_setup(SQLFunctionCtx *pCtx) {
|
||||||
|
|
|
@ -408,7 +408,7 @@ static bool isTopBottomQuery(SQuery *pQuery) {
|
||||||
static bool timeWindowInterpoRequired(SQuery *pQuery) {
|
static bool timeWindowInterpoRequired(SQuery *pQuery) {
|
||||||
for(int32_t i = 0; i < pQuery->numOfOutput; ++i) {
|
for(int32_t i = 0; i < pQuery->numOfOutput; ++i) {
|
||||||
int32_t functionId = pQuery->pExpr1[i].base.functionId;
|
int32_t functionId = pQuery->pExpr1[i].base.functionId;
|
||||||
if (functionId == TSDB_FUNC_TWA) {
|
if (functionId == TSDB_FUNC_TWA || functionId == TSDB_FUNC_INTERP) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -818,6 +818,7 @@ static int32_t getNumOfRowsInTimeWindow(SQuery *pQuery, SDataBlockInfo *pDataBlo
|
||||||
return num;
|
return num;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO decouple the data block and the SQLFunctionCtx
|
||||||
static void doBlockwiseApplyFunctions(SQueryRuntimeEnv *pRuntimeEnv, STimeWindow *pWin, int32_t offset, int32_t forwardStep, TSKEY *tsCol, int32_t numOfTotal) {
|
static void doBlockwiseApplyFunctions(SQueryRuntimeEnv *pRuntimeEnv, STimeWindow *pWin, int32_t offset, int32_t forwardStep, TSKEY *tsCol, int32_t numOfTotal) {
|
||||||
SQuery *pQuery = pRuntimeEnv->pQuery;
|
SQuery *pQuery = pRuntimeEnv->pQuery;
|
||||||
SQLFunctionCtx *pCtx = pRuntimeEnv->pCtx;
|
SQLFunctionCtx *pCtx = pRuntimeEnv->pCtx;
|
||||||
|
@ -825,8 +826,8 @@ static void doBlockwiseApplyFunctions(SQueryRuntimeEnv *pRuntimeEnv, STimeWindow
|
||||||
bool hasPrev = pCtx[0].preAggVals.isSet;
|
bool hasPrev = pCtx[0].preAggVals.isSet;
|
||||||
|
|
||||||
for (int32_t k = 0; k < pQuery->numOfOutput; ++k) {
|
for (int32_t k = 0; k < pQuery->numOfOutput; ++k) {
|
||||||
pCtx[k].nStartQueryTimestamp = pWin->skey;
|
|
||||||
pCtx[k].size = forwardStep;
|
pCtx[k].size = forwardStep;
|
||||||
|
pCtx[k].nStartQueryTimestamp = pWin->skey;
|
||||||
pCtx[k].startOffset = (QUERY_IS_ASC_QUERY(pQuery)) ? offset : offset - (forwardStep - 1);
|
pCtx[k].startOffset = (QUERY_IS_ASC_QUERY(pQuery)) ? offset : offset - (forwardStep - 1);
|
||||||
|
|
||||||
int32_t functionId = pQuery->pExpr1[k].base.functionId;
|
int32_t functionId = pQuery->pExpr1[k].base.functionId;
|
||||||
|
@ -1029,7 +1030,8 @@ static void setNotInterpoWindowKey(SQLFunctionCtx* pCtx, int32_t numOfOutput, in
|
||||||
}
|
}
|
||||||
|
|
||||||
// window start key interpolation
|
// window start key interpolation
|
||||||
static bool setTimeWindowInterpolationStartTs(SQueryRuntimeEnv* pRuntimeEnv, int32_t pos, int32_t numOfRows, SArray* pDataBlock, TSKEY* tsCols, STimeWindow* win) {
|
static bool setTimeWindowInterpolationStartTs(SQueryRuntimeEnv* pRuntimeEnv, int32_t pos, int32_t numOfRows,
|
||||||
|
SArray* pDataBlock, TSKEY* tsCols, STimeWindow* win, int16_t type) {
|
||||||
SQuery* pQuery = pRuntimeEnv->pQuery;
|
SQuery* pQuery = pRuntimeEnv->pQuery;
|
||||||
|
|
||||||
TSKEY curTs = tsCols[pos];
|
TSKEY curTs = tsCols[pos];
|
||||||
|
@ -1118,6 +1120,8 @@ static void doWindowBorderInterpolation(SQueryRuntimeEnv* pRuntimeEnv, SDataBloc
|
||||||
assert(pDataBlock != NULL);
|
assert(pDataBlock != NULL);
|
||||||
|
|
||||||
SQuery* pQuery = pRuntimeEnv->pQuery;
|
SQuery* pQuery = pRuntimeEnv->pQuery;
|
||||||
|
int32_t fillType = pQuery->fillType;
|
||||||
|
|
||||||
int32_t step = GET_FORWARD_DIRECTION_FACTOR(pQuery->order.order);
|
int32_t step = GET_FORWARD_DIRECTION_FACTOR(pQuery->order.order);
|
||||||
|
|
||||||
SColumnInfoData *pColInfo = taosArrayGet(pDataBlock, 0);
|
SColumnInfoData *pColInfo = taosArrayGet(pDataBlock, 0);
|
||||||
|
@ -1126,7 +1130,7 @@ static void doWindowBorderInterpolation(SQueryRuntimeEnv* pRuntimeEnv, SDataBloc
|
||||||
bool done = resultRowInterpolated(pResult, RESULT_ROW_START_INTERP);
|
bool done = resultRowInterpolated(pResult, RESULT_ROW_START_INTERP);
|
||||||
if (!done) {
|
if (!done) {
|
||||||
int32_t startRowIndex = startPos;
|
int32_t startRowIndex = startPos;
|
||||||
bool interp = setTimeWindowInterpolationStartTs(pRuntimeEnv, startRowIndex, pDataBlockInfo->rows, pDataBlock, tsCols, win);
|
bool interp = setTimeWindowInterpolationStartTs(pRuntimeEnv, startRowIndex, pDataBlockInfo->rows, pDataBlock, tsCols, win, fillType);
|
||||||
if (interp) {
|
if (interp) {
|
||||||
setResultRowInterpo(pResult, RESULT_ROW_START_INTERP);
|
setResultRowInterpo(pResult, RESULT_ROW_START_INTERP);
|
||||||
}
|
}
|
||||||
|
@ -1134,6 +1138,12 @@ static void doWindowBorderInterpolation(SQueryRuntimeEnv* pRuntimeEnv, SDataBloc
|
||||||
setNotInterpoWindowKey(pRuntimeEnv->pCtx, pQuery->numOfOutput, RESULT_ROW_START_INTERP);
|
setNotInterpoWindowKey(pRuntimeEnv->pCtx, pQuery->numOfOutput, RESULT_ROW_START_INTERP);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// point interpolation does not require the end key time window interpolation.
|
||||||
|
if (isPointInterpoQuery(pQuery)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// interpolation query does not generate the time window end interpolation
|
||||||
done = resultRowInterpolated(pResult, RESULT_ROW_END_INTERP);
|
done = resultRowInterpolated(pResult, RESULT_ROW_END_INTERP);
|
||||||
if (!done) {
|
if (!done) {
|
||||||
int32_t endRowIndex = startPos + (forwardStep - 1) * step;
|
int32_t endRowIndex = startPos + (forwardStep - 1) * step;
|
||||||
|
@ -1259,7 +1269,7 @@ static void blockwiseApplyFunctions(SQueryRuntimeEnv *pRuntimeEnv, SDataStatis *
|
||||||
for (int32_t k = 0; k < pQuery->numOfOutput; ++k) {
|
for (int32_t k = 0; k < pQuery->numOfOutput; ++k) {
|
||||||
int32_t functionId = pQuery->pExpr1[k].base.functionId;
|
int32_t functionId = pQuery->pExpr1[k].base.functionId;
|
||||||
if (functionNeedToExecute(pRuntimeEnv, &pCtx[k], functionId)) {
|
if (functionNeedToExecute(pRuntimeEnv, &pCtx[k], functionId)) {
|
||||||
pCtx[k].nStartQueryTimestamp = pDataBlockInfo->window.skey;
|
pCtx[k].nStartQueryTimestamp = pQuery->window.skey;
|
||||||
aAggs[functionId].xFunction(&pCtx[k]);
|
aAggs[functionId].xFunction(&pCtx[k]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1423,11 +1433,13 @@ static bool functionNeedToExecute(SQueryRuntimeEnv *pRuntimeEnv, SQLFunctionCtx
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void doRowwiseTimeWindowInterpolation(SQueryRuntimeEnv* pRuntimeEnv, SArray* pDataBlock, TSKEY prevTs, int32_t prevRowIndex, TSKEY curTs, int32_t curRowIndex, TSKEY windowKey, int32_t type) {
|
void doRowwiseTimeWindowInterpolation(SQueryRuntimeEnv *pRuntimeEnv, SArray *pDataBlock, TSKEY prevTs,
|
||||||
|
int32_t prevRowIndex, TSKEY curTs, int32_t curRowIndex, TSKEY windowKey,
|
||||||
|
int32_t type) {
|
||||||
SQuery *pQuery = pRuntimeEnv->pQuery;
|
SQuery *pQuery = pRuntimeEnv->pQuery;
|
||||||
for (int32_t k = 0; k < pQuery->numOfOutput; ++k) {
|
for (int32_t k = 0; k < pQuery->numOfOutput; ++k) {
|
||||||
int32_t functionId = pQuery->pExpr1[k].base.functionId;
|
int32_t functionId = pQuery->pExpr1[k].base.functionId;
|
||||||
if (functionId != TSDB_FUNC_TWA) {
|
if (functionId != TSDB_FUNC_TWA && functionId != TSDB_FUNC_INTERP) {
|
||||||
pRuntimeEnv->pCtx[k].start.key = INT64_MIN;
|
pRuntimeEnv->pCtx[k].start.key = INT64_MIN;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -1450,7 +1462,9 @@ void doRowwiseTimeWindowInterpolation(SQueryRuntimeEnv* pRuntimeEnv, SArray* pDa
|
||||||
SPoint point1 = (SPoint){.key = prevTs, .val = &v1};
|
SPoint point1 = (SPoint){.key = prevTs, .val = &v1};
|
||||||
SPoint point2 = (SPoint){.key = curTs, .val = &v2};
|
SPoint point2 = (SPoint){.key = curTs, .val = &v2};
|
||||||
SPoint point = (SPoint){.key = windowKey, .val = &v};
|
SPoint point = (SPoint){.key = windowKey, .val = &v};
|
||||||
taosGetLinearInterpolationVal(TSDB_DATA_TYPE_DOUBLE, &point1, &point2, &point);
|
|
||||||
|
if (functionId == TSDB_FUNC_TWA) {
|
||||||
|
taosGetLinearInterpolationVal(&point, TSDB_DATA_TYPE_DOUBLE, &point1, &point2, TSDB_DATA_TYPE_DOUBLE);
|
||||||
|
|
||||||
if (type == RESULT_ROW_START_INTERP) {
|
if (type == RESULT_ROW_START_INTERP) {
|
||||||
pRuntimeEnv->pCtx[k].start.key = point.key;
|
pRuntimeEnv->pCtx[k].start.key = point.key;
|
||||||
|
@ -1459,6 +1473,15 @@ void doRowwiseTimeWindowInterpolation(SQueryRuntimeEnv* pRuntimeEnv, SArray* pDa
|
||||||
pRuntimeEnv->pCtx[k].end.key = point.key;
|
pRuntimeEnv->pCtx[k].end.key = point.key;
|
||||||
pRuntimeEnv->pCtx[k].end.val = v;
|
pRuntimeEnv->pCtx[k].end.val = v;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
if (type == RESULT_ROW_START_INTERP) {
|
||||||
|
pRuntimeEnv->pCtx[k].start.key = prevTs;
|
||||||
|
pRuntimeEnv->pCtx[k].start.val = v1;
|
||||||
|
|
||||||
|
pRuntimeEnv->pCtx[k].end.key = curTs;
|
||||||
|
pRuntimeEnv->pCtx[k].end.val = v2;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1796,13 +1819,7 @@ void setExecParams(SQuery *pQuery, SQLFunctionCtx *pCtx, void* inputData, TSKEY
|
||||||
pCtx->preAggVals.statis.max = pBlockInfo->window.ekey;
|
pCtx->preAggVals.statis.max = pBlockInfo->window.ekey;
|
||||||
}
|
}
|
||||||
} else if (functionId == TSDB_FUNC_INTERP) {
|
} else if (functionId == TSDB_FUNC_INTERP) {
|
||||||
SResultRowCellInfo* pInfo = GET_RES_INFO(pCtx);
|
pCtx->param[2].i64 = (int8_t) pQuery->fillType;
|
||||||
|
|
||||||
SInterpInfoDetail *pInterpInfo = (SInterpInfoDetail *)GET_ROWCELL_INTERBUF(pInfo);
|
|
||||||
pInterpInfo->type = (int8_t)pQuery->fillType;
|
|
||||||
pInterpInfo->ts = pQuery->window.skey;
|
|
||||||
pInterpInfo->primaryCol = (colId == PRIMARYKEY_TIMESTAMP_COL_INDEX);
|
|
||||||
|
|
||||||
if (pQuery->fillVal != NULL) {
|
if (pQuery->fillVal != NULL) {
|
||||||
if (isNull((const char*) &pQuery->fillVal[colIndex], pCtx->inputType)) {
|
if (isNull((const char*) &pQuery->fillVal[colIndex], pCtx->inputType)) {
|
||||||
pCtx->param[1].nType = TSDB_DATA_TYPE_NULL;
|
pCtx->param[1].nType = TSDB_DATA_TYPE_NULL;
|
||||||
|
@ -2579,7 +2596,6 @@ int32_t loadDataBlockOnDemand(SQueryRuntimeEnv *pRuntimeEnv, SResultRowInfo * pW
|
||||||
if (pQuery->numOfFilterCols > 0 || pRuntimeEnv->pTsBuf > 0) {
|
if (pQuery->numOfFilterCols > 0 || pRuntimeEnv->pTsBuf > 0) {
|
||||||
*status = BLK_DATA_ALL_NEEDED;
|
*status = BLK_DATA_ALL_NEEDED;
|
||||||
} else { // check if this data block is required to load
|
} else { // check if this data block is required to load
|
||||||
|
|
||||||
// Calculate all time windows that are overlapping or contain current data block.
|
// Calculate all time windows that are overlapping or contain current data block.
|
||||||
// If current data block is contained by all possible time window, do not load current data block.
|
// If current data block is contained by all possible time window, do not load current data block.
|
||||||
if (QUERY_IS_INTERVAL_QUERY(pQuery) && overlapWithTimeWindow(pQuery, pBlockInfo)) {
|
if (QUERY_IS_INTERVAL_QUERY(pQuery) && overlapWithTimeWindow(pQuery, pBlockInfo)) {
|
||||||
|
@ -2818,6 +2834,10 @@ static int64_t doScanAllDataBlocks(SQueryRuntimeEnv *pRuntimeEnv) {
|
||||||
while (tsdbNextDataBlock(pQueryHandle)) {
|
while (tsdbNextDataBlock(pQueryHandle)) {
|
||||||
summary->totalBlocks += 1;
|
summary->totalBlocks += 1;
|
||||||
|
|
||||||
|
if (IS_MASTER_SCAN(pRuntimeEnv)) {
|
||||||
|
pQuery->numOfCheckedBlocks += 1;
|
||||||
|
}
|
||||||
|
|
||||||
if (isQueryKilled(GET_QINFO_ADDR(pRuntimeEnv))) {
|
if (isQueryKilled(GET_QINFO_ADDR(pRuntimeEnv))) {
|
||||||
longjmp(pRuntimeEnv->env, TSDB_CODE_TSC_QUERY_CANCELLED);
|
longjmp(pRuntimeEnv->env, TSDB_CODE_TSC_QUERY_CANCELLED);
|
||||||
}
|
}
|
||||||
|
@ -3557,7 +3577,7 @@ void setQueryStatus(SQuery *pQuery, int8_t status) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool needScanDataBlocksAgain(SQueryRuntimeEnv *pRuntimeEnv) {
|
bool needRepeatScan(SQueryRuntimeEnv *pRuntimeEnv) {
|
||||||
SQuery *pQuery = pRuntimeEnv->pQuery;
|
SQuery *pQuery = pRuntimeEnv->pQuery;
|
||||||
|
|
||||||
bool toContinue = false;
|
bool toContinue = false;
|
||||||
|
@ -3711,7 +3731,7 @@ void scanOneTableDataBlocks(SQueryRuntimeEnv *pRuntimeEnv, TSKEY start) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!needScanDataBlocksAgain(pRuntimeEnv)) {
|
if (!needRepeatScan(pRuntimeEnv)) {
|
||||||
// restore the status code and jump out of loop
|
// restore the status code and jump out of loop
|
||||||
if (pRuntimeEnv->scanFlag == REPEAT_SCAN) {
|
if (pRuntimeEnv->scanFlag == REPEAT_SCAN) {
|
||||||
pQuery->status = qstatus.status;
|
pQuery->status = qstatus.status;
|
||||||
|
@ -3737,17 +3757,9 @@ void scanOneTableDataBlocks(SQueryRuntimeEnv *pRuntimeEnv, TSKEY start) {
|
||||||
|
|
||||||
qDebug("QInfo:%p start to repeat scan data blocks due to query func required, qrange:%"PRId64"-%"PRId64, pQInfo,
|
qDebug("QInfo:%p start to repeat scan data blocks due to query func required, qrange:%"PRId64"-%"PRId64, pQInfo,
|
||||||
cond.twindow.skey, cond.twindow.ekey);
|
cond.twindow.skey, cond.twindow.ekey);
|
||||||
|
|
||||||
// check if query is killed or not
|
|
||||||
if (isQueryKilled(pQInfo)) {
|
|
||||||
longjmp(pRuntimeEnv->env, TSDB_CODE_TSC_QUERY_CANCELLED);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!needReverseScan(pQuery)) {
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (needReverseScan(pQuery)) {
|
||||||
setEnvBeforeReverseScan(pRuntimeEnv, &qstatus);
|
setEnvBeforeReverseScan(pRuntimeEnv, &qstatus);
|
||||||
|
|
||||||
// reverse scan from current position
|
// reverse scan from current position
|
||||||
|
@ -3757,6 +3769,62 @@ void scanOneTableDataBlocks(SQueryRuntimeEnv *pRuntimeEnv, TSKEY start) {
|
||||||
clearEnvAfterReverseScan(pRuntimeEnv, &qstatus);
|
clearEnvAfterReverseScan(pRuntimeEnv, &qstatus);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isPointInterpoQuery(pQuery) && pQuery->numOfCheckedBlocks == 0) {
|
||||||
|
SArray *prev = tsdbGetExternalRow(pRuntimeEnv->pQueryHandle, &pQInfo->memRef, TSDB_PREV_ROW);
|
||||||
|
SArray *next = tsdbGetExternalRow(pRuntimeEnv->pQueryHandle, &pQInfo->memRef, TSDB_NEXT_ROW);
|
||||||
|
|
||||||
|
if (prev == NULL || next == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// setup the pCtx->start/end info and calculate the interpolation value
|
||||||
|
SColumnInfoData *startTs = taosArrayGet(prev, 0);
|
||||||
|
SColumnInfoData *endTs = taosArrayGet(next, 0);
|
||||||
|
|
||||||
|
for (int32_t i = 0; i < pQuery->numOfOutput; ++i) {
|
||||||
|
SQLFunctionCtx* pCtx = &pRuntimeEnv->pCtx[i];
|
||||||
|
|
||||||
|
int32_t functionId = pQuery->pExpr1[i].base.functionId;
|
||||||
|
SColIndex *pColIndex = &pQuery->pExpr1[i].base.colInfo;
|
||||||
|
|
||||||
|
if (!TSDB_COL_IS_NORMAL_COL(pColIndex->flag)) {
|
||||||
|
aAggs[functionId].xFunction(pCtx);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
SColumnInfoData *p = taosArrayGet(prev, pColIndex->colIndex);
|
||||||
|
SColumnInfoData *n = taosArrayGet(next, pColIndex->colIndex);
|
||||||
|
|
||||||
|
assert(p->info.colId == pColIndex->colId);
|
||||||
|
|
||||||
|
pCtx->start.key = *(TSKEY *)startTs->pData;
|
||||||
|
pCtx->end.key = *(TSKEY *)endTs->pData;
|
||||||
|
|
||||||
|
if (p->info.type != TSDB_DATA_TYPE_BINARY && p->info.type != TSDB_DATA_TYPE_NCHAR) {
|
||||||
|
GET_TYPED_DATA(pCtx->start.val, double, p->info.type, p->pData);
|
||||||
|
GET_TYPED_DATA(pCtx->end.val, double, n->info.type, n->pData);
|
||||||
|
} else { // string pointer
|
||||||
|
pCtx->start.ptr = p->pData;
|
||||||
|
pCtx->end.ptr = n->pData;
|
||||||
|
}
|
||||||
|
|
||||||
|
pCtx->param[2].i64 = (int8_t)pQuery->fillType;
|
||||||
|
pCtx->nStartQueryTimestamp = pQuery->window.skey;
|
||||||
|
if (pQuery->fillVal != NULL) {
|
||||||
|
if (isNull((const char*) &pQuery->fillVal[i], pCtx->inputType)) {
|
||||||
|
pCtx->param[1].nType = TSDB_DATA_TYPE_NULL;
|
||||||
|
} else { // todo refactor, tVariantCreateFromBinary should handle the NULL value
|
||||||
|
if (pCtx->inputType != TSDB_DATA_TYPE_BINARY && pCtx->inputType != TSDB_DATA_TYPE_NCHAR) {
|
||||||
|
tVariantCreateFromBinary(&pCtx->param[1], (char*) &pQuery->fillVal[i], pCtx->inputBytes, pCtx->inputType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
aAggs[functionId].xFunction(pCtx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void finalizeQueryResult(SQueryRuntimeEnv *pRuntimeEnv) {
|
void finalizeQueryResult(SQueryRuntimeEnv *pRuntimeEnv) {
|
||||||
SQuery *pQuery = pRuntimeEnv->pQuery;
|
SQuery *pQuery = pRuntimeEnv->pQuery;
|
||||||
|
|
||||||
|
@ -4891,6 +4959,7 @@ static bool multiTableMultioutputHelper(SQInfo *pQInfo, int32_t index) {
|
||||||
.order = pQuery->order.order,
|
.order = pQuery->order.order,
|
||||||
.colList = pQuery->colList,
|
.colList = pQuery->colList,
|
||||||
.numOfCols = pQuery->numOfCols,
|
.numOfCols = pQuery->numOfCols,
|
||||||
|
.loadExternalRows = false,
|
||||||
};
|
};
|
||||||
|
|
||||||
// todo refactor
|
// todo refactor
|
||||||
|
@ -4985,6 +5054,7 @@ STsdbQueryCond createTsdbQueryCond(SQuery* pQuery, STimeWindow* win) {
|
||||||
.colList = pQuery->colList,
|
.colList = pQuery->colList,
|
||||||
.order = pQuery->order.order,
|
.order = pQuery->order.order,
|
||||||
.numOfCols = pQuery->numOfCols,
|
.numOfCols = pQuery->numOfCols,
|
||||||
|
.loadExternalRows = false,
|
||||||
};
|
};
|
||||||
|
|
||||||
TIME_WINDOW_COPY(cond.twindow, *win);
|
TIME_WINDOW_COPY(cond.twindow, *win);
|
||||||
|
@ -5727,8 +5797,17 @@ static void tableIntervalProcess(SQInfo *pQInfo, STableQueryInfo* pTableInfo) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO opt performance
|
||||||
|
// if (isPointInterpoQuery(pQuery)) {
|
||||||
|
// SArray *prev = tsdbGetExternalRow(pRuntimeEnv->pQueryHandle, &pQInfo->memRef, TSDB_PREV_ROW);
|
||||||
|
//
|
||||||
|
// for(int32_t i = 0; i < pQuery->numOfCols; ++i) {
|
||||||
|
// SColumnInfoData *p = taosArrayGet(prev, i);
|
||||||
|
// memcpy(pRuntimeEnv->prevRow[i], p->pData, p->info.bytes);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
scanOneTableDataBlocks(pRuntimeEnv, newStartKey);
|
scanOneTableDataBlocks(pRuntimeEnv, newStartKey);
|
||||||
assert(!Q_STATUS_EQUAL(pQuery->status, QUERY_NOT_COMPLETED));
|
|
||||||
|
|
||||||
finalizeQueryResult(pRuntimeEnv);
|
finalizeQueryResult(pRuntimeEnv);
|
||||||
|
|
||||||
|
@ -5736,7 +5815,7 @@ static void tableIntervalProcess(SQInfo *pQInfo, STableQueryInfo* pTableInfo) {
|
||||||
pQuery->rec.rows = 0;
|
pQuery->rec.rows = 0;
|
||||||
|
|
||||||
// not fill or no result generated during this query
|
// not fill or no result generated during this query
|
||||||
if (pQuery->fillType == TSDB_FILL_NONE || pRuntimeEnv->windowResInfo.size == 0) {
|
if (pQuery->fillType == TSDB_FILL_NONE || pRuntimeEnv->windowResInfo.size == 0 || isPointInterpoQuery(pQuery)) {
|
||||||
// all data scanned, the group by normal column can return
|
// all data scanned, the group by normal column can return
|
||||||
int32_t numOfClosed = numOfClosedResultRows(&pRuntimeEnv->windowResInfo);
|
int32_t numOfClosed = numOfClosedResultRows(&pRuntimeEnv->windowResInfo);
|
||||||
if (pQuery->limit.offset > numOfClosed) {
|
if (pQuery->limit.offset > numOfClosed) {
|
||||||
|
@ -5771,7 +5850,7 @@ static void tableQueryImpl(SQInfo *pQInfo) {
|
||||||
SQuery * pQuery = pRuntimeEnv->pQuery;
|
SQuery * pQuery = pRuntimeEnv->pQuery;
|
||||||
|
|
||||||
if (hasNotReturnedResults(pRuntimeEnv)) {
|
if (hasNotReturnedResults(pRuntimeEnv)) {
|
||||||
if (pQuery->fillType != TSDB_FILL_NONE) {
|
if (pQuery->fillType != TSDB_FILL_NONE && !isPointInterpoQuery(pQuery)) {
|
||||||
/*
|
/*
|
||||||
* There are remain results that are not returned due to result interpolation
|
* There are remain results that are not returned due to result interpolation
|
||||||
* So, we do keep in this procedure instead of launching retrieve procedure for next results.
|
* So, we do keep in this procedure instead of launching retrieve procedure for next results.
|
||||||
|
|
|
@ -120,7 +120,7 @@ static void doFillOneRowResult(SFillInfo* pFillInfo, tFilePage** data, char** sr
|
||||||
point1 = (SPoint){.key = *(TSKEY*)(prev), .val = prev + pCol->col.offset};
|
point1 = (SPoint){.key = *(TSKEY*)(prev), .val = prev + pCol->col.offset};
|
||||||
point2 = (SPoint){.key = ts, .val = srcData[i] + pFillInfo->index * bytes};
|
point2 = (SPoint){.key = ts, .val = srcData[i] + pFillInfo->index * bytes};
|
||||||
point = (SPoint){.key = pFillInfo->currentKey, .val = val1};
|
point = (SPoint){.key = pFillInfo->currentKey, .val = val1};
|
||||||
taosGetLinearInterpolationVal(type, &point1, &point2, &point);
|
taosGetLinearInterpolationVal(&point, type, &point1, &point2, type);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
setNullValueForRow(pFillInfo, data, pFillInfo->numOfCols, index);
|
setNullValueForRow(pFillInfo, data, pFillInfo->numOfCols, index);
|
||||||
|
@ -479,25 +479,13 @@ int64_t getNumOfResultsAfterFillGap(SFillInfo* pFillInfo, TSKEY ekey, int32_t ma
|
||||||
return (numOfRes > maxNumOfRows) ? maxNumOfRows : numOfRes;
|
return (numOfRes > maxNumOfRows) ? maxNumOfRows : numOfRes;
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t taosGetLinearInterpolationVal(int32_t type, SPoint* point1, SPoint* point2, SPoint* point) {
|
int32_t taosGetLinearInterpolationVal(SPoint* point, int32_t outputType, SPoint* point1, SPoint* point2, int32_t inputType) {
|
||||||
double v1 = -1;
|
double v1 = -1, v2 = -1;
|
||||||
double v2 = -1;
|
GET_TYPED_DATA(v1, double, inputType, point1->val);
|
||||||
|
GET_TYPED_DATA(v2, double, inputType, point2->val);
|
||||||
GET_TYPED_DATA(v1, double, type, point1->val);
|
|
||||||
GET_TYPED_DATA(v2, double, type, point2->val);
|
|
||||||
|
|
||||||
double r = DO_INTERPOLATION(v1, v2, point1->key, point2->key, point->key);
|
double r = DO_INTERPOLATION(v1, v2, point1->key, point2->key, point->key);
|
||||||
|
SET_TYPED_DATA(point->val, outputType, r);
|
||||||
switch(type) {
|
|
||||||
case TSDB_DATA_TYPE_TINYINT: *(int8_t*) point->val = (int8_t) r;break;
|
|
||||||
case TSDB_DATA_TYPE_SMALLINT: *(int16_t*) point->val = (int16_t) r;break;
|
|
||||||
case TSDB_DATA_TYPE_INT: *(int32_t*) point->val = (int32_t) r;break;
|
|
||||||
case TSDB_DATA_TYPE_BIGINT: *(int64_t*) point->val = (int64_t) r;break;
|
|
||||||
case TSDB_DATA_TYPE_DOUBLE: *(double*) point->val = (double) r;break;
|
|
||||||
case TSDB_DATA_TYPE_FLOAT: *(float*) point->val = (float) r;break;
|
|
||||||
default:
|
|
||||||
assert(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
return TSDB_CODE_SUCCESS;
|
return TSDB_CODE_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
|
@ -111,6 +111,7 @@ typedef struct STsdbQueryHandle {
|
||||||
int32_t activeIndex;
|
int32_t activeIndex;
|
||||||
bool checkFiles; // check file stage
|
bool checkFiles; // check file stage
|
||||||
bool cachelastrow; // check if last row cached
|
bool cachelastrow; // check if last row cached
|
||||||
|
bool loadExternalRow; // load time window external data rows
|
||||||
void* qinfo; // query info handle, for debug purpose
|
void* qinfo; // query info handle, for debug purpose
|
||||||
int32_t type; // query type: retrieve all data blocks, 2. retrieve only last row, 3. retrieve direct prev|next rows
|
int32_t type; // query type: retrieve all data blocks, 2. retrieve only last row, 3. retrieve direct prev|next rows
|
||||||
SFileGroup* pFileGroup;
|
SFileGroup* pFileGroup;
|
||||||
|
@ -125,6 +126,8 @@ typedef struct STsdbQueryHandle {
|
||||||
SDataBlockLoadInfo dataBlockLoadInfo; /* record current block load information */
|
SDataBlockLoadInfo dataBlockLoadInfo; /* record current block load information */
|
||||||
SLoadCompBlockInfo compBlockLoadInfo; /* record current compblock information in SQuery */
|
SLoadCompBlockInfo compBlockLoadInfo; /* record current compblock information in SQuery */
|
||||||
|
|
||||||
|
SArray *prev; // previous row which is before than time window
|
||||||
|
SArray *next; // next row which is after the query time window
|
||||||
SIOCostSummary cost;
|
SIOCostSummary cost;
|
||||||
} STsdbQueryHandle;
|
} STsdbQueryHandle;
|
||||||
|
|
||||||
|
@ -141,10 +144,10 @@ static int32_t tsdbGetCachedLastRow(STable* pTable, SDataRow* pRes, TSKEY* lastK
|
||||||
static void changeQueryHandleForInterpQuery(TsdbQueryHandleT pHandle);
|
static void changeQueryHandleForInterpQuery(TsdbQueryHandleT pHandle);
|
||||||
static void doMergeTwoLevelData(STsdbQueryHandle* pQueryHandle, STableCheckInfo* pCheckInfo, SCompBlock* pBlock);
|
static void doMergeTwoLevelData(STsdbQueryHandle* pQueryHandle, STableCheckInfo* pCheckInfo, SCompBlock* pBlock);
|
||||||
static int32_t binarySearchForKey(char* pValue, int num, TSKEY key, int order);
|
static int32_t binarySearchForKey(char* pValue, int num, TSKEY key, int order);
|
||||||
static int tsdbReadRowsFromCache(STableCheckInfo* pCheckInfo, TSKEY maxKey, int maxRowsToRead, STimeWindow* win,
|
static int32_t tsdbReadRowsFromCache(STableCheckInfo* pCheckInfo, TSKEY maxKey, int maxRowsToRead, STimeWindow* win, STsdbQueryHandle* pQueryHandle);
|
||||||
STsdbQueryHandle* pQueryHandle);
|
static int32_t tsdbCheckInfoCompar(const void* key1, const void* key2);
|
||||||
static int tsdbCheckInfoCompar(const void* key1, const void* key2);
|
static int32_t doGetExternalRow(STsdbQueryHandle* pQueryHandle, int16_t type, SMemRef* pMemRef);
|
||||||
|
static void* doFreeColumnInfoData(SArray* pColumnInfoData);
|
||||||
|
|
||||||
static void tsdbInitDataBlockLoadInfo(SDataBlockLoadInfo* pBlockLoadInfo) {
|
static void tsdbInitDataBlockLoadInfo(SDataBlockLoadInfo* pBlockLoadInfo) {
|
||||||
pBlockLoadInfo->slot = -1;
|
pBlockLoadInfo->slot = -1;
|
||||||
|
@ -294,6 +297,7 @@ static STsdbQueryHandle* tsdbQueryTablesImpl(TSDB_REPO_T* tsdb, STsdbQueryCond*
|
||||||
pQueryHandle->allocSize = 0;
|
pQueryHandle->allocSize = 0;
|
||||||
pQueryHandle->locateStart = false;
|
pQueryHandle->locateStart = false;
|
||||||
pQueryHandle->pMemRef = pMemRef;
|
pQueryHandle->pMemRef = pMemRef;
|
||||||
|
pQueryHandle->loadExternalRow = pCond->loadExternalRows;
|
||||||
|
|
||||||
if (tsdbInitReadHelper(&pQueryHandle->rhelper, (STsdbRepo*) tsdb) != 0) {
|
if (tsdbInitReadHelper(&pQueryHandle->rhelper, (STsdbRepo*) tsdb) != 0) {
|
||||||
goto out_of_memory;
|
goto out_of_memory;
|
||||||
|
@ -410,10 +414,11 @@ SArray* tsdbGetQueriedTableList(TsdbQueryHandleT *pHandle) {
|
||||||
|
|
||||||
TsdbQueryHandleT tsdbQueryRowsInExternalWindow(TSDB_REPO_T *tsdb, STsdbQueryCond* pCond, STableGroupInfo *groupList, void* qinfo, SMemRef* pRef) {
|
TsdbQueryHandleT tsdbQueryRowsInExternalWindow(TSDB_REPO_T *tsdb, STsdbQueryCond* pCond, STableGroupInfo *groupList, void* qinfo, SMemRef* pRef) {
|
||||||
STsdbQueryHandle *pQueryHandle = (STsdbQueryHandle*) tsdbQueryTables(tsdb, pCond, groupList, qinfo, pRef);
|
STsdbQueryHandle *pQueryHandle = (STsdbQueryHandle*) tsdbQueryTables(tsdb, pCond, groupList, qinfo, pRef);
|
||||||
|
pQueryHandle->loadExternalRow = true;
|
||||||
if (pQueryHandle != NULL) {
|
if (pQueryHandle != NULL) {
|
||||||
pQueryHandle->type = TSDB_QUERY_TYPE_EXTERNAL;
|
|
||||||
changeQueryHandleForInterpQuery(pQueryHandle);
|
changeQueryHandleForInterpQuery(pQueryHandle);
|
||||||
}
|
}
|
||||||
|
|
||||||
return pQueryHandle;
|
return pQueryHandle;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1900,17 +1905,22 @@ static bool doHasDataInBuffer(STsdbQueryHandle* pQueryHandle) {
|
||||||
pQueryHandle->activeIndex += 1;
|
pQueryHandle->activeIndex += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (pQueryHandle->loadExternalRow && pQueryHandle->window.skey == pQueryHandle->window.ekey) {
|
||||||
|
SMemRef* pMemRef = pQueryHandle->pMemRef;
|
||||||
|
doGetExternalRow(pQueryHandle, TSDB_PREV_ROW, pMemRef);
|
||||||
|
doGetExternalRow(pQueryHandle, TSDB_NEXT_ROW, pMemRef);
|
||||||
|
}
|
||||||
|
|
||||||
// no data in memtable or imemtable, decrease the memory reference.
|
// no data in memtable or imemtable, decrease the memory reference.
|
||||||
tsdbMayUnTakeMemSnapshot(pQueryHandle);
|
tsdbMayUnTakeMemSnapshot(pQueryHandle);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//todo not unref yet, since it is not support multi-group interpolation query
|
||||||
static void changeQueryHandleForInterpQuery(TsdbQueryHandleT pHandle) {
|
static void changeQueryHandleForInterpQuery(TsdbQueryHandleT pHandle) {
|
||||||
// filter the queried time stamp in the first place
|
// filter the queried time stamp in the first place
|
||||||
STsdbQueryHandle* pQueryHandle = (STsdbQueryHandle*) pHandle;
|
STsdbQueryHandle* pQueryHandle = (STsdbQueryHandle*) pHandle;
|
||||||
pQueryHandle->order = TSDB_ORDER_DESC;
|
// pQueryHandle->order = TSDB_ORDER_DESC;
|
||||||
|
|
||||||
assert(pQueryHandle->window.skey == pQueryHandle->window.ekey);
|
|
||||||
|
|
||||||
// starts from the buffer in case of descending timestamp order check data blocks
|
// starts from the buffer in case of descending timestamp order check data blocks
|
||||||
size_t numOfTables = taosArrayGetSize(pQueryHandle->pTableCheckInfo);
|
size_t numOfTables = taosArrayGetSize(pQueryHandle->pTableCheckInfo);
|
||||||
|
@ -1940,7 +1950,7 @@ static void changeQueryHandleForInterpQuery(TsdbQueryHandleT pHandle) {
|
||||||
taosArrayPush(pQueryHandle->pTableCheckInfo, &info);
|
taosArrayPush(pQueryHandle->pTableCheckInfo, &info);
|
||||||
|
|
||||||
// update the query time window according to the chosen last timestamp
|
// update the query time window according to the chosen last timestamp
|
||||||
pQueryHandle->window = (STimeWindow) {info.lastKey, TSKEY_INITIAL_VAL};
|
// pQueryHandle->window = (STimeWindow) {info.lastKey, TSKEY_INITIAL_VAL};
|
||||||
}
|
}
|
||||||
|
|
||||||
static int tsdbReadRowsFromCache(STableCheckInfo* pCheckInfo, TSKEY maxKey, int maxRowsToRead, STimeWindow* win,
|
static int tsdbReadRowsFromCache(STableCheckInfo* pCheckInfo, TSKEY maxKey, int maxRowsToRead, STimeWindow* win,
|
||||||
|
@ -2029,110 +2039,147 @@ static void destroyHelper(void* param) {
|
||||||
free(param);
|
free(param);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool getNeighborRows(STsdbQueryHandle* pQueryHandle) {
|
//static bool getNeighborRows(STsdbQueryHandle* pQueryHandle) {
|
||||||
assert (pQueryHandle->type == TSDB_QUERY_TYPE_EXTERNAL);
|
// assert(pQueryHandle->type == TSDB_QUERY_TYPE_EXTERNAL);
|
||||||
|
//
|
||||||
SDataBlockInfo blockInfo = {{0}, 0};
|
// SDataBlockInfo blockInfo = {{0}, 0};
|
||||||
|
//
|
||||||
pQueryHandle->type = TSDB_QUERY_TYPE_ALL;
|
// pQueryHandle->type = TSDB_QUERY_TYPE_ALL;
|
||||||
pQueryHandle->order = TSDB_ORDER_DESC;
|
// pQueryHandle->order = TSDB_ORDER_DESC;
|
||||||
|
//
|
||||||
if (!tsdbNextDataBlock((void*) pQueryHandle)) {
|
// if (!tsdbNextDataBlock((void*)pQueryHandle)) {
|
||||||
return false;
|
// return false;
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
tsdbRetrieveDataBlockInfo((void*) pQueryHandle, &blockInfo);
|
// tsdbRetrieveDataBlockInfo((void*)pQueryHandle, &blockInfo);
|
||||||
/*SArray *pDataBlock = */tsdbRetrieveDataBlock((void*) pQueryHandle, pQueryHandle->defaultLoadColumn);
|
// /*SArray *pDataBlock = */ tsdbRetrieveDataBlock((void*)pQueryHandle, pQueryHandle->defaultLoadColumn);
|
||||||
if (terrno != TSDB_CODE_SUCCESS) {
|
// if (terrno != TSDB_CODE_SUCCESS) {
|
||||||
return false;
|
// return false;
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
if (pQueryHandle->cur.win.ekey == pQueryHandle->window.skey) {
|
// STimeWindow* win = &pQueryHandle->window;
|
||||||
// data already retrieve, discard other data rows and return
|
//
|
||||||
int32_t numOfCols = (int32_t)(QH_GET_NUM_OF_COLS(pQueryHandle));
|
// // the skey == ekey means only one data row is required.
|
||||||
for (int32_t i = 0; i < numOfCols; ++i) {
|
// // the data row of this timestamp is already retrieved, discard other data rows and return.
|
||||||
SColumnInfoData* pCol = taosArrayGet(pQueryHandle->pColumns, i);
|
// if (win->skey == win->ekey) {
|
||||||
memcpy((char*)pCol->pData, (char*)pCol->pData + pCol->info.bytes * (pQueryHandle->cur.rows - 1), pCol->info.bytes);
|
// if (pQueryHandle->cur.win.ekey == win->skey) {
|
||||||
}
|
// int32_t numOfCols = (int32_t)(QH_GET_NUM_OF_COLS(pQueryHandle));
|
||||||
|
// for (int32_t i = 0; i < numOfCols; ++i) {
|
||||||
pQueryHandle->cur.win = (STimeWindow){pQueryHandle->window.skey, pQueryHandle->window.skey};
|
// SColumnInfoData* pCol = taosArrayGet(pQueryHandle->pColumns, i);
|
||||||
pQueryHandle->window = pQueryHandle->cur.win;
|
// memcpy((char*)pCol->pData, (char*)pCol->pData + pCol->info.bytes * (pQueryHandle->cur.rows - 1),
|
||||||
pQueryHandle->cur.rows = 1;
|
// pCol->info.bytes);
|
||||||
pQueryHandle->type = TSDB_QUERY_TYPE_ALL;
|
// }
|
||||||
return true;
|
//
|
||||||
} else {
|
// pQueryHandle->cur.win = (STimeWindow){win->skey, win->skey};
|
||||||
STimeWindow win = (STimeWindow) {pQueryHandle->window.skey, INT64_MAX};
|
// pQueryHandle->window = pQueryHandle->cur.win;
|
||||||
STsdbQueryCond cond = {
|
// pQueryHandle->cur.rows = 1;
|
||||||
.order = TSDB_ORDER_ASC,
|
// pQueryHandle->type = TSDB_QUERY_TYPE_ALL;
|
||||||
.numOfCols = (int32_t)(QH_GET_NUM_OF_COLS(pQueryHandle))
|
// return true;
|
||||||
};
|
// } else {
|
||||||
cond.twindow = win;
|
// STimeWindow win1 = (STimeWindow){pQueryHandle->window.skey, INT64_MAX};
|
||||||
|
// STsdbQueryCond cond = {.order = TSDB_ORDER_ASC, .numOfCols = (int32_t)(QH_GET_NUM_OF_COLS(pQueryHandle))};
|
||||||
cond.colList = calloc(cond.numOfCols, sizeof(SColumnInfo));
|
//
|
||||||
if (cond.colList == NULL) {
|
// cond.twindow = win1;
|
||||||
terrno = TSDB_CODE_QRY_OUT_OF_MEMORY;
|
//
|
||||||
return false;
|
// cond.colList = calloc(cond.numOfCols, sizeof(SColumnInfo));
|
||||||
}
|
// if (cond.colList == NULL) {
|
||||||
|
// terrno = TSDB_CODE_QRY_OUT_OF_MEMORY;
|
||||||
for(int32_t i = 0; i < cond.numOfCols; ++i) {
|
// return false;
|
||||||
SColumnInfoData* pColInfoData = taosArrayGet(pQueryHandle->pColumns, i);
|
// }
|
||||||
memcpy(&cond.colList[i], &pColInfoData->info, sizeof(SColumnInfo));
|
//
|
||||||
}
|
// for (int32_t i = 0; i < cond.numOfCols; ++i) {
|
||||||
|
// SColumnInfoData* pColInfoData = taosArrayGet(pQueryHandle->pColumns, i);
|
||||||
STsdbQueryHandle* pSecQueryHandle = tsdbQueryTablesImpl(pQueryHandle->pTsdb, &cond, pQueryHandle->qinfo, pQueryHandle->pMemRef);
|
// memcpy(&cond.colList[i], &pColInfoData->info, sizeof(SColumnInfo));
|
||||||
|
// }
|
||||||
tfree(cond.colList);
|
//
|
||||||
|
// STsdbQueryHandle* pSecQueryHandle =
|
||||||
pSecQueryHandle->pTableCheckInfo = createCheckInfoFromCheckInfo(pQueryHandle->pTableCheckInfo, pSecQueryHandle->window.skey);
|
// tsdbQueryTablesImpl(pQueryHandle->pTsdb, &cond, pQueryHandle->qinfo, pQueryHandle->pMemRef);
|
||||||
if (pSecQueryHandle->pTableCheckInfo == NULL) {
|
//
|
||||||
tsdbCleanupQueryHandle(pSecQueryHandle);
|
// tfree(cond.colList);
|
||||||
return false;
|
//
|
||||||
}
|
// pSecQueryHandle->pTableCheckInfo =
|
||||||
|
// createCheckInfoFromCheckInfo(pQueryHandle->pTableCheckInfo, pSecQueryHandle->window.skey);
|
||||||
if (!tsdbNextDataBlock((void*) pSecQueryHandle)) {
|
// if (pSecQueryHandle->pTableCheckInfo == NULL) {
|
||||||
tsdbCleanupQueryHandle(pSecQueryHandle);
|
// tsdbCleanupQueryHandle(pSecQueryHandle);
|
||||||
return false;
|
// return false;
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
tsdbRetrieveDataBlockInfo((void*) pSecQueryHandle, &blockInfo);
|
// if (!tsdbNextDataBlock((void*)pSecQueryHandle)) {
|
||||||
tsdbRetrieveDataBlock((void*) pSecQueryHandle, pSecQueryHandle->defaultLoadColumn);
|
// tsdbCleanupQueryHandle(pSecQueryHandle);
|
||||||
|
// return false;
|
||||||
int32_t numOfCols = (int32_t)(QH_GET_NUM_OF_COLS(pSecQueryHandle));
|
// }
|
||||||
size_t si = taosArrayGetSize(pSecQueryHandle->pTableCheckInfo);
|
//
|
||||||
|
// tsdbRetrieveDataBlockInfo((void*)pSecQueryHandle, &blockInfo);
|
||||||
for (int32_t i = 0; i < numOfCols; ++i) {
|
// tsdbRetrieveDataBlock((void*)pSecQueryHandle, pSecQueryHandle->defaultLoadColumn);
|
||||||
SColumnInfoData* pCol = taosArrayGet(pQueryHandle->pColumns, i);
|
//
|
||||||
memcpy((char*)pCol->pData, (char*)pCol->pData + pCol->info.bytes * (pQueryHandle->cur.rows - 1), pCol->info.bytes);
|
// int32_t numOfCols = (int32_t)(QH_GET_NUM_OF_COLS(pSecQueryHandle));
|
||||||
|
// size_t si = taosArrayGetSize(pSecQueryHandle->pTableCheckInfo);
|
||||||
SColumnInfoData* pCol1 = taosArrayGet(pSecQueryHandle->pColumns, i);
|
//
|
||||||
assert(pCol->info.colId == pCol1->info.colId);
|
// for (int32_t i = 0; i < numOfCols; ++i) {
|
||||||
|
// SColumnInfoData* pCol = taosArrayGet(pQueryHandle->pColumns, i);
|
||||||
memcpy((char*)pCol->pData + pCol->info.bytes, pCol1->pData, pCol1->info.bytes);
|
// memcpy((char*)pCol->pData, (char*)pCol->pData + pCol->info.bytes * (pQueryHandle->cur.rows - 1),
|
||||||
}
|
// pCol->info.bytes);
|
||||||
|
//
|
||||||
SColumnInfoData* pTSCol = taosArrayGet(pQueryHandle->pColumns, 0);
|
// SColumnInfoData* pCol1 = taosArrayGet(pSecQueryHandle->pColumns, i);
|
||||||
|
// assert(pCol->info.colId == pCol1->info.colId);
|
||||||
// it is ascending order
|
//
|
||||||
pQueryHandle->order = TSDB_ORDER_DESC;
|
// memcpy((char*)pCol->pData + pCol->info.bytes, pCol1->pData, pCol1->info.bytes);
|
||||||
pQueryHandle->window = pQueryHandle->cur.win;
|
// }
|
||||||
pQueryHandle->cur.win = (STimeWindow){((TSKEY*)pTSCol->pData)[0], ((TSKEY*)pTSCol->pData)[1]};
|
//
|
||||||
pQueryHandle->cur.rows = 2;
|
// SColumnInfoData* pTSCol = taosArrayGet(pQueryHandle->pColumns, 0);
|
||||||
pQueryHandle->cur.mixBlock = true;
|
//
|
||||||
|
// // it is ascending order
|
||||||
int32_t step = -1;// one step for ascending order traverse
|
// pQueryHandle->order = TSDB_ORDER_DESC;
|
||||||
for (int32_t j = 0; j < si; ++j) {
|
// pQueryHandle->window = pQueryHandle->cur.win;
|
||||||
STableCheckInfo* pCheckInfo = (STableCheckInfo*) taosArrayGet(pQueryHandle->pTableCheckInfo, j);
|
// pQueryHandle->cur.win = (STimeWindow){((TSKEY*)pTSCol->pData)[0], ((TSKEY*)pTSCol->pData)[1]};
|
||||||
pCheckInfo->lastKey = pQueryHandle->cur.win.ekey + step;
|
// pQueryHandle->cur.rows = 2;
|
||||||
}
|
// pQueryHandle->cur.mixBlock = true;
|
||||||
|
//
|
||||||
tsdbCleanupQueryHandle(pSecQueryHandle);
|
// int32_t step = -1; // one step for ascending order traverse
|
||||||
}
|
// for (int32_t j = 0; j < si; ++j) {
|
||||||
|
// STableCheckInfo* pCheckInfo = (STableCheckInfo*)taosArrayGet(pQueryHandle->pTableCheckInfo, j);
|
||||||
//disable it after retrieve data
|
// pCheckInfo->lastKey = pQueryHandle->cur.win.ekey + step;
|
||||||
pQueryHandle->type = TSDB_QUERY_TYPE_EXTERNAL;
|
// }
|
||||||
pQueryHandle->checkFiles = false;
|
//
|
||||||
return true;
|
// tsdbCleanupQueryHandle(pSecQueryHandle);
|
||||||
}
|
// }
|
||||||
|
// } else { // go back to normal query
|
||||||
|
// if (pQueryHandle->cur.win.ekey == win->skey) {
|
||||||
|
// pQueryHandle->type = TSDB_QUERY_TYPE_ALL;
|
||||||
|
//
|
||||||
|
// STsdbQueryCond cond = {.order = TSDB_ORDER_ASC, .numOfCols = (int32_t)(QH_GET_NUM_OF_COLS(pQueryHandle))};
|
||||||
|
//
|
||||||
|
// cond.twindow = pQueryHandle->oriWindow;;
|
||||||
|
//
|
||||||
|
// cond.colList = calloc(cond.numOfCols, sizeof(SColumnInfo));
|
||||||
|
// if (cond.colList == NULL) {
|
||||||
|
// terrno = TSDB_CODE_QRY_OUT_OF_MEMORY;
|
||||||
|
// return false;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// STsdbQueryHandle* pSecQueryHandle =
|
||||||
|
// tsdbQueryTablesImpl(pQueryHandle->pTsdb, &cond, pQueryHandle->qinfo, pQueryHandle->pMemRef);
|
||||||
|
//
|
||||||
|
// tfree(cond.colList);
|
||||||
|
//
|
||||||
|
// pSecQueryHandle->pTableCheckInfo =
|
||||||
|
// createCheckInfoFromCheckInfo(pQueryHandle->pTableCheckInfo, pSecQueryHandle->window.skey);
|
||||||
|
// if (pSecQueryHandle->pTableCheckInfo == NULL) {
|
||||||
|
// tsdbCleanupQueryHandle(pSecQueryHandle);
|
||||||
|
// return false;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// return true;
|
||||||
|
// } else {
|
||||||
|
// // save the pre rows for interpolation query.
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// // disable it after retrieve data
|
||||||
|
// pQueryHandle->type = TSDB_QUERY_TYPE_EXTERNAL;
|
||||||
|
// pQueryHandle->checkFiles = false;
|
||||||
|
// return true;
|
||||||
|
//}
|
||||||
|
|
||||||
// handle data in cache situation
|
// handle data in cache situation
|
||||||
bool tsdbNextDataBlock(TsdbQueryHandleT* pHandle) {
|
bool tsdbNextDataBlock(TsdbQueryHandleT* pHandle) {
|
||||||
|
@ -2144,16 +2191,16 @@ bool tsdbNextDataBlock(TsdbQueryHandleT* pHandle) {
|
||||||
size_t numOfTables = taosArrayGetSize(pQueryHandle->pTableCheckInfo);
|
size_t numOfTables = taosArrayGetSize(pQueryHandle->pTableCheckInfo);
|
||||||
assert(numOfTables > 0);
|
assert(numOfTables > 0);
|
||||||
|
|
||||||
if (pQueryHandle->type == TSDB_QUERY_TYPE_EXTERNAL) {
|
// if (pQueryHandle->type == TSDB_QUERY_TYPE_EXTERNAL) {
|
||||||
SMemRef* pMemRef = pQueryHandle->pMemRef;
|
// SMemRef* pMemRef = pQueryHandle->pMemRef;
|
||||||
tsdbMayTakeMemSnapshot(pQueryHandle);
|
// tsdbMayTakeMemSnapshot(pQueryHandle);
|
||||||
bool ret = getNeighborRows(pQueryHandle);
|
// bool ret = getNeighborRows(pQueryHandle);
|
||||||
tsdbMayUnTakeMemSnapshot(pQueryHandle);
|
// tsdbMayUnTakeMemSnapshot(pQueryHandle);
|
||||||
|
//
|
||||||
// restore the pMemRef
|
// // restore the pMemRef
|
||||||
pQueryHandle->pMemRef = pMemRef;
|
// pQueryHandle->pMemRef = pMemRef;
|
||||||
return ret;
|
// return ret;
|
||||||
} else if (pQueryHandle->type == TSDB_QUERY_TYPE_LAST && pQueryHandle->cachelastrow) {
|
/*} else*/ if (pQueryHandle->type == TSDB_QUERY_TYPE_LAST && pQueryHandle->cachelastrow) {
|
||||||
// the last row is cached in buffer, return it directly.
|
// the last row is cached in buffer, return it directly.
|
||||||
// here note that the pQueryHandle->window must be the TS_INITIALIZER
|
// here note that the pQueryHandle->window must be the TS_INITIALIZER
|
||||||
int32_t numOfCols = (int32_t)(QH_GET_NUM_OF_COLS(pQueryHandle));
|
int32_t numOfCols = (int32_t)(QH_GET_NUM_OF_COLS(pQueryHandle));
|
||||||
|
@ -2218,6 +2265,115 @@ bool tsdbNextDataBlock(TsdbQueryHandleT* pHandle) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int32_t doGetExternalRow(STsdbQueryHandle* pQueryHandle, int16_t type, SMemRef* pMemRef) {
|
||||||
|
STsdbQueryHandle* pSecQueryHandle = NULL;
|
||||||
|
|
||||||
|
if (type == TSDB_PREV_ROW && pQueryHandle->prev) {
|
||||||
|
return TSDB_CODE_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type == TSDB_NEXT_ROW && pQueryHandle->next) {
|
||||||
|
return TSDB_CODE_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
// prepare the structure
|
||||||
|
int32_t numOfCols = QH_GET_NUM_OF_COLS(pQueryHandle);
|
||||||
|
|
||||||
|
if (type == TSDB_PREV_ROW) {
|
||||||
|
pQueryHandle->prev = taosArrayInit(numOfCols, sizeof(SColumnInfoData));
|
||||||
|
if (pQueryHandle->prev == NULL) {
|
||||||
|
terrno = TSDB_CODE_QRY_OUT_OF_MEMORY;
|
||||||
|
goto out_of_memory;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
pQueryHandle->next = taosArrayInit(numOfCols, sizeof(SColumnInfoData));
|
||||||
|
if (pQueryHandle->next == NULL) {
|
||||||
|
terrno = TSDB_CODE_QRY_OUT_OF_MEMORY;
|
||||||
|
goto out_of_memory;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SArray* row = (type == TSDB_PREV_ROW)? pQueryHandle->prev:pQueryHandle->next;
|
||||||
|
|
||||||
|
for (int32_t i = 0; i < numOfCols; ++i) {
|
||||||
|
SColumnInfoData* pCol = taosArrayGet(pQueryHandle->pColumns, i);
|
||||||
|
|
||||||
|
SColumnInfoData colInfo = {{0}, 0};
|
||||||
|
colInfo.info = pCol->info;
|
||||||
|
colInfo.pData = calloc(1, pCol->info.bytes);
|
||||||
|
if (colInfo.pData == NULL) {
|
||||||
|
terrno = TSDB_CODE_QRY_OUT_OF_MEMORY;
|
||||||
|
goto out_of_memory;
|
||||||
|
}
|
||||||
|
|
||||||
|
taosArrayPush(row, &colInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
// load the previous row
|
||||||
|
STsdbQueryCond cond = {.numOfCols = numOfCols, .loadExternalRows = false,};
|
||||||
|
if (type == TSDB_PREV_ROW) {
|
||||||
|
cond.order = TSDB_ORDER_DESC;
|
||||||
|
cond.twindow = (STimeWindow){pQueryHandle->window.skey, INT64_MIN};
|
||||||
|
} else {
|
||||||
|
cond.order = TSDB_ORDER_ASC;
|
||||||
|
cond.twindow = (STimeWindow){pQueryHandle->window.skey, INT64_MAX};
|
||||||
|
}
|
||||||
|
|
||||||
|
cond.colList = calloc(cond.numOfCols, sizeof(SColumnInfo));
|
||||||
|
if (cond.colList == NULL) {
|
||||||
|
terrno = TSDB_CODE_QRY_OUT_OF_MEMORY;
|
||||||
|
goto out_of_memory;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int32_t i = 0; i < cond.numOfCols; ++i) {
|
||||||
|
SColumnInfoData* pColInfoData = taosArrayGet(pQueryHandle->pColumns, i);
|
||||||
|
memcpy(&cond.colList[i], &pColInfoData->info, sizeof(SColumnInfo));
|
||||||
|
}
|
||||||
|
|
||||||
|
pSecQueryHandle = tsdbQueryTablesImpl(pQueryHandle->pTsdb, &cond, pQueryHandle->qinfo, pMemRef);
|
||||||
|
|
||||||
|
tfree(cond.colList);
|
||||||
|
pSecQueryHandle->pTableCheckInfo = createCheckInfoFromCheckInfo(pQueryHandle->pTableCheckInfo, pSecQueryHandle->window.skey);
|
||||||
|
if (pSecQueryHandle->pTableCheckInfo == NULL) {
|
||||||
|
terrno = TSDB_CODE_QRY_OUT_OF_MEMORY;
|
||||||
|
goto out_of_memory;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!tsdbNextDataBlock((void*)pSecQueryHandle)) {
|
||||||
|
// no result in current query, free the corresponding result rows structure
|
||||||
|
if (type == TSDB_PREV_ROW) {
|
||||||
|
pQueryHandle->prev = doFreeColumnInfoData(pQueryHandle->prev);
|
||||||
|
} else {
|
||||||
|
pQueryHandle->next = doFreeColumnInfoData(pQueryHandle->next);
|
||||||
|
}
|
||||||
|
|
||||||
|
goto out_of_memory;
|
||||||
|
}
|
||||||
|
|
||||||
|
SDataBlockInfo blockInfo = {{0}, 0};
|
||||||
|
tsdbRetrieveDataBlockInfo((void*)pSecQueryHandle, &blockInfo);
|
||||||
|
tsdbRetrieveDataBlock((void*)pSecQueryHandle, pSecQueryHandle->defaultLoadColumn);
|
||||||
|
|
||||||
|
row = (type == TSDB_PREV_ROW)? pQueryHandle->prev:pQueryHandle->next;
|
||||||
|
int32_t pos = (type == TSDB_PREV_ROW)?pSecQueryHandle->cur.rows - 1:0;
|
||||||
|
|
||||||
|
for (int32_t i = 0; i < numOfCols; ++i) {
|
||||||
|
SColumnInfoData* pCol = taosArrayGet(row, i);
|
||||||
|
SColumnInfoData* s = taosArrayGet(pSecQueryHandle->pColumns, i);
|
||||||
|
memcpy((char*)pCol->pData, (char*)s->pData + s->info.bytes * pos, pCol->info.bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
out_of_memory:
|
||||||
|
tsdbCleanupQueryHandle(pSecQueryHandle);
|
||||||
|
return terrno;
|
||||||
|
}
|
||||||
|
|
||||||
|
SArray* tsdbGetExternalRow(TsdbQueryHandleT *pHandle, SMemRef* pMemRef, int16_t type) {
|
||||||
|
STsdbQueryHandle* pQueryHandle = (STsdbQueryHandle*) pHandle;
|
||||||
|
assert(type == TSDB_PREV_ROW || type == TSDB_NEXT_ROW);
|
||||||
|
return (type == TSDB_PREV_ROW)? pQueryHandle->prev:pQueryHandle->next;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 1. no data at all (pTable->lastKey = TSKEY_INITIAL_VAL), just return TSKEY_INITIAL_VAL
|
* 1. no data at all (pTable->lastKey = TSKEY_INITIAL_VAL), just return TSKEY_INITIAL_VAL
|
||||||
* 2. has data but not loaded, just return lastKey but not set pRes
|
* 2. has data but not loaded, just return lastKey but not set pRes
|
||||||
|
@ -2890,6 +3046,21 @@ int32_t tsdbGetTableGroupFromIdList(TSDB_REPO_T* tsdb, SArray* pTableIdList, STa
|
||||||
return TSDB_CODE_SUCCESS;
|
return TSDB_CODE_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void* doFreeColumnInfoData(SArray* pColumnInfoData) {
|
||||||
|
if (pColumnInfoData == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t cols = taosArrayGetSize(pColumnInfoData);
|
||||||
|
for (int32_t i = 0; i < cols; ++i) {
|
||||||
|
SColumnInfoData* pColInfo = taosArrayGet(pColumnInfoData, i);
|
||||||
|
tfree(pColInfo->pData);
|
||||||
|
}
|
||||||
|
|
||||||
|
taosArrayDestroy(pColumnInfoData);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
void tsdbCleanupQueryHandle(TsdbQueryHandleT queryHandle) {
|
void tsdbCleanupQueryHandle(TsdbQueryHandleT queryHandle) {
|
||||||
STsdbQueryHandle* pQueryHandle = (STsdbQueryHandle*)queryHandle;
|
STsdbQueryHandle* pQueryHandle = (STsdbQueryHandle*)queryHandle;
|
||||||
if (pQueryHandle == NULL) {
|
if (pQueryHandle == NULL) {
|
||||||
|
@ -2907,14 +3078,7 @@ void tsdbCleanupQueryHandle(TsdbQueryHandleT queryHandle) {
|
||||||
taosArrayDestroy(pQueryHandle->pTableCheckInfo);
|
taosArrayDestroy(pQueryHandle->pTableCheckInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pQueryHandle->pColumns != NULL) {
|
pQueryHandle->pColumns = doFreeColumnInfoData(pQueryHandle->pColumns);
|
||||||
size_t cols = taosArrayGetSize(pQueryHandle->pColumns);
|
|
||||||
for (int32_t i = 0; i < cols; ++i) {
|
|
||||||
SColumnInfoData* pColInfo = taosArrayGet(pQueryHandle->pColumns, i);
|
|
||||||
tfree(pColInfo->pData);
|
|
||||||
}
|
|
||||||
taosArrayDestroy(pQueryHandle->pColumns);
|
|
||||||
}
|
|
||||||
|
|
||||||
taosArrayDestroy(pQueryHandle->defaultLoadColumn);
|
taosArrayDestroy(pQueryHandle->defaultLoadColumn);
|
||||||
tfree(pQueryHandle->pDataBlockInfo);
|
tfree(pQueryHandle->pDataBlockInfo);
|
||||||
|
@ -2928,6 +3092,9 @@ void tsdbCleanupQueryHandle(TsdbQueryHandleT queryHandle) {
|
||||||
tdFreeDataCols(pQueryHandle->pDataCols);
|
tdFreeDataCols(pQueryHandle->pDataCols);
|
||||||
pQueryHandle->pDataCols = NULL;
|
pQueryHandle->pDataCols = NULL;
|
||||||
|
|
||||||
|
pQueryHandle->prev = doFreeColumnInfoData(pQueryHandle->prev);
|
||||||
|
pQueryHandle->next = doFreeColumnInfoData(pQueryHandle->next);
|
||||||
|
|
||||||
SIOCostSummary* pCost = &pQueryHandle->cost;
|
SIOCostSummary* pCost = &pQueryHandle->cost;
|
||||||
tsdbDebug("%p :io-cost summary: statis-info:%"PRId64" us, datablock:%" PRId64" us, check data:%"PRId64" us, %p",
|
tsdbDebug("%p :io-cost summary: statis-info:%"PRId64" us, datablock:%" PRId64" us, check data:%"PRId64" us, %p",
|
||||||
pQueryHandle, pCost->statisInfoLoadTime, pCost->blockLoadTime, pCost->checkForNextTime, pQueryHandle->qinfo);
|
pQueryHandle, pCost->statisInfoLoadTime, pCost->blockLoadTime, pCost->checkForNextTime, pQueryHandle->qinfo);
|
||||||
|
|
|
@ -844,3 +844,87 @@ endi
|
||||||
if $data29 != NULL then
|
if $data29 != NULL then
|
||||||
return -1
|
return -1
|
||||||
endi
|
endi
|
||||||
|
|
||||||
|
sql_error select interp(ts,c1) from intp_tb0 where ts>'2018-11-25 19:19:00' and ts<'2018-11-25 19:19:12';
|
||||||
|
sql select interp(ts,c1) from intp_tb0 where ts>'2018-11-25 19:19:00' and ts<'2018-11-25 19:19:12' interval(1s) fill(linear);
|
||||||
|
if $rows != 0 then
|
||||||
|
return -1
|
||||||
|
endi
|
||||||
|
|
||||||
|
sql select interp(c1) from intp_tb0 where ts>'2018-11-25 18:09:00' and ts<'2018-11-25 19:20:12' interval(18m);
|
||||||
|
if $rows != 0 then
|
||||||
|
return -1
|
||||||
|
endi
|
||||||
|
|
||||||
|
if $data00 != @2018-11-25 18:30:00.000@ then
|
||||||
|
return -1
|
||||||
|
endi
|
||||||
|
|
||||||
|
if $data01 != 3 then
|
||||||
|
return -1
|
||||||
|
endi
|
||||||
|
|
||||||
|
sql select interp(c1,c3,c4,ts) from intp_tb0 where ts>'2018-11-25 18:09:00' and ts<'2018-11-25 19:20:12' interval(18m) fill(linear)
|
||||||
|
if $rows != 5 then
|
||||||
|
return -1
|
||||||
|
endi
|
||||||
|
|
||||||
|
if $data00 != @2018-11-25 17:54:00.000@ then
|
||||||
|
return -1
|
||||||
|
endi
|
||||||
|
|
||||||
|
if $data01 != 0 then
|
||||||
|
return -1
|
||||||
|
endi
|
||||||
|
|
||||||
|
if $data02 != 0.00000 then
|
||||||
|
return -1
|
||||||
|
endi
|
||||||
|
|
||||||
|
if $data03 != 0.000000000 then
|
||||||
|
return -1
|
||||||
|
endi
|
||||||
|
|
||||||
|
if $data04 != @2018-11-25 17:54:00.000@ then
|
||||||
|
return -1
|
||||||
|
endi
|
||||||
|
|
||||||
|
if $data10 != @2018-11-25 18:12:00.000@ then
|
||||||
|
return -1
|
||||||
|
endi
|
||||||
|
|
||||||
|
if $data11 != 1 then
|
||||||
|
return -1
|
||||||
|
endi
|
||||||
|
|
||||||
|
if $data12 != 1.20000 then
|
||||||
|
return -1
|
||||||
|
endi
|
||||||
|
|
||||||
|
if $data13 != 1.200000000 then
|
||||||
|
return -1
|
||||||
|
endi
|
||||||
|
|
||||||
|
if $data14 != @2018-11-25 18:12:00.000@ then
|
||||||
|
return -1
|
||||||
|
endi
|
||||||
|
|
||||||
|
if $data40 != @2018-11-25 19:06:00.000@ then
|
||||||
|
return -1
|
||||||
|
endi
|
||||||
|
|
||||||
|
if $data41 != 6 then
|
||||||
|
return -1
|
||||||
|
endi
|
||||||
|
|
||||||
|
if $data42 != 6.60000 then
|
||||||
|
return -1
|
||||||
|
endi
|
||||||
|
|
||||||
|
if $data43 != 6.600000000 then
|
||||||
|
return -1
|
||||||
|
endi
|
||||||
|
|
||||||
|
if $data44 != @2018-11-25 19:06:00.000@ then
|
||||||
|
return -1
|
||||||
|
endi
|
Loading…
Reference in New Issue