From 3204cd86c10ef9c376d61100d6d92929cb8092b0 Mon Sep 17 00:00:00 2001 From: Jing Sima Date: Wed, 15 Jan 2025 08:54:06 +0800 Subject: [PATCH] feat:[TS-4897] Add auth test and fix bugs. --- include/common/tmsg.h | 1 + include/libs/qcom/query.h | 52 ++- include/util/taoserror.h | 4 +- source/common/src/msg/tmsg.c | 10 +- source/dnode/mnode/impl/src/mndStb.c | 2 + source/dnode/vnode/src/meta/metaTable.c | 15 +- source/dnode/vnode/src/vnd/vnodeQuery.c | 1 + source/libs/catalog/inc/catalogInt.h | 10 +- source/libs/catalog/src/catalog.c | 32 +- source/libs/catalog/src/ctgAsync.c | 63 ++- source/libs/catalog/src/ctgCache.c | 25 +- source/libs/catalog/src/ctgUtil.c | 9 +- source/libs/parser/src/parAuthenticator.c | 5 +- source/libs/parser/src/parTranslater.c | 25 +- source/libs/qcom/src/querymsg.c | 56 ++- tests/army/vtable/test_vtable_alter.py | 2 +- tests/army/vtable/test_vtable_auth.py | 480 ++++++++++++++++++++++ tests/parallel_test/cases.task | 4 + 18 files changed, 735 insertions(+), 61 deletions(-) create mode 100644 tests/army/vtable/test_vtable_auth.py diff --git a/include/common/tmsg.h b/include/common/tmsg.h index 6d0b2d30924..a57d90f330f 100644 --- a/include/common/tmsg.h +++ b/include/common/tmsg.h @@ -654,6 +654,7 @@ typedef struct { SSchema* pSchemas; SSchemaExt* pSchemaExt; int8_t virtualStb; + int32_t numOfColRefs; SColRef* pColRefs; } STableMetaRsp; diff --git a/include/libs/qcom/query.h b/include/libs/qcom/query.h index 821e97b1665..74f16517621 100644 --- a/include/libs/qcom/query.h +++ b/include/libs/qcom/query.h @@ -105,8 +105,20 @@ typedef struct SCTableMeta { } SCTableMeta; #pragma pack(pop) +#pragma pack(push, 1) +typedef struct SVCTableMeta { + uint64_t uid; + uint64_t suid; + int32_t vgId; + int8_t tableType; + int32_t numOfColRefs; + SColRef* colRef; +} SVCTableMeta; +#pragma pack(pop) + #pragma pack(push, 1) typedef struct STableMeta { + // BEGIN: KEEP THIS PART SAME WITH SVCTableMeta // BEGIN: KEEP THIS PART SAME WITH SCTableMeta uint64_t uid; uint64_t suid; @@ -114,6 +126,10 @@ typedef struct STableMeta { int8_t tableType; // END: KEEP THIS PART SAME WITH SCTableMeta + int32_t numOfColRefs; + SColRef* colRef; + // END: KEEP THIS PART SAME WITH SVCTableMeta + // if the table is TSDB_CHILD_TABLE, the following information is acquired from the corresponding super table meta // info int32_t sversion; @@ -121,9 +137,8 @@ typedef struct STableMeta { STableComInfo tableInfo; SSchemaExt* schemaExt; // There is no additional memory allocation, and the pointer is fixed to the next address of // the schema content. - SColRef* colRef; int8_t virtualStb; - SSchema schema[]; + SSchema schema[]; } STableMeta; #pragma pack(pop) @@ -155,16 +170,22 @@ typedef struct SUseDbOutput { SDBVgInfo* dbVgroup; } SUseDbOutput; -enum { META_TYPE_NULL_TABLE = 1, META_TYPE_CTABLE, META_TYPE_TABLE, META_TYPE_BOTH_TABLE }; +enum { META_TYPE_NULL_TABLE = 1, + META_TYPE_CTABLE, + META_TYPE_VCTABLE, + META_TYPE_TABLE, + META_TYPE_BOTH_TABLE, + META_TYPE_BOTH_VTABLE}; typedef struct STableMetaOutput { - int32_t metaType; - uint64_t dbId; - char dbFName[TSDB_DB_FNAME_LEN]; - char ctbName[TSDB_TABLE_NAME_LEN]; - char tbName[TSDB_TABLE_NAME_LEN]; - SCTableMeta ctbMeta; - STableMeta* tbMeta; + int32_t metaType; + uint64_t dbId; + char dbFName[TSDB_DB_FNAME_LEN]; + char ctbName[TSDB_TABLE_NAME_LEN]; + char tbName[TSDB_TABLE_NAME_LEN]; + SCTableMeta ctbMeta; + SVCTableMeta* vctbMeta; + STableMeta* tbMeta; } STableMetaOutput; typedef struct SViewMetaOutput { @@ -332,6 +353,7 @@ bool tIsValidSchema(struct SSchema* pSchema, int32_t numOfCols, int32_ int32_t getAsofJoinReverseOp(EOperatorType op); int32_t queryCreateCTableMetaFromMsg(STableMetaRsp* msg, SCTableMeta* pMeta); +int32_t queryCreateVCTableMetaFromMsg(STableMetaRsp *msg, SVCTableMeta **pMeta); int32_t queryCreateTableMetaFromMsg(STableMetaRsp* msg, bool isSuperTable, STableMeta** pMeta); int32_t queryCreateTableMetaExFromMsg(STableMetaRsp* msg, bool isSuperTable, STableMeta** pMeta); char* jobTaskStatusStr(int32_t status); @@ -355,10 +377,12 @@ extern int32_t (*queryProcessMsgRsp[TDMT_MAX])(void* output, char* msg, int32_t void* getTaskPoolWorkerCb(); -#define SET_META_TYPE_NULL(t) (t) = META_TYPE_NULL_TABLE -#define SET_META_TYPE_CTABLE(t) (t) = META_TYPE_CTABLE -#define SET_META_TYPE_TABLE(t) (t) = META_TYPE_TABLE -#define SET_META_TYPE_BOTH_TABLE(t) (t) = META_TYPE_BOTH_TABLE +#define SET_META_TYPE_NULL(t) (t) = META_TYPE_NULL_TABLE +#define SET_META_TYPE_CTABLE(t) (t) = META_TYPE_CTABLE +#define SET_META_TYPE_VCTABLE(t) (t) = META_TYPE_CTABLE +#define SET_META_TYPE_TABLE(t) (t) = META_TYPE_TABLE +#define SET_META_TYPE_BOTH_TABLE(t) (t) = META_TYPE_BOTH_TABLE +#define SET_META_TYPE_BOTH_VTABLE(t) (t) = META_TYPE_BOTH_VTABLE #define NEED_CLIENT_RM_TBLMETA_ERROR(_code) \ ((_code) == TSDB_CODE_PAR_TABLE_NOT_EXIST || (_code) == TSDB_CODE_TDB_TABLE_NOT_EXIST || \ diff --git a/include/util/taoserror.h b/include/util/taoserror.h index 49f854325a3..a8fb7f9a028 100644 --- a/include/util/taoserror.h +++ b/include/util/taoserror.h @@ -1048,8 +1048,8 @@ int32_t taosGetErrSize(); // VTABLE #define TSDB_CODE_VTABLE_SCAN_UNMATCHED_COLUMN TAOS_DEF_ERROR_CODE(0, 0x6200) #define TSDB_CODE_VTABLE_SCAN_INVALID_DOWNSTREAM TAOS_DEF_ERROR_CODE(0, 0x6201) -#define TSDB_CODE_VTABLE_PRIMTS_HAS_REF TAOS_DEF_ERROR_CODE(0, 0x6201) -#define TSDB_CODE_VTABLE_NOT_VIRTUAL_SUPER_TABLE TAOS_DEF_ERROR_CODE(0, 0x6202) +#define TSDB_CODE_VTABLE_PRIMTS_HAS_REF TAOS_DEF_ERROR_CODE(0, 0x6202) +#define TSDB_CODE_VTABLE_NOT_VIRTUAL_SUPER_TABLE TAOS_DEF_ERROR_CODE(0, 0x6203) #ifdef __cplusplus } #endif diff --git a/source/common/src/msg/tmsg.c b/source/common/src/msg/tmsg.c index 702410e49d5..dfd5b150c6d 100644 --- a/source/common/src/msg/tmsg.c +++ b/source/common/src/msg/tmsg.c @@ -6041,8 +6041,9 @@ static int32_t tEncodeSTableMetaRsp(SEncoder *pEncoder, STableMetaRsp *pRsp) { } TAOS_CHECK_RETURN(tEncodeI8(pEncoder, pRsp->virtualStb)); + TAOS_CHECK_RETURN(tEncodeI32(pEncoder, pRsp->numOfColRefs)); if (hasRefCol(pRsp->tableType)) { - for (int32_t i = 0; i < pRsp->numOfColumns; ++i) { + for (int32_t i = 0; i < pRsp->numOfColRefs; ++i) { SColRef *pColRef = &pRsp->pColRefs[i]; TAOS_CHECK_RETURN(tEncodeSColRef(pEncoder, pColRef)); } @@ -6098,13 +6099,14 @@ static int32_t tDecodeSTableMetaRsp(SDecoder *pDecoder, STableMetaRsp *pRsp) { } if (!tDecodeIsEnd(pDecoder)) { TAOS_CHECK_RETURN(tDecodeI8(pDecoder, &pRsp->virtualStb)); - if (hasRefCol(pRsp->tableType) && pRsp->numOfColumns > 0) { - pRsp->pColRefs = taosMemoryMalloc(sizeof(SColRef) * pRsp->numOfColumns); + TAOS_CHECK_RETURN(tDecodeI32(pDecoder, &pRsp->numOfColRefs)); + if (hasRefCol(pRsp->tableType) && pRsp->numOfColRefs > 0) { + pRsp->pColRefs = taosMemoryMalloc(sizeof(SColRef) * pRsp->numOfColRefs); if (pRsp->pColRefs == NULL) { TAOS_CHECK_RETURN(terrno); } - for (int32_t i = 0; i < pRsp->numOfColumns; ++i) { + for (int32_t i = 0; i < pRsp->numOfColRefs; ++i) { SColRef *pColRef = &pRsp->pColRefs[i]; TAOS_CHECK_RETURN(tDecodeSColRef(pDecoder, pColRef)); } diff --git a/source/dnode/mnode/impl/src/mndStb.c b/source/dnode/mnode/impl/src/mndStb.c index 387ad52f266..9a65ad17185 100644 --- a/source/dnode/mnode/impl/src/mndStb.c +++ b/source/dnode/mnode/impl/src/mndStb.c @@ -2121,6 +2121,7 @@ static int32_t mndSetAlterStbRedoActions2(SMnode *pMnode, STrans *pTrans, SDbObj TAOS_RETURN(code); } + static int32_t mndBuildStbSchemaImp(SDbObj *pDb, SStbObj *pStb, const char *tbName, STableMetaRsp *pRsp) { int32_t code = 0; taosRLockLatch(&pStb->lock); @@ -2138,6 +2139,7 @@ static int32_t mndBuildStbSchemaImp(SDbObj *pDb, SStbObj *pStb, const char *tbNa code = terrno; TAOS_RETURN(code); } + pRsp->numOfColRefs = 0; pRsp->pColRefs = NULL; tstrncpy(pRsp->dbFName, pStb->db, sizeof(pRsp->dbFName)); tstrncpy(pRsp->tbName, tbName, sizeof(pRsp->tbName)); diff --git a/source/dnode/vnode/src/meta/metaTable.c b/source/dnode/vnode/src/meta/metaTable.c index 5ee99985b84..3406c152669 100644 --- a/source/dnode/vnode/src/meta/metaTable.c +++ b/source/dnode/vnode/src/meta/metaTable.c @@ -94,17 +94,11 @@ int32_t updataTableColRef(SColRefWrapper *pWp, const SSchema *pSchema, int8_t ad pWp->nCols = nCols + 1; pWp->version = ver; } else { - for (int32_t i = 0; i < nCols; i++) { - SColRef *pOCRef = &pWp->pColRef[i]; - if (pOCRef->id == pSchema->colId) { - int32_t left = (nCols - i - 1) * sizeof(SColRef); - if (left) { - memmove(pWp->pColRef + i, pWp->pColRef + i + 1, left); - } - nCols--; - break; - } + int32_t left = (nCols - pSchema->colId) * sizeof(SColRef); + if (left) { + memmove(pWp->pColRef + pSchema->colId, pWp->pColRef + pSchema->colId + 1, left); } + nCols--; pWp->nCols = nCols; pWp->version = ver; } @@ -168,6 +162,7 @@ int32_t metaUpdateVtbMetaRsp(tb_uid_t uid, char *tbName, SSchemaWrapper *pSchema pMetaRsp->tuid = uid; pMetaRsp->tableType = tableType; pMetaRsp->virtualStb = false; // super table will never be processed here + pMetaRsp->numOfColRefs = pRef->nCols; return code; _return: diff --git a/source/dnode/vnode/src/vnd/vnodeQuery.c b/source/dnode/vnode/src/vnd/vnodeQuery.c index 5166e2abf8f..89a6a07f02d 100644 --- a/source/dnode/vnode/src/vnd/vnodeQuery.c +++ b/source/dnode/vnode/src/vnd/vnodeQuery.c @@ -192,6 +192,7 @@ int32_t vnodeGetTableMeta(SVnode *pVnode, SRpcMsg *pMsg, bool direct) { goto _exit; } } + metaRsp.numOfColRefs = metaRsp.numOfColumns; // encode and send response rspLen = tSerializeSTableMetaRsp(NULL, 0, &metaRsp); diff --git a/source/libs/catalog/inc/catalogInt.h b/source/libs/catalog/inc/catalogInt.h index 359bdc2b454..67483bf696b 100644 --- a/source/libs/catalog/inc/catalogInt.h +++ b/source/libs/catalog/inc/catalogInt.h @@ -776,10 +776,12 @@ typedef struct SCtgCacheItemInfo { #define CTG_META_NHIT_INC() CTG_CACHE_NHIT_INC(CTG_CI_OTHERTABLE_META, 1) -#define CTG_IS_META_NULL(type) ((type) == META_TYPE_NULL_TABLE) -#define CTG_IS_META_CTABLE(type) ((type) == META_TYPE_CTABLE) -#define CTG_IS_META_TABLE(type) ((type) == META_TYPE_TABLE) -#define CTG_IS_META_BOTH(type) ((type) == META_TYPE_BOTH_TABLE) +#define CTG_IS_META_NULL(type) ((type) == META_TYPE_NULL_TABLE) +#define CTG_IS_META_CTABLE(type) ((type) == META_TYPE_CTABLE) +#define CTG_IS_META_VCTABLE(type) ((type) == META_TYPE_VCTABLE) +#define CTG_IS_META_TABLE(type) ((type) == META_TYPE_TABLE) +#define CTG_IS_META_BOTH(type) ((type) == META_TYPE_BOTH_TABLE) +#define CTG_IS_META_VBOTH(type) ((type) == META_TYPE_BOTH_VTABLE) #define CTG_FLAG_STB 0x1 #define CTG_FLAG_NOT_STB 0x2 diff --git a/source/libs/catalog/src/catalog.c b/source/libs/catalog/src/catalog.c index 2e16b0968af..4f6be255a19 100644 --- a/source/libs/catalog/src/catalog.c +++ b/source/libs/catalog/src/catalog.c @@ -138,7 +138,7 @@ int32_t ctgRefreshTbMeta(SCatalog* pCtg, SRequestConnInfo* pConn, SCtgTbMetaCtx* taosMemoryFreeClear(output->tbMeta); CTG_ERR_JRET(ctgGetTbMetaFromMnodeImpl(pCtg, pConn, output->dbFName, output->tbName, output, NULL)); - } else if (CTG_IS_META_BOTH(output->metaType)) { + } else if (CTG_IS_META_BOTH(output->metaType) || CTG_IS_META_VBOTH(output->metaType)) { int32_t exist = 0; if (!CTG_FLAG_IS_FORCE_UPDATE(ctx->flag)) { CTG_ERR_JRET(ctgTbMetaExistInCache(pCtg, output->dbFName, output->tbName, &exist)); @@ -190,6 +190,7 @@ int32_t ctgRefreshTbMeta(SCatalog* pCtg, SRequestConnInfo* pConn, SCtgTbMetaCtx* if (output) { taosMemoryFreeClear(output->tbMeta); + taosMemoryFreeClear(output->vctbMeta); taosMemoryFreeClear(output); } @@ -220,8 +221,29 @@ int32_t ctgGetTbMeta(SCatalog* pCtg, SRequestConnInfo* pConn, SCtgTbMetaCtx* ctx goto _return; } + if (CTG_IS_META_VBOTH(output->metaType) || CTG_IS_META_VCTABLE(output->metaType)) { + int32_t colRefSize = output->vctbMeta->numOfColRefs * sizeof(SColRef); + if (output->tbMeta) { + int32_t metaSize = CTG_META_SIZE(output->tbMeta); + int32_t schemaExtSize = 0; + if (useCompress(output->tbMeta->tableType) && output->tbMeta->schemaExt) { + schemaExtSize = output->tbMeta->tableInfo.numOfColumns * sizeof(SSchemaExt); + } + TAOS_MEMCPY(output->tbMeta, output->vctbMeta, sizeof(SVCTableMeta)); + output->tbMeta->colRef = (SColRef *)((char *)output->tbMeta + metaSize + schemaExtSize); + TAOS_MEMCPY(output->tbMeta->colRef, output->vctbMeta->colRef, colRefSize); + } else { + TAOS_MEMCPY(output->tbMeta, output->vctbMeta, sizeof(SVCTableMeta) + colRefSize); + output->tbMeta->colRef = (SColRef *)((char *)output->tbMeta + sizeof(SVCTableMeta)); + } + + *pTableMeta = output->tbMeta; + goto _return; + } + if ((!CTG_IS_META_CTABLE(output->metaType)) || output->tbMeta) { ctgError("invalid metaType:%d", output->metaType); + taosMemoryFreeClear(output->vctbMeta); taosMemoryFreeClear(output->tbMeta); CTG_ERR_JRET(TSDB_CODE_CTG_INTERNAL_ERROR); } @@ -229,6 +251,7 @@ int32_t ctgGetTbMeta(SCatalog* pCtg, SRequestConnInfo* pConn, SCtgTbMetaCtx* ctx // HANDLE ONLY CHILD TABLE META taosMemoryFreeClear(output->tbMeta); + taosMemoryFreeClear(output->vctbMeta); SName stbName = *ctx->pName; TAOS_STRCPY(stbName.tname, output->tbName); @@ -293,6 +316,12 @@ int32_t ctgUpdateTbMeta(SCatalog* pCtg, STableMetaRsp* rspMsg, bool syncOp) { SET_META_TYPE_CTABLE(output->metaType); CTG_ERR_JRET(queryCreateCTableMetaFromMsg(rspMsg, &output->ctbMeta)); + } else if (TSDB_VIRTUAL_CHILD_TABLE == rspMsg->tableType && NULL == rspMsg->pSchemas) { + TAOS_STRCPY(output->ctbName, rspMsg->tbName); + + SET_META_TYPE_VCTABLE(output->metaType); + + CTG_ERR_JRET(queryCreateVCTableMetaFromMsg(rspMsg, &output->vctbMeta)); } else { TAOS_STRCPY(output->tbName, rspMsg->tbName); @@ -311,6 +340,7 @@ int32_t ctgUpdateTbMeta(SCatalog* pCtg, STableMetaRsp* rspMsg, bool syncOp) { if (output) { taosMemoryFreeClear(output->tbMeta); + taosMemoryFreeClear(output->vctbMeta); taosMemoryFreeClear(output); } diff --git a/source/libs/catalog/src/ctgAsync.c b/source/libs/catalog/src/ctgAsync.c index 18532e7ad71..5d13804fd33 100644 --- a/source/libs/catalog/src/ctgAsync.c +++ b/source/libs/catalog/src/ctgAsync.c @@ -1638,7 +1638,7 @@ int32_t ctgHandleGetTbMetaRsp(SCtgTaskReq* tReq, int32_t reqType, const SDataBuf taosMemoryFreeClear(pOut->tbMeta); CTG_RET(ctgGetTbMetaFromMnode(pCtg, pConn, pName, NULL, tReq)); - } else if (CTG_IS_META_BOTH(pOut->metaType)) { + } else if (CTG_IS_META_BOTH(pOut->metaType) || CTG_IS_META_VBOTH(pOut->metaType)) { int32_t exist = 0; if (!CTG_FLAG_IS_FORCE_UPDATE(flag)) { SName stbName = *pName; @@ -1674,6 +1674,26 @@ int32_t ctgHandleGetTbMetaRsp(SCtgTaskReq* tReq, int32_t reqType, const SDataBuf TAOS_MEMCPY(pOut->tbMeta, &pOut->ctbMeta, sizeof(pOut->ctbMeta)); } + if (CTG_IS_META_VBOTH(pOut->metaType)) { + int32_t colRefSize = pOut->vctbMeta->numOfColRefs * sizeof(SColRef); + if (pOut->tbMeta) { + int32_t metaSize = CTG_META_SIZE(pOut->tbMeta); + int32_t schemaExtSize = 0; + if (useCompress(pOut->tbMeta->tableType) && pOut->tbMeta->schemaExt) { + schemaExtSize = pOut->tbMeta->tableInfo.numOfColumns * sizeof(SSchemaExt); + } + pOut->tbMeta = taosMemoryRealloc(pOut->tbMeta, metaSize + schemaExtSize + colRefSize); + TAOS_MEMCPY(pOut->tbMeta, pOut->vctbMeta, sizeof(SVCTableMeta)); + pOut->tbMeta->colRef = (SColRef *)((char *)pOut->tbMeta + metaSize + schemaExtSize); + TAOS_MEMCPY(pOut->tbMeta->colRef, pOut->vctbMeta->colRef, colRefSize); + } else { + pOut->tbMeta = taosMemoryRealloc(pOut->tbMeta, sizeof(STableMeta) + colRefSize); + TAOS_MEMCPY(pOut->tbMeta, pOut->vctbMeta, sizeof(SVCTableMeta)); + TAOS_MEMCPY(pOut->tbMeta + sizeof(STableMeta), pOut->vctbMeta + sizeof(SVCTableMeta), colRefSize); + pOut->tbMeta->colRef = (SColRef *)((char *)pOut->tbMeta + sizeof(STableMeta)); + } + } + /* else if (CTG_IS_META_CTABLE(pOut->metaType)) { SName stbName = *pName; @@ -1823,7 +1843,7 @@ int32_t ctgHandleGetTbMetasRsp(SCtgTaskReq* tReq, int32_t reqType, const SDataBu taosMemoryFreeClear(pOut->tbMeta); CTG_RET(ctgGetTbMetaFromMnode(pCtg, pConn, pName, NULL, tReq)); - } else if (CTG_IS_META_BOTH(pOut->metaType)) { + } else if (CTG_IS_META_BOTH(pOut->metaType) || CTG_IS_META_VBOTH(pOut->metaType)) { int32_t exist = 0; if (!CTG_FLAG_IS_FORCE_UPDATE(flag)) { SName stbName = *pName; @@ -1865,6 +1885,25 @@ int32_t ctgHandleGetTbMetasRsp(SCtgTaskReq* tReq, int32_t reqType, const SDataBu TAOS_MEMCPY(pOut->tbMeta, &pOut->ctbMeta, sizeof(pOut->ctbMeta)); } + if (CTG_IS_META_VBOTH(pOut->metaType)) { + int32_t colRefSize = pOut->vctbMeta->numOfColRefs * sizeof(SColRef); + if (pOut->tbMeta) { + int32_t metaSize = CTG_META_SIZE(pOut->tbMeta); + int32_t schemaExtSize = 0; + if (useCompress(pOut->tbMeta->tableType) && pOut->tbMeta->schemaExt) { + schemaExtSize = pOut->tbMeta->tableInfo.numOfColumns * sizeof(SSchemaExt); + } + pOut->tbMeta = taosMemoryRealloc(pOut->tbMeta, metaSize + schemaExtSize + colRefSize); + TAOS_MEMCPY(pOut->tbMeta, pOut->vctbMeta, sizeof(SVCTableMeta)); + pOut->tbMeta->colRef = (SColRef *)((char *)pOut->tbMeta + metaSize + schemaExtSize); + TAOS_MEMCPY(pOut->tbMeta->colRef, pOut->vctbMeta->colRef, colRefSize); + } else { + pOut->tbMeta = taosMemoryRealloc(pOut->tbMeta, sizeof(STableMeta) + colRefSize); + TAOS_MEMCPY(pOut->tbMeta, pOut->vctbMeta, sizeof(SVCTableMeta)); + TAOS_MEMCPY(pOut->tbMeta + sizeof(STableMeta), pOut->vctbMeta + sizeof(SVCTableMeta), colRefSize); + pOut->tbMeta->colRef = (SColRef *)((char *)pOut->tbMeta + sizeof(STableMeta)); + } + } /* else if (CTG_IS_META_CTABLE(pOut->metaType)) { SName stbName = *pName; @@ -2066,6 +2105,26 @@ static int32_t ctgHandleGetTbNamesRsp(SCtgTaskReq* tReq, int32_t reqType, const TAOS_MEMCPY(pOut->tbMeta, &pOut->ctbMeta, sizeof(pOut->ctbMeta)); } + if (CTG_IS_META_VBOTH(pOut->metaType)) { + int32_t colRefSize = pOut->vctbMeta->numOfColRefs * sizeof(SColRef); + if (pOut->tbMeta) { + int32_t metaSize = CTG_META_SIZE(pOut->tbMeta); + int32_t schemaExtSize = 0; + if (useCompress(pOut->tbMeta->tableType) && pOut->tbMeta->schemaExt) { + schemaExtSize = pOut->tbMeta->tableInfo.numOfColumns * sizeof(SSchemaExt); + } + pOut->tbMeta = taosMemoryRealloc(pOut->tbMeta, metaSize + schemaExtSize + colRefSize); + TAOS_MEMCPY(pOut->tbMeta, pOut->vctbMeta, sizeof(SVCTableMeta)); + pOut->tbMeta->colRef = (SColRef *)((char *)pOut->tbMeta + metaSize + schemaExtSize); + TAOS_MEMCPY(pOut->tbMeta->colRef, pOut->vctbMeta->colRef, colRefSize); + } else { + pOut->tbMeta = taosMemoryRealloc(pOut->tbMeta, sizeof(STableMeta) + colRefSize); + TAOS_MEMCPY(pOut->tbMeta, pOut->vctbMeta, sizeof(SVCTableMeta)); + TAOS_MEMCPY(pOut->tbMeta + sizeof(STableMeta), pOut->vctbMeta + sizeof(SVCTableMeta), colRefSize); + pOut->tbMeta->colRef = (SColRef *)((char *)pOut->tbMeta + sizeof(STableMeta)); + } + } + SMetaRes* pRes = taosArrayGet(ctx->pResList, pFetch->resIdx); if (NULL == pRes) { ctgTaskError("fail to get the %dth res in pResList, resNum:%d", pFetch->resIdx, diff --git a/source/libs/catalog/src/ctgCache.c b/source/libs/catalog/src/ctgCache.c index 4debfa2f709..a5c04ca7772 100644 --- a/source/libs/catalog/src/ctgCache.c +++ b/source/libs/catalog/src/ctgCache.c @@ -1239,6 +1239,7 @@ int32_t ctgUpdateTbMetaEnqueue(SCatalog *pCtg, STableMetaOutput *output, bool sy if (output) { taosMemoryFree(output->tbMeta); + taosMemoryFree(output->vctbMeta); taosMemoryFree(output); } @@ -2442,12 +2443,14 @@ int32_t ctgOpUpdateTbMeta(SCtgCacheOperation *operation) { goto _return; } - if ((!CTG_IS_META_CTABLE(pMeta->metaType)) && NULL == pMeta->tbMeta) { + if ((!CTG_IS_META_CTABLE(pMeta->metaType) && !CTG_IS_META_VCTABLE(pMeta->metaType)) && NULL == pMeta->tbMeta) { ctgError("no valid tbmeta got from meta rsp, dbFName:%s, tbName:%s", pMeta->dbFName, pMeta->tbName); CTG_ERR_JRET(TSDB_CODE_CTG_INTERNAL_ERROR); } - if (CTG_IS_META_BOTH(pMeta->metaType) && TSDB_SUPER_TABLE != pMeta->tbMeta->tableType) { + if ((CTG_IS_META_BOTH(pMeta->metaType) || + CTG_IS_META_VBOTH(pMeta->metaType)) && + TSDB_SUPER_TABLE != pMeta->tbMeta->tableType) { ctgError("table type error, expected:%d, actual:%d", TSDB_SUPER_TABLE, pMeta->tbMeta->tableType); CTG_ERR_JRET(TSDB_CODE_CTG_INTERNAL_ERROR); } @@ -2458,7 +2461,7 @@ int32_t ctgOpUpdateTbMeta(SCtgCacheOperation *operation) { CTG_ERR_JRET(TSDB_CODE_CTG_INTERNAL_ERROR); } - if (CTG_IS_META_TABLE(pMeta->metaType) || CTG_IS_META_BOTH(pMeta->metaType)) { + if (CTG_IS_META_TABLE(pMeta->metaType) || CTG_IS_META_BOTH(pMeta->metaType) || CTG_IS_META_VBOTH(pMeta->metaType)) { code = ctgWriteTbMetaToCache(pCtg, dbCache, pMeta->dbFName, pMeta->dbId, pMeta->tbName, pMeta->tbMeta); pMeta->tbMeta = NULL; CTG_ERR_JRET(code); @@ -2474,9 +2477,22 @@ int32_t ctgOpUpdateTbMeta(SCtgCacheOperation *operation) { (STableMeta *)ctbMeta)); } + if (CTG_IS_META_VCTABLE(pMeta->metaType) || CTG_IS_META_VBOTH(pMeta->metaType)) { + int32_t colRefSize = sizeof(SColRef) * pMeta->vctbMeta->numOfColRefs; + SVCTableMeta *ctbMeta = taosMemoryMalloc(sizeof(STableMeta) + colRefSize); + if (NULL == ctbMeta) { + CTG_ERR_JRET(terrno); + } + TAOS_MEMCPY(ctbMeta, pMeta->vctbMeta, sizeof(SVCTableMeta)); + ctbMeta->colRef = (SColRef *)((char *)ctbMeta + sizeof(STableMeta)); + TAOS_MEMCPY(ctbMeta->colRef, pMeta->vctbMeta->colRef, colRefSize); + CTG_ERR_JRET(ctgWriteTbMetaToCache(pCtg, dbCache, pMeta->dbFName, pMeta->dbId, pMeta->ctbName, + (STableMeta *)ctbMeta)); + } _return: taosMemoryFreeClear(pMeta->tbMeta); + taosMemoryFreeClear(pMeta->vctbMeta); taosMemoryFreeClear(pMeta); taosMemoryFreeClear(msg); @@ -3171,6 +3187,7 @@ void ctgFreeCacheOperationData(SCtgCacheOperation *op) { case CTG_OP_UPDATE_TB_META: { SCtgUpdateTbMetaMsg *msg = op->data; taosMemoryFreeClear(msg->pMeta->tbMeta); + taosMemoryFreeClear(msg->pMeta->vctbMeta); taosMemoryFreeClear(msg->pMeta); taosMemoryFreeClear(op->data); break; @@ -3669,7 +3686,7 @@ int32_t ctgGetTbMetasFromCache(SCatalog *pCtg, SRequestConnInfo *pConn, SCtgTbMe schemaExtSize = stbMeta->tableInfo.numOfColumns * sizeof(SSchemaExt); } if (tbMeta->colRef != NULL) { - colRefSize = tbMeta->tableInfo.numOfColumns * sizeof(SColRef); + colRefSize = tbMeta->numOfColRefs * sizeof(SColRef); } metaSize = CTG_META_SIZE(stbMeta); pTableMeta = taosMemoryRealloc(pTableMeta, metaSize + schemaExtSize + colRefSize); diff --git a/source/libs/catalog/src/ctgUtil.c b/source/libs/catalog/src/ctgUtil.c index a037ee3cd06..7df488a0ad4 100644 --- a/source/libs/catalog/src/ctgUtil.c +++ b/source/libs/catalog/src/ctgUtil.c @@ -591,6 +591,7 @@ void ctgFreeMsgCtx(SCtgMsgCtx* pCtx) { case TDMT_VND_TABLE_NAME: { STableMetaOutput* pOut = (STableMetaOutput*)pCtx->out; taosMemoryFree(pOut->tbMeta); + taosMemoryFree(pOut->vctbMeta); taosMemoryFreeClear(pCtx->out); break; } @@ -676,6 +677,7 @@ void ctgFreeSTableMetaOutput(STableMetaOutput* pOutput) { } taosMemoryFree(pOutput->tbMeta); + taosMemoryFree(pOutput->vctbMeta); taosMemoryFree(pOutput); } @@ -1681,6 +1683,7 @@ int32_t ctgCloneMetaOutput(STableMetaOutput* output, STableMetaOutput** pOutput) } } + return TSDB_CODE_SUCCESS; } @@ -2063,12 +2066,12 @@ int32_t ctgChkSetTbAuthRes(SCatalog* pCtg, SCtgAuthReq* req, SCtgAuthRsp* res) { CTG_ERR_JRET(ctgGetTbMeta(pCtg, req->pConn, &ctx, &pMeta)); } - if (TSDB_SUPER_TABLE == pMeta->tableType || TSDB_NORMAL_TABLE == pMeta->tableType) { + if (TSDB_SUPER_TABLE == pMeta->tableType || TSDB_NORMAL_TABLE == pMeta->tableType || TSDB_VIRTUAL_TABLE == pMeta->tableType) { res->pRawRes->pass[AUTH_RES_BASIC] = false; goto _return; } - if (TSDB_CHILD_TABLE == pMeta->tableType) { + if (TSDB_CHILD_TABLE == pMeta->tableType || TSDB_VIRTUAL_CHILD_TABLE == pMeta->tableType) { CTG_ERR_JRET(ctgGetCachedStbNameFromSuid(pCtg, dbFName, pMeta->suid, &stbName)); if (NULL == stbName) { if (req->onlyCache) { @@ -2386,6 +2389,8 @@ FORCE_INLINE uint64_t ctgGetTbMetaCacheSize(STableMeta* pMeta) { return sizeof(*pMeta) + (pMeta->tableInfo.numOfColumns + pMeta->tableInfo.numOfTags) * sizeof(SSchema); case TSDB_CHILD_TABLE: return sizeof(SCTableMeta); + case TSDB_VIRTUAL_CHILD_TABLE: + return sizeof(*pMeta); default: return sizeof(*pMeta) + pMeta->tableInfo.numOfColumns * sizeof(SSchema); } diff --git a/source/libs/parser/src/parAuthenticator.c b/source/libs/parser/src/parAuthenticator.c index ee2ddaf0785..6b06ff7e6d3 100644 --- a/source/libs/parser/src/parAuthenticator.c +++ b/source/libs/parser/src/parAuthenticator.c @@ -383,7 +383,10 @@ static int32_t authAlterVTable(SAuthCxt* pCxt, SAlterTableStmt* pStmt) { return TSDB_CODE_OPS_NOT_SUPPORT; #endif PAR_ERR_RET(checkAuth(pCxt, pStmt->dbName, pStmt->tableName, AUTH_TYPE_WRITE, NULL)); - PAR_ERR_RET(checkAuth(pCxt, pStmt->dbName, pStmt->refTableName, AUTH_TYPE_READ, NULL)); + if (pStmt->alterType == TSDB_ALTER_TABLE_ADD_COLUMN_WITH_COLUMN_REF || + pStmt->alterType == TSDB_ALTER_TABLE_ALTER_COLUMN_REF) { + PAR_ERR_RET(checkAuth(pCxt, pStmt->dbName, pStmt->refTableName, AUTH_TYPE_READ, NULL)); + } PAR_RET(TSDB_CODE_SUCCESS); } diff --git a/source/libs/parser/src/parTranslater.c b/source/libs/parser/src/parTranslater.c index 875bc69aced..1add2162719 100755 --- a/source/libs/parser/src/parTranslater.c +++ b/source/libs/parser/src/parTranslater.c @@ -12744,7 +12744,8 @@ static int32_t translateGrantTagCond(STranslateContext* pCxt, SGrantStmt* pStmt, return code; } - if (TSDB_SUPER_TABLE != pTable->pMeta->tableType && TSDB_NORMAL_TABLE != pTable->pMeta->tableType) { + if (TSDB_SUPER_TABLE != pTable->pMeta->tableType && TSDB_NORMAL_TABLE != pTable->pMeta->tableType && + TSDB_VIRTUAL_TABLE != pTable->pMeta->tableType) { nodesDestroyNode((SNode*)pTable); return generateSyntaxErrMsgExt(&pCxt->msgBuf, TSDB_CODE_PAR_SYNTAX_ERROR, "Only supertable and normal table can be granted"); @@ -15955,26 +15956,22 @@ static int32_t buildDropVirtualTableVgroupHashmap(STranslateContext* pCxt, SDrop } if (TSDB_CODE_PAR_TABLE_NOT_EXIST == code && pStmt->ignoreNotExists) { - code = TSDB_CODE_SUCCESS; - goto over; + PAR_RET(TSDB_CODE_SUCCESS); } + PAR_ERR_JRET(code); if (!isVirtualTable(pTableMeta->tableType)) { - code = TSDB_CODE_PAR_INVALID_TABLE_TYPE; - goto over; + PAR_ERR_JRET(TSDB_CODE_PAR_INVALID_TABLE_TYPE); } SVgroupInfo info = {0}; - if (TSDB_CODE_SUCCESS == code) { - code = getTableHashVgroup(pCxt, pStmt->dbName, pStmt->tableName, &info); - } - if (TSDB_CODE_SUCCESS == code) { - SVDropTbReq req = {.suid = pTableMeta->suid, .igNotExists = pStmt->ignoreNotExists, .isVirtual = true}; - req.name = pStmt->tableName; - code = addDropTbReqIntoVgroup(pVgroupHashmap, &info, &req); - } + PAR_ERR_JRET(getTableHashVgroup(pCxt, pStmt->dbName, pStmt->tableName, &info)); -over: + SVDropTbReq req = {.suid = pTableMeta->suid, .igNotExists = pStmt->ignoreNotExists, .isVirtual = true}; + req.name = pStmt->tableName; + PAR_ERR_JRET(addDropTbReqIntoVgroup(pVgroupHashmap, &info, &req)); + +_return: taosMemoryFreeClear(pTableMeta); return code; } diff --git a/source/libs/qcom/src/querymsg.c b/source/libs/qcom/src/querymsg.c index 2629fffbbf3..1204d6be8d8 100644 --- a/source/libs/qcom/src/querymsg.c +++ b/source/libs/qcom/src/querymsg.c @@ -553,13 +553,42 @@ int32_t queryCreateCTableMetaFromMsg(STableMetaRsp *msg, SCTableMeta *pMeta) { return TSDB_CODE_SUCCESS; } +int32_t queryCreateVCTableMetaFromMsg(STableMetaRsp *msg, SVCTableMeta **pMeta) { + QUERY_PARAM_CHECK(msg); + QUERY_PARAM_CHECK(pMeta); + QUERY_PARAM_CHECK(msg->pColRefs); + + int32_t pColRefSize = sizeof(SColRef) * msg->numOfColRefs; + + SVCTableMeta *pTableMeta = taosMemoryCalloc(1, sizeof(SVCTableMeta) + pColRefSize); + if (NULL == pTableMeta) { + qError("calloc size[%d] failed", (int32_t)sizeof(SVCTableMeta) + pColRefSize); + return terrno; + } + + pTableMeta->vgId = msg->vgId; + pTableMeta->tableType = msg->tableType; + pTableMeta->uid = msg->tuid; + pTableMeta->suid = msg->suid; + pTableMeta->numOfColRefs = msg->numOfColRefs; + + pTableMeta->colRef = (SColRef *)((char *)pTableMeta + sizeof(SVCTableMeta)); + memcpy(pTableMeta->colRef, msg->pColRefs, pColRefSize); + + qDebug("ctable %s uid %" PRIx64 " meta returned, type %d vgId:%d db %s suid %" PRIx64, msg->tbName, (pTableMeta)->uid, + (pTableMeta)->tableType, (pTableMeta)->vgId, msg->dbFName, (pTableMeta)->suid); + + *pMeta = pTableMeta; + return TSDB_CODE_SUCCESS; +} + int32_t queryCreateTableMetaFromMsg(STableMetaRsp *msg, bool isStb, STableMeta **pMeta) { QUERY_PARAM_CHECK(msg); QUERY_PARAM_CHECK(pMeta); int32_t total = msg->numOfColumns + msg->numOfTags; int32_t metaSize = sizeof(STableMeta) + sizeof(SSchema) * total; int32_t schemaExtSize = (useCompress(msg->tableType) && msg->pSchemaExt) ? sizeof(SSchemaExt) * msg->numOfColumns : 0; - int32_t pColRefSize = (hasRefCol(msg->tableType) && msg->pColRefs) ? sizeof(SColRef) * msg->numOfColumns : 0; + int32_t pColRefSize = (hasRefCol(msg->tableType) && msg->pColRefs && !isStb) ? sizeof(SColRef) * msg->numOfColRefs : 0; STableMeta *pTableMeta = taosMemoryCalloc(1, metaSize + schemaExtSize + pColRefSize); if (NULL == pTableMeta) { @@ -589,7 +618,7 @@ int32_t queryCreateTableMetaFromMsg(STableMetaRsp *msg, bool isStb, STableMeta * pTableMeta->schemaExt = NULL; } - if (hasRefCol(msg->tableType) && msg->pColRefs) { + if (hasRefCol(msg->tableType) && msg->pColRefs && !isStb) { pTableMeta->colRef = (SColRef *)((char *)pTableMeta + metaSize + schemaExtSize); memcpy(pTableMeta->colRef, msg->pColRefs, pColRefSize); } else { @@ -729,6 +758,17 @@ int32_t queryProcessTableMetaRsp(void *output, char *msg, int32_t msgSize) { pOut->ctbMeta.uid = metaRsp.tuid; pOut->ctbMeta.suid = metaRsp.suid; + code = queryCreateTableMetaFromMsg(&metaRsp, true, &pOut->tbMeta); + } if (metaRsp.tableType == TSDB_VIRTUAL_CHILD_TABLE) { + SET_META_TYPE_BOTH_VTABLE(pOut->metaType); + + tstrncpy(pOut->ctbName, metaRsp.tbName, TSDB_TABLE_NAME_LEN); + tstrncpy(pOut->tbName, metaRsp.stbName, TSDB_TABLE_NAME_LEN); + + code = queryCreateVCTableMetaFromMsg(&metaRsp, &pOut->vctbMeta); + if (TSDB_CODE_SUCCESS != code) { + goto PROCESS_META_OVER; + } code = queryCreateTableMetaFromMsg(&metaRsp, true, &pOut->tbMeta); } else { SET_META_TYPE_TABLE(pOut->metaType); @@ -785,6 +825,18 @@ static int32_t queryProcessTableNameRsp(void *output, char *msg, int32_t msgSize pOut->ctbMeta.uid = metaRsp.tuid; pOut->ctbMeta.suid = metaRsp.suid; + code = queryCreateTableMetaExFromMsg(&metaRsp, true, &pOut->tbMeta); + } else if (metaRsp.tableType == TSDB_VIRTUAL_CHILD_TABLE) { + SET_META_TYPE_BOTH_VTABLE(pOut->metaType); + + tstrncpy(pOut->ctbName, metaRsp.tbName, TSDB_TABLE_NAME_LEN); + tstrncpy(pOut->tbName, metaRsp.stbName, TSDB_TABLE_NAME_LEN); + + code = queryCreateVCTableMetaFromMsg(&metaRsp, &pOut->vctbMeta); + if (TSDB_CODE_SUCCESS != code) { + goto PROCESS_NAME_OVER; + } + code = queryCreateTableMetaExFromMsg(&metaRsp, true, &pOut->tbMeta); } else { SET_META_TYPE_TABLE(pOut->metaType); diff --git a/tests/army/vtable/test_vtable_alter.py b/tests/army/vtable/test_vtable_alter.py index b89821f937b..daa0c6b7c01 100644 --- a/tests/army/vtable/test_vtable_alter.py +++ b/tests/army/vtable/test_vtable_alter.py @@ -17,7 +17,7 @@ from frame.sql import * from frame.caseBase import * from frame.common import * - +import time class TDTestCase(TBase): def prepare_vtables(self): diff --git a/tests/army/vtable/test_vtable_auth.py b/tests/army/vtable/test_vtable_auth.py new file mode 100644 index 00000000000..fc7f1235085 --- /dev/null +++ b/tests/army/vtable/test_vtable_auth.py @@ -0,0 +1,480 @@ +################################################################### +# 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 -*- + +from frame.etool import * +from frame.log import * +from frame.cases import * +from frame.sql import * +from frame.caseBase import * +from frame.common import * + +import taos +import time + +class TDTestCase(TBase): + + def prepare_data(self): + tdLog.info(f"prepare databases.") + tdSql.execute("drop database if exists test_vtable_auth_create;") + tdSql.execute("drop database if exists test_vtable_auth_alter;") + tdSql.execute("drop database if exists test_vtable_auth_select;") + tdSql.execute("drop database if exists test_vctable_auth_create;") + tdSql.execute("drop database if exists test_vctable_auth_alter;") + tdSql.execute("create database test_vtable_auth_create;") + tdSql.execute("create database test_vtable_auth_alter;") + tdSql.execute("create database test_vtable_auth_select;") + tdSql.execute("create database test_vctable_auth_create;") + tdSql.execute("create database test_vctable_auth_alter;") + + + def test_alter_drop_virtual_normal_table(self): + tdSql.execute("use test_vtable_auth_alter;") + tdSql.execute("create table test_vtable_auth_org_table_1(ts timestamp, int_col int);") + tdSql.execute("create table test_vtable_auth_org_table_2(ts timestamp, int_col int, bin_32_col binary(32), bin_64_col binary(64));") + tdSql.execute("create user test_vtable_user_alter PASS 'test12@#*';") + + priv_list = ["write", "read", "none", "all"] + + testconn = taos.connect(user='test_vtable_user_alter', password='test12@#*') + cursor = testconn.cursor() + testSql = TDSql() + testSql.init(cursor) + + i = 0 + for priv_db in priv_list: + if (priv_db == "none"): + continue # meaningless to test db has no privilege + for priv_vtb in priv_list: + for priv_orgtb in priv_list: + tdSql.execute("use test_vtable_auth_alter;") + tdSql.execute(f"create vtable test_vtable_auth_vtb_{i}(" + "ts timestamp, " + "int_col_1 int from test_vtable_auth_org_table_1.int_col, " + "int_col_2 int, " + "bin_32_col_1 binary(32) from test_vtable_auth_org_table_2.bin_32_col);") + + tdSql.execute(f"grant {priv_db} on test_vtable_auth_alter to test_vtable_user_alter;") + if (priv_vtb != "none"): + tdSql.execute(f"grant {priv_vtb} on test_vtable_auth_alter.test_vtable_auth_vtb_{i} to test_vtable_user_alter;") + if (priv_orgtb != "none"): + tdSql.execute(f"grant {priv_orgtb} on test_vtable_auth_alter.test_vtable_auth_org_table_2 to test_vtable_user_alter;") + + sleep(2) + + tdLog.info(f"priv_db: {priv_db}, priv_tb1: {priv_vtb}, priv_tb2: {priv_orgtb}") + testSql.execute("use test_vtable_auth_alter;") + if (priv_db == "read"): + if (priv_vtb == "write" or priv_vtb == "all"): + testSql.execute(f"alter vtable test_vtable_auth_vtb_{i} add column int_col_3 int;") + testSql.execute(f"alter vtable test_vtable_auth_vtb_{i} add column int_col_4 int from test_vtable_auth_org_table_2.int_col;") + testSql.execute(f"alter vtable test_vtable_auth_vtb_{i} alter column int_col_2 set test_vtable_auth_org_table_2.int_col;") + testSql.execute(f"alter vtable test_vtable_auth_vtb_{i} alter column bin_32_col_1 SET NULL;") + testSql.execute(f"alter vtable test_vtable_auth_vtb_{i} modify column bin_32_col_1 binary(64);") + testSql.execute(f"alter vtable test_vtable_auth_vtb_{i} alter column bin_32_col_1 SET test_vtable_auth_org_table_2.bin_64_col;") + testSql.execute(f"alter vtable test_vtable_auth_vtb_{i} rename column bin_32_col_1 bin_64_col_1;") + testSql.execute(f"alter vtable test_vtable_auth_vtb_{i} drop column int_col_2;") + else: + testSql.error(f"alter vtable test_vtable_auth_vtb_{i} add column int_col_3 int;", expectErrInfo="Permission denied or target object not exist") + testSql.error(f"alter vtable test_vtable_auth_vtb_{i} add column int_col_4 int from test_vtable_auth_org_table_2.int_col;", expectErrInfo="Permission denied or target object not exist") + testSql.error(f"alter vtable test_vtable_auth_vtb_{i} alter column int_col_2 set test_vtable_auth_org_table_2.int_col;", expectErrInfo="Permission denied or target object not exist") + testSql.error(f"alter vtable test_vtable_auth_vtb_{i} alter column bin_32_col_1 SET NULL;", expectErrInfo="Permission denied or target object not exist") + testSql.error(f"alter vtable test_vtable_auth_vtb_{i} modify column bin_32_col_1 binary(64);", expectErrInfo="Permission denied or target object not exist") + testSql.error(f"alter vtable test_vtable_auth_vtb_{i} alter column bin_32_col_1 SET test_vtable_auth_org_table_2.bin_64_col;", expectErrInfo="Permission denied or target object not exist") + testSql.error(f"alter vtable test_vtable_auth_vtb_{i} rename column bin_32_col_1 bin_64_col_1;", expectErrInfo="Permission denied or target object not exist") + testSql.error(f"alter vtable test_vtable_auth_vtb_{i} drop column int_col_2;", expectErrInfo="Permission denied or target object not exist") + elif (priv_db == "all"): + testSql.execute(f"alter vtable test_vtable_auth_vtb_{i} add column int_col_3 int;") + testSql.execute(f"alter vtable test_vtable_auth_vtb_{i} add column int_col_4 int from test_vtable_auth_org_table_2.int_col;") + testSql.execute(f"alter vtable test_vtable_auth_vtb_{i} alter column int_col_2 set test_vtable_auth_org_table_2.int_col;") + testSql.execute(f"alter vtable test_vtable_auth_vtb_{i} alter column bin_32_col_1 SET NULL;") + testSql.execute(f"alter vtable test_vtable_auth_vtb_{i} modify column bin_32_col_1 binary(64);") + testSql.execute(f"alter vtable test_vtable_auth_vtb_{i} alter column bin_32_col_1 SET test_vtable_auth_org_table_2.bin_64_col;") + testSql.execute(f"alter vtable test_vtable_auth_vtb_{i} rename column bin_32_col_1 bin_64_col_1;") + testSql.execute(f"alter vtable test_vtable_auth_vtb_{i} drop column int_col_2;") + else: + if (priv_orgtb == "none" or priv_orgtb == "write"): + testSql.execute(f"alter vtable test_vtable_auth_vtb_{i} add column int_col_3 int;") + testSql.error(f"alter vtable test_vtable_auth_vtb_{i} add column int_col_4 int from test_vtable_auth_org_table_2.int_col;") + testSql.error(f"alter vtable test_vtable_auth_vtb_{i} alter column int_col_2 set test_vtable_auth_org_table_2.int_col;") + testSql.execute(f"alter vtable test_vtable_auth_vtb_{i} alter column bin_32_col_1 SET NULL;") + testSql.execute(f"alter vtable test_vtable_auth_vtb_{i} modify column bin_32_col_1 binary(64);") + testSql.error(f"alter vtable test_vtable_auth_vtb_{i} alter column bin_32_col_1 SET test_vtable_auth_org_table_2.bin_64_col;") + testSql.execute(f"alter vtable test_vtable_auth_vtb_{i} rename column bin_32_col_1 bin_64_col_1;") + testSql.execute(f"alter vtable test_vtable_auth_vtb_{i} drop column int_col_2;") + else: + testSql.execute(f"alter vtable test_vtable_auth_vtb_{i} add column int_col_3 int;") + testSql.execute(f"alter vtable test_vtable_auth_vtb_{i} add column int_col_4 int from test_vtable_auth_org_table_2.int_col;") + testSql.execute(f"alter vtable test_vtable_auth_vtb_{i} alter column int_col_2 set test_vtable_auth_org_table_2.int_col;") + testSql.execute(f"alter vtable test_vtable_auth_vtb_{i} alter column bin_32_col_1 SET NULL;") + testSql.execute(f"alter vtable test_vtable_auth_vtb_{i} modify column bin_32_col_1 binary(64);") + testSql.execute(f"alter vtable test_vtable_auth_vtb_{i} alter column bin_32_col_1 SET test_vtable_auth_org_table_2.bin_64_col;") + testSql.execute(f"alter vtable test_vtable_auth_vtb_{i} rename column bin_32_col_1 bin_64_col_1;") + testSql.execute(f"alter vtable test_vtable_auth_vtb_{i} drop column int_col_2;") + + + if (priv_db == "read"): + if (priv_vtb == "write" or priv_vtb == "all"): + testSql.execute(f"drop vtable test_vtable_auth_vtb_{i};") + else: + testSql.error(f"drop vtable test_vtable_auth_vtb_{i};", expectErrInfo="Permission denied or target object not exist") + elif (priv_db == "all"): + testSql.execute(f"drop vtable test_vtable_auth_vtb_{i};") + else: + testSql.execute(f"drop vtable test_vtable_auth_vtb_{i};") + + tdSql.execute(f"revoke {priv_db} on test_vtable_auth_alter from test_vtable_user_alter;") + if (priv_vtb != "none"): + tdSql.execute(f"revoke {priv_vtb} on test_vtable_auth_alter.test_vtable_auth_vtb_{i} from test_vtable_user_alter;") + if (priv_orgtb != "none"): + tdSql.execute(f"revoke {priv_orgtb} on test_vtable_auth_alter.test_vtable_auth_org_table_2 from test_vtable_user_alter;") + i+=1 + + tdSql.execute("drop database test_vtable_auth_alter;") + + def test_create_virtual_normal_table(self): + tdSql.execute("use test_vtable_auth_create;") + tdSql.execute("create table test_vtable_auth_org_table_1(ts timestamp, int_col int);") + tdSql.execute("create table test_vtable_auth_org_table_2(ts timestamp, int_col int);") + tdSql.execute("create user test_vtable_user_create PASS 'test12@#*';") + + priv_list = ["write", "read", "none", "all"] + + testconn = taos.connect(user='test_vtable_user_create', password='test12@#*') + cursor = testconn.cursor() + testSql = TDSql() + testSql.init(cursor) + + i = 0 + for priv_db in priv_list: + if (priv_db == "none"): + continue # meaningless to test db has no privilege + for priv_tb1 in priv_list: + for priv_tb2 in priv_list: + tdSql.execute("use test_vtable_auth_create;") + tdSql.execute(f"grant {priv_db} on test_vtable_auth_create to test_vtable_user_create;") + if (priv_tb1 != "none"): + tdSql.execute(f"grant {priv_tb1} on test_vtable_auth_create.test_vtable_auth_org_table_1 to test_vtable_user_create;") + if (priv_tb2 != "none"): + tdSql.execute(f"grant {priv_tb2} on test_vtable_auth_create.test_vtable_auth_org_table_2 to test_vtable_user_create;") + + sleep(2) + tdLog.info(f"priv_db: {priv_db}, priv_tb1: {priv_tb1}, priv_tb2: {priv_tb2}") + testSql.execute("use test_vtable_auth_create;") + if (priv_db == "read"): + testSql.error(f"create vtable test_vtable_auth_vtb_{i}(" + "ts timestamp, " + "int_col_1 int from test_vtable_auth_org_table_1.int_col, " + "int_col_2 int from test_vtable_auth_org_table_2.int_col);", expectErrInfo="Permission denied or target object not exist") + elif (priv_db == "all"): + testSql.execute(f"create vtable test_vtable_auth_vtb_{i}(" + "ts timestamp, " + "int_col_1 int from test_vtable_auth_org_table_1.int_col, " + "int_col_2 int from test_vtable_auth_org_table_2.int_col);") + elif (priv_tb1 == "write" or priv_tb2 == "write" or priv_tb1 == "none" or priv_tb2 == "none"): + testSql.error(f"create vtable test_vtable_auth_vtb_{i}(" + "ts timestamp, " + "int_col_1 int from test_vtable_auth_org_table_1.int_col, " + "int_col_2 int from test_vtable_auth_org_table_2.int_col);", expectErrInfo="Permission denied or target object not exist") + else: + testSql.execute(f"create vtable test_vtable_auth_vtb_{i}(" + "ts timestamp, " + "int_col_1 int from test_vtable_auth_org_table_1.int_col, " + "int_col_2 int from test_vtable_auth_org_table_2.int_col);") + + + + tdSql.execute(f"revoke {priv_db} on test_vtable_auth_create from test_vtable_user_create;") + if (priv_tb1 != "none"): + tdSql.execute(f"revoke {priv_tb1} on test_vtable_auth_create.test_vtable_auth_org_table_1 from test_vtable_user_create;") + if (priv_tb2 != "none"): + tdSql.execute(f"revoke {priv_tb2} on test_vtable_auth_create.test_vtable_auth_org_table_2 from test_vtable_user_create;") + i+=1 + + tdSql.execute("drop database test_vtable_auth_create;") + + def test_select_virtual_normal_table(self): + tdSql.execute("use test_vtable_auth_select;") + tdSql.execute("create table test_vtable_auth_org_table_1(ts timestamp, int_col int);") + tdSql.execute("create table test_vtable_auth_org_table_2(ts timestamp, int_col int);") + tdSql.execute("create user test_vtable_user_select PASS 'test12@#*';") + tdSql.execute("create vtable test_vtable_auth_vtb_0(" + "ts timestamp, " + "int_col_1 int from test_vtable_auth_org_table_1.int_col, " + "int_col_2 int from test_vtable_auth_org_table_2.int_col);") + + priv_list = ["write", "read", "none", "all"] + + testconn = taos.connect(user='test_vtable_user_select', password='test12@#*') + cursor = testconn.cursor() + testSql = TDSql() + testSql.init(cursor) + + i = 0 + for priv_db in priv_list: + if (priv_db == "none"): + continue # meaningless to test db has no privilege + for priv_vtb in priv_list: + tdSql.execute("use test_vtable_auth_select;") + + tdSql.execute(f"grant {priv_db} on test_vtable_auth_select to test_vtable_user_select;") + if (priv_vtb != "none"): + tdSql.execute(f"grant {priv_vtb} on test_vtable_auth_select.test_vtable_auth_vtb_0 to test_vtable_user_select;") + + sleep(2) + + tdLog.info(f"priv_db: {priv_db}, priv_vtb: {priv_vtb}") + testSql.execute("use test_vtable_auth_select;") + if (priv_db == "read" or priv_db == "all"): + testSql.query("select * from test_vtable_auth_vtb_0;") + testSql.checkRows(0) + testSql.query("select int_col_1 from test_vtable_auth_vtb_0;") + testSql.checkRows(0) + testSql.query("select int_col_2 from test_vtable_auth_vtb_0;") + testSql.checkRows(0) + else: + if (priv_vtb == "read" or priv_vtb == "all"): + testSql.query("select * from test_vtable_auth_vtb_0;") + testSql.checkRows(0) + testSql.query("select int_col_1 from test_vtable_auth_vtb_0;") + testSql.checkRows(0) + testSql.query("select int_col_2 from test_vtable_auth_vtb_0;") + testSql.checkRows(0) + else: + testSql.error("select * from test_vtable_auth_vtb_0;", expectErrInfo="Permission denied or target object not exist") + testSql.error("select int_col_1 from test_vtable_auth_vtb_0;", expectErrInfo="Permission denied or target object not exist") + testSql.error("select int_col_2 from test_vtable_auth_vtb_0;", expectErrInfo="Permission denied or target object not exist") + + tdSql.execute(f"revoke {priv_db} on test_vtable_auth_select from test_vtable_user_select;") + if (priv_vtb != "none"): + tdSql.execute(f"revoke {priv_vtb} on test_vtable_auth_select.test_vtable_auth_vtb_0 from test_vtable_user_select;") + i+=1 + + tdSql.execute("drop database test_vtable_auth_select;") + + def test_create_virtual_child_table(self): + tdSql.execute("use test_vctable_auth_create;") + tdSql.execute("create table test_vtable_auth_org_table_1(ts timestamp, int_col int);") + tdSql.execute("create table test_vtable_auth_org_table_2(ts timestamp, int_col int);") + tdSql.execute("create user test_vct_user_create PASS 'test12@#*';") + tdSql.execute("create stable test_vtable_auth_stb_1(ts timestamp, int_col_1 int, int_col_2 int) TAGS (int_tag int) virtual 1;") + priv_list = ["write", "read", "none", "all"] + + testconn = taos.connect(user='test_vct_user_create', password='test12@#*') + cursor = testconn.cursor() + testSql = TDSql() + testSql.init(cursor) + + i = 0 + for priv_db in priv_list: + if (priv_db == "none"): + continue # meaningless to test db has no privilege + for priv_tb1 in priv_list: + for priv_tb2 in priv_list: + tdSql.execute("use test_vctable_auth_create;") + tdSql.execute(f"grant {priv_db} on test_vctable_auth_create to test_vct_user_create;") + if (priv_tb1 != "none"): + tdSql.execute(f"grant {priv_tb1} on test_vctable_auth_create.test_vtable_auth_org_table_1 to test_vct_user_create;") + if (priv_tb2 != "none"): + tdSql.execute(f"grant {priv_tb2} on test_vctable_auth_create.test_vtable_auth_org_table_2 to test_vct_user_create;") + + sleep(2) + tdLog.info(f"priv_db: {priv_db}, priv_tb1: {priv_tb1}, priv_tb2: {priv_tb2}") + testSql.execute("use test_vctable_auth_create;") + if (priv_db == "read"): + testSql.error(f"create vtable test_vctable_auth_vtb_{i}(" + "test_vtable_auth_org_table_1.int_col, " + "test_vtable_auth_org_table_2.int_col) " + "USING test_vtable_auth_stb_1 " + "TAGS (1);", expectErrInfo="Permission denied or target object not exist") + elif (priv_db == "all"): + testSql.execute(f"create vtable test_vctable_auth_vtb_{i}(" + "test_vtable_auth_org_table_1.int_col, " + "test_vtable_auth_org_table_2.int_col)" + "USING test_vtable_auth_stb_1 " + "TAGS (1);") + else: + if (priv_tb1 == "write" or priv_tb1 == "none" or priv_tb2 == "write" or priv_tb2 == "none"): + testSql.error(f"create vtable test_vctable_auth_vtb_{i}(" + "test_vtable_auth_org_table_1.int_col, " + "test_vtable_auth_org_table_2.int_col) " + "USING test_vtable_auth_stb_1 " + "TAGS (1);", expectErrInfo="Permission denied or target object not exist") + else: + testSql.execute(f"create vtable test_vctable_auth_vtb_{i}(" + "test_vtable_auth_org_table_1.int_col, " + "test_vtable_auth_org_table_2.int_col)" + "USING test_vtable_auth_stb_1 " + "TAGS (1);") + + + + tdSql.execute(f"revoke {priv_db} on test_vctable_auth_create from test_vct_user_create;") + if (priv_tb1 != "none"): + tdSql.execute(f"revoke {priv_tb1} on test_vctable_auth_create.test_vtable_auth_org_table_1 from test_vct_user_create;") + if (priv_tb2 != "none"): + tdSql.execute(f"revoke {priv_tb2} on test_vctable_auth_create.test_vtable_auth_org_table_2 from test_vct_user_create;") + i+=1 + + tdSql.execute("drop database test_vctable_auth_create;") + + def test_alter_drop_virtual_child_table(self): + tdSql.execute("use test_vctable_auth_alter;") + tdSql.execute("create table test_vtable_auth_org_table_1(ts timestamp, int_col int);") + tdSql.execute("create table test_vtable_auth_org_table_2(ts timestamp, int_col int);") + tdSql.execute("create user test_vct_user_alter PASS 'test12@#*';") + tdSql.execute("create stable test_vtable_auth_stb_1(ts timestamp, int_col_1 int, int_col_2 int) TAGS (int_tag int) virtual 1;") + priv_list = ["write", "read", "none", "all"] + + testconn = taos.connect(user='test_vct_user_alter', password='test12@#*') + cursor = testconn.cursor() + testSql = TDSql() + testSql.init(cursor) + + i = 0 + for priv_db in priv_list: + if (priv_db == "none"): + continue # meaningless to test db has no privilege + for priv_vtb in priv_list: + for priv_orgtb in priv_list: + tdSql.execute("use test_vctable_auth_alter;") + tdSql.execute(f"create vtable test_vctable_auth_vtb_{i}(" + "test_vtable_auth_org_table_1.int_col)" + "USING test_vtable_auth_stb_1 " + "TAGS (1);") + tdSql.execute(f"grant {priv_db} on test_vctable_auth_alter to test_vct_user_alter;") + if (priv_vtb != "none"): + tdSql.execute(f"grant {priv_vtb} on test_vctable_auth_alter.test_vtable_auth_stb_1 to test_vct_user_alter;") + if (priv_orgtb != "none"): + tdSql.execute(f"grant {priv_orgtb} on test_vctable_auth_alter.test_vtable_auth_org_table_2 to test_vct_user_alter;") + + sleep(2) + + tdLog.info(f"priv_db: {priv_db}, priv_tb1: {priv_vtb}, priv_tb2: {priv_orgtb}") + testSql.execute("use test_vctable_auth_alter;") + if (priv_db == "read"): + if (priv_vtb == "write" or priv_vtb == "all"): + testSql.execute(f"alter vtable test_vctable_auth_vtb_{i} alter column int_col_2 set test_vtable_auth_org_table_2.int_col;") + testSql.execute(f"alter vtable test_vctable_auth_vtb_{i} alter column int_col_2 SET NULL;") + testSql.execute(f"alter vtable test_vctable_auth_vtb_{i} set tag int_tag = 2;") + else: + testSql.error(f"alter vtable test_vctable_auth_vtb_{i} alter column int_col_2 set test_vtable_auth_org_table_2.int_col;", expectErrInfo="Permission denied or target object not exist") + testSql.error(f"alter vtable test_vctable_auth_vtb_{i} alter column int_col_2 SET NULL;", expectErrInfo="Permission denied or target object not exist") + testSql.error(f"alter vtable test_vctable_auth_vtb_{i} set tag int_tag = 2;", expectErrInfo="Permission denied or target object not exist") + elif (priv_db == "all"): + testSql.execute(f"alter vtable test_vctable_auth_vtb_{i} alter column int_col_2 set test_vtable_auth_org_table_2.int_col;") + testSql.execute(f"alter vtable test_vctable_auth_vtb_{i} alter column int_col_2 SET NULL;") + testSql.execute(f"alter vtable test_vctable_auth_vtb_{i} set tag int_tag = 2;") + else: + if (priv_orgtb == "none" or priv_orgtb == "write"): + testSql.error(f"alter vtable test_vctable_auth_vtb_{i} alter column int_col_2 set test_vtable_auth_org_table_2.int_col;") + testSql.execute(f"alter vtable test_vctable_auth_vtb_{i} alter column int_col_2 SET NULL;") + testSql.execute(f"alter vtable test_vctable_auth_vtb_{i} set tag int_tag = 2;") + else: + testSql.execute(f"alter vtable test_vctable_auth_vtb_{i} alter column int_col_2 set test_vtable_auth_org_table_2.int_col;") + testSql.execute(f"alter vtable test_vctable_auth_vtb_{i} alter column int_col_2 SET NULL;") + testSql.execute(f"alter vtable test_vctable_auth_vtb_{i} set tag int_tag = 2;") + + + if (priv_db == "read"): + if (priv_vtb == "write" or priv_vtb == "all"): + testSql.execute(f"drop vtable test_vctable_auth_vtb_{i};") + else: + testSql.error(f"drop vtable test_vctable_auth_vtb_{i};", expectErrInfo="Permission denied or target object not exist") + elif (priv_db == "all"): + testSql.execute(f"drop vtable test_vctable_auth_vtb_{i};") + else: + testSql.execute(f"drop vtable test_vctable_auth_vtb_{i};") + + tdSql.execute(f"revoke {priv_db} on test_vctable_auth_alter from test_vct_user_alter;") + if (priv_vtb != "none"): + tdSql.execute(f"revoke {priv_vtb} on test_vctable_auth_alter.test_vtable_auth_stb_1 from test_vct_user_alter;") + if (priv_orgtb != "none"): + tdSql.execute(f"revoke {priv_orgtb} on test_vctable_auth_alter.test_vtable_auth_org_table_2 from test_vct_user_alter;") + i+=1 + + tdSql.execute("drop database test_vctable_auth_alter;") + + def test_select_virtual_child_table(self): + tdSql.execute("drop database if exists test_vctable_auth_select;") + tdSql.execute("create database test_vctable_auth_select;") + tdSql.execute("use test_vctable_auth_select;") + tdSql.execute("create table test_vtable_auth_org_table_1(ts timestamp, int_col int);") + tdSql.execute("create table test_vtable_auth_org_table_2(ts timestamp, int_col int);") + tdSql.execute("create user test_vct_user_select PASS 'test12@#*';") + tdSql.execute("create stable test_vtable_auth_stb_1(ts timestamp, int_col_1 int, int_col_2 int) TAGS (int_tag int) virtual 1;") + tdSql.execute(f"create vtable test_vctable_auth_vtb_0(test_vtable_auth_org_table_1.int_col, test_vtable_auth_org_table_2.int_col) USING test_vtable_auth_stb_1 TAGS (1);") + + priv_list = ["write", "read", "none", "all"] + + testconn = taos.connect(user='test_vct_user_select', password='test12@#*') + cursor = testconn.cursor() + testSql = TDSql() + testSql.init(cursor) + + i = 0 + for priv_db in priv_list: + if (priv_db == "none"): + continue # meaningless to test db has no privilege + for priv_vtb in priv_list: + tdSql.execute("use test_vctable_auth_select;") + + tdSql.execute(f"grant {priv_db} on test_vctable_auth_select to test_vct_user_select;") + if (priv_vtb != "none"): + tdSql.execute(f"grant {priv_vtb} on test_vctable_auth_select.test_vtable_auth_stb_1 with int_tag = 1 to test_vct_user_select;") + + sleep(2) + + tdLog.info(f"priv_db: {priv_db}, priv_vtb: {priv_vtb}") + testSql.execute("use test_vctable_auth_select;") + if (priv_db == "read" or priv_db == "all"): + testSql.query("select * from test_vtable_auth_vtb_0;") + testSql.checkRows(0) + testSql.query("select int_col_1 from test_vtable_auth_vtb_0;") + testSql.checkRows(0) + testSql.query("select int_col_2 from test_vtable_auth_vtb_0;") + testSql.checkRows(0) + else: + if (priv_vtb == "read" or priv_vtb == "all"): + testSql.query("select * from test_vtable_auth_vtb_0;") + testSql.checkRows(0) + testSql.query("select int_col_1 from test_vtable_auth_vtb_0;") + testSql.checkRows(0) + testSql.query("select int_col_2 from test_vtable_auth_vtb_0;") + testSql.checkRows(0) + else: + testSql.error("select * from test_vtable_auth_vtb_0;", expectErrInfo="Permission denied or target object not exist") + testSql.error("select int_col_1 from test_vtable_auth_vtb_0;", expectErrInfo="Permission denied or target object not exist") + testSql.error("select int_col_2 from test_vtable_auth_vtb_0;", expectErrInfo="Permission denied or target object not exist") + + tdSql.execute(f"revoke {priv_db} on test_vctable_auth_select from test_vct_user_select;") + if (priv_vtb != "none"): + tdSql.execute(f"revoke {priv_vtb} on test_vctable_auth_select.test_vtable_auth_stb_1 with int_tag = 1 from test_vct_user_select;") + i+=1 + + tdSql.execute("drop database if exists test_vctable_auth_select;") + + def run(self): + tdLog.debug(f"start to excute {__file__}") + + #self.prepare_data() + #self.test_create_virtual_normal_table() + #self.test_alter_drop_virtual_normal_table() + #self.test_select_virtual_normal_table() + #self.test_create_virtual_child_table() + #self.test_alter_drop_virtual_child_table() + self.test_select_virtual_child_table() + tdLog.success(f"{__file__} successfully executed") + + +tdCases.addLinux(__file__, TDTestCase()) +tdCases.addWindows(__file__, TDTestCase()) diff --git a/tests/parallel_test/cases.task b/tests/parallel_test/cases.task index 0201c88d2b2..90b8336edff 100644 --- a/tests/parallel_test/cases.task +++ b/tests/parallel_test/cases.task @@ -24,6 +24,10 @@ ,,y,army,./pytest.sh python3 ./test.py -f cluster/arbitrator.py -N 3 ,,n,army,python3 ./test.py -f storage/s3/s3Basic.py -N 3 ,,y,army,./pytest.sh python3 ./test.py -f cluster/snapshot.py -N 3 -L 3 -D 2 +,,y,army,./pytest.sh python3 ./test.py -f vtable/test_vtable_create.py +,,y,army,./pytest.sh python3 ./test.py -f vtable/test_vtable_alter.py +,,y,army,./pytest.sh python3 ./test.py -f vtable/test_vtable_drop.py +,,y,army,./pytest.sh python3 ./test.py -f vtable/test_vtable_meta.py ,,y,army,./pytest.sh python3 ./test.py -f query/function/test_func_elapsed.py ,,y,army,./pytest.sh python3 ./test.py -f query/function/test_function.py ,,y,army,./pytest.sh python3 ./test.py -f query/function/test_selection_function_with_json.py