Code:
/ Dotnetfx_Win7_3.5.1 / Dotnetfx_Win7_3.5.1 / 3.5.1 / DEVDIV / depot / DevDiv / releases / Orcas / NetFXw7 / ndp / fx / src / DataEntity / System / Data / Map / Update / Internal / Propagator.JoinPropagator.cs / 1 / Propagator.JoinPropagator.cs
//---------------------------------------------------------------------- //// Copyright (c) Microsoft Corporation. All rights reserved. // // // @owner [....] // @backupOwner [....] //--------------------------------------------------------------------- using System.Data.Common.CommandTrees; using System.Collections.Generic; using System.Data.Common.Utils; using System.Diagnostics; using System.Data.Metadata.Edm; namespace System.Data.Mapping.Update.Internal { internal partial class Propagator { ////// Performs join propagation. The basic strategy is to identify changes (inserts, deletes) /// on either side of the join that are related according to the join criteria. Support is restricted /// to conjunctions of equality predicates of the form ///left property == right property . /// When a group of related changes is identified, rules are applied based on the existence of /// different components (e.g., a left insert + right insert). ////// The joins handled by this class are degenerate in the sense that a row in the 'left' input always /// joins with at most one row in the 'right' input. The restrictions that allow for this assumption /// are described in the update design spec (see 'Level 5 Optimization'). /// ////// Propagation rules for joins are stored in static fields of the class (initialized in the static /// constructor for the class). /// private partial class JoinPropagator { #region Constructors ////// Constructs a join propagator. /// /// Result of propagating changes in the left input to the join /// Result of propagating changes in the right input to the join /// Join operator in update mapping view over which to propagate changes /// Handler of propagation for the entire update mapping view internal JoinPropagator(ChangeNode left, ChangeNode right, DbJoinExpression node, Propagator parent) { EntityUtil.CheckArgumentNull(left, "left"); EntityUtil.CheckArgumentNull(right, "right"); EntityUtil.CheckArgumentNull(node, "node"); EntityUtil.CheckArgumentNull(parent, "parent"); Debug.Assert(DbExpressionKind.LeftOuterJoin == node.ExpressionKind || DbExpressionKind.InnerJoin == node.ExpressionKind, "(Update/JoinPropagagtor/JoinEvaluator) " + "caller must ensure only left outer and inner joins are requested"); m_joinExpression = node; m_left = left; m_right = right; m_parent = parent; Initialize(); } #endregion #region Fields #region Propagation rules /** * These static dictionaries are initialized by the static constructor for this class. * They describe for each combination of input elements (the key) propagation rules, which * are expressions over the input expressions. * */ private static Dictionarys_innerJoinInsertRules; private static Dictionary s_innerJoinDeleteRules; private static Dictionary s_leftOuterJoinInsertRules; private static Dictionary s_leftOuterJoinDeleteRules; private static bool s_rulesInitialized; private static object s_initializeRulesLockObject = new object(); #endregion private DbExpression[] m_leftProperties; private DbExpression[] m_rightProperties; private Dictionary m_leftInserts; private Dictionary m_leftDeletes; private Dictionary m_rightInserts; private Dictionary m_rightDeletes; private Set m_allKeys; private DbJoinExpression m_joinExpression; private ChangeNode m_left; private ChangeNode m_right; private Propagator m_parent; private Dictionary m_insertRules; private Dictionary m_deleteRules; private Dictionary m_leftKeyMap; private Dictionary m_rightKeyMap; #endregion #region Methods /// /// Initialize rules. /// private static void InitializeRules() { s_innerJoinInsertRules = new Dictionary(EqualityComparer .Default); s_innerJoinDeleteRules = new Dictionary (EqualityComparer .Default); s_leftOuterJoinInsertRules = new Dictionary (EqualityComparer .Default); s_leftOuterJoinDeleteRules = new Dictionary (EqualityComparer .Default); #region Initialize propagation rules // InitializeRule(Ops.LeftUpdate | Ops.RightUpdate, Ops.LeftInsertJoinRightInsert, Ops.LeftDeleteJoinRightDelete, Ops.LeftInsertJoinRightInsert, Ops.LeftDeleteJoinRightDelete); InitializeRule(Ops.LeftDelete | Ops.RightDelete, Ops.Nothing, Ops.LeftDeleteJoinRightDelete, Ops.Nothing, Ops.LeftDeleteJoinRightDelete); InitializeRule(Ops.LeftInsert | Ops.RightInsert, Ops.LeftInsertJoinRightInsert, Ops.Nothing, Ops.LeftInsertJoinRightInsert, Ops.Nothing); InitializeRule(Ops.LeftUpdate, Ops.LeftInsertUnknownExtended, Ops.LeftDeleteUnknownExtended, Ops.LeftInsertUnknownExtended, Ops.LeftDeleteUnknownExtended); InitializeRule(Ops.RightUpdate, Ops.RightInsertUnknownExtended, Ops.RightDeleteUnknownExtended, Ops.RightInsertUnknownExtended, Ops.RightDeleteUnknownExtended); InitializeRule(Ops.LeftUpdate | Ops.RightDelete, Ops.Nothing, Ops.Nothing, Ops.LeftInsertNullModifiedExtended, Ops.LeftDeleteJoinRightDelete); InitializeRule(Ops.LeftUpdate | Ops.RightInsert, Ops.Nothing, Ops.Nothing, Ops.LeftInsertJoinRightInsert, Ops.LeftDeleteNullModifiedExtended); InitializeRule(Ops.LeftDelete, Ops.Nothing, Ops.Nothing, Ops.Nothing, Ops.LeftDeleteNullPreserveExtended); InitializeRule(Ops.LeftInsert, Ops.Nothing, Ops.Nothing, Ops.LeftInsertNullModifiedExtended, Ops.Nothing); InitializeRule(Ops.RightDelete, Ops.Nothing, Ops.Nothing, Ops.LeftUnknownNullModifiedExtended, Ops.RightDeleteUnknownExtended); InitializeRule(Ops.RightInsert, Ops.Nothing, Ops.Nothing, Ops.RightInsertUnknownExtended, Ops.LeftUnknownNullModifiedExtended); InitializeRule(Ops.LeftDelete | Ops.RightUpdate, Ops.Nothing, Ops.Nothing, Ops.Nothing, Ops.Nothing); InitializeRule(Ops.LeftDelete | Ops.RightInsert, Ops.Nothing, Ops.Nothing, Ops.Nothing, Ops.Nothing); InitializeRule(Ops.LeftInsert | Ops.RightUpdate, Ops.Nothing, Ops.Nothing, Ops.Nothing, Ops.Nothing); InitializeRule(Ops.LeftInsert | Ops.RightDelete, Ops.Nothing, Ops.Nothing, Ops.Nothing, Ops.Nothing); #endregion } /// /// Initializes propagation rules for a specific input combination. /// /// Describes the elements available in the input /// Describes the rule for inserts when the operator is an inner join /// Describes the rule for deletes when the operator is an inner join /// Describes the rule for inserts when the operator is a left outer join /// Describes the rule for deletes when the operator is a left outer join private static void InitializeRule(Ops input, Ops joinInsert, Ops joinDelete, Ops lojInsert, Ops lojDelete) { s_innerJoinInsertRules.Add(input, joinInsert); s_innerJoinDeleteRules.Add(input, joinDelete); s_leftOuterJoinInsertRules.Add(input, lojInsert); s_leftOuterJoinDeleteRules.Add(input, lojDelete); // Ensure that the right hand side of each rule contains no requests for specific row values // that are not also in the input. Debug.Assert((((joinInsert | joinDelete | lojInsert | lojDelete) & (Ops.LeftInsert | Ops.LeftDelete | Ops.RightInsert | Ops.RightDelete)) & (~input)) == Ops.Nothing, "(Update/JoinPropagator/Initialization) Rules can't use unavailable data"); // An unknown value can appear in both the delete and insert rule result or neither. Debug.Assert(((joinInsert ^ joinDelete) & (Ops.LeftUnknown | Ops.RightUnknown)) == Ops.Nothing && ((lojInsert ^ lojDelete) & (Ops.LeftUnknown | Ops.RightUnknown)) == Ops.Nothing, "(Update/JoinPropagator/Initialization) Unknowns must appear in both delete and insert rules " + "or in neither (in other words, for updates only)"); } ////// Determines locations of join key components in /// Empty record used for null/unknown extensions in propagation /// rules /// Expressions describing the location of join key properties. ///. /// Map from expressions in the placeholder to join key ordinals. private DictionaryGetKeyMap(PropagatorResult placeholder, DbExpression[] properties) { Dictionary map = new Dictionary (); for (int i = 0; i < properties.Length; i++) { // Determine the position of the key property in the placeholder DbExpression keyProperty = properties[i]; PropagatorResult locationInPlaceholder = Evaluator.Evaluate(keyProperty, placeholder, m_parent); Debug.Assert(locationInPlaceholder.IsSimple, "key values must be simple constants"); map[locationInPlaceholder] = i; } return map; } /// /// Performs join propagation. /// ///Changes propagated to the current join node in the update mapping view. internal ChangeNode ExecutePropagation() { // Construct an empty change node for the result ChangeNode result = Propagator.BuildChangeNode(m_joinExpression); // Perform propagation one key at a time foreach (CompositeKey key in m_allKeys) { Propagate(key, result); } // Construct a new placeholder (see ChangeNode.Placeholder) for the join result node. result.Placeholder = Join(m_left.Placeholder, m_right.Placeholder, result); return result; } ////// Joins rows that are related. /// /// Left row. /// Right row. /// Result change node; used for type information. ///Result of joining the input rows. private static PropagatorResult Join(PropagatorResult left, PropagatorResult right, ChangeNode result) { PropagatorResult[] joinRecordValues = new PropagatorResult[2]; joinRecordValues[0] = left; joinRecordValues[1] = right; PropagatorResult join = PropagatorResult.CreateStructuralValue(joinRecordValues, (StructuralType)result.ElementType.EdmType, false); return join; } ////// Propagate all changes associated with a particular join key. /// /// Key. /// Resulting changes are added to this result. private void Propagate(CompositeKey key, ChangeNode result) { // Retrieve changes associates with this join key PropagatorResult leftInsert = null; PropagatorResult leftDelete = null; PropagatorResult rightInsert = null; PropagatorResult rightDelete = null; Ops input = Ops.Nothing; if (m_leftInserts.TryGetValue(key, out leftInsert)) { input |= Ops.LeftInsert; } if (m_leftDeletes.TryGetValue(key, out leftDelete)) { input |= Ops.LeftDelete; } if (m_rightInserts.TryGetValue(key, out rightInsert)) { input |= Ops.RightInsert; } if (m_rightDeletes.TryGetValue(key, out rightDelete)) { input |= Ops.RightDelete; } // Get propagation rules for the changes Ops insertRule = m_insertRules[input]; Ops deleteRule = m_deleteRules[input]; if (Ops.Unsupported == insertRule || Ops.Unsupported == deleteRule) { Debug.Fail("no propagation rules specify unsupported"); throw EntityUtil.NotSupported(); } // Where needed, substitute null/unknown placeholders. In some of the join propagation // rules, we handle the case where a side of the join is 'unknown', or where one side // of a join is comprised of an record containing only nulls. For instance, we may update // only one extent appearing in a row of a table (unknown), or; we may insert only // the left hand side of a left outer join, in which case the right hand side is 'null'. if (0 != (Ops.LeftUnknown & insertRule)) { leftInsert = LeftPlaceholder(key, PopulateMode.Unknown); } if (0 != (Ops.LeftUnknown & deleteRule)) { leftDelete = LeftPlaceholder(key, PopulateMode.Unknown); } if (0 != (Ops.RightNullModified & insertRule)) { rightInsert = RightPlaceholder(key, PopulateMode.NullModified); } else if (0 != (Ops.RightNullPreserve & insertRule)) { rightInsert = RightPlaceholder(key, PopulateMode.NullPreserve); } else if (0 != (Ops.RightUnknown & insertRule)) { rightInsert = RightPlaceholder(key, PopulateMode.Unknown); } if (0 != (Ops.RightNullModified & deleteRule)) { rightDelete = RightPlaceholder(key, PopulateMode.NullModified); } else if (0 != (Ops.RightNullPreserve & deleteRule)) { rightDelete = RightPlaceholder(key, PopulateMode.NullPreserve); } else if (0 != (Ops.RightUnknown & deleteRule)) { rightDelete = RightPlaceholder(key, PopulateMode.Unknown); } if (null != leftInsert && null != rightInsert) { result.Inserted.Add(Join(leftInsert, rightInsert, result)); } if (null != leftDelete && null != leftDelete) { result.Deleted.Add(Join(leftDelete, rightDelete, result)); } } ////// Constructs a new placeholder record for the left hand side of the join. Values taken /// from the join key are injected into the record. /// /// Key producing the left hand side. /// Mode used to populate the placeholder ///Record corresponding to the type of the left input to the join. Each value in /// the record is flagged as private PropagatorResult LeftPlaceholder(CompositeKey key, PopulateMode mode) { return PlaceholderPopulator.Populate(m_left.Placeholder, key, m_leftKeyMap, mode, m_parent.UpdateTranslator); } ///except when it is /// a component of the key. /// See /// /// ////// private PropagatorResult RightPlaceholder(CompositeKey key, PopulateMode mode) { return PlaceholderPopulator.Populate(m_right.Placeholder, key, m_rightKeyMap, mode, m_parent.UpdateTranslator); } /// /// Initialize all structures. /// private void Initialize() { // Check that static rule definitions have been initialized lock (s_initializeRulesLockObject) { if (!s_rulesInitialized) { InitializeRules(); s_rulesInitialized = true; } } // Extract join key properties from the left and right sides of the join JoinPredicateVisitor.ExtractEquijoinProperties(m_joinExpression.JoinCondition, out m_leftProperties, out m_rightProperties); // Initialize key maps, which map from expressions in the placeholders for the join inputs to // ordinals in the join key. See ChangeNode.Placeholder and HashJoinKey for additional context. m_leftKeyMap = GetKeyMap(m_left.Placeholder, m_leftProperties); m_rightKeyMap = GetKeyMap(m_right.Placeholder, m_rightProperties); // Retrieve propagation rules for the join type of the expression. if (DbExpressionKind.InnerJoin == m_joinExpression.ExpressionKind) { m_insertRules = s_innerJoinInsertRules; m_deleteRules = s_innerJoinDeleteRules; } else { m_insertRules = s_leftOuterJoinInsertRules; m_deleteRules = s_leftOuterJoinDeleteRules; } // Determine key values for keys in the insert and delete sets from the left and right hand sides // of the join input. Also construct a set of all keys. m_allKeys = new Set(m_parent.UpdateTranslator.KeyComparer); m_leftInserts = ProcessKeys(m_left.Inserted, m_leftProperties); m_leftDeletes = ProcessKeys(m_left.Deleted, m_leftProperties); m_rightInserts = ProcessKeys(m_right.Inserted, m_rightProperties); m_rightDeletes = ProcessKeys(m_right.Deleted, m_rightProperties); } /// /// Produces a hash table of all instances and processes join keys, adding them to the list /// of keys handled by this node. /// /// List of instances (whether delete or insert) for this node. /// Properties of an instance that constitute the join key. ///A map from join keys to instances. private DictionaryProcessKeys(IEnumerable instances, DbExpression[] properties) { Dictionary hash = new Dictionary ( m_parent.UpdateTranslator.KeyComparer); foreach (PropagatorResult instance in instances) { CompositeKey key = new CompositeKey(GetKeyConstants(instance, properties)); // check if this key has been added already (if not, add it) if (!m_allKeys.Contains(key)) { m_allKeys.Add(key); } hash[key] = instance; } return hash; } // extracts key values from row expression private PropagatorResult[] GetKeyConstants(PropagatorResult change, DbExpression[] properties) { Debug.Assert(null != change && null != properties); PropagatorResult[] keyConstants = new PropagatorResult[properties.Length]; for (int i = 0; i < properties.Length; i++) { PropagatorResult constant = Evaluator.Evaluate(properties[i], change, m_parent); keyConstants[i] = constant; } return keyConstants; } #endregion #region Nested types /// /// Flags indicating which change elements are available (0-4) and propagation /// rules (0, 5-512) /// [Flags] enum Ops : uint { Nothing = 0, LeftInsert = 1, LeftDelete = 2, RightInsert = 4, RightDelete = 8, LeftUnknown = 32, RightNullModified = 128, RightNullPreserve = 256, RightUnknown = 512, LeftUpdate = LeftInsert | LeftDelete, RightUpdate = RightInsert | RightDelete, Unsupported = 4096, #region Propagation rule descriptions LeftInsertJoinRightInsert = LeftInsert | RightInsert, LeftDeleteJoinRightDelete = LeftDelete | RightDelete, LeftInsertNullModifiedExtended = LeftInsert | RightNullModified, LeftInsertNullPreserveExtended = LeftInsert | RightNullPreserve, LeftInsertUnknownExtended = LeftInsert | RightUnknown, LeftDeleteNullModifiedExtended = LeftDelete | RightNullModified, LeftDeleteNullPreserveExtended = LeftDelete | RightNullPreserve, LeftDeleteUnknownExtended = LeftDelete | RightUnknown, LeftUnknownNullModifiedExtended = LeftUnknown | RightNullModified, LeftUnknownNullPreserveExtended = LeftUnknown | RightNullPreserve, RightInsertUnknownExtended = LeftUnknown | RightInsert, RightDeleteUnknownExtended = LeftUnknown | RightDelete, #endregion } #endregion } } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. //---------------------------------------------------------------------- //// Copyright (c) Microsoft Corporation. All rights reserved. // // // @owner [....] // @backupOwner [....] //--------------------------------------------------------------------- using System.Data.Common.CommandTrees; using System.Collections.Generic; using System.Data.Common.Utils; using System.Diagnostics; using System.Data.Metadata.Edm; namespace System.Data.Mapping.Update.Internal { internal partial class Propagator { ////// Performs join propagation. The basic strategy is to identify changes (inserts, deletes) /// on either side of the join that are related according to the join criteria. Support is restricted /// to conjunctions of equality predicates of the form ///left property == right property . /// When a group of related changes is identified, rules are applied based on the existence of /// different components (e.g., a left insert + right insert). ////// The joins handled by this class are degenerate in the sense that a row in the 'left' input always /// joins with at most one row in the 'right' input. The restrictions that allow for this assumption /// are described in the update design spec (see 'Level 5 Optimization'). /// ////// Propagation rules for joins are stored in static fields of the class (initialized in the static /// constructor for the class). /// private partial class JoinPropagator { #region Constructors ////// Constructs a join propagator. /// /// Result of propagating changes in the left input to the join /// Result of propagating changes in the right input to the join /// Join operator in update mapping view over which to propagate changes /// Handler of propagation for the entire update mapping view internal JoinPropagator(ChangeNode left, ChangeNode right, DbJoinExpression node, Propagator parent) { EntityUtil.CheckArgumentNull(left, "left"); EntityUtil.CheckArgumentNull(right, "right"); EntityUtil.CheckArgumentNull(node, "node"); EntityUtil.CheckArgumentNull(parent, "parent"); Debug.Assert(DbExpressionKind.LeftOuterJoin == node.ExpressionKind || DbExpressionKind.InnerJoin == node.ExpressionKind, "(Update/JoinPropagagtor/JoinEvaluator) " + "caller must ensure only left outer and inner joins are requested"); m_joinExpression = node; m_left = left; m_right = right; m_parent = parent; Initialize(); } #endregion #region Fields #region Propagation rules /** * These static dictionaries are initialized by the static constructor for this class. * They describe for each combination of input elements (the key) propagation rules, which * are expressions over the input expressions. * */ private static Dictionarys_innerJoinInsertRules; private static Dictionary s_innerJoinDeleteRules; private static Dictionary s_leftOuterJoinInsertRules; private static Dictionary s_leftOuterJoinDeleteRules; private static bool s_rulesInitialized; private static object s_initializeRulesLockObject = new object(); #endregion private DbExpression[] m_leftProperties; private DbExpression[] m_rightProperties; private Dictionary m_leftInserts; private Dictionary m_leftDeletes; private Dictionary m_rightInserts; private Dictionary m_rightDeletes; private Set m_allKeys; private DbJoinExpression m_joinExpression; private ChangeNode m_left; private ChangeNode m_right; private Propagator m_parent; private Dictionary m_insertRules; private Dictionary m_deleteRules; private Dictionary m_leftKeyMap; private Dictionary m_rightKeyMap; #endregion #region Methods /// /// Initialize rules. /// private static void InitializeRules() { s_innerJoinInsertRules = new Dictionary(EqualityComparer .Default); s_innerJoinDeleteRules = new Dictionary (EqualityComparer .Default); s_leftOuterJoinInsertRules = new Dictionary (EqualityComparer .Default); s_leftOuterJoinDeleteRules = new Dictionary (EqualityComparer .Default); #region Initialize propagation rules // InitializeRule(Ops.LeftUpdate | Ops.RightUpdate, Ops.LeftInsertJoinRightInsert, Ops.LeftDeleteJoinRightDelete, Ops.LeftInsertJoinRightInsert, Ops.LeftDeleteJoinRightDelete); InitializeRule(Ops.LeftDelete | Ops.RightDelete, Ops.Nothing, Ops.LeftDeleteJoinRightDelete, Ops.Nothing, Ops.LeftDeleteJoinRightDelete); InitializeRule(Ops.LeftInsert | Ops.RightInsert, Ops.LeftInsertJoinRightInsert, Ops.Nothing, Ops.LeftInsertJoinRightInsert, Ops.Nothing); InitializeRule(Ops.LeftUpdate, Ops.LeftInsertUnknownExtended, Ops.LeftDeleteUnknownExtended, Ops.LeftInsertUnknownExtended, Ops.LeftDeleteUnknownExtended); InitializeRule(Ops.RightUpdate, Ops.RightInsertUnknownExtended, Ops.RightDeleteUnknownExtended, Ops.RightInsertUnknownExtended, Ops.RightDeleteUnknownExtended); InitializeRule(Ops.LeftUpdate | Ops.RightDelete, Ops.Nothing, Ops.Nothing, Ops.LeftInsertNullModifiedExtended, Ops.LeftDeleteJoinRightDelete); InitializeRule(Ops.LeftUpdate | Ops.RightInsert, Ops.Nothing, Ops.Nothing, Ops.LeftInsertJoinRightInsert, Ops.LeftDeleteNullModifiedExtended); InitializeRule(Ops.LeftDelete, Ops.Nothing, Ops.Nothing, Ops.Nothing, Ops.LeftDeleteNullPreserveExtended); InitializeRule(Ops.LeftInsert, Ops.Nothing, Ops.Nothing, Ops.LeftInsertNullModifiedExtended, Ops.Nothing); InitializeRule(Ops.RightDelete, Ops.Nothing, Ops.Nothing, Ops.LeftUnknownNullModifiedExtended, Ops.RightDeleteUnknownExtended); InitializeRule(Ops.RightInsert, Ops.Nothing, Ops.Nothing, Ops.RightInsertUnknownExtended, Ops.LeftUnknownNullModifiedExtended); InitializeRule(Ops.LeftDelete | Ops.RightUpdate, Ops.Nothing, Ops.Nothing, Ops.Nothing, Ops.Nothing); InitializeRule(Ops.LeftDelete | Ops.RightInsert, Ops.Nothing, Ops.Nothing, Ops.Nothing, Ops.Nothing); InitializeRule(Ops.LeftInsert | Ops.RightUpdate, Ops.Nothing, Ops.Nothing, Ops.Nothing, Ops.Nothing); InitializeRule(Ops.LeftInsert | Ops.RightDelete, Ops.Nothing, Ops.Nothing, Ops.Nothing, Ops.Nothing); #endregion } /// /// Initializes propagation rules for a specific input combination. /// /// Describes the elements available in the input /// Describes the rule for inserts when the operator is an inner join /// Describes the rule for deletes when the operator is an inner join /// Describes the rule for inserts when the operator is a left outer join /// Describes the rule for deletes when the operator is a left outer join private static void InitializeRule(Ops input, Ops joinInsert, Ops joinDelete, Ops lojInsert, Ops lojDelete) { s_innerJoinInsertRules.Add(input, joinInsert); s_innerJoinDeleteRules.Add(input, joinDelete); s_leftOuterJoinInsertRules.Add(input, lojInsert); s_leftOuterJoinDeleteRules.Add(input, lojDelete); // Ensure that the right hand side of each rule contains no requests for specific row values // that are not also in the input. Debug.Assert((((joinInsert | joinDelete | lojInsert | lojDelete) & (Ops.LeftInsert | Ops.LeftDelete | Ops.RightInsert | Ops.RightDelete)) & (~input)) == Ops.Nothing, "(Update/JoinPropagator/Initialization) Rules can't use unavailable data"); // An unknown value can appear in both the delete and insert rule result or neither. Debug.Assert(((joinInsert ^ joinDelete) & (Ops.LeftUnknown | Ops.RightUnknown)) == Ops.Nothing && ((lojInsert ^ lojDelete) & (Ops.LeftUnknown | Ops.RightUnknown)) == Ops.Nothing, "(Update/JoinPropagator/Initialization) Unknowns must appear in both delete and insert rules " + "or in neither (in other words, for updates only)"); } ////// Determines locations of join key components in /// Empty record used for null/unknown extensions in propagation /// rules /// Expressions describing the location of join key properties. ///. /// Map from expressions in the placeholder to join key ordinals. private DictionaryGetKeyMap(PropagatorResult placeholder, DbExpression[] properties) { Dictionary map = new Dictionary (); for (int i = 0; i < properties.Length; i++) { // Determine the position of the key property in the placeholder DbExpression keyProperty = properties[i]; PropagatorResult locationInPlaceholder = Evaluator.Evaluate(keyProperty, placeholder, m_parent); Debug.Assert(locationInPlaceholder.IsSimple, "key values must be simple constants"); map[locationInPlaceholder] = i; } return map; } /// /// Performs join propagation. /// ///Changes propagated to the current join node in the update mapping view. internal ChangeNode ExecutePropagation() { // Construct an empty change node for the result ChangeNode result = Propagator.BuildChangeNode(m_joinExpression); // Perform propagation one key at a time foreach (CompositeKey key in m_allKeys) { Propagate(key, result); } // Construct a new placeholder (see ChangeNode.Placeholder) for the join result node. result.Placeholder = Join(m_left.Placeholder, m_right.Placeholder, result); return result; } ////// Joins rows that are related. /// /// Left row. /// Right row. /// Result change node; used for type information. ///Result of joining the input rows. private static PropagatorResult Join(PropagatorResult left, PropagatorResult right, ChangeNode result) { PropagatorResult[] joinRecordValues = new PropagatorResult[2]; joinRecordValues[0] = left; joinRecordValues[1] = right; PropagatorResult join = PropagatorResult.CreateStructuralValue(joinRecordValues, (StructuralType)result.ElementType.EdmType, false); return join; } ////// Propagate all changes associated with a particular join key. /// /// Key. /// Resulting changes are added to this result. private void Propagate(CompositeKey key, ChangeNode result) { // Retrieve changes associates with this join key PropagatorResult leftInsert = null; PropagatorResult leftDelete = null; PropagatorResult rightInsert = null; PropagatorResult rightDelete = null; Ops input = Ops.Nothing; if (m_leftInserts.TryGetValue(key, out leftInsert)) { input |= Ops.LeftInsert; } if (m_leftDeletes.TryGetValue(key, out leftDelete)) { input |= Ops.LeftDelete; } if (m_rightInserts.TryGetValue(key, out rightInsert)) { input |= Ops.RightInsert; } if (m_rightDeletes.TryGetValue(key, out rightDelete)) { input |= Ops.RightDelete; } // Get propagation rules for the changes Ops insertRule = m_insertRules[input]; Ops deleteRule = m_deleteRules[input]; if (Ops.Unsupported == insertRule || Ops.Unsupported == deleteRule) { Debug.Fail("no propagation rules specify unsupported"); throw EntityUtil.NotSupported(); } // Where needed, substitute null/unknown placeholders. In some of the join propagation // rules, we handle the case where a side of the join is 'unknown', or where one side // of a join is comprised of an record containing only nulls. For instance, we may update // only one extent appearing in a row of a table (unknown), or; we may insert only // the left hand side of a left outer join, in which case the right hand side is 'null'. if (0 != (Ops.LeftUnknown & insertRule)) { leftInsert = LeftPlaceholder(key, PopulateMode.Unknown); } if (0 != (Ops.LeftUnknown & deleteRule)) { leftDelete = LeftPlaceholder(key, PopulateMode.Unknown); } if (0 != (Ops.RightNullModified & insertRule)) { rightInsert = RightPlaceholder(key, PopulateMode.NullModified); } else if (0 != (Ops.RightNullPreserve & insertRule)) { rightInsert = RightPlaceholder(key, PopulateMode.NullPreserve); } else if (0 != (Ops.RightUnknown & insertRule)) { rightInsert = RightPlaceholder(key, PopulateMode.Unknown); } if (0 != (Ops.RightNullModified & deleteRule)) { rightDelete = RightPlaceholder(key, PopulateMode.NullModified); } else if (0 != (Ops.RightNullPreserve & deleteRule)) { rightDelete = RightPlaceholder(key, PopulateMode.NullPreserve); } else if (0 != (Ops.RightUnknown & deleteRule)) { rightDelete = RightPlaceholder(key, PopulateMode.Unknown); } if (null != leftInsert && null != rightInsert) { result.Inserted.Add(Join(leftInsert, rightInsert, result)); } if (null != leftDelete && null != leftDelete) { result.Deleted.Add(Join(leftDelete, rightDelete, result)); } } ////// Constructs a new placeholder record for the left hand side of the join. Values taken /// from the join key are injected into the record. /// /// Key producing the left hand side. /// Mode used to populate the placeholder ///Record corresponding to the type of the left input to the join. Each value in /// the record is flagged as private PropagatorResult LeftPlaceholder(CompositeKey key, PopulateMode mode) { return PlaceholderPopulator.Populate(m_left.Placeholder, key, m_leftKeyMap, mode, m_parent.UpdateTranslator); } ///except when it is /// a component of the key. /// See /// /// ////// private PropagatorResult RightPlaceholder(CompositeKey key, PopulateMode mode) { return PlaceholderPopulator.Populate(m_right.Placeholder, key, m_rightKeyMap, mode, m_parent.UpdateTranslator); } /// /// Initialize all structures. /// private void Initialize() { // Check that static rule definitions have been initialized lock (s_initializeRulesLockObject) { if (!s_rulesInitialized) { InitializeRules(); s_rulesInitialized = true; } } // Extract join key properties from the left and right sides of the join JoinPredicateVisitor.ExtractEquijoinProperties(m_joinExpression.JoinCondition, out m_leftProperties, out m_rightProperties); // Initialize key maps, which map from expressions in the placeholders for the join inputs to // ordinals in the join key. See ChangeNode.Placeholder and HashJoinKey for additional context. m_leftKeyMap = GetKeyMap(m_left.Placeholder, m_leftProperties); m_rightKeyMap = GetKeyMap(m_right.Placeholder, m_rightProperties); // Retrieve propagation rules for the join type of the expression. if (DbExpressionKind.InnerJoin == m_joinExpression.ExpressionKind) { m_insertRules = s_innerJoinInsertRules; m_deleteRules = s_innerJoinDeleteRules; } else { m_insertRules = s_leftOuterJoinInsertRules; m_deleteRules = s_leftOuterJoinDeleteRules; } // Determine key values for keys in the insert and delete sets from the left and right hand sides // of the join input. Also construct a set of all keys. m_allKeys = new Set(m_parent.UpdateTranslator.KeyComparer); m_leftInserts = ProcessKeys(m_left.Inserted, m_leftProperties); m_leftDeletes = ProcessKeys(m_left.Deleted, m_leftProperties); m_rightInserts = ProcessKeys(m_right.Inserted, m_rightProperties); m_rightDeletes = ProcessKeys(m_right.Deleted, m_rightProperties); } /// /// Produces a hash table of all instances and processes join keys, adding them to the list /// of keys handled by this node. /// /// List of instances (whether delete or insert) for this node. /// Properties of an instance that constitute the join key. ///A map from join keys to instances. private DictionaryProcessKeys(IEnumerable instances, DbExpression[] properties) { Dictionary hash = new Dictionary ( m_parent.UpdateTranslator.KeyComparer); foreach (PropagatorResult instance in instances) { CompositeKey key = new CompositeKey(GetKeyConstants(instance, properties)); // check if this key has been added already (if not, add it) if (!m_allKeys.Contains(key)) { m_allKeys.Add(key); } hash[key] = instance; } return hash; } // extracts key values from row expression private PropagatorResult[] GetKeyConstants(PropagatorResult change, DbExpression[] properties) { Debug.Assert(null != change && null != properties); PropagatorResult[] keyConstants = new PropagatorResult[properties.Length]; for (int i = 0; i < properties.Length; i++) { PropagatorResult constant = Evaluator.Evaluate(properties[i], change, m_parent); keyConstants[i] = constant; } return keyConstants; } #endregion #region Nested types /// /// Flags indicating which change elements are available (0-4) and propagation /// rules (0, 5-512) /// [Flags] enum Ops : uint { Nothing = 0, LeftInsert = 1, LeftDelete = 2, RightInsert = 4, RightDelete = 8, LeftUnknown = 32, RightNullModified = 128, RightNullPreserve = 256, RightUnknown = 512, LeftUpdate = LeftInsert | LeftDelete, RightUpdate = RightInsert | RightDelete, Unsupported = 4096, #region Propagation rule descriptions LeftInsertJoinRightInsert = LeftInsert | RightInsert, LeftDeleteJoinRightDelete = LeftDelete | RightDelete, LeftInsertNullModifiedExtended = LeftInsert | RightNullModified, LeftInsertNullPreserveExtended = LeftInsert | RightNullPreserve, LeftInsertUnknownExtended = LeftInsert | RightUnknown, LeftDeleteNullModifiedExtended = LeftDelete | RightNullModified, LeftDeleteNullPreserveExtended = LeftDelete | RightNullPreserve, LeftDeleteUnknownExtended = LeftDelete | RightUnknown, LeftUnknownNullModifiedExtended = LeftUnknown | RightNullModified, LeftUnknownNullPreserveExtended = LeftUnknown | RightNullPreserve, RightInsertUnknownExtended = LeftUnknown | RightInsert, RightDeleteUnknownExtended = LeftUnknown | RightDelete, #endregion } #endregion } } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007.
Link Menu

This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- ProfileSettings.cs
- WebServiceHandler.cs
- QilList.cs
- ZipIOCentralDirectoryDigitalSignature.cs
- SamlAuthenticationStatement.cs
- Attributes.cs
- FormViewInsertEventArgs.cs
- IChannel.cs
- TextTreeFixupNode.cs
- SystemIPGlobalProperties.cs
- X509CertificateValidator.cs
- MultilineStringConverter.cs
- TransferMode.cs
- BaseTreeIterator.cs
- BinaryExpressionHelper.cs
- BoundingRectTracker.cs
- ExpressionDumper.cs
- SymLanguageVendor.cs
- StandardRuntimeEnumValidator.cs
- ArithmeticException.cs
- MobileControlDesigner.cs
- Validator.cs
- FontUnit.cs
- ContainerCodeDomSerializer.cs
- EastAsianLunisolarCalendar.cs
- SqlDataSourceTableQuery.cs
- UiaCoreTypesApi.cs
- ToolBarPanel.cs
- _CommandStream.cs
- InkCanvasSelectionAdorner.cs
- ListViewItem.cs
- CommandField.cs
- ExpandButtonVisibilityConverter.cs
- CollectionBuilder.cs
- ToolboxItemLoader.cs
- EditorPartCollection.cs
- RegexCompilationInfo.cs
- ServiceHttpModule.cs
- EncoderExceptionFallback.cs
- ELinqQueryState.cs
- DataColumnPropertyDescriptor.cs
- EntityDataSourceWrapperCollection.cs
- BamlMapTable.cs
- SoapIgnoreAttribute.cs
- XmlSchemaComplexContentExtension.cs
- ConstructorBuilder.cs
- AspNetCompatibilityRequirementsAttribute.cs
- ConfigurationStrings.cs
- ContainerUtilities.cs
- ByteStorage.cs
- SamlSubject.cs
- WebEvents.cs
- DeviceContexts.cs
- MachineKeyConverter.cs
- TransformerInfoCollection.cs
- UnionCodeGroup.cs
- DataGridViewSelectedColumnCollection.cs
- AppLevelCompilationSectionCache.cs
- Argument.cs
- TypePresenter.xaml.cs
- ToolStripItem.cs
- ExternalFile.cs
- MessageBox.cs
- FixUp.cs
- CssTextWriter.cs
- MergeFilterQuery.cs
- UnsafeNativeMethods.cs
- FindRequestContext.cs
- NavigationProgressEventArgs.cs
- WebPartMenu.cs
- _NestedSingleAsyncResult.cs
- SymbolDocumentInfo.cs
- RuntimeHandles.cs
- TextContainerChangedEventArgs.cs
- WpfWebRequestHelper.cs
- CheckBoxAutomationPeer.cs
- HeaderedItemsControl.cs
- QueryTask.cs
- Rule.cs
- bindurihelper.cs
- DataRowChangeEvent.cs
- DetailsViewRow.cs
- ChannelManager.cs
- UniqueID.cs
- SynchronizedDispatch.cs
- QilStrConcatenator.cs
- ProcessProtocolHandler.cs
- Compensation.cs
- ListMarkerLine.cs
- MenuItem.cs
- UrlRoutingHandler.cs
- ApplicationDirectory.cs
- XPathDocumentNavigator.cs
- QuadraticBezierSegment.cs
- BindingMemberInfo.cs
- DBConcurrencyException.cs
- PeerNearMe.cs
- ObjectQueryProvider.cs
- IIS7UserPrincipal.cs
- VisualBrush.cs