Merge pull request #6639 from taosdata/feature/TD-4825
[TD-4825]<feature> order by col after group-by
This commit is contained in:
commit
7cf7f8e991
|
@ -5102,7 +5102,7 @@ static void setDefaultOrderInfo(SQueryInfo* pQueryInfo) {
|
|||
int32_t validateOrderbyNode(SSqlCmd* pCmd, SQueryInfo* pQueryInfo, SSqlNode* pSqlNode, SSchema* pSchema) {
|
||||
const char* msg0 = "only support order by primary timestamp";
|
||||
const char* msg1 = "invalid column name";
|
||||
const char* msg2 = "order by primary timestamp or first tag in groupby clause allowed";
|
||||
const char* msg2 = "order by primary timestamp, first tag or groupby column in groupby clause allowed";
|
||||
const char* msg3 = "invalid column in order by clause, only primary timestamp or first tag in groupby clause allowed";
|
||||
|
||||
setDefaultOrderInfo(pQueryInfo);
|
||||
|
@ -5155,6 +5155,7 @@ int32_t validateOrderbyNode(SSqlCmd* pCmd, SQueryInfo* pQueryInfo, SSqlNode* pSq
|
|||
|
||||
bool orderByTags = false;
|
||||
bool orderByTS = false;
|
||||
bool orderByGroupbyCol = false;
|
||||
|
||||
if (index.columnIndex >= tscGetNumOfColumns(pTableMetaInfo->pTableMeta)) {
|
||||
int32_t relTagIndex = index.columnIndex - tscGetNumOfColumns(pTableMetaInfo->pTableMeta);
|
||||
|
@ -5174,11 +5175,18 @@ int32_t validateOrderbyNode(SSqlCmd* pCmd, SQueryInfo* pQueryInfo, SSqlNode* pSq
|
|||
if (PRIMARYKEY_TIMESTAMP_COL_INDEX == index.columnIndex) {
|
||||
orderByTS = true;
|
||||
}
|
||||
|
||||
if (!(orderByTags || orderByTS) && !isTopBottomQuery(pQueryInfo)) {
|
||||
|
||||
SArray *columnInfo = pQueryInfo->groupbyExpr.columnInfo;
|
||||
if (columnInfo != NULL && taosArrayGetSize(columnInfo) > 0) {
|
||||
SColIndex* pColIndex = taosArrayGet(columnInfo, 0);
|
||||
if (PRIMARYKEY_TIMESTAMP_COL_INDEX != index.columnIndex && pColIndex->colIndex == index.columnIndex) {
|
||||
orderByGroupbyCol = true;
|
||||
}
|
||||
}
|
||||
if (!(orderByTags || orderByTS || orderByGroupbyCol) && !isTopBottomQuery(pQueryInfo)) {
|
||||
return invalidOperationMsg(tscGetErrorMsgPayload(pCmd), msg3);
|
||||
} else { // order by top/bottom result value column is not supported in case of interval query.
|
||||
assert(!(orderByTags && orderByTS));
|
||||
assert(!(orderByTags && orderByTS && orderByGroupbyCol));
|
||||
}
|
||||
|
||||
size_t s = taosArrayGetSize(pSortorder);
|
||||
|
@ -5188,6 +5196,11 @@ int32_t validateOrderbyNode(SSqlCmd* pCmd, SQueryInfo* pQueryInfo, SSqlNode* pSq
|
|||
|
||||
tVariantListItem* p1 = taosArrayGet(pSqlNode->pSortOrder, 0);
|
||||
pQueryInfo->groupbyExpr.orderType = p1->sortOrder;
|
||||
} else if (orderByGroupbyCol) {
|
||||
tVariantListItem* p1 = taosArrayGet(pSqlNode->pSortOrder, 0);
|
||||
|
||||
pQueryInfo->groupbyExpr.orderType = p1->sortOrder;
|
||||
pQueryInfo->order.orderColId = pSchema[index.columnIndex].colId;
|
||||
} else if (isTopBottomQuery(pQueryInfo)) {
|
||||
/* order of top/bottom query in interval is not valid */
|
||||
SExprInfo* pExpr = tscExprGet(pQueryInfo, 0);
|
||||
|
@ -5220,6 +5233,9 @@ int32_t validateOrderbyNode(SSqlCmd* pCmd, SQueryInfo* pQueryInfo, SSqlNode* pSq
|
|||
if (orderByTags) {
|
||||
pQueryInfo->groupbyExpr.orderIndex = index.columnIndex - tscGetNumOfColumns(pTableMetaInfo->pTableMeta);
|
||||
pQueryInfo->groupbyExpr.orderType = pItem->sortOrder;
|
||||
} else if (orderByGroupbyCol){
|
||||
pQueryInfo->order.order = pItem->sortOrder;
|
||||
pQueryInfo->order.orderColId = index.columnIndex;
|
||||
} else {
|
||||
pQueryInfo->order.order = pItem->sortOrder;
|
||||
pQueryInfo->order.orderColId = PRIMARYKEY_TIMESTAMP_COL_INDEX;
|
||||
|
@ -5245,9 +5261,20 @@ int32_t validateOrderbyNode(SSqlCmd* pCmd, SQueryInfo* pQueryInfo, SSqlNode* pSq
|
|||
if (getColumnIndexByName(pCmd, &columnName, pQueryInfo, &index) != TSDB_CODE_SUCCESS) {
|
||||
return invalidOperationMsg(tscGetErrorMsgPayload(pCmd), msg1);
|
||||
}
|
||||
|
||||
if (index.columnIndex != PRIMARYKEY_TIMESTAMP_COL_INDEX && !isTopBottomQuery(pQueryInfo)) {
|
||||
return invalidOperationMsg(tscGetErrorMsgPayload(pCmd), msg2);
|
||||
bool validOrder = false;
|
||||
SArray *columnInfo = pQueryInfo->groupbyExpr.columnInfo;
|
||||
if (columnInfo != NULL && taosArrayGetSize(columnInfo) > 0) {
|
||||
SColIndex* pColIndex = taosArrayGet(columnInfo, 0);
|
||||
validOrder = (pColIndex->colIndex == index.columnIndex);
|
||||
}
|
||||
if (!validOrder) {
|
||||
return invalidOperationMsg(tscGetErrorMsgPayload(pCmd), msg2);
|
||||
}
|
||||
tVariantListItem* p1 = taosArrayGet(pSqlNode->pSortOrder, 0);
|
||||
pQueryInfo->groupbyExpr.orderIndex = pSchema[index.columnIndex].colId;
|
||||
pQueryInfo->groupbyExpr.orderType = p1->sortOrder;
|
||||
|
||||
}
|
||||
|
||||
if (isTopBottomQuery(pQueryInfo)) {
|
||||
|
@ -5268,6 +5295,7 @@ int32_t validateOrderbyNode(SSqlCmd* pCmd, SQueryInfo* pQueryInfo, SSqlNode* pSq
|
|||
|
||||
tVariantListItem* pItem = taosArrayGet(pSqlNode->pSortOrder, 0);
|
||||
pQueryInfo->order.order = pItem->sortOrder;
|
||||
pQueryInfo->order.orderColId = pSchema[index.columnIndex].colId;
|
||||
}
|
||||
|
||||
return TSDB_CODE_SUCCESS;
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include "qFill.h"
|
||||
#include "taosmsg.h"
|
||||
#include "tglobal.h"
|
||||
#include "talgo.h"
|
||||
|
||||
#include "exception.h"
|
||||
#include "hash.h"
|
||||
|
@ -26,6 +27,7 @@
|
|||
#include "queryLog.h"
|
||||
#include "tlosertree.h"
|
||||
#include "ttype.h"
|
||||
#include "tcompare.h"
|
||||
#include "tscompression.h"
|
||||
|
||||
#define IS_MASTER_SCAN(runtime) ((runtime)->scanFlag == MASTER_SCAN)
|
||||
|
@ -207,7 +209,66 @@ static void doSetTableGroupOutputBuf(SQueryRuntimeEnv* pRuntimeEnv, SResultRowIn
|
|||
SQLFunctionCtx* pCtx, int32_t* rowCellInfoOffset, int32_t numOfOutput,
|
||||
int32_t groupIndex);
|
||||
|
||||
// setup the output buffer for each operator
|
||||
SArray* getOrderCheckColumns(SQueryAttr* pQuery);
|
||||
|
||||
|
||||
typedef struct SRowCompSupporter {
|
||||
SQueryRuntimeEnv *pRuntimeEnv;
|
||||
int16_t dataOffset;
|
||||
__compar_fn_t comFunc;
|
||||
} SRowCompSupporter;
|
||||
|
||||
static int compareRowData(const void *a, const void *b, const void *userData) {
|
||||
const SResultRow *pRow1 = (const SResultRow *)a;
|
||||
const SResultRow *pRow2 = (const SResultRow *)b;
|
||||
|
||||
SRowCompSupporter *supporter = (SRowCompSupporter *)userData;
|
||||
SQueryRuntimeEnv* pRuntimeEnv = supporter->pRuntimeEnv;
|
||||
|
||||
tFilePage *page1 = getResBufPage(pRuntimeEnv->pResultBuf, pRow1->pageId);
|
||||
tFilePage *page2 = getResBufPage(pRuntimeEnv->pResultBuf, pRow2->pageId);
|
||||
|
||||
int16_t offset = supporter->dataOffset;
|
||||
char *in1 = getPosInResultPage(pRuntimeEnv->pQueryAttr, page1, pRow1->offset, offset);
|
||||
char *in2 = getPosInResultPage(pRuntimeEnv->pQueryAttr, page2, pRow2->offset, offset);
|
||||
|
||||
return (in1 != NULL && in2 != NULL) ? supporter->comFunc(in1, in2) : 0;
|
||||
}
|
||||
|
||||
static void sortGroupResByOrderList(SGroupResInfo *pGroupResInfo, SQueryRuntimeEnv *pRuntimeEnv, SSDataBlock* pDataBlock) {
|
||||
SArray *columnOrderList = getOrderCheckColumns(pRuntimeEnv->pQueryAttr);
|
||||
if (taosArrayGetSize(columnOrderList) <= 0) {
|
||||
return;
|
||||
}
|
||||
int32_t orderId = pRuntimeEnv->pQueryAttr->order.orderColId;
|
||||
if (orderId <= 0) {
|
||||
return;
|
||||
}
|
||||
bool found = false;
|
||||
int16_t dataOffset = 0;
|
||||
|
||||
//SColIndex *index = taosArrayGet(columnOrderList, 0);
|
||||
for (int32_t j = 0; j < pDataBlock->info.numOfCols; ++j) {
|
||||
SColumnInfoData* pColInfoData = (SColumnInfoData *)taosArrayGet(pDataBlock->pDataBlock, j);
|
||||
if (orderId == j) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
dataOffset += pColInfoData->info.bytes;
|
||||
}
|
||||
|
||||
if (found == false) {
|
||||
return;
|
||||
}
|
||||
int16_t type = pRuntimeEnv->pQueryAttr->pExpr1[orderId].base.resType;
|
||||
|
||||
SRowCompSupporter support = {.pRuntimeEnv = pRuntimeEnv, .dataOffset = dataOffset, .comFunc = getComparFunc(type, 0)};
|
||||
|
||||
taosArraySortPWithExt(pGroupResInfo->pRows, compareRowData, &support);
|
||||
return;
|
||||
|
||||
}
|
||||
//setup the output buffer for each operator
|
||||
SSDataBlock* createOutputBuf(SExprInfo* pExpr, int32_t numOfOutput, int32_t numOfRows) {
|
||||
const static int32_t minSize = 8;
|
||||
|
||||
|
@ -5588,8 +5649,11 @@ static SSDataBlock* hashGroupbyAggregate(void* param, bool* newgroup) {
|
|||
}
|
||||
|
||||
initGroupResInfo(&pRuntimeEnv->groupResInfo, &pInfo->binfo.resultRowInfo);
|
||||
if (!pRuntimeEnv->pQueryAttr->stableQuery) {
|
||||
sortGroupResByOrderList(&pRuntimeEnv->groupResInfo, pRuntimeEnv, pInfo->binfo.pRes);
|
||||
}
|
||||
toSSDataBlock(&pRuntimeEnv->groupResInfo, pRuntimeEnv, pInfo->binfo.pRes);
|
||||
|
||||
|
||||
if (pInfo->binfo.pRes->info.rows == 0 || !hasRemainDataInCurrentGroup(&pRuntimeEnv->groupResInfo)) {
|
||||
pOperator->status = OP_EXEC_DONE;
|
||||
}
|
||||
|
|
|
@ -197,8 +197,21 @@ void* taosArraySearch(const SArray* pArray, const void* key, __compar_fn_t compa
|
|||
*/
|
||||
char* taosArraySearchString(const SArray* pArray, const char* key, __compar_fn_t comparFn, int flags);
|
||||
|
||||
|
||||
/**
|
||||
* sort the pointer data in the array
|
||||
* @param pArray
|
||||
* @param compar
|
||||
* @param param
|
||||
* @return
|
||||
*/
|
||||
|
||||
void taosArraySortPWithExt(SArray* pArray, __ext_compar_fn_t fn, const void *param);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#endif // TDENGINE_TAOSARRAY_H
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
|
||||
#include "os.h"
|
||||
#include "tarray.h"
|
||||
#include "talgo.h"
|
||||
|
||||
void* taosArrayInit(size_t size, size_t elemSize) {
|
||||
assert(elemSize > 0);
|
||||
|
@ -249,4 +250,62 @@ char* taosArraySearchString(const SArray* pArray, const char* key, __compar_fn_t
|
|||
return NULL;
|
||||
}
|
||||
return *(char**)p;
|
||||
}
|
||||
}
|
||||
|
||||
static int taosArrayPartition(SArray *pArray, int i, int j, __ext_compar_fn_t fn, const void *userData) {
|
||||
void* key = taosArrayGetP(pArray, i);
|
||||
while (i < j) {
|
||||
while (i < j && fn(taosArrayGetP(pArray, j), key, userData) >= 0) { j--; }
|
||||
if (i < j) {
|
||||
void *a = taosArrayGetP(pArray, j);
|
||||
taosArraySet(pArray, i, &a);
|
||||
}
|
||||
while (i < j && fn(taosArrayGetP(pArray, i), key, userData) <= 0) { i++;}
|
||||
if (i < j) {
|
||||
void *a = taosArrayGetP(pArray, i);
|
||||
taosArraySet(pArray, j, &a);
|
||||
}
|
||||
}
|
||||
taosArraySet(pArray, i, &key);
|
||||
return i;
|
||||
}
|
||||
|
||||
static void taosArrayQuicksortHelper(SArray *pArray, int low, int high, __ext_compar_fn_t fn, const void *param) {
|
||||
if (low < high) {
|
||||
int idx = taosArrayPartition(pArray, low, high, fn, param);
|
||||
taosArrayQuicksortHelper(pArray, low, idx - 1, fn, param);
|
||||
taosArrayQuicksortHelper(pArray, idx + 1, high, fn, param);
|
||||
}
|
||||
}
|
||||
|
||||
static void taosArrayQuickSort(SArray* pArray, __ext_compar_fn_t fn, const void *param) {
|
||||
if (pArray->size <= 1) {
|
||||
return;
|
||||
}
|
||||
taosArrayQuicksortHelper(pArray, 0, (int)(taosArrayGetSize(pArray) - 1), fn, param);
|
||||
}
|
||||
static void taosArrayInsertSort(SArray* pArray, __ext_compar_fn_t fn, const void *param) {
|
||||
if (pArray->size <= 1) {
|
||||
return;
|
||||
}
|
||||
for (int i = 1; i <= pArray->size - 1; ++i) {
|
||||
for (int j = i; j > 0; --j) {
|
||||
if (fn(taosArrayGetP(pArray, j), taosArrayGetP(pArray, j - 1), param) == -1) {
|
||||
void *a = taosArrayGetP(pArray, j);
|
||||
void *b = taosArrayGetP(pArray, j - 1);
|
||||
taosArraySet(pArray, j - 1, &a);
|
||||
taosArraySet(pArray, j, &b);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return;
|
||||
|
||||
}
|
||||
// order array<type *>
|
||||
void taosArraySortPWithExt(SArray* pArray, __ext_compar_fn_t fn, const void *param) {
|
||||
taosArrayGetSize(pArray) > 8 ?
|
||||
taosArrayQuickSort(pArray, fn, param) : taosArrayInsertSort(pArray, fn, param);
|
||||
}
|
||||
//TODO(yihaoDeng) add order array<type>
|
||||
|
|
Loading…
Reference in New Issue