diff --git a/src/client/src/tscSQLParser.c b/src/client/src/tscSQLParser.c index 3efcc3e7855a61f1dbfc9d56b0520785729c8519..b42bcfbfb1e444f22537d6bec7755452964cf36e 100644 --- a/src/client/src/tscSQLParser.c +++ b/src/client/src/tscSQLParser.c @@ -2830,15 +2830,16 @@ int32_t addExprAndResultField(SSqlCmd* pCmd, SQueryInfo* pQueryInfo, int32_t col // todo REFACTOR // set the first column ts for top/bottom query + int32_t tsFuncId = (functionId == TSDB_FUNC_MAVG) ? TSDB_FUNC_TS_DUMMY : TSDB_FUNC_TS; SColumnIndex index1 = {index.tableIndex, PRIMARYKEY_TIMESTAMP_COL_INDEX}; - pExpr = tscExprAppend(pQueryInfo, TSDB_FUNC_TS_DUMMY, &index1, TSDB_DATA_TYPE_TIMESTAMP, TSDB_KEYSIZE, getNewResColId(pCmd), + pExpr = tscExprAppend(pQueryInfo, tsFuncId, &index1, TSDB_DATA_TYPE_TIMESTAMP, TSDB_KEYSIZE, getNewResColId(pCmd), 0, false); - tstrncpy(pExpr->base.aliasName, aAggs[TSDB_FUNC_TS_DUMMY].name, sizeof(pExpr->base.aliasName)); + tstrncpy(pExpr->base.aliasName, aAggs[tsFuncId].name, sizeof(pExpr->base.aliasName)); const int32_t TS_COLUMN_INDEX = PRIMARYKEY_TIMESTAMP_COL_INDEX; SColumnList ids = createColumnList(1, index.tableIndex, TS_COLUMN_INDEX); insertResultField(pQueryInfo, colIndex, &ids, TSDB_KEYSIZE, TSDB_DATA_TYPE_TIMESTAMP, - aAggs[TSDB_FUNC_TS_DUMMY].name, pExpr); + aAggs[tsFuncId].name, pExpr); colIndex += 1; // the first column is ts @@ -5585,7 +5586,8 @@ int32_t validateFillNode(SSqlCmd* pCmd, SQueryInfo* pQueryInfo, SSqlNode* pSqlNo size_t numOfExprs = tscNumOfExprs(pQueryInfo); for(int32_t i = 0; i < numOfExprs; ++i) { SExprInfo* pExpr = tscExprGet(pQueryInfo, i); - if (pExpr->base.functionId == TSDB_FUNC_TOP || pExpr->base.functionId == TSDB_FUNC_BOTTOM) { + if (pExpr->base.functionId == TSDB_FUNC_TOP || pExpr->base.functionId == TSDB_FUNC_BOTTOM + || pExpr->base.functionId == TSDB_FUNC_SAMPLE) { return invalidOperationMsg(tscGetErrorMsgPayload(pCmd), msg3); } } diff --git a/src/query/src/qAggMain.c b/src/query/src/qAggMain.c index aa1defc26975871ae3b140d8ccb8e03de53b413f..ce870fb2ead17765005eab2d003254d5740f7e2a 100644 --- a/src/query/src/qAggMain.c +++ b/src/query/src/qAggMain.c @@ -186,6 +186,7 @@ typedef struct { int16_t colBytes; char *values; int64_t *timeStamps; + char *taglists; } SSampleFuncInfo; int32_t getResultDataInfo(int32_t dataType, int32_t dataBytes, int32_t functionId, int32_t param, int16_t *type, @@ -323,7 +324,7 @@ int32_t getResultDataInfo(int32_t dataType, int32_t dataBytes, int32_t functionI return TSDB_CODE_SUCCESS; } else if (functionId == TSDB_FUNC_SAMPLE) { *type = TSDB_DATA_TYPE_BINARY; - *bytes = (int16_t)(sizeof(SSampleFuncInfo) + dataBytes * param + sizeof(int64_t) * param); + *bytes = (int16_t)(sizeof(SSampleFuncInfo) + dataBytes*param + sizeof(int64_t)*param + extLength*param); *interBytes = *bytes; return TSDB_CODE_SUCCESS; @@ -438,7 +439,7 @@ int32_t getResultDataInfo(int32_t dataType, int32_t dataBytes, int32_t functionI } else if (functionId == TSDB_FUNC_SAMPLE) { *type = (int16_t)dataType; *bytes = (int16_t)dataBytes; - size_t size = sizeof(SSampleFuncInfo) + sizeof(dataBytes) * param + sizeof(int64_t) * param; + size_t size = sizeof(SSampleFuncInfo) + dataBytes*param + sizeof(int64_t)*param + extLength*param; *interBytes = (int32_t)size; } else if (functionId == TSDB_FUNC_LAST_ROW) { *type = (int16_t)dataType; @@ -4684,21 +4685,38 @@ static SSampleFuncInfo* getSampleFuncOutputInfo(SQLFunctionCtx *pCtx) { } } -static void assignResultSample(SSampleFuncInfo *pInfo, int32_t index, int64_t ts, void *pData, uint16_t type, int16_t bytes) { +static void assignResultSample(SQLFunctionCtx *pCtx, SSampleFuncInfo *pInfo, int32_t index, int64_t ts, void *pData, uint16_t type, int16_t bytes, char *inputTags) { assignVal(pInfo->values + index*bytes, pData, bytes, type); *(pInfo->timeStamps + index) = ts; - return; + + SExtTagsInfo* pTagInfo = &pCtx->tagInfo; + int32_t posTag = 0; + char* tags = pInfo->taglists + pTagInfo->tagsLen; + if (pCtx->currentStage == MERGE_STAGE) { + memcpy(tags, inputTags, (size_t)pTagInfo->tagsLen); + } else { + for (int32_t i = 0; i < pTagInfo->numOfTagCols; ++i) { + SQLFunctionCtx* ctx = pTagInfo->pTagCtxList[i]; + if (ctx->functionId == TSDB_FUNC_TS_DUMMY) { + ctx->tag.nType = TSDB_DATA_TYPE_BIGINT; + ctx->tag.i64 = ts; + } + + tVariantDump(&ctx->tag, tags + posTag, ctx->tag.nType, true); + posTag += pTagInfo->pTagCtxList[i]->outputBytes; + } + } } -static void do_reservoir_sample(SSampleFuncInfo *pInfo, int32_t samplesK, int64_t ts, void *pData, uint16_t type, int16_t bytes) { +static void do_reservoir_sample(SQLFunctionCtx *pCtx, SSampleFuncInfo *pInfo, int32_t samplesK, int64_t ts, void *pData, uint16_t type, int16_t bytes) { pInfo->totalPoints++; if (pInfo->numSampled < samplesK) { - assignResultSample(pInfo, pInfo->numSampled, ts, pData, type, bytes); + assignResultSample(pCtx, pInfo, pInfo->numSampled, ts, pData, type, bytes, NULL); pInfo->numSampled++; } else { int32_t j = rand() % (pInfo->totalPoints); if (j < samplesK) { - assignResultSample(pInfo, j, ts, pData, type, bytes); + assignResultSample(pCtx, pInfo, j, ts, pData, type, bytes, NULL); } } } @@ -4712,11 +4730,25 @@ static void copySampleFuncRes(SQLFunctionCtx *pCtx, int32_t type) { for (int32_t i = 0; i < pRes->numSampled; ++i) { assignVal(pOutput, pRes->values + i*pRes->colBytes, pRes->colBytes, type); *pTimestamp = *(pRes->timeStamps + i); - pOutput += pCtx->outputBytes; pTimestamp++; } + char **pData = calloc(pCtx->tagInfo.numOfTagCols, POINTER_BYTES); + for (int32_t i = 0; i < pCtx->tagInfo.numOfTagCols; ++i) { + pData[i] = pCtx->tagInfo.pTagCtxList[i]->pOutput; + } + + for (int32_t i = 0; i < pRes->numSampled; ++i) { + int16_t tagOffset = 0; + for (int32_t j = 0; j < pCtx->tagInfo.numOfTagCols; ++j) { + memcpy(pData[j], pRes->taglists + i*pCtx->tagInfo.tagsLen + tagOffset, (size_t)pCtx->tagInfo.pTagCtxList[j]->outputBytes); + tagOffset += pCtx->tagInfo.pTagCtxList[j]->outputBytes; + pData[j] += pCtx->tagInfo.pTagCtxList[j]->outputBytes; + } + } + + tfree(pData); } static bool sample_function_setup(SQLFunctionCtx *pCtx, SResultRowCellInfo* pResInfo) { @@ -4732,6 +4764,7 @@ static bool sample_function_setup(SQLFunctionCtx *pCtx, SResultRowCellInfo* pRes pRes->values = ((char*)pRes + sizeof(SSampleFuncInfo)); pRes->colBytes = (pCtx->currentStage != MERGE_STAGE) ? pCtx->inputBytes : pCtx->outputBytes; pRes->timeStamps = (int64_t *)((char *)pRes->values + pRes->colBytes * pCtx->param[0].i64); + pRes->taglists = (char*)pRes->timeStamps + sizeof(int64_t) * pCtx->param[0].i64; return true; } @@ -4744,6 +4777,7 @@ static void sample_function(SQLFunctionCtx *pCtx) { if (pRes->values != ((char*)pRes + sizeof(SSampleFuncInfo))) { pRes->values = ((char*)pRes + sizeof(SSampleFuncInfo)); pRes->timeStamps = (int64_t*)((char*)pRes->values + pRes->colBytes * pCtx->param[0].i64); + pRes->taglists = (char*)pRes->timeStamps + sizeof(int64_t) * pCtx->param[0].i64; } for (int32_t i = 0; i < pCtx->size; ++i) { @@ -4755,7 +4789,7 @@ static void sample_function(SQLFunctionCtx *pCtx) { notNullElems++; TSKEY ts = (pCtx->ptsList != NULL)? GET_TS_DATA(pCtx, i):0; - do_reservoir_sample(pRes, (int32_t)pCtx->param[0].i64, ts, data, pCtx->inputType, pRes->colBytes); + do_reservoir_sample(pCtx, pRes, (int32_t)pCtx->param[0].i64, ts, data, pCtx->inputType, pRes->colBytes); } if (!pCtx->hasNull) { @@ -4774,13 +4808,15 @@ static void sample_func_merge(SQLFunctionCtx *pCtx) { SSampleFuncInfo* pInput = (SSampleFuncInfo*)GET_INPUT_DATA_LIST(pCtx); pInput->values = ((char*)pInput + sizeof(SSampleFuncInfo)); pInput->timeStamps = (int64_t*)((char*)pInput->values + pInput->colBytes * pCtx->param[0].i64); + pInput->taglists = (char*)pInput->timeStamps + sizeof(int64_t)*pCtx->param[0].i64; SSampleFuncInfo *pOutput = getSampleFuncOutputInfo(pCtx); pOutput->totalPoints = pInput->totalPoints; pOutput->numSampled = pInput->numSampled; for (int32_t i = 0; i < pInput->numSampled; ++i) { - assignResultSample(pOutput, i, pInput->timeStamps[i], - pInput->values + i * pInput->colBytes, pCtx->outputType, pInput->colBytes); + assignResultSample(pCtx, pOutput, i, pInput->timeStamps[i], + pInput->values + i * pInput->colBytes, pCtx->outputType, pInput->colBytes, + pInput->taglists + i*pCtx->tagInfo.tagsLen); } SET_VAL(pCtx, pInput->numSampled, pOutput->numSampled); diff --git a/src/query/src/qExecutor.c b/src/query/src/qExecutor.c index 8d1f523574d48d90fe19d8c7b00c0c732244d1d1..75759f3a12f334f794e493ddbca76617e8d81819 100644 --- a/src/query/src/qExecutor.c +++ b/src/query/src/qExecutor.c @@ -3986,7 +3986,9 @@ void setResultOutputBuf(SQueryRuntimeEnv *pRuntimeEnv, SResultRow *pResult, SQLF offset += pCtx[i].outputBytes; int32_t functionId = pCtx[i].functionId; - if (functionId == TSDB_FUNC_TOP || functionId == TSDB_FUNC_BOTTOM || functionId == TSDB_FUNC_DIFF || functionId == TSDB_FUNC_DERIVATIVE) { + if (functionId == TSDB_FUNC_TOP || functionId == TSDB_FUNC_BOTTOM || + functionId == TSDB_FUNC_DIFF || functionId == TSDB_FUNC_DERIVATIVE || + functionId == TSDB_FUNC_SAMPLE || functionId == TSDB_FUNC_MAVG || functionId == TSDB_FUNC_CSUM) { if(i > 0) pCtx[i].ptsOutputBuf = pCtx[i-1].pOutput; } diff --git a/tests/script/general/parser/col_arithmetic_operation.sim b/tests/script/general/parser/col_arithmetic_operation.sim index c4d0fdfeed8173d5f5b48a0cbcec392b99c0500b..6f628090020afbba6e938fa4b95d1cfb9062944e 100644 --- a/tests/script/general/parser/col_arithmetic_operation.sim +++ b/tests/script/general/parser/col_arithmetic_operation.sim @@ -124,6 +124,7 @@ sql select spread(ts )/(1000*3600*24) from $stb interval(1y) sql_error select first(c1, c2) - last(c1, c2) from $stb interval(1y) sql_error select first(ts) - last(ts) from $stb interval(1y) sql_error select top(c1, 2) - last(c1) from $stb; +sql_error select sample(c1, 2) - last(c1) from $stb; sql_error select stddev(c1) - last(c1) from $stb; sql_error select diff(c1) - last(c1) from $stb; sql_error select csum(c1) - last(c1) from $stb; diff --git a/tests/script/general/parser/col_arithmetic_query.sim b/tests/script/general/parser/col_arithmetic_query.sim index 17ae6cfd6b8b5636101e67e8d99f6999e50a06a5..502de9583e9727d2dbee4a5601f974d6a46173ba 100644 --- a/tests/script/general/parser/col_arithmetic_query.sim +++ b/tests/script/general/parser/col_arithmetic_query.sim @@ -174,6 +174,9 @@ endi sql_error select top(c1, 1) - bottom(c1, 1) from $tb sql_error select top(c1, 99) - bottom(c1, 99) from $tb sql_error select top(c1,1) - 88 from $tb +sql_error select sample(c1, 1) - bottom(c1, 1) from $tb +sql_error select sample(c1, 99) - bottom(c1, 99) from $tb +sql_error select sample(c1,1) - 88 from $tb # all data types [d.6] ================================================================ sql select c2-c1*1.1, c3/c2, c4*c3, c5%c4, (c6+c4)%22, c2-c2 from $tb @@ -475,11 +478,16 @@ endi sql_error select first(c1, c2) - last(c1, c2) from $stb sql_error select top(c1, 5) - bottom(c1, 5) from $stb sql_error select first(*) - 99 from $stb +sql_error select sample(c1, 5) - bottom(c1, 5) from $stb + # multi row result aggregation [d.4] sql_error select top(c1, 1) - bottom(c1, 1) from $stb sql_error select top(c1, 99) - bottom(c1, 99) from $stb +sql_error select sample(c1, 1) - top(c1, 1) from $stb +sql_error select sample(c1, 99) - top(c1, 99) from $stb + # query on super table [d.5]============================================================= # all cases in this part are query on super table diff --git a/tests/script/general/parser/having.sim b/tests/script/general/parser/having.sim index 01811ea00564dffd098c39b453e15ccc31b0ed28..117245491233dbd432ce6effc564aaeedb79aebe 100644 --- a/tests/script/general/parser/having.sim +++ b/tests/script/general/parser/having.sim @@ -121,6 +121,7 @@ if $data31 != 4 then return -1 endi +sql_error select sample(f1,2) from st2 group by f1 having count(f2) > 0; sql_error select top(f1,2) from st2 group by f1 having count(f2) > 0; sql select last(f1) from st2 group by f1 having count(f2) > 0; @@ -140,9 +141,12 @@ if $data30 != 4 then return -1 endi -sql_error select top(f1,2) from st2 group by f1 having count(f2) > 0; -sql_error select top(f1,2) from st2 group by f1 having count(f2) > 0; -sql_error select top(f1,2) from st2 group by f1 having avg(f1) > 0; +sql_error select sample(f1,2) from st2 group by f1 having count(f2) > 0; +sql_error select sample(f1,2) from st2 group by f1 having count(f2) > 0; +sql_error select sample(f1,2) from st2 group by f1 having avg(f1) > 0; +sql_error select sample(f1,2) from st2 group by f1 having count(f2) > 0; +sql_error select sample(f1,2) from st2 group by f1 having count(f2) > 0; +sql_error select sample(f1,2) from st2 group by f1 having avg(f1) > 0; sql select avg(f1),count(f1) from st2 group by f1 having avg(f1) > 2; if $rows != 2 then @@ -1059,6 +1063,13 @@ if $data26 != 4 then endi +sql_error select avg(f1),count(st2.*),sum(f1),stddev(f1),min(f1),max(f1),first(f1),last(f1) from st2 group by f1 having sample(f1,1); + +sql_error select avg(f1),count(st2.*),sum(f1),stddev(f1),min(f1),max(f1),first(f1),last(f1) from st2 group by f1 having sample(f1,1) > 1; + +sql_error select avg(f1),count(st2.*),sum(f1),stddev(f1),min(f1),max(f1),first(f1),last(f1),sample(f1,1) from st2 group by f1 having sum(f1) > 1; + +sql_error select avg(f1),count(st2.*),sum(f1),stddev(f1),min(f1),max(f1),first(f1),last(f1),sample(f1,1),bottom(f1,1) from st2 group by f1 having bottom(f1,1) > 1; sql_error select avg(f1),count(st2.*),sum(f1),stddev(f1),min(f1),max(f1),first(f1),last(f1) from st2 group by f1 having top(f1,1); @@ -1840,6 +1851,7 @@ if $data04 != 1 then return -1 endi +sql_error select sample(f1,2) from tb1 group by f1 having count(f1) > 0; sql_error select top(f1,2) from tb1 group by f1 having count(f1) > 0; sql_error select count(*) from tb1 group by f1 having last(*) > 0; diff --git a/tests/script/general/parser/limit.sim b/tests/script/general/parser/limit.sim index 3af2cb301854b27bc1b9c33bf8b06cbd17e87fd3..00ebc7601386e1a19cd43253794f891441e87fe3 100644 --- a/tests/script/general/parser/limit.sim +++ b/tests/script/general/parser/limit.sim @@ -80,4 +80,7 @@ sql use $db sql select * from (select ts, top(c1, 5) from $tb where ts >= $ts0 order by ts desc limit 3 offset 1) sql select * from (select ts, top(c1, 5) from $stb where ts >= $ts0 order by ts desc limit 3 offset 1) -system sh/exec.sh -n dnode1 -s stop -x SIGINT \ No newline at end of file +sql select * from (select ts, sample(c1, 5) from $tb where ts >= $ts0 order by ts desc limit 3 offset 1) +sql_error select * from (select ts, sample(c1, 5) from $stb where ts >= $ts0 order by ts desc limit 3 offset 1) + +system sh/exec.sh -n dnode1 -s stop -x SIGINT diff --git a/tests/script/general/parser/limit_stb.sim b/tests/script/general/parser/limit_stb.sim index ec7c0e0f138e677c7da95c20af4bd13908aa1a0c..2e6c10cd96db8536e12acf57bf9283eb20f59d1b 100644 --- a/tests/script/general/parser/limit_stb.sim +++ b/tests/script/general/parser/limit_stb.sim @@ -828,6 +828,8 @@ if $data59 != 4 then return -1 endi +sql_error select sample(c1, 1) from $stb where ts >= $ts0 and ts <= $tsu limit 5 offset 1 + sql select top(c1, 1) from $stb where ts >= $ts0 and ts <= $tsu limit 5 offset 1 if $rows != 0 then return -1 diff --git a/tests/script/general/parser/limit_tb.sim b/tests/script/general/parser/limit_tb.sim index a47a1557680c59664faed0380d28c3c32f88ffb9..6750203dcadcafe7ae0f7e86f3a2b2445f7ac76b 100644 --- a/tests/script/general/parser/limit_tb.sim +++ b/tests/script/general/parser/limit_tb.sim @@ -355,6 +355,21 @@ sql select top(c1, 1) from $tb where ts >= $ts0 and ts <= $tsu limit 5 offset 1 if $rows != 0 then return -1 endi +sql select sample(c1, 1) from $tb where ts >= $ts0 and ts <= $tsu limit 5 offset 1 +if $rows != 0 then + return -1 +endi + +sql select * from (select ts, sample(c1, 5) from $tb where ts >= $ts0 and ts <= $tsu order by ts desc limit 3 offset 1) + +sql select ts,sample(c1, 5) from $tb where ts >= $ts0 and ts <= $tsu order by ts desc limit 3 offset 1 +if $rows != 3 then + return -1 +endi +print select ts,sample(c1, 5) from $tb where ts >= $ts0 and ts <= $tsu order by ts desc limit 3 offset 1 +print $data00 $data01 $data02 +print $data10 $data11 $data12 +print $data20 $data21 $data22 print ========> TD-6017 sql select * from (select ts, top(c1, 5) from $tb where ts >= $ts0 and ts <= $tsu order by ts desc limit 3 offset 1) diff --git a/tests/script/general/parser/nestquery.sim b/tests/script/general/parser/nestquery.sim index 6cf8ac37181087cc16cf616c801daf0fe3f19e6f..4dca34f7c067019067fb3927dcebb7d99f0c793d 100644 --- a/tests/script/general/parser/nestquery.sim +++ b/tests/script/general/parser/nestquery.sim @@ -335,6 +335,8 @@ if $data12 != 71680.000000000 then return -1 endi +sql select sample(x, 20) from (select c1 x from nest_tb0); + sql select top(x, 20) from (select c1 x from nest_tb0); sql select bottom(x, 20) from (select c1 x from nest_tb0) diff --git a/tests/script/general/parser/projection_limit_offset.sim b/tests/script/general/parser/projection_limit_offset.sim index ffbcb28ffd9b4e15f707509dc5cc808ef3f8ce4a..f2bde7f003df8ef765664c89862cbc35aeb18c45 100644 --- a/tests/script/general/parser/projection_limit_offset.sim +++ b/tests/script/general/parser/projection_limit_offset.sim @@ -296,6 +296,7 @@ sql_error select last(t1) from group_mt0; sql_error select min(t1) from group_mt0; sql_error select max(t1) from group_mt0; sql_error select top(t1, 20) from group_mt0; +sql_error select sample(t1, 20) from group_mt0; sql_error select bottom(t1, 20) from group_mt0; sql_error select avg(t1) from group_mt0; sql_error select percentile(t1, 50) from group_mt0; diff --git a/tests/script/general/parser/udf_dll_stable.sim b/tests/script/general/parser/udf_dll_stable.sim index b8da57467e912ff27f4fbda7226c75e089f04808..15becaab22476d12829abc62db4de4f914eef271 100644 --- a/tests/script/general/parser/udf_dll_stable.sim +++ b/tests/script/general/parser/udf_dll_stable.sim @@ -508,6 +508,7 @@ sql_error select ts,sum_double(f1),f1 from tb1; sql_error select add_one(f1),count(f1) from tb1; sql_error select sum_double(f1),count(f1) from tb1; sql_error select add_one(f1),top(f1,3) from tb1; +sql_error select add_one(f1),sample(f1,3) from tb1; sql_error select add_one(f1) from tb1 interval(10a);