Skip to content

Commit

Permalink
Merge branch 'main' into Sarunas/array-includes-nulls
Browse files Browse the repository at this point in the history
  • Loading branch information
6ar8nas authored Jul 15, 2024
2 parents 39c951a + febd217 commit a177a41
Show file tree
Hide file tree
Showing 13 changed files with 488 additions and 7 deletions.
12 changes: 10 additions & 2 deletions iModelCore/ECDb/CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,16 @@ This document including important changes to syntax or file format.

| Module | Version |
| ------- | --------- |
| Profile | `4.0.0.4` |
| ECSQL | `1.2.10.0` |
| Profile | `4.0.0.5` |
| ECSQL | `1.2.11.0` |

## `07/11/2024`: Add PRAGMA purge_orphan_relationships

* ECSql version change `1.2.10.0` -> `1.2.11.0`.
* Added new command `PRAGMA purge_orphan_relationships` which will delete all orphaned instances in link table relationship tables.
* The command requires neither any arguments nor any boolean assignments.
* The use of this command in ECSQL requires either enabling experimental features globally with PRAGMA or specifying `OPTIONS ENABLE_EXPERIMENTAL_FEATURES` in the ecsql.
* Example: `PRAGMA purge_orphan_relationships options enable_experimental_features`.

## `1/10/2024`: Add support for navigation value creation function

Expand Down
1 change: 1 addition & 0 deletions iModelCore/ECDb/ECDb/ECDbImpl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,7 @@ void ECDb::Impl::RegisterECSqlPragmas() const
GetPragmaManager().Register(PragmaIntegrityCheck::Create());
GetPragmaManager().Register(PragmaExperimentalFeatures::Create());
GetPragmaManager().Register(PragmaParseTree::Create());
GetPragmaManager().Register(PragmaPurgeOrphanRelationships::Create());
}

//--------------------------------------------------------------------------------------
Expand Down
70 changes: 70 additions & 0 deletions iModelCore/ECDb/ECDb/ECSql/ECSqlPragmas.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -729,5 +729,75 @@ DbResult PragmaIntegrityCheck::Write(PragmaManager::RowSet& rowSet, ECDbCR ecdb,
}


//=======================================================================================
// PurgeOrphanedRelationships
//=======================================================================================
//---------------------------------------------------------------------------------------
// @bsimethod
//---------------------------------------------------------------------------------------
DbResult PragmaPurgeOrphanRelationships::Read(PragmaManager::RowSet& rowSet, ECDbCR ecdb, const PragmaVal& val, PragmaManager::OptionsMap const& options)
{
if (!isExperimentalFeatureAllowed(ecdb, options))
{
ecdb.GetImpl().Issues().ReportV(IssueSeverity::Error, IssueCategory::BusinessProperties, IssueType::ECSQL, ECDbIssueId::ECDb_0729, "'PRAGMA %s' is an experimental feature and is disabled by default.", GetName().c_str());
return BE_SQLITE_ERROR;
}

rowSet = std::make_unique<StaticPragmaResult>(ecdb);
rowSet->FreezeSchemaChanges();

std::vector<ECClassId> rootRels;
if (const auto rc = IntegrityChecker(ecdb).GetRootLinkTableRelationships(rootRels); rc != BE_SQLITE_OK)
return rc;

for (const auto& relId : rootRels)
{
const auto classCP = ecdb.Schemas().GetClass(relId);
if (classCP == nullptr)
{
ecdb.GetImpl().Issues().ReportV(IssueSeverity::Error, IssueCategory::BusinessProperties, IssueType::ECSQL, ECDbIssueId::ECDb_0730, "Failed to find class with id '%s'.", relId.ToHexStr().c_str());
return BE_SQLITE_ERROR;
}

const auto relCP = classCP->GetRelationshipClassCP();
const auto relName = relCP->GetECSqlName().c_str();
const auto sourceClassName = relCP->GetSource().GetConstraintClasses().front()->GetECSqlName().c_str();
const auto targetClassName = relCP->GetTarget().GetConstraintClasses().front()->GetECSqlName().c_str();

const auto ecSqlQuery = R"sql(
delete from %s where ECInstanceId in
(select r.ECInstanceId from %s r left join %s s on r.SourceECInstanceId = s.ECInstanceId where s.ECInstanceId is null
union
select r.ECInstanceId from %s r left join %s t on r.TargetECInstanceId = t.ECInstanceId where t.ECInstanceId is null)
)sql";

ECSqlStatement stmt;
if (ECSqlStatus::Success != stmt.Prepare(ecdb, SqlPrintfString(ecSqlQuery, relName, relName, sourceClassName, relName, targetClassName).GetUtf8CP()))
{
ecdb.GetImpl().Issues().ReportV(IssueSeverity::Error, IssueCategory::BusinessProperties, IssueType::ECSQL, ECDbIssueId::ECDb_0731, "failed to prepared ecsql for nav prop integrity check");
return BE_SQLITE_ERROR;
}
if (stmt.Step() == BE_SQLITE_ERROR)
return BE_SQLITE_ERROR;
}
return BE_SQLITE_OK;
}

//---------------------------------------------------------------------------------------
// @bsimethod
//---------------------------------------------------------------------------------------
DbResult PragmaPurgeOrphanRelationships::Write(PragmaManager::RowSet& rowSet, ECDbCR ecdb, PragmaVal const&, PragmaManager::OptionsMap const& options)
{
if (!isExperimentalFeatureAllowed(ecdb, options))
{
ecdb.GetImpl().Issues().ReportV(IssueSeverity::Error, IssueCategory::BusinessProperties, IssueType::ECSQL, ECDbIssueId::ECDb_0732, "'PRAGMA %s' is an experimental feature and is disabled by default.", GetName().c_str());
return BE_SQLITE_ERROR;
}

ecdb.GetImpl().Issues().ReportV(IssueSeverity::Error, IssueCategory::BusinessProperties, IssueType::ECSQL, ECDbIssueId::ECDb_0733, "PRAGMA %s does not accept assignment arguments.", GetName().c_str());
return BE_SQLITE_ERROR;
}


END_BENTLEY_SQLITE_EC_NAMESPACE

12 changes: 12 additions & 0 deletions iModelCore/ECDb/ECDb/ECSql/ECSqlPragmas.h
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,18 @@ struct PragmaIntegrityCheck : PragmaManager::GlobalHandler {
static std::unique_ptr<PragmaManager::Handler> Create () { return std::make_unique<PragmaIntegrityCheck>(); }

};

//=======================================================================================
// @bsiclass
//+===============+===============+===============+===============+===============+======
struct PragmaPurgeOrphanRelationships : PragmaManager::GlobalHandler {
PragmaPurgeOrphanRelationships():GlobalHandler("purge_orphan_relationships","removes orphaned link-table relationships from ECDb"){}
~PragmaPurgeOrphanRelationships(){}
virtual DbResult Read(PragmaManager::RowSet&, ECDbCR, PragmaVal const&, PragmaManager::OptionsMap const&) override;
virtual DbResult Write(PragmaManager::RowSet&, ECDbCR, PragmaVal const&, PragmaManager::OptionsMap const&) override;
static std::unique_ptr<PragmaManager::Handler> Create () { return std::make_unique<PragmaPurgeOrphanRelationships>(); }
};

//=======================================================================================
// @bsiclass
//+===============+===============+===============+===============+===============+======
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ Utf8CP PragmaManager::Handler::GetTypeString() const {
BeJsValue StaticPragmaResult::AppendRow() {
BeMutexHolder lock(GetMutex());
if (GetColumnCount() ==0) {
throw std::runtime_error("now columns added");
throw std::runtime_error("no columns added");
}
return m_doc.appendArray();
}
Expand Down
2 changes: 1 addition & 1 deletion iModelCore/ECDb/ECDb/IntegrityChecker.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@ struct IntegrityChecker final {
bmap<Checks, Utf8CP> m_checkIdToName;

DbResult GetTablePerHierarchyClasses(std::vector<ECClassId>&);
DbResult GetRootLinkTableRelationships(std::vector<ECClassId>&);
DbResult GetNavigationProperties(std::map<ECN::ECClassId, std::vector<std::string>>&);
DbResult GetMappedClasses(std::set<ECN::ECClassId>&);

Expand Down Expand Up @@ -87,6 +86,7 @@ struct IntegrityChecker final {
DbResult CheckSchemaLoad(std::function<bool(Utf8CP)>);
// Callback(check-name, status)
DbResult QuickCheck(Checks, std::function<void(Utf8CP, bool, BeDuration)>);
DbResult GetRootLinkTableRelationships(std::vector<ECClassId>&);
};

END_BENTLEY_SQLITE_EC_NAMESPACE
5 changes: 5 additions & 0 deletions iModelCore/ECDb/ECDb/IssueReporter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -725,6 +725,11 @@ IssueId ECDbIssueId::ECDb_0725 = IssueId("ECDb_0725");
IssueId ECDbIssueId::ECDb_0726 = IssueId("ECDb_0726");
IssueId ECDbIssueId::ECDb_0727 = IssueId("ECDb_0727");
IssueId ECDbIssueId::ECDb_0728 = IssueId("ECDb_0728");
IssueId ECDbIssueId::ECDb_0729 = IssueId("ECDb_0729");
IssueId ECDbIssueId::ECDb_0730 = IssueId("ECDb_0730");
IssueId ECDbIssueId::ECDb_0731 = IssueId("ECDb_0731");
IssueId ECDbIssueId::ECDb_0732 = IssueId("ECDb_0732");
IssueId ECDbIssueId::ECDb_0733 = IssueId("ECDb_0733");

//---------------------------------------------------------------------------------------
// @bsimethod
Expand Down
5 changes: 5 additions & 0 deletions iModelCore/ECDb/ECDb/IssueReporter.h
Original file line number Diff line number Diff line change
Expand Up @@ -746,6 +746,11 @@ struct ECDB_EXPORT ECDbIssueId
static ECN::IssueId ECDb_0726;
static ECN::IssueId ECDb_0727;
static ECN::IssueId ECDb_0728;
static ECN::IssueId ECDb_0729;
static ECN::IssueId ECDb_0730;
static ECN::IssueId ECDb_0731;
static ECN::IssueId ECDb_0732;
static ECN::IssueId ECDb_0733;
};

//---------------------------------------------------------------------------------------
Expand Down
2 changes: 1 addition & 1 deletion iModelCore/ECDb/PublicAPI/ECDb/ECDb.h
Original file line number Diff line number Diff line change
Expand Up @@ -303,7 +303,7 @@ struct EXPORT_VTABLE_ATTRIBUTE ECDb : Db
// e.g. Remove a sql function or change required argument or format of its return value.
// Sub1: Backward compatible change to 'Syntax'. For example adding new syntax/functions but not breaking any existing.
// Sub2: Backward compatible change to 'Runtime'. For example adding a new sql function.
static BeVersion GetECSqlVersion() { return BeVersion(1, 2, 8, 1); }
static BeVersion GetECSqlVersion() { return BeVersion(1, 2, 11, 0); }

//! Gets the current version of the ECDb profile
static ProfileVersion CurrentECDbProfileVersion() { return ProfileVersion(4, 0, 0, 5); }
Expand Down
2 changes: 1 addition & 1 deletion iModelCore/ECDb/Tests/NonPublished/ECDbTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -688,7 +688,7 @@ TEST_F(ECDbTestFixture, GetAndChangeGUIDForDb)
//+---------------+---------------+---------------+---------------+---------------+------
TEST_F(ECDbTestFixture, CurrentECSqlVersion)
{
BeVersion expectedVersion (1, 2, 8, 1);
BeVersion expectedVersion (1, 2, 11, 0);
ASSERT_EQ(ECDb::GetECSqlVersion(), expectedVersion);
}

Expand Down
Loading

0 comments on commit a177a41

Please sign in to comment.