From 016c260f1a8550cfd1690a146ddd91b146283a37 Mon Sep 17 00:00:00 2001 From: Jing Sima Date: Thu, 27 Nov 2025 17:46:12 +0800 Subject: [PATCH] fix: [TD-38729] Forbid virtual table's timestamp precision different from origin table's timestamp precision. --- source/libs/parser/src/parTranslater.c | 33 ++++++++++++++++--------- tests/army/vtable/test_vtable_alter.py | 24 ++++++++++++++++++ tests/army/vtable/test_vtable_create.py | 22 +++++++++++++++++ 3 files changed, 68 insertions(+), 11 deletions(-) diff --git a/source/libs/parser/src/parTranslater.c b/source/libs/parser/src/parTranslater.c index 2910630ad9f7..cf2ca57e19a5 100644 --- a/source/libs/parser/src/parTranslater.c +++ b/source/libs/parser/src/parTranslater.c @@ -18025,12 +18025,16 @@ static int32_t buildUpdateMultiTagValReq(STranslateContext* pCxt, SAlterTableStm return code; } -static int32_t checkColRef(STranslateContext* pCxt, char* pRefDbName, char* pRefTableName, char* pRefColName, SDataType type) { +static int32_t checkColRef(STranslateContext* pCxt, char* pRefDbName, char* pRefTableName, char* pRefColName, + SDataType type, int8_t precision) { STableMeta* pRefTableMeta = NULL; int32_t code = TSDB_CODE_SUCCESS; PAR_ERR_JRET(getTableMeta(pCxt, pRefDbName, pRefTableName, &pRefTableMeta)); + if (pRefTableMeta->tableInfo.precision != precision) { + PAR_ERR_JRET(generateSyntaxErrMsgExt(&pCxt->msgBuf, TSDB_CODE_PAR_INVALID_REF_COLUMN_TYPE, "timestamp precision of virtual table and its reference table do not match")); + } // org table cannot has composite primary key if (pRefTableMeta->tableInfo.numOfColumns > 1 && pRefTableMeta->schema[1].flags & COL_IS_KEY) { PAR_ERR_JRET(generateSyntaxErrMsg(&pCxt->msgBuf, TSDB_CODE_PAR_INVALID_REF_COLUMN)); @@ -18098,8 +18102,8 @@ static int32_t buildAddColReq(STranslateContext* pCxt, SAlterTableStmt* pStmt, S // check ref column exists and check type PAR_ERR_RET(checkColRef(pCxt, pStmt->refDbName, pStmt->refTableName, pStmt->refColName, - (SDataType){.type = pStmt->dataType.type, - .bytes = calcTypeBytes(pStmt->dataType)})); + (SDataType){.type = pStmt->dataType.type, .bytes = calcTypeBytes(pStmt->dataType)}, + pTableMeta->tableInfo.precision)); pReq->type = pStmt->dataType.type; pReq->bytes = calcTypeBytes(pStmt->dataType); @@ -18311,7 +18315,8 @@ static int buildAlterTableColumnRef(STranslateContext* pCxt, SAlterTableStmt* pS } PAR_ERR_JRET(checkColRef(pCxt, pStmt->refDbName, pStmt->refTableName, pStmt->refColName, - (SDataType){.type = pSchema->type, .bytes = pSchema->bytes})); + (SDataType){.type = pSchema->type, .bytes = pSchema->bytes}, + pTableMeta->tableInfo.precision)); pReq->colName = taosStrdup(pStmt->colName); pReq->refDbName = taosStrdup(pStmt->refDbName); @@ -18588,6 +18593,8 @@ static int32_t rewriteCreateVirtualTable(STranslateContext* pCxt, SQuery* pQuery SArray* pBufArray = NULL; SNode* pNode = NULL; int32_t index = 0; + SDbCfgInfo dbCfg = {0}; + int8_t precision = 0; PAR_ERR_JRET(checkCreateVirtualTable(pCxt, pStmt)); @@ -18598,6 +18605,7 @@ static int32_t rewriteCreateVirtualTable(STranslateContext* pCxt, SQuery* pQuery toName(pCxt->pParseCxt->acctId, pStmt->dbName, pStmt->tableName, &name); + FOREACH(pNode, pStmt->pCols) { SColumnDefNode *pColNode = (SColumnDefNode *)pNode; SColumnOptions *pColOptions = (SColumnOptions*)pColNode->pOptions; @@ -18608,9 +18616,10 @@ static int32_t rewriteCreateVirtualTable(STranslateContext* pCxt, SQuery* pQuery if (IS_DECIMAL_TYPE(pColNode->dataType.type)) { PAR_ERR_JRET(generateSyntaxErrMsg(&pCxt->msgBuf, TSDB_CODE_VTABLE_NOT_SUPPORT_DATA_TYPE)); } - PAR_ERR_JRET(checkColRef(pCxt, pColOptions->refDb, pColOptions->refTable, pColOptions->refColumn, - (SDataType){.type = pColNode->dataType.type, - .bytes = calcTypeBytes(pColNode->dataType)})); + PAR_ERR_JRET( + checkColRef(pCxt, pColOptions->refDb, pColOptions->refTable, pColOptions->refColumn, + (SDataType){.type = pColNode->dataType.type, .bytes = calcTypeBytes(pColNode->dataType)}, + dbCfg.precision)); } index++; } @@ -18665,15 +18674,17 @@ static int32_t rewriteCreateVirtualSubTable(STranslateContext* pCxt, SQuery* pQu PAR_ERR_JRET(TSDB_CODE_VTABLE_PRIMTS_HAS_REF); } PAR_ERR_JRET(checkColRef(pCxt, pColRef->refDbName, pColRef->refTableName, pColRef->refColName, - (SDataType){.type = pSchema->type, .bytes = pSchema->bytes})); + (SDataType){.type = pSchema->type, .bytes = pSchema->bytes}, + pSuperTableMeta->tableInfo.precision)); } } else if (pStmt->pColRefs) { int32_t index = 1; FOREACH(pCol, pStmt->pColRefs) { SColumnRefNode* pColRef = (SColumnRefNode*)pCol; - PAR_ERR_JRET(checkColRef(pCxt, pColRef->refDbName, pColRef->refTableName, pColRef->refColName, - (SDataType){.type = pSuperTableMeta->schema[index].type, - .bytes = pSuperTableMeta->schema[index].bytes})); + PAR_ERR_JRET(checkColRef( + pCxt, pColRef->refDbName, pColRef->refTableName, pColRef->refColName, + (SDataType){.type = pSuperTableMeta->schema[index].type, .bytes = pSuperTableMeta->schema[index].bytes}, + pSuperTableMeta->tableInfo.precision)); index++; } } else { diff --git a/tests/army/vtable/test_vtable_alter.py b/tests/army/vtable/test_vtable_alter.py index 2cfa1c498e8c..a637fd8a08b9 100644 --- a/tests/army/vtable/test_vtable_alter.py +++ b/tests/army/vtable/test_vtable_alter.py @@ -21,6 +21,7 @@ class TDTestCase(TBase): def prepare_vtables(self): + tdSql.execute("use test_vtable_alter;") tdSql.execute("drop table if exists vtb_virtual_stb;") tdSql.execute("drop table if exists vtb_virtual_stb_1;") tdSql.execute("drop table if exists vtb_virtual_ctb0;") @@ -137,6 +138,8 @@ def prepare_tables(self): tdLog.info(f"prepare org tables.") tdSql.execute("drop database if exists test_vtable_alter;") tdSql.execute("create database test_vtable_alter;") + tdSql.execute("create database test_vtable_alter_us PRECISION 'us';") + tdSql.execute("create database test_vtable_alter_ns PRECISION 'ns';") tdSql.execute("use test_vtable_alter;") tdLog.info(f"prepare org super table.") @@ -178,6 +181,12 @@ def prepare_tables(self): for i in range(30): tdSql.execute(f"CREATE TABLE `vtb_org_normal_{i}` (ts timestamp, u_tinyint_col tinyint unsigned, u_smallint_col smallint unsigned, u_int_col int unsigned, u_bigint_col bigint unsigned, tinyint_col tinyint, smallint_col smallint, int_col int, bigint_col bigint, float_col float, double_col double, bool_col bool, binary_16_col binary(16), binary_32_col binary(32), nchar_16_col nchar(16), nchar_32_col nchar(32), varbinary_16_col varbinary(16), varbinary_32_col varbinary(32), geo_16_col geometry(16), geo_32_col geometry(32))") + tdSql.execute("use test_vtable_alter_ns;") + tdSql.execute(f"CREATE TABLE `vtb_org_normal_ns` (ts timestamp, int_col int, u_smallint_col int unsigned)") + + tdSql.execute("use test_vtable_alter_us;") + tdSql.execute(f"CREATE TABLE `vtb_org_normal_us` (ts timestamp, int_col int, u_smallint_col int unsigned)") + self.prepare_vtables() def check_col_num(self, isnormal, col_num): @@ -385,6 +394,16 @@ def test_error_cases(self): # 1.7. add column with decimal type tdSql.error("alter vtable vtb_virtual_ntb0 add column extra_decimal decimal(38,38)") + # 1.8. add column with column reference from different database precision + tdSql.error("alter vtable vtb_virtual_ntb0 add column extra_int_col int from test_vtable_alter_us.vtb_org_normal_us.int_col;") + + tdSql.error("alter vtable vtb_virtual_ntb0 add column extra_int_col int from test_vtable_alter_ns.vtb_org_normal_ns.int_col;") + + # 1.9. change column reference from different database precision + tdSql.error("alter vtable vtb_virtual_ntb0 alter column int_col set test_vtable_alter_ns.vtb_org_normal_ns.int_col") + + tdSql.error("alter vtable vtb_virtual_ntb0 alter column int_col set test_vtable_alter_us.vtb_org_normal_us.int_col") + # 2. child table # 2.1. change column reference with wrong type tdSql.error("alter vtable vtb_virtual_ctb0 alter column int_col set vtb_org_child_19.tinyint_col") @@ -392,6 +411,11 @@ def test_error_cases(self): # 2.2. change column reference with non-exist column tdSql.error("alter vtable vtb_virtual_ctb0 alter column int_col set not_exist_org_table.int_col") + # 2.3 change column reference from different database precision + tdSql.error("alter vtable vtb_virtual_ctb0 alter column int_col set test_vtable_alter_ns.vtb_org_normal_ns.int_col") + + tdSql.error("alter vtable vtb_virtual_ctb0 alter column int_col set test_vtable_alter_us.vtb_org_normal_us.int_col") + # 3. super table # 3.1. add column with column reference tdSql.error("alter stable vtb_virtual_stb add column extra_intcol int from vtb_org_child_19.int_col") diff --git a/tests/army/vtable/test_vtable_create.py b/tests/army/vtable/test_vtable_create.py index e2a0bddb82fc..cf929ec627fd 100644 --- a/tests/army/vtable/test_vtable_create.py +++ b/tests/army/vtable/test_vtable_create.py @@ -24,6 +24,8 @@ def prepare_org_tables(self): tdLog.info(f"prepare org tables.") tdSql.execute("create database test_vtable_create;") + tdSql.execute("create database test_vtable_create_us PRECISION 'us';") + tdSql.execute("create database test_vtable_create_ns PRECISION 'ns';") tdSql.execute("use test_vtable_create;") tdLog.info(f"prepare org super table.") @@ -68,6 +70,12 @@ def prepare_org_tables(self): tdLog.info(f"prepare org normal table with compositive primary key.") tdSql.execute(f"CREATE TABLE `vtb_org_normal_pk` (ts timestamp, int_col int PRIMARY KEY, u_smallint_col int unsigned)") + tdSql.execute("use test_vtable_create_ns;") + tdSql.execute(f"CREATE TABLE `vtb_org_normal_ns` (ts timestamp, int_col int, u_smallint_col int unsigned)") + + tdSql.execute("use test_vtable_create_us;") + tdSql.execute(f"CREATE TABLE `vtb_org_normal_us` (ts timestamp, int_col int, u_smallint_col int unsigned)") + def test_create_virtual_super_table(self): tdLog.info(f"test create virtual super tables.") @@ -773,6 +781,20 @@ def test_error_cases(self): "u_tinyint_col tinyint unsigned from vtb_org_normal_0.u_tinyint_col, " "u_smallint_col smallint unsigned from vtb_org_normal_1.u_smallint_col, " "decimal_col decimal(38,38))") + + # 12. create virtual table using origin table with different precision + # 12.1 vtable is ms, from ns + # 12.1.1 child table + tdSql.error("CREATE VTABLE `error_vtb_virtual_ctb13`(int_col FROM test_vtable_create_ns.vtb_org_normal_ns.int_col) USING vtb_virtual_stb TAGS (13, false, 13, 13, 'vchild13', 'vchild13')") + # 12.1.2 normal table + tdSql.error("CREATE VTABLE `error_vtb_virtual_ntb9` (ts timestamp, int_col int from test_vtable_create_ns.vtb_org_normal_ns.int_col)") + + # 12.2 vtable is ms, from us + # 12.2.1 child table + tdSql.error("CREATE VTABLE `error_vtb_virtual_ctb14`(int_col FROM test_vtable_create_us.vtb_org_normal_us.int_col) USING vtb_virtual_stb TAGS (14, false, 14, 14, 'vchild14', 'vchild14')") + # 12.2.2 normal table + tdSql.error("CREATE VTABLE `error_vtb_virtual_ntb10` (ts timestamp, int_col int from test_vtable_create_us.vtb_org_normal_us.int_col)") + def run(self): tdLog.debug(f"start to excute {__file__}")