Code:
/ Dotnetfx_Vista_SP2 / Dotnetfx_Vista_SP2 / 8.0.50727.4016 / DEVDIV / depot / DevDiv / releases / Orcas / QFE / ndp / fx / src / DataEntity / System / Data / Map / Update / Internal / Propagator.JoinPropagator.cs / 2 / 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
- ServiceOperation.cs
- cookiecontainer.cs
- Vector3DCollectionConverter.cs
- ListDictionary.cs
- DateTimeConverter2.cs
- CellLabel.cs
- WrapPanel.cs
- UpWmlMobileTextWriter.cs
- FixedTextContainer.cs
- Win32NamedPipes.cs
- SettingsPropertyCollection.cs
- FileFormatException.cs
- NameValuePermission.cs
- AddInActivator.cs
- PenThreadWorker.cs
- FilteredDataSetHelper.cs
- WebPermission.cs
- handlecollector.cs
- ChannelServices.cs
- Rect3DConverter.cs
- KeyConverter.cs
- PointConverter.cs
- CryptoStream.cs
- PasswordBox.cs
- StandardCommands.cs
- BaseCodeDomTreeGenerator.cs
- LayeredChannelFactory.cs
- precedingquery.cs
- Cursors.cs
- WebBrowserSiteBase.cs
- SchemaSetCompiler.cs
- KeyConverter.cs
- x509utils.cs
- TypeUsageBuilder.cs
- ContractUtils.cs
- DiagnosticTraceSource.cs
- ListViewGroup.cs
- CompilerState.cs
- ScriptServiceAttribute.cs
- FormViewDeleteEventArgs.cs
- SecurityResources.cs
- TextEditorSpelling.cs
- Figure.cs
- BindingBase.cs
- CodeEntryPointMethod.cs
- CustomTypeDescriptor.cs
- RequestStatusBarUpdateEventArgs.cs
- SafeRightsManagementPubHandle.cs
- Tracking.cs
- InvokeProviderWrapper.cs
- WebPartVerbCollection.cs
- VirtualPath.cs
- DocumentEventArgs.cs
- ExtensionQuery.cs
- FileDataSourceCache.cs
- PeerEndPoint.cs
- PartDesigner.cs
- ServicePointManager.cs
- StringBuilder.cs
- MeshGeometry3D.cs
- DataBindingHandlerAttribute.cs
- ConfigUtil.cs
- ElementUtil.cs
- ListBindableAttribute.cs
- _Events.cs
- AnimationTimeline.cs
- TypeUtil.cs
- BlockExpression.cs
- validationstate.cs
- ImageIndexConverter.cs
- SQLInt64Storage.cs
- LinqDataSourceEditData.cs
- SubtreeProcessor.cs
- Label.cs
- UnicastIPAddressInformationCollection.cs
- Int32Converter.cs
- RequestCacheManager.cs
- EFDataModelProvider.cs
- SqlUtils.cs
- Memoizer.cs
- DbSetClause.cs
- ApplicationTrust.cs
- StringInfo.cs
- OleDbPermission.cs
- IsolatedStorageFilePermission.cs
- XmlSchemaAppInfo.cs
- PropertyItemInternal.cs
- ValueUtilsSmi.cs
- DictionaryContent.cs
- SelectingProviderEventArgs.cs
- SchemaImporterExtensionElementCollection.cs
- BamlCollectionHolder.cs
- ReflectEventDescriptor.cs
- HttpHandler.cs
- UInt32Storage.cs
- ProviderIncompatibleException.cs
- Compiler.cs
- HttpPostClientProtocol.cs
- AssemblyNameProxy.cs
- PerformanceCounterPermissionEntryCollection.cs