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 Dictionary s_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 Dictionary GetKeyMap(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 except when it is
/// a component of the key.
private PropagatorResult LeftPlaceholder(CompositeKey key, PopulateMode mode)
{
return PlaceholderPopulator.Populate(m_left.Placeholder, key, m_leftKeyMap, mode, m_parent.UpdateTranslator);
}
///
/// 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 Dictionary ProcessKeys(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 Dictionary s_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 Dictionary GetKeyMap(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 except when it is
/// a component of the key.
private PropagatorResult LeftPlaceholder(CompositeKey key, PopulateMode mode)
{
return PlaceholderPopulator.Populate(m_left.Placeholder, key, m_leftKeyMap, mode, m_parent.UpdateTranslator);
}
///
/// 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 Dictionary ProcessKeys(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
- DataGridViewUtilities.cs
- StaticExtensionConverter.cs
- SyndicationLink.cs
- ValidationSummaryDesigner.cs
- LeafCellTreeNode.cs
- CodeCatchClause.cs
- RepeaterItemCollection.cs
- FixedStringLookup.cs
- Selection.cs
- EntityProviderFactory.cs
- GlobalId.cs
- ISAPIRuntime.cs
- Rectangle.cs
- SystemColorTracker.cs
- RTLAwareMessageBox.cs
- MenuCommands.cs
- PointF.cs
- InternalPermissions.cs
- TagPrefixAttribute.cs
- TaiwanLunisolarCalendar.cs
- WindowInteropHelper.cs
- SynchronizationHandlesCodeDomSerializer.cs
- SimplePropertyEntry.cs
- GeneralTransform3DCollection.cs
- XmlChoiceIdentifierAttribute.cs
- Msec.cs
- EntityDataSourceDataSelectionPanel.cs
- SmtpReplyReader.cs
- HttpServerVarsCollection.cs
- IntSecurity.cs
- ClickablePoint.cs
- XmlAutoDetectWriter.cs
- RadioButtonRenderer.cs
- Graphics.cs
- FragmentQueryProcessor.cs
- ClientApiGenerator.cs
- ArrayList.cs
- WorkflowTimerService.cs
- TimeSpanParse.cs
- StorageInfo.cs
- DateTimeOffsetConverter.cs
- CompilationSection.cs
- TextParagraph.cs
- AppDomainFactory.cs
- Application.cs
- UIElementCollection.cs
- EntitySet.cs
- BitmapEffectDrawingContextWalker.cs
- ProxyAttribute.cs
- MemoryMappedViewStream.cs
- ISO2022Encoding.cs
- UriWriter.cs
- SiteMembershipCondition.cs
- SQLBinaryStorage.cs
- RoleManagerModule.cs
- SerializationStore.cs
- Fonts.cs
- InternalBase.cs
- ListViewItem.cs
- ListViewItemMouseHoverEvent.cs
- parserscommon.cs
- Reference.cs
- MenuBase.cs
- DbConnectionPoolCounters.cs
- CqlBlock.cs
- ObjectItemLoadingSessionData.cs
- ResourceDictionaryCollection.cs
- ScrollEventArgs.cs
- EventsTab.cs
- _FtpDataStream.cs
- MenuAutomationPeer.cs
- TableItemProviderWrapper.cs
- WebPartCancelEventArgs.cs
- Utils.cs
- Timeline.cs
- PrivilegeNotHeldException.cs
- ViewGenResults.cs
- Function.cs
- ReversePositionQuery.cs
- AnnotationComponentManager.cs
- RegistrationContext.cs
- ClientBuildManager.cs
- SqlWebEventProvider.cs
- ColorConverter.cs
- PropertyTabAttribute.cs
- CultureSpecificCharacterBufferRange.cs
- ColumnPropertiesGroup.cs
- JsonObjectDataContract.cs
- DefaultValueTypeConverter.cs
- ServiceSecurityAuditElement.cs
- EnumDataContract.cs
- ConvertEvent.cs
- WebControlAdapter.cs
- TreeNodeBinding.cs
- TemplateControlCodeDomTreeGenerator.cs
- MultiView.cs
- ComboBoxAutomationPeer.cs
- Permission.cs
- GPRECT.cs
- StaticDataManager.cs