Skip to content

Commit bffc07a

Browse files
authored
enh: stmt2 support vtable query (#33825)
1 parent 358b97a commit bffc07a

File tree

6 files changed

+156
-47
lines changed

6 files changed

+156
-47
lines changed

source/client/test/stmt2Test.cpp

Lines changed: 124 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -387,44 +387,6 @@ TEST(stmt2Case, timezone) {
387387
}
388388
}
389389

390-
TEST(stmt2Case, not_support_vtable) {
391-
TAOS* taos = taos_connect("localhost", "root", "taosdata", "", 0);
392-
ASSERT_NE(taos, nullptr);
393-
do_query(taos, "drop database if exists stmt2_testdb_37");
394-
do_query(taos, "create database IF NOT EXISTS stmt2_testdb_37");
395-
do_query(taos,
396-
"CREATE STABLE stmt2_testdb_37.meters_v (ts timestamp,current float, voltage int, phase float) "
397-
"TAGS(location varchar(64), "
398-
"group_id int) VIRTUAL 1;");
399-
do_query(taos, "use stmt2_testdb_37");
400-
401-
TAOS_STMT2_OPTION option = {0, true, true, NULL, NULL};
402-
403-
TAOS_STMT2* stmt = taos_stmt2_init(taos, &option);
404-
ASSERT_NE(stmt, nullptr);
405-
406-
const char* sql = "select * from stmt2_testdb_37.meters_v where ts > ? and ts < ? limit ?";
407-
int code = taos_stmt2_prepare(stmt, sql, 0);
408-
checkError(stmt, code, __FILE__, __LINE__);
409-
410-
int t64_len[1] = {sizeof(int64_t)};
411-
int b_len[1] = {3};
412-
int x = 2;
413-
int x_len = sizeof(int);
414-
int64_t ts[2] = {1591060627000, 1591060628005};
415-
TAOS_STMT2_BIND params[3] = {{TSDB_DATA_TYPE_TIMESTAMP, &ts[0], t64_len, NULL, 1},
416-
{TSDB_DATA_TYPE_TIMESTAMP, &ts[1], t64_len, NULL, 1},
417-
{TSDB_DATA_TYPE_INT, &x, &x_len, NULL, 1}};
418-
TAOS_STMT2_BIND* paramv = &params[0];
419-
TAOS_STMT2_BINDV bindv = {1, NULL, NULL, &paramv};
420-
code = taos_stmt2_bind_param(stmt, &bindv, -1);
421-
ASSERT_EQ(code, TSDB_CODE_VTABLE_NOT_SUPPORT_STMT);
422-
423-
taos_stmt2_close(stmt);
424-
do_query(taos, "drop database if exists stmt2_testdb_7");
425-
taos_close(taos);
426-
}
427-
428390
TEST(stmt2Case, stmt2_test_limit) {
429391
TAOS* taos = taos_connect("localhost", "root", "taosdata", "", 0);
430392
ASSERT_NE(taos, nullptr);
@@ -4089,9 +4051,8 @@ TEST(stmt2Case, tbname) {
40894051

40904052
taos_free_result(result);
40914053
taos_stmt2_close(stmt);
4092-
do_query(taos, "drop table if exists stmt2_testdb_22.tb1");
4093-
do_query(taos, "drop table if exists stmt2_testdb_22.tb2");
40944054
}
4055+
do_query(taos, "drop database if exists stmt2_testdb_22");
40954056
}
40964057

40974058
// TS-7074
@@ -4241,4 +4202,127 @@ TEST(stmt2Case, no_tag) {
42414202
taos_close(taos);
42424203
}
42434204

4205+
TEST(stmt2Case, vtable) {
4206+
TAOS* taos = taos_connect("localhost", "root", "taosdata", "", 0);
4207+
ASSERT_NE(taos, nullptr);
4208+
4209+
// Drop database if exists
4210+
do_query(taos, "drop database if exists stmt2_testdb_29");
4211+
4212+
// Create database
4213+
do_query(taos, "create database stmt2_testdb_29");
4214+
do_query(taos, "use stmt2_testdb_29");
4215+
4216+
// Create normal table
4217+
do_query(taos, "create table ntb_0(ts timestamp, c1 int, c2 int, c3 int)");
4218+
4219+
// Create super table and child table
4220+
do_query(taos, "create stable stb (ts timestamp, c1 int, c2 int, c3 int) tags (t1 int)");
4221+
do_query(taos, "create table ctb_0 using stb tags (1)");
4222+
4223+
// Insert data
4224+
do_query(taos, "insert into ntb_0 values(1591060628000, 1, 1, 1)");
4225+
do_query(taos, "insert into ntb_0 values(1591060628100, 2, 2, 2)");
4226+
do_query(taos, "insert into ntb_0 values(1591060628200, 3, 3, 3)");
4227+
4228+
do_query(taos, "insert into ctb_0 values(1591060628000, 1, 1, 1)");
4229+
do_query(taos, "insert into ctb_0 values(1591060628100, 2, 2, 2)");
4230+
do_query(taos, "insert into ctb_0 values(1591060628200, 3, 3, 3)");
4231+
4232+
// Create virtual tables
4233+
do_query(taos, "create stable vstb (ts timestamp, c1 int, c2 int, c3 int) tags (t1 int) virtual 1");
4234+
do_query(taos, "create vtable vtb_0 (c1 from ntb_0.c1, c2 from ntb_0.c2, c3 from ntb_0.c3) using vstb tags (1)");
4235+
do_query(taos, "create vtable vtb_1 (c1 from ctb_0.c1, c2 from ctb_0.c2, c3 from ctb_0.c3) using vstb tags (2)");
4236+
4237+
// 0. Query vstable before alter origin table
4238+
TAOS_STMT2_OPTION option = {0, true, true, NULL, NULL};
4239+
4240+
TAOS_STMT2* stmt = taos_stmt2_init(taos, &option);
4241+
ASSERT_NE(stmt, nullptr);
4242+
4243+
// query virtual super table
4244+
const char* sql = "select tbname,c1 from vstb where ts = ? order by tbname";
4245+
int code = taos_stmt2_prepare(stmt, sql, 0);
4246+
checkError(stmt, code, __FILE__, __LINE__);
4247+
4248+
int fieldNum = 0;
4249+
TAOS_FIELD_ALL* pFields = NULL;
4250+
code = taos_stmt2_get_fields(stmt, &fieldNum, &pFields);
4251+
checkError(stmt, code, __FILE__, __LINE__);
4252+
ASSERT_EQ(fieldNum, 1);
4253+
4254+
int t64_len = sizeof(int64_t);
4255+
int64_t ts = 1591060628000;
4256+
TAOS_STMT2_BIND params = {TSDB_DATA_TYPE_TIMESTAMP, &ts, &t64_len, NULL, 1};
4257+
TAOS_STMT2_BIND* paramv = &params;
4258+
TAOS_STMT2_BINDV bindv = {1, NULL, NULL, &paramv};
4259+
code = taos_stmt2_bind_param(stmt, &bindv, -1);
4260+
checkError(stmt, code, __FILE__, __LINE__);
4261+
4262+
taos_stmt2_exec(stmt, NULL);
4263+
checkError(stmt, code, __FILE__, __LINE__);
4264+
4265+
TAOS_RES* pRes = taos_stmt2_result(stmt);
4266+
ASSERT_NE(pRes, nullptr);
4267+
TAOS_ROW row = taos_fetch_row(pRes);
4268+
ASSERT_NE(row, nullptr);
4269+
ASSERT_EQ(strncmp((char*)row[0], "vtb_0", 5), 0);
4270+
ASSERT_EQ(*(int*)row[1], 1);
4271+
row = taos_fetch_row(pRes);
4272+
ASSERT_NE(row, nullptr);
4273+
ASSERT_EQ(strncmp((char*)row[0], "vtb_1", 5), 0);
4274+
ASSERT_EQ(*(int*)row[1], 1);
4275+
4276+
// query virtual child table
4277+
code = taos_stmt2_prepare(stmt, "select c1 from vtb_0 where ts = ? order by c1", 0);
4278+
checkError(stmt, code, __FILE__, __LINE__);
4279+
int t2_len = 5;
4280+
code = taos_stmt2_bind_param(stmt, &bindv, -1);
4281+
checkError(stmt, code, __FILE__, __LINE__);
4282+
code = taos_stmt2_exec(stmt, NULL);
4283+
checkError(stmt, code, __FILE__, __LINE__);
4284+
pRes = taos_stmt2_result(stmt);
4285+
ASSERT_NE(pRes, nullptr);
4286+
row = taos_fetch_row(pRes);
4287+
ASSERT_NE(row, nullptr);
4288+
ASSERT_EQ(*(int*)row[0], 1);
4289+
4290+
// composite condition
4291+
code = taos_stmt2_prepare(stmt, "select c1,c2,c3 from vstb where c1 > ? and c3 < ? order by c1", 0);
4292+
checkError(stmt, code, __FILE__, __LINE__);
4293+
fieldNum = 0;
4294+
pFields = NULL;
4295+
code = taos_stmt2_get_fields(stmt, &fieldNum, &pFields);
4296+
checkError(stmt, code, __FILE__, __LINE__);
4297+
ASSERT_EQ(fieldNum, 2);
4298+
4299+
int c1 = 1;
4300+
int c3 = 3;
4301+
int c3_len = sizeof(int);
4302+
TAOS_STMT2_BIND params2[2] = {{TSDB_DATA_TYPE_INT, &c1, &c3_len, NULL, 1},
4303+
{TSDB_DATA_TYPE_INT, &c3, &c3_len, NULL, 1}};
4304+
TAOS_STMT2_BIND* paramv2 = &params2[0];
4305+
TAOS_STMT2_BINDV bindv2 = {1, NULL, NULL, &paramv2};
4306+
code = taos_stmt2_bind_param(stmt, &bindv2, -1);
4307+
checkError(stmt, code, __FILE__, __LINE__);
4308+
code = taos_stmt2_exec(stmt, NULL);
4309+
checkError(stmt, code, __FILE__, __LINE__);
4310+
pRes = taos_stmt2_result(stmt);
4311+
ASSERT_NE(pRes, nullptr);
4312+
row = taos_fetch_row(pRes);
4313+
ASSERT_NE(row, nullptr);
4314+
ASSERT_EQ(*(int*)row[0], 2);
4315+
ASSERT_EQ(*(int*)row[1], 2);
4316+
ASSERT_EQ(*(int*)row[2], 2);
4317+
row = taos_fetch_row(pRes);
4318+
ASSERT_NE(row, nullptr);
4319+
row = taos_fetch_row(pRes);
4320+
ASSERT_EQ(row, nullptr);
4321+
4322+
// Cleanup
4323+
taos_stmt2_close(stmt);
4324+
do_query(taos, "drop database if exists stmt2_testdb_29");
4325+
taos_close(taos);
4326+
}
4327+
42444328
#pragma GCC diagnostic pop

source/libs/catalog/src/ctgCache.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -643,6 +643,8 @@ int32_t ctgCopyTbMeta(SCatalog *pCtg, SCtgTbMetaCtx *ctx, SCtgDBCache **pDb, SCt
643643
if (colRefSize != 0) {
644644
(*pTableMeta)->colRef = (SColRef *)((char *)*pTableMeta + metaSize + schemaExtSize);
645645
TAOS_MEMCPY((*pTableMeta)->colRef, tmpRef, colRefSize);
646+
(*pTableMeta)->numOfColRefs = numOfColRefs; // Set numOfColRefs for virtual child table
647+
(*pTableMeta)->rversion = rversion; // Set rversion for virtual child table
646648
} else {
647649
(*pTableMeta)->colRef = NULL;
648650
}

source/libs/parser/src/parInsertSql.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3277,8 +3277,7 @@ static int32_t checkTableClauseFirstToken(SInsertParseContext* pCxt, SVnodeModif
32773277
}
32783278
} else {
32793279
pCxt->stmtTbNameFlag |= IS_FIXED_VALUE;
3280-
parserWarn("QID:0x%" PRIx64 ", table name is specified in sql, ignore the table name in bind param",
3281-
pCxt->pComCxt->requestId);
3280+
parserTrace("QID:0x%" PRIx64 ", stmt tbname:%s is specified in sql", pCxt->pComCxt->requestId, pTbName->z);
32823281
*pHasData = true;
32833282
}
32843283
return TSDB_CODE_SUCCESS;

source/libs/parser/src/parTranslater.c

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4916,9 +4916,20 @@ static int32_t setVSuperTableRefScanVgroupList(STranslateContext* pCxt, SName* p
49164916
vgroupList = taosArrayInit(1, sizeof(SVgroupInfo));
49174917
QUERY_CHECK_NULL(vgroupList, code, lino, _return, terrno);
49184918

4919-
49204919
SArray* pVStbRefs = NULL;
4921-
PAR_ERR_JRET(getVStbRefDbsFromCache(pCxt->pMetaCache, pName, &pVStbRefs));
4920+
code = getVStbRefDbsFromCache(pCxt->pMetaCache, pName, &pVStbRefs);
4921+
4922+
// Handle the case where VStbRefDbs data is not available (e.g., stmt scenario)
4923+
if (TSDB_CODE_PAR_TABLE_NOT_EXIST == code || TSDB_CODE_PAR_INTERNAL_ERROR == code) {
4924+
// VStbRefDbs not available in cache (stmt scenario without async metadata fetch)
4925+
// Use empty vgroup list - the executor will resolve vgroups at runtime
4926+
taosMemoryFreeClear(pRefScanTable->pVgroupList);
4927+
PAR_ERR_JRET(toVgroupsInfo(vgroupList, &pRefScanTable->pVgroupList));
4928+
code = TSDB_CODE_SUCCESS;
4929+
goto _return;
4930+
}
4931+
PAR_ERR_JRET(code);
4932+
49224933
dbNameHash = tSimpleHashInit(taosArrayGetSize(pVStbRefs), taosGetDefaultHashFunction(TSDB_DATA_TYPE_BINARY));
49234934
QUERY_CHECK_NULL(dbNameHash, code, lino, _return, terrno);
49244935

@@ -5748,9 +5759,7 @@ static int32_t translateVirtualTable(STranslateContext* pCxt, SNode** pTable, SN
57485759
// virtual table only support select operation
57495760
PAR_ERR_JRET(TSDB_CODE_TSC_INVALID_OPERATION);
57505761
}
5751-
if (pCxt->pParseCxt->stmtBindVersion > 0) {
5752-
PAR_ERR_JRET(TSDB_CODE_VTABLE_NOT_SUPPORT_STMT);
5753-
}
5762+
57545763
if (pCxt->pParseCxt->topicQuery) {
57555764
PAR_ERR_JRET(TSDB_CODE_VTABLE_NOT_SUPPORT_TOPIC);
57565765
}

source/libs/parser/src/parUtil.c

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1561,8 +1561,22 @@ int32_t getVStbRefDbsFromCache(SParseMetaCache* pMetaCache, const SName* pName,
15611561
if (TSDB_CODE_SUCCESS != code) {
15621562
return code;
15631563
}
1564+
1565+
if (NULL == pMetaCache || NULL == pMetaCache->pVStbRefDbs) {
1566+
return TSDB_CODE_PAR_TABLE_NOT_EXIST;
1567+
}
1568+
15641569
SArray* pRefs = NULL;
15651570
code = getMetaDataFromHash(fullName, strlen(fullName), pMetaCache->pVStbRefDbs, (void**)&pRefs);
1571+
1572+
// Special handling for stmt scenario where slot is reserved but data is not filled
1573+
// In this case, getMetaDataFromHash returns INTERNAL_ERROR because value is nullPointer
1574+
if (TSDB_CODE_PAR_INTERNAL_ERROR == code) {
1575+
// Data not filled in cache (stmt scenario without putMetaDataToCache)
1576+
// Return table not exist to indicate VStbRefDbs is not available
1577+
return TSDB_CODE_PAR_TABLE_NOT_EXIST;
1578+
}
1579+
15661580
if (TSDB_CODE_SUCCESS == code && NULL != pRefs) {
15671581
*pOutput = pRefs;
15681582
}

source/libs/planner/src/planLogicCreater.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1131,6 +1131,7 @@ static int32_t createVirtualSuperTableLogicNode(SLogicPlanContext* pCxt, SSelect
11311131
// TODO(smj) : create a fake logic node, no need to collect column
11321132
PLAN_ERR_JRET(createScanLogicNode(pCxt, pSelect, (SRealTableNode*)nodesListGetNode(pVirtualTable->refTables, 1), &pInsColumnsScan));
11331133
nodesDestroyList(((SScanLogicNode*)pInsColumnsScan)->node.pTargets);
1134+
((SScanLogicNode*)pInsColumnsScan)->node.pTargets = NULL; // Set to NULL after destroy to avoid use-after-free
11341135
PLAN_ERR_JRET(addInsColumnScanCol((SRealTableNode*)nodesListGetNode(pVirtualTable->refTables, 1), &((SScanLogicNode*)pInsColumnsScan)->pScanCols));
11351136
PLAN_ERR_JRET(createColumnByRewriteExprs(((SScanLogicNode*)pInsColumnsScan)->pScanCols, &((SScanLogicNode*)pInsColumnsScan)->node.pTargets));
11361137
((SScanLogicNode *)pInsColumnsScan)->virtualStableScan = true;

0 commit comments

Comments
 (0)