diff --git a/src/client/src/tscSQLParser.c b/src/client/src/tscSQLParser.c index 15a76daab78701e80f532001bddc4d984cdecc01..e7a821ddf4643e78ae521eaf534ee8881a8974c4 100644 --- a/src/client/src/tscSQLParser.c +++ b/src/client/src/tscSQLParser.c @@ -63,6 +63,9 @@ static SExprInfo* doAddProjectCol(SQueryInfo* pQueryInfo, int32_t colIndex, int3 static int32_t setShowInfo(SSqlObj* pSql, SSqlInfo* pInfo); static char* getAccountId(SSqlObj* pSql); +static bool serializeExprListToVariant(SArray* pList, tVariant **dest, int16_t colType); +static int32_t validateParamOfRelationIn(tVariant *pVar, int32_t colType); + static bool has(SArray* pFieldList, int32_t startIdx, const char* name); static char* cloneCurrentDBName(SSqlObj* pSql); static int32_t getDelimiterIndex(SStrToken* pTableName); @@ -134,14 +137,97 @@ static bool validateDebugFlag(int32_t v); static int32_t checkQueryRangeForFill(SSqlCmd* pCmd, SQueryInfo* pQueryInfo); static int32_t loadAllTableMeta(SSqlObj* pSql, struct SSqlInfo* pInfo); -static bool isTimeWindowQuery(SQueryInfo* pQueryInfo) { +static bool isTimeWindowQuery(SQueryInfo* pQueryInfo) { return pQueryInfo->interval.interval > 0 || pQueryInfo->sessionWindow.gap > 0; } + int16_t getNewResColId(SSqlCmd* pCmd) { return pCmd->resColumnId--; } +// serialize expr in exprlist to binary +// formate "type | size | value" +bool serializeExprListToVariant(SArray* pList, tVariant **dst, int16_t colType) { + bool ret = false; + if (!pList || pList->size <= 0) { + return ret; + } + if (colType == TSDB_DATA_TYPE_DOUBLE || colType == TSDB_DATA_TYPE_FLOAT) { + return ret; + } + + tSqlExprItem* item = (tSqlExprItem *)taosArrayGet(pList, 0); + int32_t firstTokenType = item->pNode->token.type; + int32_t type = firstTokenType; + + //nchar to binary and + toTSDBType(type); + if (type != colType && (type != TSDB_DATA_TYPE_BINARY || colType != TSDB_DATA_TYPE_NCHAR)) { + return false; + } + type = colType; + + SBufferWriter bw = tbufInitWriter( NULL, false ); + tbufEnsureCapacity(&bw, 512); + + int32_t size = (int32_t)(pList->size); + tbufWriteUint32(&bw, type); + tbufWriteInt32(&bw, size); + + for (int32_t i = 0; i < size; i++) { + tSqlExpr* pSub = ((tSqlExprItem*)(taosArrayGet(pList, i)))->pNode; + + // check all the token type in expr list same or not + if (firstTokenType != pSub->token.type) { + break; + } + + toTSDBType(pSub->token.type); + + tVariant var; + tVariantCreate(&var, &pSub->token); + if (type == TSDB_DATA_TYPE_BOOL || type == TSDB_DATA_TYPE_TINYINT || type == TSDB_DATA_TYPE_SMALLINT + || type == TSDB_DATA_TYPE_BIGINT || type == TSDB_DATA_TYPE_INT) { + tbufWriteInt64(&bw, var.i64); + } else if (type == TSDB_DATA_TYPE_DOUBLE || type == TSDB_DATA_TYPE_FLOAT) { + tbufWriteDouble(&bw, var.dKey); + } else if (type == TSDB_DATA_TYPE_BINARY){ + tbufWriteBinary(&bw, var.pz, var.nLen); + } else if (type == TSDB_DATA_TYPE_NCHAR) { + char *buf = (char *)calloc(1, (var.nLen + 1)*TSDB_NCHAR_SIZE); + if (tVariantDump(&var, buf, type, false) != TSDB_CODE_SUCCESS) { + free(buf); + tVariantDestroy(&var); + break; + } + tbufWriteBinary(&bw, buf, twcslen((wchar_t *)buf) * TSDB_NCHAR_SIZE); + free(buf); + } + tVariantDestroy(&var); + + if (i == size - 1) { ret = true;} + } + + if (ret == true) { + if ((*dst = calloc(1, sizeof(tVariant))) != NULL) { + tVariantCreateFromBinary(*dst, tbufGetData(&bw, false), tbufTell(&bw), TSDB_DATA_TYPE_BINARY); + } else { + ret = false; + } + } + tbufCloseWriter(&bw); + return ret; +} + +static int32_t validateParamOfRelationIn(tVariant *pVar, int32_t colType) { + if (pVar->nType != TSDB_DATA_TYPE_BINARY) { + return -1; + } + SBufferReader br = tbufInitReader(pVar->pz, pVar->nLen, false); + return colType == TSDB_DATA_TYPE_NCHAR ? 0 : (tbufReadUint32(&br) == colType ? 0: -1); +} + static uint8_t convertOptr(SStrToken *pToken) { switch (pToken->type) { case TK_LT: @@ -162,6 +248,7 @@ static uint8_t convertOptr(SStrToken *pToken) { return TSDB_RELATION_EQUAL; case TK_PLUS: return TSDB_BINARY_OP_ADD; + case TK_MINUS: return TSDB_BINARY_OP_SUBTRACT; case TK_STAR: @@ -177,6 +264,8 @@ static uint8_t convertOptr(SStrToken *pToken) { return TSDB_RELATION_ISNULL; case TK_NOTNULL: return TSDB_RELATION_NOTNULL; + case TK_IN: + return TSDB_RELATION_IN; default: { return 0; } } } @@ -3229,6 +3318,25 @@ static int32_t doExtractColumnFilterInfo(SSqlCmd* pCmd, SQueryInfo* pQueryInfo, retVal = tVariantDump(&pRight->value, (char*)&pColumnFilter->upperBndd, colType, false); // TK_GT,TK_GE,TK_EQ,TK_NE are based on the pColumn->lowerBndd + } else if (pExpr->tokenId == TK_IN) { + tVariant *pVal; + if (pRight->tokenId != TK_SET || !serializeExprListToVariant(pRight->pParam, &pVal, colType) || colType == TSDB_DATA_TYPE_TIMESTAMP) { + return invalidOperationMsg(tscGetErrorMsgPayload(pCmd), msg); + } + if (validateParamOfRelationIn(pVal, colType) != TSDB_CODE_SUCCESS) { + tVariantDestroy(pVal); + free(pVal); + return invalidOperationMsg(tscGetErrorMsgPayload(pCmd), msg); + } + pColumnFilter->pz = (int64_t)calloc(1, pVal->nLen + 1); + pColumnFilter->len = pVal->nLen; + pColumnFilter->filterstr = 1; + memcpy((char *)(pColumnFilter->pz), (char *)(pVal->pz), pVal->nLen); + //retVal = tVariantDump(pVal, (char *)(pColumnFilter->pz), TSDB_DATA_TYPE_BINARY, false); + + tVariantDestroy(pVal); + free(pVal); + } else if (colType == TSDB_DATA_TYPE_BINARY) { pColumnFilter->pz = (int64_t)calloc(1, bufLen * TSDB_NCHAR_SIZE); pColumnFilter->len = pRight->value.nLen; @@ -3277,6 +3385,9 @@ static int32_t doExtractColumnFilterInfo(SSqlCmd* pCmd, SQueryInfo* pQueryInfo, case TK_NOTNULL: pColumnFilter->lowerRelOptr = TSDB_RELATION_NOTNULL; break; + case TK_IN: + pColumnFilter->lowerRelOptr = TSDB_RELATION_IN; + break; default: return invalidOperationMsg(tscGetErrorMsgPayload(pCmd), msg); } @@ -3392,7 +3503,7 @@ static int32_t extractColumnFilterInfo(SSqlCmd* pCmd, SQueryInfo* pQueryInfo, SC && pExpr->tokenId != TK_ISNULL && pExpr->tokenId != TK_NOTNULL && pExpr->tokenId != TK_LIKE - ) { + && pExpr->tokenId != TK_IN) { return invalidOperationMsg(tscGetErrorMsgPayload(pCmd), msg2); } } else { @@ -3402,7 +3513,7 @@ static int32_t extractColumnFilterInfo(SSqlCmd* pCmd, SQueryInfo* pQueryInfo, SC if (pSchema->type == TSDB_DATA_TYPE_BOOL) { int32_t t = pExpr->tokenId; - if (t != TK_EQ && t != TK_NE && t != TK_NOTNULL && t != TK_ISNULL) { + if (t != TK_EQ && t != TK_NE && t != TK_NOTNULL && t != TK_ISNULL && t != TK_IN) { return invalidOperationMsg(tscGetErrorMsgPayload(pCmd), msg3); } } @@ -4444,7 +4555,11 @@ static int32_t validateTagCondExpr(SSqlCmd* pCmd, tExprNode *p) { free(tmp); } else { double tmp; - retVal = tVariantDump(vVariant, (char*)&tmp, schemaType, false); + if (p->_node.optr == TSDB_RELATION_IN) { + retVal = validateParamOfRelationIn(vVariant, schemaType); + } else { + retVal = tVariantDump(vVariant, (char*)&tmp, schemaType, false); + } } if (retVal != TSDB_CODE_SUCCESS) { @@ -7953,6 +8068,24 @@ int32_t exprTreeFromSqlExpr(SSqlCmd* pCmd, tExprNode **pExpr, const tSqlExpr* pS } return TSDB_CODE_SUCCESS; + } else if (pSqlExpr->tokenId == TK_SET) { + int32_t type = -1; + STableMeta* pTableMeta = tscGetMetaInfo(pQueryInfo, 0)->pTableMeta; + if (pCols != NULL) { + SColIndex* idx = taosArrayGet(pCols, 0); + SSchema* pSchema = tscGetTableColumnSchema(pTableMeta, idx->colIndex); + if (pSchema != NULL) { + type = pSchema->type; + } + } + + tVariant *pVal; + if (serializeExprListToVariant(pSqlExpr->pParam, &pVal, type) == false) { + return invalidOperationMsg(tscGetErrorMsgPayload(pCmd), "not support filter expression"); + } + *pExpr = calloc(1, sizeof(tExprNode)); + (*pExpr)->nodeType = TSQL_NODE_VALUE; + (*pExpr)->pVal = pVal; } else { return invalidOperationMsg(tscGetErrorMsgPayload(pCmd), "not support filter expression"); } diff --git a/src/common/inc/texpr.h b/src/common/inc/texpr.h index 275dd12fd7ca9f9771592039d846593fa958f240..2e49a69366c2277c98ec32a1d8419c141ddecc0f 100644 --- a/src/common/inc/texpr.h +++ b/src/common/inc/texpr.h @@ -94,6 +94,8 @@ bool exprTreeApplyFilter(tExprNode *pExpr, const void *pItem, SExprTraverseSupp void arithmeticTreeTraverse(tExprNode *pExprs, int32_t numOfRows, char *pOutput, void *param, int32_t order, char *(*cb)(void *, const char*, int32_t)); +void buildFilterSetFromBinary(void **q, const char *buf, int32_t len); + #ifdef __cplusplus } #endif diff --git a/src/common/src/texpr.c b/src/common/src/texpr.c index f2dd3890a163ec1e1e25d2ac8b55f23aa9d5a79d..6fa4d68734df6fde94725026bd65b219cc6564ab 100644 --- a/src/common/src/texpr.c +++ b/src/common/src/texpr.c @@ -466,6 +466,32 @@ tExprNode* exprTreeFromTableName(const char* tbnameCond) { return expr; } +void buildFilterSetFromBinary(void **q, const char *buf, int32_t len) { + SBufferReader br = tbufInitReader(buf, len, false); + uint32_t type = tbufReadUint32(&br); + SHashObj *pObj = taosHashInit(256, taosGetDefaultHashFunction(type), true, false); + int dummy = -1; + int32_t sz = tbufReadInt32(&br); + for (int32_t i = 0; i < sz; i++) { + if (type == TSDB_DATA_TYPE_BOOL || type == TSDB_DATA_TYPE_TINYINT || type == TSDB_DATA_TYPE_SMALLINT || type == TSDB_DATA_TYPE_BIGINT || type == TSDB_DATA_TYPE_INT) { + int64_t val = tbufReadInt64(&br); + taosHashPut(pObj, (char *)&val, sizeof(val), &dummy, sizeof(dummy)); + } else if (type == TSDB_DATA_TYPE_DOUBLE || type == TSDB_DATA_TYPE_FLOAT) { + double val = tbufReadDouble(&br); + taosHashPut(pObj, (char *)&val, sizeof(val), &dummy, sizeof(dummy)); + } else if (type == TSDB_DATA_TYPE_BINARY) { + size_t t = 0; + const char *val = tbufReadBinary(&br, &t); + taosHashPut(pObj, (char *)val, t, &dummy, sizeof(dummy)); + } else if (type == TSDB_DATA_TYPE_NCHAR) { + size_t t = 0; + const char *val = tbufReadBinary(&br, &t); + taosHashPut(pObj, (char *)val, t, &dummy, sizeof(dummy)); + } + } + *q = (void *)pObj; +} + tExprNode* exprdup(tExprNode* pNode) { if (pNode == NULL) { return NULL; diff --git a/src/query/inc/qExecutor.h b/src/query/inc/qExecutor.h index 7e76bd762202a80ff7c3a4ef612599746fc5ee25..24547c1e0bdbfd86b9eb9a4ab45001733fea868e 100644 --- a/src/query/inc/qExecutor.h +++ b/src/query/inc/qExecutor.h @@ -113,6 +113,7 @@ typedef struct SColumnFilterElem { int16_t bytes; // column length __filter_func_t fp; SColumnFilterInfo filterInfo; + void *q; } SColumnFilterElem; typedef struct SSingleColumnFilterInfo { diff --git a/src/query/src/qExecutor.c b/src/query/src/qExecutor.c index 7da209aef99c128ba919390a2ca89df9e8f17cbb..3c999fca0b35fafb0a34d298f8479e42060758ba 100644 --- a/src/query/src/qExecutor.c +++ b/src/query/src/qExecutor.c @@ -6942,6 +6942,10 @@ int32_t doCreateFilterInfo(SColumnInfo* pCols, int32_t numOfCols, int32_t numOfF } pSingleColFilter->bytes = pCols[i].bytes; + + if (lower == TSDB_RELATION_IN) { + buildFilterSetFromBinary(&pSingleColFilter->q, (char *)(pSingleColFilter->filterInfo.pz), (int32_t)(pSingleColFilter->filterInfo.len)); + } } j++; @@ -6954,6 +6958,9 @@ int32_t doCreateFilterInfo(SColumnInfo* pCols, int32_t numOfCols, int32_t numOfF void* doDestroyFilterInfo(SSingleColumnFilterInfo* pFilterInfo, int32_t numOfFilterCols) { for (int32_t i = 0; i < numOfFilterCols; ++i) { if (pFilterInfo[i].numOfFilters > 0) { + if (pFilterInfo[i].pFilters->filterInfo.lowerRelOptr == TSDB_RELATION_IN) { + taosHashCleanup((SHashObj *)(pFilterInfo[i].pFilters->q)); + } tfree(pFilterInfo[i].pFilters); } } diff --git a/src/query/src/qFilterfunc.c b/src/query/src/qFilterfunc.c index dabce88423f762029a4b27dc3fb4731fd28e6406..663f8814a0d57eb8cecad7f2d62944425510f029 100644 --- a/src/query/src/qFilterfunc.c +++ b/src/query/src/qFilterfunc.c @@ -253,6 +253,27 @@ bool isNullOperator(SColumnFilterElem *pFilter, const char* minval, const char* bool notNullOperator(SColumnFilterElem *pFilter, const char* minval, const char* maxval, int16_t type) { return true; } +bool inOperator(SColumnFilterElem *pFilter, const char* minval, const char* maxval, int16_t type) { + if (type == TSDB_DATA_TYPE_BOOL || type == TSDB_DATA_TYPE_TINYINT || type == TSDB_DATA_TYPE_SMALLINT || type == TSDB_DATA_TYPE_BIGINT || type == TSDB_DATA_TYPE_INT) { + int64_t minv = -1, maxv = -1; + GET_TYPED_DATA(minv, int64_t, type, minval); + GET_TYPED_DATA(maxv, int64_t, type, maxval); + if (minv == maxv) { + return NULL != taosHashGet((SHashObj *)pFilter->q, (char *)&minv, sizeof(minv)); + } + return true; + } else if (type == TSDB_DATA_TYPE_DOUBLE || type == TSDB_DATA_TYPE_DOUBLE) { + double v; + GET_TYPED_DATA(v, double, type, minval); + return NULL != taosHashGet((SHashObj *)pFilter->q, (char *)&v, sizeof(v)); + } else if (type == TSDB_DATA_TYPE_BINARY) { + return NULL != taosHashGet((SHashObj *)pFilter->q, varDataVal(minval), varDataLen(minval)); + } else if (type == TSDB_DATA_TYPE_NCHAR){ + return NULL != taosHashGet((SHashObj *)pFilter->q, varDataVal(minval), varDataLen(minval)); + } + + return false; +} /////////////////////////////////////////////////////////////////////////////// bool rangeFilter_ii(SColumnFilterElem *pFilter, const char *minval, const char *maxval, int16_t type) { @@ -389,6 +410,7 @@ bool (*filterOperators[])(SColumnFilterElem *pFilter, const char* minval, const likeOperator, isNullOperator, notNullOperator, + inOperator, }; bool (*rangeFilterOperators[])(SColumnFilterElem *pFilter, const char* minval, const char* maxval, int16_t type) = { @@ -397,6 +419,7 @@ bool (*rangeFilterOperators[])(SColumnFilterElem *pFilter, const char* minval, c rangeFilter_ie, rangeFilter_ei, rangeFilter_ii, + }; __filter_func_t getFilterOperator(int32_t lowerOptr, int32_t upperOptr) { diff --git a/src/tsdb/src/tsdbRead.c b/src/tsdb/src/tsdbRead.c index c333294179f215890f06ae8d30bf6316f379f875..6c7c14c13c3e9c6de89f712601a60502dac62d2b 100644 --- a/src/tsdb/src/tsdbRead.c +++ b/src/tsdb/src/tsdbRead.c @@ -2397,6 +2397,8 @@ static void destroyHelper(void* param) { tQueryInfo* pInfo = (tQueryInfo*)param; if (pInfo->optr != TSDB_RELATION_IN) { tfree(pInfo->q); + } else { + taosHashCleanup((SHashObj *)(pInfo->q)); } free(param); @@ -3155,11 +3157,23 @@ void filterPrepare(void* expr, void* param) { pInfo->sch = *pSchema; pInfo->optr = pExpr->_node.optr; - pInfo->compare = getComparFunc(pSchema->type, pInfo->optr); + pInfo->compare = getComparFunc(pInfo->sch.type, pInfo->optr); pInfo->indexed = pTSSchema->columns->colId == pInfo->sch.colId; if (pInfo->optr == TSDB_RELATION_IN) { - pInfo->q = (char*) pCond->arr; + int dummy = -1; + SHashObj *pObj = NULL; + if (pInfo->sch.colId == TSDB_TBNAME_COLUMN_INDEX) { + pObj = taosHashInit(256, taosGetDefaultHashFunction(pInfo->sch.type), true, false); + SArray *arr = (SArray *)(pCond->arr); + for (size_t i = 0; i < taosArrayGetSize(arr); i++) { + char* p = taosArrayGetP(arr, i); + taosHashPut(pObj, varDataVal(p),varDataLen(p), &dummy, sizeof(dummy)); + } + } else { + buildFilterSetFromBinary((void **)&pObj, pCond->pz, pCond->nLen); + } + pInfo->q = (char *)pObj; } else if (pCond != NULL) { uint32_t size = pCond->nLen * TSDB_NCHAR_SIZE; if (size < (uint32_t)pSchema->bytes) { @@ -3330,6 +3344,20 @@ static bool tableFilterFp(const void* pNode, void* param) { } else if (pInfo->optr == TSDB_RELATION_NOTNULL) { return (val != NULL) && (!isNull(val, pInfo->sch.type)); } + } else if (pInfo->optr == TSDB_RELATION_IN) { + int type = pInfo->sch.type; + if (type == TSDB_DATA_TYPE_BOOL || type == TSDB_DATA_TYPE_TINYINT || type == TSDB_DATA_TYPE_SMALLINT || type == TSDB_DATA_TYPE_BIGINT || type == TSDB_DATA_TYPE_INT) { + int64_t v; + GET_TYPED_DATA(v, int64_t, pInfo->sch.type, val); + return NULL != taosHashGet((SHashObj *)pInfo->q, (char *)&v, sizeof(v)); + } else if (type == TSDB_DATA_TYPE_DOUBLE || type == TSDB_DATA_TYPE_DOUBLE) { + double v; + GET_TYPED_DATA(v, double, pInfo->sch.type, val); + return NULL != taosHashGet((SHashObj *)pInfo->q, (char *)&v, sizeof(v)); + } else if (type == TSDB_DATA_TYPE_BINARY || type == TSDB_DATA_TYPE_NCHAR){ + return NULL != taosHashGet((SHashObj *)pInfo->q, varDataVal(val), varDataLen(val)); + } + } int32_t ret = 0; @@ -3672,14 +3700,18 @@ static int32_t setQueryCond(tQueryInfo *queryColInfo, SQueryCond* pCond) { if (optr == TSDB_RELATION_GREATER || optr == TSDB_RELATION_GREATER_EQUAL || optr == TSDB_RELATION_EQUAL || optr == TSDB_RELATION_NOT_EQUAL) { - pCond->start = calloc(1, sizeof(SEndPoint)); + pCond->start = calloc(1, sizeof(SEndPoint)); pCond->start->optr = queryColInfo->optr; - pCond->start->v = queryColInfo->q; + pCond->start->v = queryColInfo->q; } else if (optr == TSDB_RELATION_LESS || optr == TSDB_RELATION_LESS_EQUAL) { - pCond->end = calloc(1, sizeof(SEndPoint)); + pCond->end = calloc(1, sizeof(SEndPoint)); pCond->end->optr = queryColInfo->optr; - pCond->end->v = queryColInfo->q; - } else if (optr == TSDB_RELATION_IN || optr == TSDB_RELATION_LIKE) { + pCond->end->v = queryColInfo->q; + } else if (optr == TSDB_RELATION_IN) { + pCond->start = calloc(1, sizeof(SEndPoint)); + pCond->start->optr = queryColInfo->optr; + pCond->start->v = queryColInfo->q; + } else if (optr == TSDB_RELATION_LIKE) { assert(0); } @@ -3764,6 +3796,19 @@ static void queryIndexedColumn(SSkipList* pSkipList, tQueryInfo* pQueryInfo, SAr taosArrayPush(result, &info); } + } else if (optr == TSDB_RELATION_IN) { + while(tSkipListIterNext(iter)) { + SSkipListNode* pNode = tSkipListIterGet(iter); + + int32_t ret = pQueryInfo->compare(SL_GET_NODE_KEY(pSkipList, pNode), cond.start->v); + if (ret != 0) { + break; + } + + STableKeyInfo info = {.pTable = (void*)SL_GET_NODE_DATA(pNode), .lastKey = TSKEY_INITIAL_VAL}; + taosArrayPush(result, &info); + } + } else { assert(0); } @@ -3857,7 +3902,7 @@ void getTableListfromSkipList(tExprNode *pExpr, SSkipList *pSkipList, SArray *re param->setupInfoFn(pExpr, param->pExtInfo); tQueryInfo *pQueryInfo = pExpr->_node.info; - if (pQueryInfo->indexed && pQueryInfo->optr != TSDB_RELATION_LIKE) { + if (pQueryInfo->indexed && (pQueryInfo->optr != TSDB_RELATION_LIKE && pQueryInfo->optr != TSDB_RELATION_IN)) { queryIndexedColumn(pSkipList, pQueryInfo, result); } else { queryIndexlessColumn(pSkipList, pQueryInfo, result, param->nodeFilterFn); diff --git a/src/util/src/tcompare.c b/src/util/src/tcompare.c index 09199eaee36a7233a3b31494ea3a515aa9ff78be..f91d13e6d0a4310181594b840631249bd1bcade8 100644 --- a/src/util/src/tcompare.c +++ b/src/util/src/tcompare.c @@ -17,6 +17,7 @@ #include "ttype.h" #include "tcompare.h" #include "tarray.h" +#include "hash.h" int32_t compareInt32Val(const void *pLeft, const void *pRight) { int32_t left = GET_INT32_VAL(pLeft), right = GET_INT32_VAL(pRight); @@ -291,9 +292,12 @@ int32_t taosArrayCompareString(const void* a, const void* b) { return compareLenPrefixedStr(x, y); } -static int32_t compareFindStrInArray(const void* pLeft, const void* pRight) { - const SArray* arr = (const SArray*) pRight; - return taosArraySearchString(arr, pLeft, taosArrayCompareString, TD_EQ) == NULL ? 0 : 1; +//static int32_t compareFindStrInArray(const void* pLeft, const void* pRight) { +// const SArray* arr = (const SArray*) pRight; +// return taosArraySearchString(arr, pLeft, taosArrayCompareString, TD_EQ) == NULL ? 0 : 1; +//} +static int32_t compareFindItemInSet(const void *pLeft, const void* pRight) { + return NULL != taosHashGet((SHashObj *)pRight, varDataVal(pLeft), varDataLen(pLeft)) ? 1 : 0; } static int32_t compareWStrPatternComp(const void* pLeft, const void* pRight) { @@ -325,7 +329,7 @@ __compar_fn_t getComparFunc(int32_t type, int32_t optr) { if (optr == TSDB_RELATION_LIKE) { /* wildcard query using like operator */ comparFn = compareStrPatternComp; } else if (optr == TSDB_RELATION_IN) { - comparFn = compareFindStrInArray; + comparFn = compareFindItemInSet; } else { /* normal relational comparFn */ comparFn = compareLenPrefixedStr; } diff --git a/tests/pytest/query/in.py b/tests/pytest/query/in.py new file mode 100644 index 0000000000000000000000000000000000000000..8644b74a45099fcaa7c7608d8d33140b0a30f82f --- /dev/null +++ b/tests/pytest/query/in.py @@ -0,0 +1,163 @@ +################################################################### +# Copyright (c) 2016 by TAOS Technologies, Inc. +# All rights reserved. +# +# This file is proprietary and confidential to TAOS Technologies. +# No part of this file may be reproduced, stored, transmitted, +# disclosed or used in any form or by any means other than as +# expressly provided by the written permission from Jianhui Tao +# +################################################################### + +# -*- coding: utf-8 -*- + +import sys +import taos +from util.log import tdLog +from util.cases import tdCases +from util.sql import tdSql +from util.dnodes import tdDnodes + +class TDTestCase: + def init(self, conn, logSql): + tdLog.debug("start to execute %s" % __file__) + tdSql.init(conn.cursor(), logSql) + + self.ts = 1538548685000 + + def run(self): + tdSql.prepare() + + print("==============step1") + tdSql.execute( + "create table if not exists st (ts timestamp, tagtype int) tags(dev nchar(50))") + tdSql.execute( + 'CREATE TABLE if not exists dev_001 using st tags("dev_01")') + tdSql.execute( + 'CREATE TABLE if not exists dev_002 using st tags("dev_02")') + + print("==============step2") + tdSql.error("select * from db.st where ts in ('2020-05-13 10:00:00.000')") + + tdSql.execute( + """INSERT INTO dev_001(ts, tagtype) VALUES('2020-05-13 10:00:00.000', 1), + ('2020-05-13 10:00:00.001', 1) + dev_002 VALUES('2020-05-13 10:00:00.001', 1)""") + + # TAG nchar + tdSql.query('select count(ts) from db.st where dev in ("dev_01")') + tdSql.checkRows(1) + tdSql.checkData(0, 0, 2) + + tdSql.query('select count(ts) from db.st where dev in ("dev_01", "dev_01")') + tdSql.checkRows(1) + tdSql.checkData(0, 0, 2) + + tdSql.query('select count(ts) from db.st where dev in ("dev_01", "dev_01", "dev_02")') + tdSql.checkRows(1) + tdSql.checkData(0, 0, 3) + + + # colume int + tdSql.query("select count(ts) from db.st where tagtype in (1)") + tdSql.checkRows(1) + tdSql.checkData(0, 0, 3) + + tdSql.query("select count(ts) from db.st where tagtype in (1, 2)") + tdSql.checkRows(1) + tdSql.checkData(0, 0, 3) + tdSql.execute( + """INSERT INTO dev_001(ts, tagtype) VALUES('2020-05-13 10:00:01.000', 2), + ('2020-05-13 10:00:02.001', 2) + dev_002 VALUES('2020-05-13 10:00:03.001', 2)""") + + tdSql.query("select count(ts) from db.st where tagtype in (1, 2)") + tdSql.checkRows(1) + tdSql.checkData(0, 0, 6) + + tdSql.execute("create table tb(ts timestamp, c1 int, c2 binary(10), c3 nchar(10), c4 float, c5 bool)") + for i in range(10): + tdSql.execute("insert into tb values(%d, %d, 'binary%d', 'nchar%d', %f, %d)" % (self.ts + i, i, i, i, i + 0.1, i % 2)) + + #binary + tdSql.query('select count(ts) from db.tb where c2 in ("binary1")') + tdSql.checkRows(1) + tdSql.checkData(0, 0, 1) + + tdSql.query('select count(ts) from db.tb where c2 in ("binary1", "binary2", "binary1")') + tdSql.checkRows(1) + tdSql.checkData(0, 0, 2) + + #bool + #tdSql.query('select count(ts) from db.tb where c5 in (true)') + #tdSql.checkRows(1) + #tdSql.checkData(0, 0, 5) + + #float + #tdSql.query('select count(ts) from db.tb where c4 in (0.1)') + #tdSql.checkRows(1) + #tdSql.checkData(0, 0, 1) + + #nchar + tdSql.query('select count(ts) from db.tb where c3 in ("nchar0")') + tdSql.checkRows(1) + tdSql.checkData(0, 0, 1) + + + #tdSql.query("select tbname, dev from dev_001") + #tdSql.checkRows(1) + #tdSql.checkData(0, 0, 'dev_001') + #tdSql.checkData(0, 1, 'dev_01') + + #tdSql.query("select tbname, dev, tagtype from dev_001") + #tdSql.checkRows(2) + + ### test case for https://jira.taosdata.com:18080/browse/TD-1930 + #tdSql.execute("create table tb(ts timestamp, c1 int, c2 binary(10), c3 nchar(10), c4 float, c5 bool)") + #for i in range(10): + # tdSql.execute("insert into tb values(%d, %d, 'binary%d', 'nchar%d', %f, %d)" % (self.ts + i, i, i, i, i + 0.1, i % 2)) + # + #tdSql.error("select * from tb where c2 = binary2") + #tdSql.error("select * from tb where c3 = nchar2") + + #tdSql.query("select * from tb where c2 = 'binary2' ") + #tdSql.checkRows(1) + + #tdSql.query("select * from tb where c3 = 'nchar2' ") + #tdSql.checkRows(1) + + #tdSql.query("select * from tb where c1 = '2' ") + #tdSql.checkRows(1) + + #tdSql.query("select * from tb where c1 = 2 ") + #tdSql.checkRows(1) + + #tdSql.query("select * from tb where c4 = '0.1' ") + #tdSql.checkRows(1) + + #tdSql.query("select * from tb where c4 = 0.1 ") + #tdSql.checkRows(1) + + #tdSql.query("select * from tb where c5 = true ") + #tdSql.checkRows(5) + + #tdSql.query("select * from tb where c5 = 'true' ") + #tdSql.checkRows(5) + + ## For jira: https://jira.taosdata.com:18080/browse/TD-2850 + #tdSql.execute("create database 'Test' ") + #tdSql.execute("use 'Test' ") + #tdSql.execute("create table 'TB'(ts timestamp, 'Col1' int) tags('Tag1' int)") + #tdSql.execute("insert into 'Tb0' using tb tags(1) values(now, 1)") + #tdSql.query("select * from tb") + #tdSql.checkRows(1) + + + + def stop(self): + tdSql.close() + tdLog.success("%s successfully executed" % __file__) + + +tdCases.addWindows(__file__, TDTestCase()) +tdCases.addLinux(__file__, TDTestCase()) diff --git a/tests/script/general/parser/where.sim b/tests/script/general/parser/where.sim index 157c41ce58ddf4775c0715f35ccd77e46a7dd221..6dfea3d2e70e75f82fd7bd48cd5578971e158de4 100644 --- a/tests/script/general/parser/where.sim +++ b/tests/script/general/parser/where.sim @@ -151,18 +151,12 @@ sql_error select last(*) from wh_mt1 where c5 in ('1') sql_error select last(*) from wh_mt1_tb1 where c5 in ('1') sql_error select last(*) from wh_mt1 where c6 in ('1') sql_error select last(*) from wh_mt1_tb1 where c6 in ('1') -sql_error select last(*) from wh_mt1 where c7 in ('binary') -sql_error select last(*) from wh_mt1_tb1 where c7 in ('binary') -sql_error select last(*) from wh_mt1 where c8 in ('nchar') -sql_error select last(*) from wh_mt1_tb1 where c9 in (true, false) +#sql_error select last(*) from wh_mt1 where c7 in ('binary') +#sql_error select last(*) from wh_mt1_tb1 where c7 in ('binary') +#sql_error select last(*) from wh_mt1 where c8 in ('nchar') +#sql_error select last(*) from wh_mt1_tb1 where c9 in (true, false) sql_error select last(*) from wh_mt1 where c10 in ('2019-01-01 00:00:00.000') sql_error select last(*) from wh_mt1_tb1 where c10 in ('2019-01-01 00:00:00.000') -sql_error select last(*) from wh_mt1 where t1 in ('binary') -sql_error select last(*) from wh_mt1 where t2 in (1) -sql_error select last(*) from wh_mt1 where t3 in (1) -sql_error select last(*) from wh_mt1 where t4 in (1) -sql_error select last(*) from wh_mt1 where t5 in (1) -sql_error select last(*) from wh_mt1 where t6 in (1) sql select last(*) from wh_mt1 where c1 = 1 if $rows != 1 then return -1 @@ -359,4 +353,4 @@ if $rows != 0 then endi -system sh/exec.sh -n dnode1 -s stop -x SIGINT \ No newline at end of file +system sh/exec.sh -n dnode1 -s stop -x SIGINT