diff --git a/src/client/src/tscSQLParser.c b/src/client/src/tscSQLParser.c index 556c5dd5453a6ee0e9b239a4f035e11d18d6bdf6..0772e8d4ad74baa545a9409692234fcad5968d43 100644 --- a/src/client/src/tscSQLParser.c +++ b/src/client/src/tscSQLParser.c @@ -3130,13 +3130,15 @@ int32_t doGetColumnIndexByName(SStrToken* pToken, SQueryInfo* pQueryInfo, SColum const char* msg0 = "ambiguous column name"; const char* msg1 = "invalid column name"; + if (pToken->n == 0) { + return TSDB_CODE_TSC_INVALID_OPERATION; + } + if (isTablenameToken(pToken)) { pIndex->columnIndex = TSDB_TBNAME_COLUMN_INDEX; } else if (strlen(DEFAULT_PRIMARY_TIMESTAMP_COL_NAME) == pToken->n && strncasecmp(pToken->z, DEFAULT_PRIMARY_TIMESTAMP_COL_NAME, pToken->n) == 0) { pIndex->columnIndex = PRIMARYKEY_TIMESTAMP_COL_INDEX; // just make runtime happy, need fix java test case InsertSpecialCharacterJniTest - } else if (pToken->n == 0) { - pIndex->columnIndex = PRIMARYKEY_TIMESTAMP_COL_INDEX; // just make runtime happy, need fix java test case InsertSpecialCharacterJniTest } else { // not specify the table name, try to locate the table tsc_index by column name if (pIndex->tableIndex == COLUMN_INDEX_INITIAL_VAL) { @@ -5562,20 +5564,25 @@ 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, 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"; - const char* msg4 = "orderby column must projected in subquery"; + const char* msg0 = "only one column allowed in orderby"; + const char* msg1 = "invalid column name in orderby clause"; + const char* msg2 = "too many order by columns"; + const char* msg3 = "only primary timestamp/tbname/first tag in groupby clause allowed"; + const char* msg4 = "only tag in groupby clause allowed in order clause"; + const char* msg5 = "only primary timestamp/column in top/bottom function allowed as order column"; + const char* msg6 = "only primary timestamp allowed as the second order column"; + const char* msg7 = "only primary timestamp/column in groupby clause allowed as order column"; + const char* msg8 = "only column in groupby clause allowed as order column"; + const char* msg9 = "orderby column must projected in subquery"; + const char* msg10 = "not support distinct mixed with order by"; const char* msg11 = "not support order with udf"; + const char* msg12 = "order by tags not supported with diff/derivative/csum/mavg"; setDefaultOrderInfo(pQueryInfo); STableMetaInfo* pTableMetaInfo = tscGetMetaInfo(pQueryInfo, 0); - - if (pQueryInfo->distinct || pSqlNode->pSortOrder == NULL) { + if (pSqlNode->pSortOrder == NULL) { return TSDB_CODE_SUCCESS; } - char* pMsgBuf = tscGetErrorMsgPayload(pCmd); SArray* pSortOrder = pSqlNode->pSortOrder; @@ -5583,34 +5590,43 @@ int32_t validateOrderbyNode(SSqlCmd* pCmd, SQueryInfo* pQueryInfo, SSqlNode* pSq * for table query, there is only one or none order option is allowed, which is the * ts or values(top/bottom) order is supported. * - * for super table query, the order option must be less than 3. + * for super table query, the order option must be less than 3 and the second must be ts. + * + * order by has 5 situations + * 1. from stable group by tag1 order by tag1 [ts] + * 2. from stable group by tbname order by tbname [ts] + * 3. from stable/table group by column1 order by column1 + * 4. from stable/table order by ts + * 5. select stable/table top(column2,1) ... order by column2 */ size_t size = taosArrayGetSize(pSortOrder); - if (UTIL_TABLE_IS_NORMAL_TABLE(pTableMetaInfo) || UTIL_TABLE_IS_TMP_TABLE(pTableMetaInfo)) { + if (!UTIL_TABLE_IS_SUPER_TABLE(pTableMetaInfo)) { if (size > 1) { return invalidOperationMsg(pMsgBuf, msg0); } } else { if (size > 2) { - return invalidOperationMsg(pMsgBuf, msg3); + return invalidOperationMsg(pMsgBuf, msg2); } } + if (size > 0 && pQueryInfo->distinct) { + return invalidOperationMsg(pMsgBuf, msg10); + } // handle the first part of order by tVariant* pVar = taosArrayGet(pSortOrder, 0); - // e.g., order by 1 asc, return directly with out further check. - if (pVar->nType >= TSDB_DATA_TYPE_TINYINT && pVar->nType <= TSDB_DATA_TYPE_BIGINT) { - return TSDB_CODE_SUCCESS; + if (pVar->nType != TSDB_DATA_TYPE_BINARY){ + return invalidOperationMsg(tscGetErrorMsgPayload(pCmd), msg1); } SStrToken columnName = {pVar->nLen, pVar->nType, pVar->pz}; - SColumnIndex tsc_index = COLUMN_INDEX_INITIALIZER; + SColumnIndex indexColumn = COLUMN_INDEX_INITIALIZER; bool udf = false; if (pQueryInfo->pUdfInfo && taosArrayGetSize(pQueryInfo->pUdfInfo) > 0) { int32_t usize = (int32_t)taosArrayGetSize(pQueryInfo->pUdfInfo); - + for (int32_t i = 0; i < usize; ++i) { SUdfInfo* pUdfInfo = taosArrayGet(pQueryInfo->pUdfInfo, i); if (pUdfInfo->funcType == TSDB_UDF_TYPE_SCALAR) { @@ -5621,7 +5637,7 @@ int32_t validateOrderbyNode(SSqlCmd* pCmd, SQueryInfo* pQueryInfo, SSqlNode* pSq } if (UTIL_TABLE_IS_SUPER_TABLE(pTableMetaInfo)) { // super table query - if (getColumnIndexByName(&columnName, pQueryInfo, &tsc_index, tscGetErrorMsgPayload(pCmd)) != TSDB_CODE_SUCCESS) { + if (getColumnIndexByName(&columnName, pQueryInfo, &indexColumn, tscGetErrorMsgPayload(pCmd)) != TSDB_CODE_SUCCESS) { return invalidOperationMsg(pMsgBuf, msg1); } @@ -5629,43 +5645,49 @@ int32_t validateOrderbyNode(SSqlCmd* pCmd, SQueryInfo* pQueryInfo, SSqlNode* pSq bool orderByTS = false; bool orderByGroupbyCol = false; - if (tsc_index.columnIndex >= tscGetNumOfColumns(pTableMetaInfo->pTableMeta)) { - int32_t relTagIndex = tsc_index.columnIndex - tscGetNumOfColumns(pTableMetaInfo->pTableMeta); - + if (indexColumn.columnIndex >= tscGetNumOfColumns(pTableMetaInfo->pTableMeta)) { // order by tag1 + int32_t relTagIndex = indexColumn.columnIndex - tscGetNumOfColumns(pTableMetaInfo->pTableMeta); + // it is a tag column if (pQueryInfo->groupbyExpr.columnInfo == NULL) { - return invalidOperationMsg(pMsgBuf, msg2); + return invalidOperationMsg(pMsgBuf, msg4); } SColIndex* pColIndex = taosArrayGet(pQueryInfo->groupbyExpr.columnInfo, 0); if (relTagIndex == pColIndex->colIndex) { orderByTags = true; } - } else if (tsc_index.columnIndex == TSDB_TBNAME_COLUMN_INDEX) { - orderByTags = true; - } - - if (PRIMARYKEY_TIMESTAMP_COL_INDEX == tsc_index.columnIndex) { + } else if (indexColumn.columnIndex == TSDB_TBNAME_COLUMN_INDEX) { // order by tbname + // it is a tag column + if (pQueryInfo->groupbyExpr.columnInfo == NULL) { + return invalidOperationMsg(pMsgBuf, msg4); + } + SColIndex* pColIndex = taosArrayGet(pQueryInfo->groupbyExpr.columnInfo, 0); + if (TSDB_TBNAME_COLUMN_INDEX == pColIndex->colIndex) { + orderByTags = true; + } + }else if (indexColumn.columnIndex == PRIMARYKEY_TIMESTAMP_COL_INDEX) { // order by ts orderByTS = true; - } - - SArray *columnInfo = pQueryInfo->groupbyExpr.columnInfo; - if (columnInfo != NULL && taosArrayGetSize(columnInfo) > 0) { - SColIndex* pColIndex = taosArrayGet(columnInfo, 0); - if (PRIMARYKEY_TIMESTAMP_COL_INDEX != tsc_index.columnIndex && pColIndex->colIndex == tsc_index.columnIndex) { - orderByGroupbyCol = true; + }else{ // order by normal column + SArray *columnInfo = pQueryInfo->groupbyExpr.columnInfo; + if (columnInfo != NULL && taosArrayGetSize(columnInfo) > 0) { + SColIndex* pColIndex = taosArrayGet(columnInfo, 0); + if (pColIndex->colIndex == indexColumn.columnIndex) { + orderByGroupbyCol = true; + } } } if (!(orderByTags || orderByTS || orderByGroupbyCol) && !isTopBottomQuery(pQueryInfo)) { return invalidOperationMsg(pMsgBuf, msg3); - } else { // order by top/bottom result value column is not supported in case of interval query. - assert(!(orderByTags && orderByTS && orderByGroupbyCol)); } size_t s = taosArrayGetSize(pSortOrder); if (s == 1) { if (orderByTags) { - pQueryInfo->groupbyExpr.orderIndex = tsc_index.columnIndex - tscGetNumOfColumns(pTableMetaInfo->pTableMeta); + if (tscIsDiffDerivQuery(pQueryInfo)) { + return invalidOperationMsg(pMsgBuf, msg12); + } + pQueryInfo->groupbyExpr.orderIndex = indexColumn.columnIndex - tscGetNumOfColumns(pTableMetaInfo->pTableMeta); tVariantListItem* p1 = taosArrayGet(pSqlNode->pSortOrder, 0); pQueryInfo->groupbyExpr.orderType = p1->sortOrder; @@ -5673,25 +5695,27 @@ int32_t validateOrderbyNode(SSqlCmd* pCmd, SQueryInfo* pQueryInfo, SSqlNode* pSq tVariantListItem* p1 = taosArrayGet(pSqlNode->pSortOrder, 0); pQueryInfo->groupbyExpr.orderType = p1->sortOrder; - pQueryInfo->order.orderColId = pSchema[tsc_index.columnIndex].colId; + pQueryInfo->order.orderColId = pSchema[indexColumn.columnIndex].colId; if (udf) { return invalidOperationMsg(pMsgBuf, msg11); } } else if (isTopBottomQuery(pQueryInfo)) { - int32_t topBotIndex = tscGetTopBotQueryExprIndex(pQueryInfo); - assert(topBotIndex >= 1); /* order of top/bottom query in interval is not valid */ - SExprInfo* pExpr = tscExprGet(pQueryInfo, topBotIndex-1); + + int32_t pos = tscGetTopBotQueryExprIndex(pQueryInfo); + assert(pos > 0); + SExprInfo* pExpr = tscExprGet(pQueryInfo, pos - 1); assert(pExpr->base.functionId == TSDB_FUNC_TS); - pExpr = tscExprGet(pQueryInfo, topBotIndex); - if (pExpr->base.colInfo.colIndex != tsc_index.columnIndex && tsc_index.columnIndex != PRIMARYKEY_TIMESTAMP_COL_INDEX) { - return invalidOperationMsg(pMsgBuf, msg2); + pExpr = tscExprGet(pQueryInfo, pos); + + if (pExpr->base.colInfo.colIndex != indexColumn.columnIndex && indexColumn.columnIndex != PRIMARYKEY_TIMESTAMP_COL_INDEX) { + return invalidOperationMsg(pMsgBuf, msg5); } tVariantListItem* p1 = taosArrayGet(pSqlNode->pSortOrder, 0); pQueryInfo->order.order = p1->sortOrder; - pQueryInfo->order.orderColId = pSchema[tsc_index.columnIndex].colId; + pQueryInfo->order.orderColId = pSchema[indexColumn.columnIndex].colId; return TSDB_CODE_SUCCESS; } else { tVariantListItem* p1 = taosArrayGet(pSqlNode->pSortOrder, 0); @@ -5705,7 +5729,7 @@ int32_t validateOrderbyNode(SSqlCmd* pCmd, SQueryInfo* pQueryInfo, SSqlNode* pSq // orderby ts query on super table if (tscOrderedProjectionQueryOnSTable(pQueryInfo, 0)) { - bool found = false; + bool found = false; for (int32_t i = 0; i < tscNumOfExprs(pQueryInfo); ++i) { SExprInfo* pExpr = tscExprGet(pQueryInfo, i); if (pExpr->base.functionId == TSDB_FUNC_PRJ && pExpr->base.colInfo.colId == PRIMARYKEY_TIMESTAMP_COL_INDEX) { @@ -5714,7 +5738,7 @@ int32_t validateOrderbyNode(SSqlCmd* pCmd, SQueryInfo* pQueryInfo, SSqlNode* pSq } } if (!found && pQueryInfo->pDownstream) { - return invalidOperationMsg(pMsgBuf, msg4); + return invalidOperationMsg(pMsgBuf, msg9); } addPrimaryTsColIntoResult(pQueryInfo, pCmd); } @@ -5722,11 +5746,11 @@ int32_t validateOrderbyNode(SSqlCmd* pCmd, SQueryInfo* pQueryInfo, SSqlNode* pSq } else { tVariantListItem *pItem = taosArrayGet(pSqlNode->pSortOrder, 0); if (orderByTags) { - pQueryInfo->groupbyExpr.orderIndex = tsc_index.columnIndex - tscGetNumOfColumns(pTableMetaInfo->pTableMeta); + pQueryInfo->groupbyExpr.orderIndex = indexColumn.columnIndex - tscGetNumOfColumns(pTableMetaInfo->pTableMeta); pQueryInfo->groupbyExpr.orderType = pItem->sortOrder; } else if (orderByGroupbyCol){ pQueryInfo->order.order = pItem->sortOrder; - pQueryInfo->order.orderColId = tsc_index.columnIndex; + pQueryInfo->order.orderColId = indexColumn.columnIndex; if (udf) { return invalidOperationMsg(pMsgBuf, msg11); } @@ -5741,12 +5765,12 @@ int32_t validateOrderbyNode(SSqlCmd* pCmd, SQueryInfo* pQueryInfo, SSqlNode* pSq pItem = taosArrayGet(pSqlNode->pSortOrder, 1); tVariant* pVar2 = &pItem->pVar; SStrToken cname = {pVar2->nLen, pVar2->nType, pVar2->pz}; - if (getColumnIndexByName(&cname, pQueryInfo, &tsc_index, tscGetErrorMsgPayload(pCmd)) != TSDB_CODE_SUCCESS) { + if (getColumnIndexByName(&cname, pQueryInfo, &indexColumn, tscGetErrorMsgPayload(pCmd)) != TSDB_CODE_SUCCESS) { return invalidOperationMsg(pMsgBuf, msg1); } - if (tsc_index.columnIndex != PRIMARYKEY_TIMESTAMP_COL_INDEX) { - return invalidOperationMsg(pMsgBuf, msg2); + if (indexColumn.columnIndex != PRIMARYKEY_TIMESTAMP_COL_INDEX) { + return invalidOperationMsg(pMsgBuf, msg6); } else { tVariantListItem* p1 = taosArrayGet(pSortOrder, 1); pQueryInfo->order.order = p1->sortOrder; @@ -5755,20 +5779,24 @@ int32_t validateOrderbyNode(SSqlCmd* pCmd, SQueryInfo* pQueryInfo, SSqlNode* pSq } } else if (UTIL_TABLE_IS_NORMAL_TABLE(pTableMetaInfo) || UTIL_TABLE_IS_CHILD_TABLE(pTableMetaInfo)) { // check order by clause for normal table & temp table - if (getColumnIndexByName(&columnName, pQueryInfo, &tsc_index, pMsgBuf) != TSDB_CODE_SUCCESS) { + if (getColumnIndexByName(&columnName, pQueryInfo, &indexColumn, pMsgBuf) != TSDB_CODE_SUCCESS) { return invalidOperationMsg(pMsgBuf, msg1); } - if (tsc_index.columnIndex != PRIMARYKEY_TIMESTAMP_COL_INDEX && !isTopBottomQuery(pQueryInfo)) { + if (indexColumn.columnIndex != PRIMARYKEY_TIMESTAMP_COL_INDEX && !isTopBottomQuery(pQueryInfo)) { bool validOrder = false; SArray *columnInfo = pQueryInfo->groupbyExpr.columnInfo; if (columnInfo != NULL && taosArrayGetSize(columnInfo) > 0) { SColIndex* pColIndex = taosArrayGet(columnInfo, 0); - validOrder = (pColIndex->colIndex == tsc_index.columnIndex); + validOrder = (pColIndex->colIndex == indexColumn.columnIndex); } if (!validOrder) { - return invalidOperationMsg(pMsgBuf, msg2); + return invalidOperationMsg(pMsgBuf, msg7); + } + + if (udf) { + return invalidOperationMsg(pMsgBuf, msg11); } if (udf) { @@ -5776,39 +5804,35 @@ int32_t validateOrderbyNode(SSqlCmd* pCmd, SQueryInfo* pQueryInfo, SSqlNode* pSq } tVariantListItem* p1 = taosArrayGet(pSqlNode->pSortOrder, 0); - pQueryInfo->groupbyExpr.orderIndex = pSchema[tsc_index.columnIndex].colId; + pQueryInfo->groupbyExpr.orderIndex = pSchema[indexColumn.columnIndex].colId; pQueryInfo->groupbyExpr.orderType = p1->sortOrder; } if (isTopBottomQuery(pQueryInfo)) { - bool validOrder = false; SArray *columnInfo = pQueryInfo->groupbyExpr.columnInfo; if (columnInfo != NULL && taosArrayGetSize(columnInfo) > 0) { SColIndex* pColIndex = taosArrayGet(columnInfo, 0); - validOrder = (pColIndex->colIndex == tsc_index.columnIndex); - } else { - int32_t topBotIndex = tscGetTopBotQueryExprIndex(pQueryInfo); - assert(topBotIndex >= 1); - /* order of top/bottom query in interval is not valid */ - SExprInfo* pExpr = tscExprGet(pQueryInfo, topBotIndex-1); - assert(pExpr->base.functionId == TSDB_FUNC_TS); - pExpr = tscExprGet(pQueryInfo, topBotIndex); - if (pExpr->base.colInfo.colIndex != tsc_index.columnIndex && tsc_index.columnIndex != PRIMARYKEY_TIMESTAMP_COL_INDEX) { - return invalidOperationMsg(pMsgBuf, msg2); + if (pColIndex->colIndex != indexColumn.columnIndex) { + return invalidOperationMsg(pMsgBuf, msg8); } + } else { + int32_t pos = tscGetTopBotQueryExprIndex(pQueryInfo); + assert(pos > 0); + SExprInfo* pExpr = tscExprGet(pQueryInfo, pos - 1); + assert(pExpr->base.functionId == TSDB_FUNC_TS); - validOrder = true; - } + pExpr = tscExprGet(pQueryInfo, pos); - if (!validOrder) { - return invalidOperationMsg(pMsgBuf, msg2); + if (pExpr->base.colInfo.colIndex != indexColumn.columnIndex && indexColumn.columnIndex != PRIMARYKEY_TIMESTAMP_COL_INDEX) { + return invalidOperationMsg(pMsgBuf, msg5); + } } tVariantListItem* pItem = taosArrayGet(pSqlNode->pSortOrder, 0); pQueryInfo->order.order = pItem->sortOrder; - pQueryInfo->order.orderColId = pSchema[tsc_index.columnIndex].colId; + pQueryInfo->order.orderColId = pSchema[indexColumn.columnIndex].colId; return TSDB_CODE_SUCCESS; } @@ -5818,13 +5842,13 @@ int32_t validateOrderbyNode(SSqlCmd* pCmd, SQueryInfo* pQueryInfo, SSqlNode* pSq tVariantListItem* pItem = taosArrayGet(pSqlNode->pSortOrder, 0); pQueryInfo->order.order = pItem->sortOrder; - pQueryInfo->order.orderColId = pSchema[tsc_index.columnIndex].colId; + pQueryInfo->order.orderColId = pSchema[indexColumn.columnIndex].colId; } else { // handle the temp table order by clause. You can order by any single column in case of the temp table, created by // inner subquery. assert(UTIL_TABLE_IS_TMP_TABLE(pTableMetaInfo) && taosArrayGetSize(pSqlNode->pSortOrder) == 1); - if (getColumnIndexByName(&columnName, pQueryInfo, &tsc_index, pMsgBuf) != TSDB_CODE_SUCCESS) { + if (getColumnIndexByName(&columnName, pQueryInfo, &indexColumn, pMsgBuf) != TSDB_CODE_SUCCESS) { return invalidOperationMsg(pMsgBuf, msg1); } @@ -5834,7 +5858,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[tsc_index.columnIndex].colId; + pQueryInfo->order.orderColId = pSchema[indexColumn.columnIndex].colId; } return TSDB_CODE_SUCCESS; diff --git a/tests/pytest/query/querySort.py b/tests/pytest/query/querySort.py index 17022bdc41057bcb67e1530a2cb6d399bada20ff..e9f6a2a0bf53405e4b460b7ec5b431a0da586f0f 100644 --- a/tests/pytest/query/querySort.py +++ b/tests/pytest/query/querySort.py @@ -122,6 +122,44 @@ class TDTestCase: (i, i)) self.checkColumnSorted(1, "desc") + # order by rules: https://jira.taosdata.com:18090/pages/viewpage.action?pageId=123455481 + tdSql.error("select tbcol1 from st order by 123") + tdSql.error("select tbcol1 from st order by tbname") + tdSql.error("select tbcol1 from st order by tagcol1") + tdSql.error("select tbcol1 from st order by ''") + tdSql.error("select top(tbcol1, 12) from st1 order by tbcol1,ts") + tdSql.error("select top(tbcol1, 12) from st order by tbcol1,ts,tbcol2") + tdSql.error("select top(tbcol1, 12) from st order by ts, tbcol1") + tdSql.error("select top(tbcol1, 2) from st1 group by tbcol1 order by tbcol2") + + tdSql.query("select top(tbcol1, 2) from st1 group by tbcol2 order by tbcol2") + tdSql.query("select top(tbcol1, 12) from st order by tbcol1, ts") + + tdSql.query("select avg(tbcol1) from st group by tbname order by tbname") + tdSql.checkData(1, 0, 5.5) + tdSql.checkData(5, 1, "st6") + + tdSql.query("select top(tbcol1, 2) from st group by tbname order by tbname") + tdSql.checkData(1, 1, 10) + tdSql.checkData(2, 2, "st2") + + tdSql.query("select top(tbcol1, 12) from st order by tbcol1") + tdSql.checkData(1, 1, 9) + + tdSql.error("select top(tbcol1, 12) from st1 order by tbcol1,ts") + tdSql.error("select top(tbcol1, 12),tbname from st order by tbcol1,tbname") + + tdSql.query("select top(tbcol1, 12) from st group by tbname order by tbname desc") + tdSql.checkData(1, 2, "st10") + tdSql.checkData(10, 2, "st9") + + tdSql.query("select top(tbcol1, 2) from st group by tbname order by tbname desc,ts") + tdSql.checkData(1, 2, "st10") + tdSql.checkData(10, 2, "st5") + tdSql.checkData(0, 0, "2018-09-17 09:00:00.109") + tdSql.checkData(1, 0, "2018-09-17 09:00:00.110") + tdSql.checkData(2, 0, "2018-09-17 09:00:00.099") + def stop(self): tdSql.close() tdLog.success("%s successfully executed" % __file__)