diff --git a/core/cmdbobject.class.inc.php b/core/cmdbobject.class.inc.php index 9de22620a..d7a62dc8e 100644 --- a/core/cmdbobject.class.inc.php +++ b/core/cmdbobject.class.inc.php @@ -162,6 +162,21 @@ abstract class CMDBObject extends DBObject protected function RecordObjCreation() { + // Delete any existing change tracking about the current object (IDs can be reused due to InnoDb bug; see TRAC #886) + // + // 1 - remove the deletion record(s) + // Note that objclass contain the ROOT class + $oFilter = new DBObjectSearch('CMDBChangeOpDelete'); + $oFilter->AddCondition('objclass', MetaModel::GetRootClass(get_class($this)), '='); + $oFilter->AddCondition('objkey', $this->GetKey(), '='); + MetaModel::PurgeData($oFilter); + // 2 - any other change tracking information left prior to 2.0.3 (when the purge of the history has been implemented in RecordObjDeletion + // In that case, objclass is the final class of the object + $oFilter = new DBObjectSearch('CMDBChangeOp'); + $oFilter->AddCondition('objclass', get_class($this), '='); + $oFilter->AddCondition('objkey', $this->GetKey(), '='); + MetaModel::PurgeData($oFilter); + parent::RecordObjCreation(); $oMyChangeOp = MetaModel::NewObject("CMDBChangeOpCreate"); $oMyChangeOp->Set("objclass", get_class($this)); @@ -171,6 +186,14 @@ abstract class CMDBObject extends DBObject protected function RecordObjDeletion($objkey) { + $sRootClass = MetaModel::GetRootClass(get_class($this)); + + // Delete any existing change tracking about the current object + $oFilter = new DBObjectSearch('CMDBChangeOp'); + $oFilter->AddCondition('objclass', get_class($this), '='); + $oFilter->AddCondition('objkey', $objkey, '='); + MetaModel::PurgeData($oFilter); + parent::RecordObjDeletion($objkey); $oMyChangeOp = MetaModel::NewObject("CMDBChangeOpDelete"); $oMyChangeOp->Set("objclass", MetaModel::GetRootClass(get_class($this))); diff --git a/core/metamodel.class.php b/core/metamodel.class.php index 6dfe213e4..00252e922 100644 --- a/core/metamodel.class.php +++ b/core/metamodel.class.php @@ -5087,6 +5087,41 @@ abstract class MetaModel } } + /** + * Helper to remove selected objects without calling any handler + * Surpasses BulkDelete as it can handle abstract classes, but has the other limitation as it bypasses standard objects handlers + * + * @param string $oFilter Scope of objects to wipe out + * @return The count of deleted objects + */ + public static function PurgeData($oFilter) + { + $sTargetClass = $oFilter->GetClass(); + $oSet = new DBObjectSet($oFilter); + $oSet->OptimizeColumnLoad(array($sTargetClass => array('finalclass'))); + $aIdToClass = $oSet->GetColumnAsArray('finalclass', true); + + $aIds = array_keys($aIdToClass); + if (count($aIds) > 0) + { + $aQuotedIds = CMDBSource::Quote($aIds); + $sIdList = implode(',', $aQuotedIds); + $aTargetClasses = array_merge( + self::EnumChildClasses($sTargetClass, ENUM_CHILD_CLASSES_ALL), + self::EnumParentClasses($sTargetClass, ENUM_PARENT_CLASSES_EXCLUDELEAF) + ); + foreach ($aTargetClasses as $sSomeClass) + { + $sTable = MetaModel::DBGetTable($sSomeClass); + $sPKField = MetaModel::DBGetKey($sSomeClass); + + $sDeleteSQL = "DELETE FROM `$sTable` WHERE `$sPKField` IN ($sIdList)"; + CMDBSource::DeleteFrom($sDeleteSQL); + } + } + return count($aIds); + } + // Links // //