//***************************************************************************** // Driver for the delta process. //***************************************************************************** __checkReturn HRESULT CMiniMdRW::ApplyDelta( CMiniMdRW &mdDelta) // Interface to MD with the ENC delta. { HRESULT hr = S_OK; ULONG iENC; // Loop control. ULONG iRid; // RID of some record. ULONG iNew; // RID of a new record. int i; // Loop control. ULONG ixTbl; // A table. #ifdef _DEBUG if (CLRConfig::GetConfigValue(CLRConfig::INTERNAL_MD_ApplyDeltaBreak)) { _ASSERTE(!"CMiniMDRW::ApplyDelta()"); } #endif // _DEBUG // Init the suppressed column table. We know this one isn't zero... if (m_SuppressedDeltaColumns[TBL_TypeDef] == 0) { m_SuppressedDeltaColumns[TBL_EventMap] = (1 << EventMapRec::COL_EventList); m_SuppressedDeltaColumns[TBL_PropertyMap] = (1 << PropertyMapRec::COL_PropertyList); m_SuppressedDeltaColumns[TBL_EventMap] = (1 << EventMapRec::COL_EventList); m_SuppressedDeltaColumns[TBL_Method] = (1 << MethodRec::COL_ParamList); m_SuppressedDeltaColumns[TBL_TypeDef] = (1 << TypeDefRec::COL_FieldList)|(1<<TypeDefRec::COL_MethodList); } // Verify the version of the MD. if (m_Schema.m_major != mdDelta.m_Schema.m_major || m_Schema.m_minor != mdDelta.m_Schema.m_minor) { _ASSERTE(!"Version of Delta MetaData is a incompatible with current MetaData."); //<TODO>@FUTURE: unique error in the future since we are not shipping ENC.</TODO> return E_INVALIDARG; } // verify MVIDs. ModuleRec *pModDelta; ModuleRec *pModBase; IfFailGo(mdDelta.GetModuleRecord(1, &pModDelta)); IfFailGo(GetModuleRecord(1, &pModBase)); GUID GuidDelta; GUID GuidBase; IfFailGo(mdDelta.getMvidOfModule(pModDelta, &GuidDelta)); IfFailGo(getMvidOfModule(pModBase, &GuidBase)); if (CLRConfig::GetConfigValue(CLRConfig::INTERNAL_MD_DeltaCheck) && (GuidDelta != GuidBase)) { _ASSERTE(!"Delta MetaData has different base than current MetaData."); return E_INVALIDARG; } #ifndef FEATURE_CORECLR // Verify that the delta is based on the base. IfFailGo(mdDelta.getEncBaseIdOfModule(pModDelta, &GuidDelta)); IfFailGo(getEncBaseIdOfModule(pModBase,&GuidBase)); if (CLRConfig::GetConfigValue(CLRConfig::INTERNAL_MD_DeltaCheck) && CLRConfig::GetConfigValue(CLRConfig::INTERNAL_MD_UseMinimalDeltas) && (GuidDelta != GuidBase)) { _ASSERTE(!"The Delta MetaData is based on a different generation than the current MetaData."); return E_INVALIDARG; } #endif //!FEATURE_CORECLR // Let the other md prepare for sparse records. IfFailGo(mdDelta.StartENCMap()); // Fix the heaps. IfFailGo(ApplyHeapDeltas(mdDelta)); // Truncate some tables in preparation to copy in new ENCLog data. for (i = 0; (ixTbl = m_TruncatedEncTables[i]) != (ULONG)-1; ++i) { m_Tables[ixTbl].Delete(); IfFailGo(m_Tables[ixTbl].InitializeEmpty_WithRecordCount( m_TableDefs[ixTbl].m_cbRec, mdDelta.m_Schema.m_cRecs[ixTbl] COMMA_INDEBUG_MD(TRUE))); // fIsReadWrite INDEBUG_MD(m_Tables[ixTbl].Debug_SetTableInfo(NULL, ixTbl)); m_Schema.m_cRecs[ixTbl] = 0; } // For each record in the ENC log... for (iENC = 1; iENC <= mdDelta.m_Schema.m_cRecs[TBL_ENCLog]; ++iENC) { // Get the record, and the updated token. ENCLogRec *pENC; IfFailGo(mdDelta.GetENCLogRecord(iENC, &pENC)); ENCLogRec *pENC2; IfFailGo(AddENCLogRecord(&pENC2, &iNew)); IfNullGo(pENC2); ENCLogRec *pENC3; _ASSERTE(iNew == iENC); ULONG func = pENC->GetFuncCode(); pENC2->SetFuncCode(pENC->GetFuncCode()); pENC2->SetToken(pENC->GetToken()); // What kind of record is this? if (IsRecId(pENC->GetToken())) { // Non-token table iRid = RidFromRecId(pENC->GetToken()); ixTbl = TblFromRecId(pENC->GetToken()); } else { // Token table. iRid = RidFromToken(pENC->GetToken()); ixTbl = GetTableForToken(pENC->GetToken()); } RID rid_Ignore; // Switch based on the function code. switch (func) { case eDeltaMethodCreate: // Next ENC record will define the new Method. MethodRec *pMethodRecord; IfFailGo(AddMethodRecord(&pMethodRecord, &rid_Ignore)); IfFailGo(AddMethodToTypeDef(iRid, m_Schema.m_cRecs[TBL_Method])); break; case eDeltaParamCreate: // Next ENC record will define the new Param. This record is // tricky because params will be re-ordered based on their sequence, // but the sequence isn't set until the NEXT record is applied. // So, for ParamCreate only, apply the param record delta before // adding the parent-child linkage. ParamRec *pParamRecord; IfFailGo(AddParamRecord(&pParamRecord, &rid_Ignore)); // Should have recorded a Param delta after the Param add. _ASSERTE(iENC<mdDelta.m_Schema.m_cRecs[TBL_ENCLog]); IfFailGo(mdDelta.GetENCLogRecord(iENC+1, &pENC3)); _ASSERTE(pENC3->GetFuncCode() == 0); _ASSERTE(GetTableForToken(pENC3->GetToken()) == TBL_Param); IfFailGo(ApplyTableDelta(mdDelta, TBL_Param, RidFromToken(pENC3->GetToken()), eDeltaFuncDefault)); // Now that Param record is OK, set up linkage. IfFailGo(AddParamToMethod(iRid, m_Schema.m_cRecs[TBL_Param])); break; case eDeltaFieldCreate: // Next ENC record will define the new Field. FieldRec *pFieldRecord; IfFailGo(AddFieldRecord(&pFieldRecord, &rid_Ignore)); IfFailGo(AddFieldToTypeDef(iRid, m_Schema.m_cRecs[TBL_Field])); break; case eDeltaPropertyCreate: // Next ENC record will define the new Property. PropertyRec *pPropertyRecord; IfFailGo(AddPropertyRecord(&pPropertyRecord, &rid_Ignore)); IfFailGo(AddPropertyToPropertyMap(iRid, m_Schema.m_cRecs[TBL_Property])); break; case eDeltaEventCreate: // Next ENC record will define the new Event. EventRec *pEventRecord; IfFailGo(AddEventRecord(&pEventRecord, &rid_Ignore)); IfFailGo(AddEventToEventMap(iRid, m_Schema.m_cRecs[TBL_Event])); break; case eDeltaFuncDefault: IfFailGo(ApplyTableDelta(mdDelta, ixTbl, iRid, func)); break; default: _ASSERTE(!"Unexpected function in ApplyDelta"); IfFailGo(E_UNEXPECTED); break; } } m_Schema.m_cRecs[TBL_ENCLog] = mdDelta.m_Schema.m_cRecs[TBL_ENCLog]; ErrExit: // Store the result for returning (IfFailRet will modify hr) HRESULT hrReturn = hr; IfFailRet(mdDelta.EndENCMap()); #ifndef FEATURE_CORECLR if (SUCCEEDED(hrReturn) && CLRConfig::GetConfigValue(CLRConfig::INTERNAL_MD_DeltaCheck) && CLRConfig::GetConfigValue(CLRConfig::INTERNAL_MD_UseMinimalDeltas)) { GUID GuidNewBase; // We'll use the delta's 'delta guid' for our new base guid IfFailRet(mdDelta.getEncIdOfModule(pModDelta, &GuidNewBase)); IfFailRet(PutGuid(TBL_Module, ModuleRec::COL_EncBaseId, pModBase, GuidNewBase)); } #endif //!FEATURE_CORECLR return hrReturn; } // CMiniMdRW::ApplyDelta