From 850f3f5081d00506744628edd0a9a982fd43c5d8 Mon Sep 17 00:00:00 2001 From: Akshay Nangare <44081595+akshay05n@users.noreply.github.com> Date: Mon, 10 Mar 2025 19:39:47 +0530 Subject: [PATCH] Fix: Ensure `ECSqlReader` returns correct metadata for instance properties (#1031) * Reset dynamic column info on ECSqlField reset --------- Co-authored-by: affank (cherry picked from commit c697af613a1a437135c0694b0bd35738f0fd4e93) --- iModelCore/ECDb/ECDb/ECSql/ECSqlField.h | 4 +- .../Tests/NonPublished/InstanceReaderTest.cpp | 75 +++++++++++++++++++ 2 files changed, 77 insertions(+), 2 deletions(-) diff --git a/iModelCore/ECDb/ECDb/ECSql/ECSqlField.h b/iModelCore/ECDb/ECDb/ECSql/ECSqlField.h index f83a21f40a0..12cffa051bd 100644 --- a/iModelCore/ECDb/ECDb/ECSql/ECSqlField.h +++ b/iModelCore/ECDb/ECDb/ECSql/ECSqlField.h @@ -24,7 +24,7 @@ struct ECSqlField : public IECSqlValue ECSqlColumnInfoCR _GetColumnInfo() const override { return m_ecsqlDynamicColumnInfo.IsValid() ? m_ecsqlDynamicColumnInfo : m_ecsqlColumnInfo; } - virtual ECSqlStatus _OnAfterReset() { return ECSqlStatus::Success; } + virtual ECSqlStatus _OnAfterReset() { SetDynamicColumnInfo(ECSqlColumnInfo()); return ECSqlStatus::Success; } virtual ECSqlStatus _OnAfterStep() { return ECSqlStatus::Success; } virtual void _OnDynamicPropertyUpdated() {} protected: @@ -38,7 +38,7 @@ struct ECSqlField : public IECSqlValue virtual ~ECSqlField() {} bool RequiresOnAfterStep() const { return m_requiresOnAfterStep; } ECSqlStatus OnAfterStep() { return _OnAfterStep(); } - bool RequiresOnAfterReset() const { return m_requiresOnAfterReset; } + bool RequiresOnAfterReset() const { return m_requiresOnAfterReset || _GetColumnInfo().IsDynamic(); } ECSqlStatus OnAfterReset() { return _OnAfterReset(); } void SetDynamicColumnInfo(ECSqlColumnInfoCR info); }; diff --git a/iModelCore/ECDb/Tests/NonPublished/InstanceReaderTest.cpp b/iModelCore/ECDb/Tests/NonPublished/InstanceReaderTest.cpp index 310000dc68c..dd6bb3d1bf1 100644 --- a/iModelCore/ECDb/Tests/NonPublished/InstanceReaderTest.cpp +++ b/iModelCore/ECDb/Tests/NonPublished/InstanceReaderTest.cpp @@ -1593,6 +1593,81 @@ TEST_F(InstanceReaderFixture, dynamic_meta_data) { } } +TEST_F(InstanceReaderFixture, ResetDynamicMetadata) { + ASSERT_EQ(SUCCESS, SetupECDb("ResetDynamicMetadata.ecdb", SchemaItem( + R"xml( + + + + A + + + + A + + + )xml"))); + + auto exec = [&](Utf8CP ecsql) { + ECSqlStatement stmt; + EXPECT_EQ(ECSqlStatus::Success, stmt.Prepare(m_ecdb, ecsql)); + EXPECT_EQ(BE_SQLITE_DONE, stmt.Step()); + m_ecdb.SaveChanges(); + }; + + auto assertDefault = [](ECSqlStatement& stmt, int cl, Utf8CP displayLabel, Utf8CP propertyName) { + ECSqlColumnInfo const* ci; + PrimitiveECPropertyCP pr; + Utf8CP className = "DynamicECSqlSelectClause"; + ci = &stmt.GetColumnInfo(cl); + EXPECT_TRUE(ci->IsDynamic()); + EXPECT_TRUE(ci->GetDataType().IsPrimitive()); + pr = ci->GetProperty()->GetAsPrimitiveProperty(); + EXPECT_FALSE(pr->HasId()); + EXPECT_EQ(PrimitiveType::PRIMITIVETYPE_String, pr->GetType()); + EXPECT_STRCASEEQ(className , pr->GetClass().GetName().c_str()); + EXPECT_STRCASEEQ(propertyName , pr->GetName().c_str()); + EXPECT_STRCASEEQ("" , pr->GetDescription().c_str()); + EXPECT_STRCASEEQ(displayLabel , pr->GetDisplayLabel().c_str()); + EXPECT_STRCASEEQ("json" , pr->GetExtendedTypeName().c_str()); + }; + + auto assertDynamic = [](ECSqlStatement& stmt, int cl, Utf8CP displayLabel, Utf8CP propertyName, Utf8CP description, Utf8CP className, PrimitiveType t) { + ECSqlColumnInfo const* ci; + PrimitiveECPropertyCP pr; + ci = &stmt.GetColumnInfo(cl); + EXPECT_TRUE(ci->IsDynamic()); + EXPECT_TRUE(ci->GetDataType().IsPrimitive()); + pr = ci->GetProperty()->GetAsPrimitiveProperty(); + EXPECT_TRUE(pr->HasId()); + EXPECT_EQ(t , pr->GetType()); + EXPECT_STRCASEEQ(className , pr->GetClass().GetName().c_str()); + EXPECT_STRCASEEQ(propertyName, pr->GetName().c_str()); + EXPECT_STRCASEEQ(description , pr->GetDescription().c_str()); + EXPECT_STRCASEEQ(displayLabel, pr->GetDisplayLabel().c_str()); + EXPECT_STRCASEEQ("" , pr->GetExtendedTypeName().c_str()); + }; + + exec("insert into ts.B ( ecInstanceId, B.prop ) values ( 10, 100 )"); + exec("insert into ts.C ( ecInstanceId, C.prop ) values ( 11, 101 )"); + + const auto sql = R"x( + select + $->prop + from ts.A + )x"; + + ECSqlStatement stmt; + ASSERT_EQ(ECSqlStatus::Success, stmt.Prepare(m_ecdb, sql)); + assertDefault(stmt, 0 , "$->prop", "__x0024____x002D____x003E__prop"); + ASSERT_EQ(BE_SQLITE_ROW, stmt.Step()); + assertDynamic(stmt, 0 , "prop", "prop", "", "B", PrimitiveType::PRIMITIVETYPE_Integer); + ASSERT_EQ(BE_SQLITE_ROW, stmt.Step()); + assertDynamic(stmt, 0 , "prop", "prop", "", "C", PrimitiveType::PRIMITIVETYPE_Double); + stmt.Reset(); + assertDefault(stmt, 0 , "$->prop", "__x0024____x002D____x003E__prop"); +} + //--------------------------------------------------------------------------------------- // @bsimethod //+---------------+---------------+---------------+---------------+---------------+------