Imported Upstream version 4.6.0.125

Former-commit-id: a2155e9bd80020e49e72e86c44da02a8ac0e57a4
This commit is contained in:
Xamarin Public Jenkins (auto-signing)
2016-08-03 10:59:49 +00:00
parent a569aebcfd
commit e79aa3c0ed
17047 changed files with 3137615 additions and 392334 deletions

View File

@ -0,0 +1,193 @@
//---------------------------------------------------------------------
// <copyright file="FragmentQuery.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//
// @owner [....]
// @backupOwner [....]
//---------------------------------------------------------------------
using System;
using System.Diagnostics;
using System.Collections.Generic;
using System.Text;
using System.Data.Common.Utils;
using System.Data.Common.Utils.Boolean;
using System.Data.Mapping.ViewGeneration.Structures;
using System.Data.Metadata.Edm;
using System.Linq;
using System.Globalization;
namespace System.Data.Mapping.ViewGeneration.QueryRewriting
{
internal class FragmentQuery : ITileQuery
{
private BoolExpression m_fromVariable; // optional
private string m_label; // optional
private HashSet<MemberPath> m_attributes;
private BoolExpression m_condition;
public HashSet<MemberPath> Attributes
{
get { return m_attributes; }
}
public BoolExpression Condition
{
get { return m_condition; }
}
public static FragmentQuery Create(BoolExpression fromVariable, CellQuery cellQuery)
{
BoolExpression whereClause = cellQuery.WhereClause;
whereClause = whereClause.MakeCopy();
whereClause.ExpensiveSimplify();
return new FragmentQuery(null /*label*/, fromVariable, new HashSet<MemberPath>(cellQuery.GetProjectedMembers()), whereClause);
}
public static FragmentQuery Create(string label, RoleBoolean roleBoolean, CellQuery cellQuery)
{
BoolExpression whereClause = cellQuery.WhereClause.Create(roleBoolean);
whereClause = BoolExpression.CreateAnd(whereClause, cellQuery.WhereClause);
//return new FragmentQuery(label, null /* fromVariable */, new HashSet<MemberPath>(cellQuery.GetProjectedMembers()), whereClause);
// don't need any attributes
whereClause = whereClause.MakeCopy();
whereClause.ExpensiveSimplify();
return new FragmentQuery(label, null /* fromVariable */, new HashSet<MemberPath>(), whereClause);
}
public static FragmentQuery Create(IEnumerable<MemberPath> attrs, BoolExpression whereClause)
{
return new FragmentQuery(null /* no name */, null /* no fromVariable*/, attrs, whereClause);
}
public static FragmentQuery Create(BoolExpression whereClause)
{
return new FragmentQuery(null /* no name */, null /* no fromVariable*/, new MemberPath[] { }, whereClause);
}
internal FragmentQuery(string label, BoolExpression fromVariable, IEnumerable<MemberPath> attrs, BoolExpression condition)
{
m_label = label;
m_fromVariable = fromVariable;
m_condition = condition;
m_attributes = new HashSet<MemberPath>(attrs);
}
public BoolExpression FromVariable
{
get { return m_fromVariable; }
}
public string Description
{
get
{
string label = m_label;
if (label == null && m_fromVariable != null)
{
label = m_fromVariable.ToString();
}
return label;
}
}
public override string ToString()
{
// attributes
StringBuilder b = new StringBuilder();
foreach (MemberPath value in this.Attributes)
{
if (b.Length > 0) { b.Append(','); }
b.Append(value.ToString());
}
if (Description != null && Description != b.ToString())
{
return String.Format(CultureInfo.InvariantCulture, "{0}: [{1} where {2}]", Description, b, this.Condition);
}
else
{
return String.Format(CultureInfo.InvariantCulture, "[{0} where {1}]", b, this.Condition);
}
}
#region Static methods
// creates a condition member=value
internal static BoolExpression CreateMemberCondition(MemberPath path, Constant domainValue, MemberDomainMap domainMap)
{
if (domainValue is TypeConstant)
{
return BoolExpression.CreateLiteral(new TypeRestriction(new MemberProjectedSlot(path),
new Domain(domainValue, domainMap.GetDomain(path))), domainMap);
}
else
{
return BoolExpression.CreateLiteral(new ScalarRestriction(new MemberProjectedSlot(path),
new Domain(domainValue, domainMap.GetDomain(path))), domainMap);
}
}
internal static IEqualityComparer<FragmentQuery> GetEqualityComparer(FragmentQueryProcessor qp)
{
return new FragmentQueryEqualityComparer(qp);
}
#endregion
#region Equality Comparer
// Two queries are "equal" if they project the same set of attributes
// and their WHERE clauses are equivalent
private class FragmentQueryEqualityComparer : IEqualityComparer<FragmentQuery>
{
FragmentQueryProcessor _qp;
internal FragmentQueryEqualityComparer(FragmentQueryProcessor qp)
{
_qp = qp;
}
#region IEqualityComparer<FragmentQuery> Members
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2140:TransparentMethodsMustNotReferenceCriticalCode", Justification = "Based on Bug VSTS Pioneer #433188: IsVisibleOutsideAssembly is wrong on generic instantiations.")]
public bool Equals(FragmentQuery x, FragmentQuery y)
{
if (!x.Attributes.SetEquals(y.Attributes))
{
return false;
}
return _qp.IsEquivalentTo(x, y);
}
// Hashing a bit naive: it exploits syntactic properties,
// i.e., some semantically equivalent queries may produce different hash codes
// But that's fine for usage scenarios in QueryRewriter.cs
public int GetHashCode(FragmentQuery q)
{
int attrHashCode = 0;
foreach (MemberPath member in q.Attributes)
{
attrHashCode ^= MemberPath.EqualityComparer.GetHashCode(member);
}
int varHashCode = 0;
int constHashCode = 0;
foreach (MemberRestriction oneOf in q.Condition.MemberRestrictions)
{
varHashCode ^= MemberPath.EqualityComparer.GetHashCode(oneOf.RestrictedMemberSlot.MemberPath);
foreach (Constant constant in oneOf.Domain.Values)
{
constHashCode ^= Constant.EqualityComparer.GetHashCode(constant);
}
}
return attrHashCode * 13 + varHashCode * 7 + constHashCode;
}
#endregion
}
#endregion
}
}

View File

@ -0,0 +1,216 @@
//---------------------------------------------------------------------
// <copyright file="FragmentQueryKB.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//
// @owner [....]
// @backupOwner [....]
//---------------------------------------------------------------------
using System;
using System.Diagnostics;
using System.Collections.Generic;
using System.Text;
using System.Data.Common.Utils;
using System.Data.Common.Utils.Boolean;
using System.Data.Mapping.ViewGeneration.Structures;
using System.Data.Metadata.Edm;
using System.Linq;
namespace System.Data.Mapping.ViewGeneration.QueryRewriting
{
internal class FragmentQueryKB : KnowledgeBase<DomainConstraint<BoolLiteral, Constant>>
{
private BoolExpr<DomainConstraint<BoolLiteral, Constant>> _kbExpression = TrueExpr<DomainConstraint<BoolLiteral, Constant>>.Value;
internal override void AddFact(BoolExpr<DomainConstraint<BoolLiteral, Constant>> fact)
{
base.AddFact(fact);
_kbExpression = new AndExpr<DomainConstraint<BoolLiteral, Constant>>(_kbExpression, fact);
}
internal BoolExpr<DomainConstraint<BoolLiteral, Constant>> KbExpression
{
get { return _kbExpression; }
}
internal void CreateVariableConstraints(EntitySetBase extent, MemberDomainMap domainMap, EdmItemCollection edmItemCollection)
{
CreateVariableConstraintsRecursion(extent.ElementType, new MemberPath(extent), domainMap, edmItemCollection);
}
internal void CreateAssociationConstraints(EntitySetBase extent, MemberDomainMap domainMap, EdmItemCollection edmItemCollection)
{
AssociationSet assocSet = extent as AssociationSet;
if (assocSet != null)
{
BoolExpression assocSetExpr = BoolExpression.CreateLiteral(new RoleBoolean(assocSet), domainMap);
//Set of Keys for this Association Set
//need to key on EdmMember and EdmType because A, B subtype of C, can have the same id (EdmMember) that is defined in C.
HashSet<Pair<EdmMember, EntityType>> associationkeys = new HashSet<Pair<EdmMember, EntityType>>();
//foreach end, add each Key
foreach (var endMember in assocSet.ElementType.AssociationEndMembers)
{
EntityType type = (EntityType)((RefType)endMember.TypeUsage.EdmType).ElementType;
type.KeyMembers.All(member => associationkeys.Add(new Pair<EdmMember, EntityType>(member, type)) || true /* prevent early termination */);
}
foreach (AssociationSetEnd end in assocSet.AssociationSetEnds)
{
// construct type condition
HashSet<EdmType> derivedTypes = new HashSet<EdmType>();
derivedTypes.UnionWith(MetadataHelper.GetTypeAndSubtypesOf(end.CorrespondingAssociationEndMember.TypeUsage.EdmType, edmItemCollection, false));
BoolExpression typeCondition = CreateIsOfTypeCondition(new MemberPath(end.EntitySet),
derivedTypes, domainMap);
BoolExpression inRoleExpression = BoolExpression.CreateLiteral(new RoleBoolean(end), domainMap);
BoolExpression inSetExpression = BoolExpression.CreateAnd(
BoolExpression.CreateLiteral(new RoleBoolean(end.EntitySet), domainMap),
typeCondition);
// InRole -> (InSet AND type(Set)=T)
AddImplication(inRoleExpression.Tree, inSetExpression.Tree);
if (MetadataHelper.IsEveryOtherEndAtLeastOne(assocSet, end.CorrespondingAssociationEndMember))
{
AddImplication(inSetExpression.Tree, inRoleExpression.Tree);
}
// Add equivalence between association set an End/Role if necessary.
// Equivalence is added when a given association end's keys subsumes keys for
// all the other association end.
// For example: We have Entity Sets A[id1], B[id2, id3] and an association A_B between them.
// Ref Constraint A.id1 = B.id2
// In this case, the Association Set has Key <id1, id2, id3>
// id1 alone can not identify a unique tuple in the Association Set, but <id2, id3> can.
// Therefore we add a constraint: InSet(B) <=> InEnd(A_B.B)
if (MetadataHelper.DoesEndKeySubsumeAssociationSetKey(assocSet,
end.CorrespondingAssociationEndMember,
associationkeys))
{
AddEquivalence(inRoleExpression.Tree, assocSetExpr.Tree);
}
}
// add rules for referential constraints (borrowed from LeftCellWrapper.cs)
AssociationType assocType = assocSet.ElementType;
foreach (ReferentialConstraint constraint in assocType.ReferentialConstraints)
{
AssociationEndMember toEndMember = (AssociationEndMember)constraint.ToRole;
EntitySet toEntitySet = MetadataHelper.GetEntitySetAtEnd(assocSet, toEndMember);
// Check if the keys of the entitySet's are equal to what is specified in the constraint
// How annoying that KeyMembers returns EdmMember and not EdmProperty
IEnumerable<EdmMember> toProperties = Helpers.AsSuperTypeList<EdmProperty, EdmMember>(constraint.ToProperties);
if (Helpers.IsSetEqual(toProperties, toEntitySet.ElementType.KeyMembers, EqualityComparer<EdmMember>.Default))
{
// Now check that the FromEnd is 1..1 (only then will all the Addresses be present in the assoc set)
if (constraint.FromRole.RelationshipMultiplicity.Equals(RelationshipMultiplicity.One))
{
// Make sure that the ToEnd is not 0..* because then the schema is broken
Debug.Assert(constraint.ToRole.RelationshipMultiplicity.Equals(RelationshipMultiplicity.Many) == false);
// Equate the ends
BoolExpression inRoleExpression1 = BoolExpression.CreateLiteral(new RoleBoolean(assocSet.AssociationSetEnds[0]), domainMap);
BoolExpression inRoleExpression2 = BoolExpression.CreateLiteral(new RoleBoolean(assocSet.AssociationSetEnds[1]), domainMap);
AddEquivalence(inRoleExpression1.Tree, inRoleExpression2.Tree);
}
}
}
}
}
internal void CreateEquivalenceConstraintForOneToOneForeignKeyAssociation(AssociationSet assocSet, MemberDomainMap domainMap,
EdmItemCollection edmItemCollection)
{
AssociationType assocType = assocSet.ElementType;
foreach (ReferentialConstraint constraint in assocType.ReferentialConstraints)
{
AssociationEndMember toEndMember = (AssociationEndMember)constraint.ToRole;
AssociationEndMember fromEndMember = (AssociationEndMember)constraint.FromRole;
EntitySet toEntitySet = MetadataHelper.GetEntitySetAtEnd(assocSet, toEndMember);
EntitySet fromEntitySet = MetadataHelper.GetEntitySetAtEnd(assocSet, fromEndMember);
// Check if the keys of the entitySet's are equal to what is specified in the constraint
IEnumerable<EdmMember> toProperties = Helpers.AsSuperTypeList<EdmProperty, EdmMember>(constraint.ToProperties);
if (Helpers.IsSetEqual(toProperties, toEntitySet.ElementType.KeyMembers, EqualityComparer<EdmMember>.Default))
{
//make sure that the method called with a 1:1 association
Debug.Assert(constraint.FromRole.RelationshipMultiplicity.Equals(RelationshipMultiplicity.One));
Debug.Assert(constraint.ToRole.RelationshipMultiplicity.Equals(RelationshipMultiplicity.One));
// Create an Equivalence between the two Sets participating in this AssociationSet
BoolExpression fromSetExpression = BoolExpression.CreateLiteral(new RoleBoolean(fromEntitySet), domainMap);
BoolExpression toSetExpression = BoolExpression.CreateLiteral(new RoleBoolean(toEntitySet), domainMap);
AddEquivalence(fromSetExpression.Tree, toSetExpression.Tree);
}
}
}
private void CreateVariableConstraintsRecursion(EdmType edmType, MemberPath currentPath, MemberDomainMap domainMap, EdmItemCollection edmItemCollection)
{
// Add the types can member have, i.e., its type and its subtypes
HashSet<EdmType> possibleTypes = new HashSet<EdmType>();
possibleTypes.UnionWith(MetadataHelper.GetTypeAndSubtypesOf(edmType, edmItemCollection, true));
foreach (EdmType possibleType in possibleTypes)
{
// determine type domain
HashSet<EdmType> derivedTypes = new HashSet<EdmType>();
derivedTypes.UnionWith(MetadataHelper.GetTypeAndSubtypesOf(possibleType, edmItemCollection, false));
if (derivedTypes.Count != 0)
{
BoolExpression typeCondition = CreateIsOfTypeCondition(currentPath, derivedTypes, domainMap);
BoolExpression typeConditionComplement = BoolExpression.CreateNot(typeCondition);
if (false == typeConditionComplement.IsSatisfiable())
{
continue;
}
StructuralType structuralType = (StructuralType)possibleType;
foreach (EdmProperty childProperty in structuralType.GetDeclaredOnlyMembers<EdmProperty>())
{
MemberPath childPath = new MemberPath(currentPath, childProperty);
bool isScalar = MetadataHelper.IsNonRefSimpleMember(childProperty);
if (domainMap.IsConditionMember(childPath) || domainMap.IsProjectedConditionMember(childPath))
{
BoolExpression nullCondition;
List<Constant> childDomain = new List<Constant>(domainMap.GetDomain(childPath));
if (isScalar)
{
nullCondition = BoolExpression.CreateLiteral(new ScalarRestriction(new MemberProjectedSlot(childPath),
new Domain(ScalarConstant.Undefined, childDomain)), domainMap);
}
else
{
nullCondition = BoolExpression.CreateLiteral(new TypeRestriction(new MemberProjectedSlot(childPath),
new Domain(TypeConstant.Undefined, childDomain)), domainMap);
}
// Properties not occuring in type are UNDEFINED
AddEquivalence(typeConditionComplement.Tree, nullCondition.Tree);
}
// recurse into complex types
if (false == isScalar)
{
CreateVariableConstraintsRecursion(childPath.EdmType, childPath, domainMap, edmItemCollection);
}
}
}
}
}
private static BoolExpression CreateIsOfTypeCondition(MemberPath currentPath, IEnumerable<EdmType> derivedTypes, MemberDomainMap domainMap)
{
Domain typeDomain = new Domain(derivedTypes.Select(derivedType => (Constant)new TypeConstant(derivedType)), domainMap.GetDomain(currentPath));
BoolExpression typeCondition = BoolExpression.CreateLiteral(new TypeRestriction(new MemberProjectedSlot(currentPath), typeDomain), domainMap);
return typeCondition;
}
}
}

View File

@ -0,0 +1,191 @@
//---------------------------------------------------------------------
// <copyright file="FragmentQueryProcessor.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//
// @owner [....]
// @backupOwner [....]
//---------------------------------------------------------------------
using System;
using System.Diagnostics;
using System.Collections.Generic;
using System.Text;
using System.Data.Common.Utils;
using System.Data.Common.Utils.Boolean;
using System.Data.Mapping.ViewGeneration.Structures;
using System.Data.Metadata.Edm;
using System.Linq;
using System.Globalization;
namespace System.Data.Mapping.ViewGeneration.QueryRewriting
{
using BoolDomainConstraint = DomainConstraint<BoolLiteral, Constant>;
internal class FragmentQueryProcessor : TileQueryProcessor<FragmentQuery>
{
private FragmentQueryKB _kb;
public FragmentQueryProcessor(FragmentQueryKB kb)
{
_kb = kb;
}
internal static FragmentQueryProcessor Merge(FragmentQueryProcessor qp1, FragmentQueryProcessor qp2)
{
FragmentQueryKB mergedKB = new FragmentQueryKB();
mergedKB.AddKnowledgeBase(qp1.KnowledgeBase);
mergedKB.AddKnowledgeBase(qp2.KnowledgeBase);
return new FragmentQueryProcessor(mergedKB);
}
internal FragmentQueryKB KnowledgeBase
{
get { return _kb; }
}
// resulting query contains an intersection of attributes
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2140:TransparentMethodsMustNotReferenceCriticalCode", Justification = "Based on Bug VSTS Pioneer #433188: IsVisibleOutsideAssembly is wrong on generic instantiations.")]
internal override FragmentQuery Union(FragmentQuery q1, FragmentQuery q2)
{
HashSet<MemberPath> attributes = new HashSet<MemberPath>(q1.Attributes);
attributes.IntersectWith(q2.Attributes);
BoolExpression condition = BoolExpression.CreateOr(q1.Condition, q2.Condition);
return FragmentQuery.Create(attributes, condition);
}
internal bool IsDisjointFrom(FragmentQuery q1, FragmentQuery q2)
{
return !IsSatisfiable(Intersect(q1, q2));
}
internal bool IsContainedIn(FragmentQuery q1, FragmentQuery q2)
{
return !IsSatisfiable(Difference(q1, q2));
}
internal bool IsEquivalentTo(FragmentQuery q1, FragmentQuery q2)
{
return IsContainedIn(q1, q2) && IsContainedIn(q2, q1);
}
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2140:TransparentMethodsMustNotReferenceCriticalCode", Justification = "Based on Bug VSTS Pioneer #433188: IsVisibleOutsideAssembly is wrong on generic instantiations.")]
internal override FragmentQuery Intersect(FragmentQuery q1, FragmentQuery q2)
{
HashSet<MemberPath> attributes = new HashSet<MemberPath>(q1.Attributes);
attributes.IntersectWith(q2.Attributes);
BoolExpression condition = BoolExpression.CreateAnd(q1.Condition, q2.Condition);
return FragmentQuery.Create(attributes, condition);
}
internal override FragmentQuery Difference(FragmentQuery qA, FragmentQuery qB)
{
return FragmentQuery.Create(qA.Attributes, BoolExpression.CreateAndNot(qA.Condition, qB.Condition));
}
internal override bool IsSatisfiable(FragmentQuery query)
{
return IsSatisfiable(query.Condition);
}
private bool IsSatisfiable(BoolExpression condition)
{
// instantiate conversion context for each check - gives better performance
BoolExpression conditionUnderKB = condition.Create(
new AndExpr<BoolDomainConstraint>(_kb.KbExpression, condition.Tree));
var context = IdentifierService<BoolDomainConstraint>.Instance.CreateConversionContext();
var converter = new Converter<BoolDomainConstraint>(conditionUnderKB.Tree, context);
bool isSatisfiable = converter.Vertex.IsZero() == false;
return isSatisfiable;
}
// creates "derived" views that may be helpful for answering the query
// for example, view = SELECT ID WHERE B=2, query = SELECT ID,B WHERE B=2
// Created derived view: SELECT ID,B WHERE B=2 by adding the attribute whose value is determined by the where clause to projected list
internal override FragmentQuery CreateDerivedViewBySelectingConstantAttributes(FragmentQuery view)
{
HashSet<MemberPath> newProjectedAttributes = new HashSet<MemberPath>();
// collect all variables from the view
IEnumerable<DomainVariable<BoolLiteral, Constant>> variables = view.Condition.Variables;
foreach (DomainVariable<BoolLiteral, Constant> var in variables)
{
MemberRestriction variableCondition = var.Identifier as MemberRestriction;
if (variableCondition != null)
{
// Is this attribute not already projected?
MemberPath conditionMember = variableCondition.RestrictedMemberSlot.MemberPath;
// Iterating through the variable domain var.Domain could be wasteful
// Instead, consider the actual condition values on the variable. Usually, they don't get repeated (if not, we could cache and check)
Domain conditionValues = variableCondition.Domain;
if ((false == view.Attributes.Contains(conditionMember))
&& !(conditionValues.AllPossibleValues.Any(it => it.HasNotNull()))) //Don't add member to the projected list if the condition involves a
{
foreach (Constant value in conditionValues.Values)
{
// construct constraint: X = value
DomainConstraint<BoolLiteral, Constant> constraint = new DomainConstraint<BoolLiteral, Constant>(var,
new Set<Constant>(new Constant[] { value }, Constant.EqualityComparer));
// is this constraint implied by the where clause?
BoolExpression exclusion = view.Condition.Create(
new AndExpr<DomainConstraint<BoolLiteral, Constant>>(view.Condition.Tree,
new NotExpr<DomainConstraint<BoolLiteral, Constant>>(new TermExpr<DomainConstraint<BoolLiteral, Constant>>(constraint))));
bool isImplied = false == IsSatisfiable(exclusion);
if (isImplied)
{
// add this variable to the projection, if it is used in the query
newProjectedAttributes.Add(conditionMember);
}
}
}
}
}
if (newProjectedAttributes.Count > 0)
{
newProjectedAttributes.UnionWith(view.Attributes);
FragmentQuery derivedView = new FragmentQuery(String.Format(CultureInfo.InvariantCulture, "project({0})", view.Description), view.FromVariable,
newProjectedAttributes, view.Condition);
return derivedView;
}
return null;
}
public override string ToString()
{
return _kb.ToString();
}
#region Private class AttributeSetComparator
private class AttributeSetComparator : IEqualityComparer<HashSet<MemberPath>>
{
internal static readonly AttributeSetComparator DefaultInstance = new AttributeSetComparator();
#region IEqualityComparer<HashSet<MemberPath>> Members
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2140:TransparentMethodsMustNotReferenceCriticalCode", Justification = "Based on Bug VSTS Pioneer #433188: IsVisibleOutsideAssembly is wrong on generic instantiations.")]
public bool Equals(HashSet<MemberPath> x, HashSet<MemberPath> y)
{
return x.SetEquals(y);
}
public int GetHashCode(HashSet<MemberPath> attrs)
{
int hashCode = 123;
foreach (MemberPath attr in attrs)
{
hashCode += MemberPath.EqualityComparer.GetHashCode(attr) * 7;
}
return hashCode;
}
#endregion
}
#endregion
}
}

View File

@ -0,0 +1,251 @@
//---------------------------------------------------------------------
// <copyright file="RewritingPass.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//
// @owner [....]
// @backupOwner [....]
//---------------------------------------------------------------------
using System;
using System.Diagnostics;
using System.Collections.Generic;
using System.Text;
using System.Linq;
namespace System.Data.Mapping.ViewGeneration.QueryRewriting
{
// Goal: use the next view to get rewritingSoFar to be closer to the goal
internal class RewritingPass<T_Tile> where T_Tile : class
{
// region that rewriting needs to cover
private readonly T_Tile m_toFill;
// region that rewriting needs to be disjoint with
private readonly T_Tile m_toAvoid;
private readonly List<T_Tile> m_views;
private readonly RewritingProcessor<T_Tile> m_qp;
private readonly Dictionary<T_Tile, TileOpKind> m_usedViews = new Dictionary<T_Tile, TileOpKind>();
public RewritingPass(T_Tile toFill, T_Tile toAvoid, List<T_Tile> views, RewritingProcessor<T_Tile> qp)
{
m_toFill = toFill;
m_toAvoid = toAvoid;
m_views = views;
m_qp = qp;
}
public static bool RewriteQuery(T_Tile toFill, T_Tile toAvoid, out T_Tile rewriting, List<T_Tile> views, RewritingProcessor<T_Tile> qp)
{
RewritingPass<T_Tile> rewritingPass = new RewritingPass<T_Tile>(toFill, toAvoid, views, qp);
if (rewritingPass.RewriteQuery(out rewriting))
{
RewritingSimplifier<T_Tile>.TrySimplifyUnionRewriting(ref rewriting, toFill, toAvoid, qp);
return true;
}
return false;
}
private static bool RewriteQueryInternal(T_Tile toFill, T_Tile toAvoid, out T_Tile rewriting, List<T_Tile> views, HashSet<T_Tile> recentlyUsedViews, RewritingProcessor<T_Tile> qp)
{
if (qp.REORDER_VIEWS && recentlyUsedViews.Count > 0)
{
// move recently used views toward the end
List<T_Tile> reorderedViews = new List<T_Tile>();
foreach (T_Tile view in views)
{
if (false == recentlyUsedViews.Contains(view))
{
reorderedViews.Add(view);
}
}
reorderedViews.AddRange(recentlyUsedViews);
views = reorderedViews;
}
RewritingPass<T_Tile> rewritingPass = new RewritingPass<T_Tile>(toFill, toAvoid, views, qp);
return rewritingPass.RewriteQuery(out rewriting);
}
private bool RewriteQuery(out T_Tile rewriting)
{
rewriting = m_toFill;
T_Tile rewritingSoFar;
if (false == FindRewritingByIncludedAndDisjoint(out rewritingSoFar))
{
if (false == FindContributingView(out rewritingSoFar))
{
return false;
}
}
bool hasExtraTuples = !m_qp.IsDisjointFrom(rewritingSoFar, m_toAvoid);
// try to cut off extra tuples using joins
if (hasExtraTuples)
{
foreach (T_Tile view in AvailableViews)
{
if (TryJoin(view, ref rewritingSoFar))
{
hasExtraTuples = false;
break;
}
}
}
// try to cut off extra tuples using anti-semijoins
if (hasExtraTuples)
{
foreach (T_Tile view in AvailableViews)
{
if (TryAntiSemiJoin(view, ref rewritingSoFar))
{
hasExtraTuples = false;
break;
}
}
}
if (hasExtraTuples)
{
return false; // won't be able to cut off extra tuples
}
// remove redundant joins and anti-semijoins
RewritingSimplifier<T_Tile>.TrySimplifyJoinRewriting(ref rewritingSoFar, m_toAvoid, m_usedViews, m_qp);
// find rewriting for missing tuples, if any
T_Tile missingTuples = m_qp.AntiSemiJoin(m_toFill, rewritingSoFar);
if (!m_qp.IsEmpty(missingTuples))
{
T_Tile rewritingForMissingTuples;
if (false == RewritingPass<T_Tile>.RewriteQueryInternal(missingTuples, m_toAvoid, out rewritingForMissingTuples, m_views, new HashSet<T_Tile>(m_usedViews.Keys), m_qp))
{
rewriting = rewritingForMissingTuples;
return false; // failure
}
else
{
// Although a more general optimization for UNIONs will handle this case,
// adding this check reduces the overall number of containment tests
if (m_qp.IsContainedIn(rewritingSoFar, rewritingForMissingTuples))
{
rewritingSoFar = rewritingForMissingTuples;
}
else
{
rewritingSoFar = m_qp.Union(rewritingSoFar, rewritingForMissingTuples);
}
}
}
// if we reached this point, we have a successful rewriting
rewriting = rewritingSoFar;
return true;
}
// returns true if no more extra tuples are left
private bool TryJoin(T_Tile view, ref T_Tile rewriting)
{
T_Tile newRewriting = m_qp.Join(rewriting, view);
if (!m_qp.IsEmpty(newRewriting))
{
m_usedViews[view] = TileOpKind.Join;
rewriting = newRewriting;
return m_qp.IsDisjointFrom(rewriting, m_toAvoid);
}
return false;
}
// returns true if no more extra tuples are left
private bool TryAntiSemiJoin(T_Tile view, ref T_Tile rewriting)
{
T_Tile newRewriting = m_qp.AntiSemiJoin(rewriting, view);
if (!m_qp.IsEmpty(newRewriting))
{
m_usedViews[view] = TileOpKind.AntiSemiJoin;
rewriting = newRewriting;
return m_qp.IsDisjointFrom(rewriting, m_toAvoid);
}
return false;
}
// Try to find a rewriting by intersecting all views which contain the query
// and subtracting all views that are disjoint from the query
private bool FindRewritingByIncludedAndDisjoint(out T_Tile rewritingSoFar)
{
// intersect all views in which m_toFill is contained
rewritingSoFar = null;
foreach (T_Tile view in AvailableViews)
{
if (m_qp.IsContainedIn(m_toFill, view)) // query <= view
{
if (rewritingSoFar == null)
{
rewritingSoFar = view;
m_usedViews[view] = TileOpKind.Join;
}
else
{
T_Tile newRewriting = m_qp.Join(rewritingSoFar, view);
if (!m_qp.IsContainedIn(rewritingSoFar, newRewriting))
{
rewritingSoFar = newRewriting;
m_usedViews[view] = TileOpKind.Join; // it is a useful join
}
else
{
continue; // useless join
}
}
if (m_qp.IsContainedIn(rewritingSoFar, m_toFill))
{
return true;
}
}
}
// subtract all views that are disjoint from m_toFill
if (rewritingSoFar != null)
{
foreach (T_Tile view in AvailableViews)
{
if (m_qp.IsDisjointFrom(m_toFill, view)) // query ^ view = {}
{
if (!m_qp.IsDisjointFrom(rewritingSoFar, view))
{
rewritingSoFar = m_qp.AntiSemiJoin(rewritingSoFar, view);
m_usedViews[view] = TileOpKind.AntiSemiJoin;
if (m_qp.IsContainedIn(rewritingSoFar, m_toFill))
{
return true;
}
}
}
}
}
return rewritingSoFar != null;
}
private bool FindContributingView(out T_Tile rewriting)
{
// find some view that helps reduce toFill
foreach (T_Tile view in AvailableViews)
{
if (false == m_qp.IsDisjointFrom(view, m_toFill))
{
rewriting = view;
m_usedViews[view] = TileOpKind.Join; // positive, intersected
return true;
}
}
rewriting = null;
return false;
}
private IEnumerable<T_Tile> AvailableViews
{
get { return m_views.Where(view => !m_usedViews.ContainsKey(view)); }
}
}
}

View File

@ -0,0 +1,288 @@
//---------------------------------------------------------------------
// <copyright file="RewritingProcessor.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//
// @owner [....]
// @backupOwner [....]
//---------------------------------------------------------------------
using System;
using System.Diagnostics;
using System.Collections.Generic;
using System.Text;
namespace System.Data.Mapping.ViewGeneration.QueryRewriting
{
internal abstract class TileProcessor<T_Tile>
{
internal abstract bool IsEmpty(T_Tile tile);
internal abstract T_Tile Union(T_Tile a, T_Tile b);
internal abstract T_Tile Join(T_Tile a, T_Tile b);
internal abstract T_Tile AntiSemiJoin(T_Tile a, T_Tile b);
internal abstract T_Tile GetArg1(T_Tile tile);
internal abstract T_Tile GetArg2(T_Tile tile);
internal abstract TileOpKind GetOpKind(T_Tile tile);
}
internal class RewritingProcessor<T_Tile> : TileProcessor<T_Tile> where T_Tile : class
{
public double PERMUTE_FRACTION = 0.0;
public int MIN_PERMUTATIONS = 0;
public int MAX_PERMUTATIONS = 0;
public bool REORDER_VIEWS = false;
private int m_numSATChecks;
private int m_numIntersection;
private int m_numDifference;
private int m_numUnion;
private int m_numErrors;
private TileProcessor<T_Tile> m_tileProcessor;
public RewritingProcessor(TileProcessor<T_Tile> tileProcessor)
{
m_tileProcessor = tileProcessor;
}
internal TileProcessor<T_Tile> TileProcessor
{
get { return m_tileProcessor; }
}
public void GetStatistics(out int numSATChecks, out int numIntersection, out int numUnion, out int numDifference, out int numErrors)
{
numSATChecks = m_numSATChecks;
numIntersection = m_numIntersection;
numUnion = m_numUnion;
numDifference = m_numDifference;
numErrors = m_numErrors;
}
public void PrintStatistics()
{
Console.WriteLine("{0} containment checks, {4} set operations ({1} intersections + {2} unions + {3} differences)",
m_numSATChecks, m_numIntersection, m_numUnion, m_numDifference,
m_numIntersection + m_numUnion + m_numDifference);
Console.WriteLine("{0} errors", m_numErrors);
}
internal override T_Tile GetArg1(T_Tile tile)
{
return m_tileProcessor.GetArg1(tile);
}
internal override T_Tile GetArg2(T_Tile tile)
{
return m_tileProcessor.GetArg2(tile);
}
internal override TileOpKind GetOpKind(T_Tile tile)
{
return m_tileProcessor.GetOpKind(tile);
}
internal override bool IsEmpty(T_Tile a)
{
m_numSATChecks++;
return m_tileProcessor.IsEmpty(a);
}
public bool IsDisjointFrom(T_Tile a, T_Tile b)
{
return m_tileProcessor.IsEmpty(Join(a, b));
}
internal bool IsContainedIn(T_Tile a, T_Tile b)
{
T_Tile difference = AntiSemiJoin(a, b);
return IsEmpty(difference);
}
internal bool IsEquivalentTo(T_Tile a, T_Tile b)
{
bool aInB = IsContainedIn(a, b);
bool bInA = IsContainedIn(b, a);
return aInB && bInA;
}
internal override T_Tile Union(T_Tile a, T_Tile b)
{
m_numUnion++;
return m_tileProcessor.Union(a, b);
}
internal override T_Tile Join(T_Tile a, T_Tile b)
{
if (a == null)
{
return b;
}
m_numIntersection++;
return m_tileProcessor.Join(a, b);
}
internal override T_Tile AntiSemiJoin(T_Tile a, T_Tile b)
{
m_numDifference++;
return m_tileProcessor.AntiSemiJoin(a, b);
}
public void AddError()
{
m_numErrors++;
}
public int CountOperators(T_Tile query)
{
int count = 0;
if (query != null)
{
if (GetOpKind(query) != TileOpKind.Named)
{
count++;
count += CountOperators(GetArg1(query));
count += CountOperators(GetArg2(query));
}
}
return count;
}
public int CountViews(T_Tile query)
{
HashSet<T_Tile> views = new HashSet<T_Tile>();
GatherViews(query, views);
return views.Count;
}
public void GatherViews(T_Tile rewriting, HashSet<T_Tile> views)
{
if (rewriting != null)
{
if (GetOpKind(rewriting) == TileOpKind.Named)
{
views.Add(rewriting);
}
else
{
GatherViews(GetArg1(rewriting), views);
GatherViews(GetArg2(rewriting), views);
}
}
}
public static IEnumerable<T> AllButOne<T>(IEnumerable<T> list, int toSkipPosition)
{
int valuePosition = 0;
foreach (T value in list)
{
if (valuePosition++ != toSkipPosition)
{
yield return value;
}
}
}
public static IEnumerable<T> Concat<T>(T value, IEnumerable<T> rest)
{
yield return value;
foreach (T restValue in rest)
{
yield return restValue;
}
}
public static IEnumerable<IEnumerable<T>> Permute<T>(IEnumerable<T> list)
{
IEnumerable<T> rest = null;
int valuePosition = 0;
foreach (T value in list)
{
rest = AllButOne<T>(list, valuePosition++);
foreach (IEnumerable<T> restPermutation in Permute<T>(rest))
{
yield return Concat<T>(value, restPermutation);
}
}
if (rest == null)
{
yield return list; // list is empty enumeration
}
}
static Random rnd = new Random(1507);
public static List<T> RandomPermutation<T>(IEnumerable<T> input)
{
List<T> output = new List<T>(input);
for (int i = 0; i < output.Count; i++)
{
int j = rnd.Next(output.Count);
T tmp = output[i];
output[i] = output[j];
output[j] = tmp;
}
return output;
}
public static IEnumerable<T> Reverse<T>(IEnumerable<T> input, HashSet<T> filter)
{
List<T> output = new List<T>(input);
output.Reverse();
foreach (T t in output)
{
if (filter.Contains(t))
{
yield return t;
}
}
}
public bool RewriteQuery(T_Tile toFill, T_Tile toAvoid, IEnumerable<T_Tile> views, out T_Tile rewriting)
{
if (RewriteQueryOnce(toFill, toAvoid, views, out rewriting))
{
HashSet<T_Tile> usedViews = new HashSet<T_Tile>();
GatherViews(rewriting, usedViews);
int opCount = CountOperators(rewriting);
// try several permutations of views, pick one with fewer operators
T_Tile newRewriting;
int permuteTries = 0;
int numPermutations = Math.Min(MAX_PERMUTATIONS, Math.Max(MIN_PERMUTATIONS, (int)(usedViews.Count * PERMUTE_FRACTION)));
while (permuteTries++ < numPermutations)
{
IEnumerable<T_Tile> permutedViews;
if (permuteTries == 1)
{
permutedViews = Reverse(views, usedViews);
}
else
{
permutedViews = RandomPermutation(usedViews); // Tradeoff: views vs. usedViews!
}
bool succeeded = RewriteQueryOnce(toFill, toAvoid, permutedViews, out newRewriting);
Debug.Assert(succeeded);
int newOpCount = CountOperators(newRewriting);
if (newOpCount < opCount)
{
opCount = newOpCount;
rewriting = newRewriting;
}
HashSet<T_Tile> newUsedViews = new HashSet<T_Tile>();
GatherViews(newRewriting, newUsedViews);
usedViews = newUsedViews; // can only be fewer!
}
return true;
}
return false;
}
public bool RewriteQueryOnce(T_Tile toFill, T_Tile toAvoid, IEnumerable<T_Tile> views, out T_Tile rewriting)
{
List<T_Tile> viewList = new List<T_Tile>(views);
return RewritingPass<T_Tile>.RewriteQuery(toFill, toAvoid, out rewriting, viewList, this);
}
}
}

View File

@ -0,0 +1,211 @@
//---------------------------------------------------------------------
// <copyright file="RewritingSimplifier.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//
// @owner [....]
// @backupOwner [....]
//---------------------------------------------------------------------
using System;
using System.Diagnostics;
using System.Collections.Generic;
using System.Text;
using System.Linq;
namespace System.Data.Mapping.ViewGeneration.QueryRewriting
{
internal class RewritingSimplifier<T_Tile> where T_Tile : class
{
private readonly T_Tile m_originalRewriting;
private readonly T_Tile m_toAvoid;
private readonly RewritingProcessor<T_Tile> m_qp;
private readonly Dictionary<T_Tile, TileOpKind> m_usedViews = new Dictionary<T_Tile, TileOpKind>();
// used for join/antisemijoin simplification
private RewritingSimplifier(T_Tile originalRewriting, T_Tile toAvoid, Dictionary<T_Tile, TileOpKind> usedViews,
RewritingProcessor<T_Tile> qp)
{
m_originalRewriting = originalRewriting;
m_toAvoid = toAvoid;
m_qp = qp;
m_usedViews = usedViews;
}
// used for union simplification
private RewritingSimplifier(T_Tile rewriting, T_Tile toFill, T_Tile toAvoid, RewritingProcessor<T_Tile> qp)
{
m_originalRewriting = toFill;
m_toAvoid = toAvoid;
m_qp = qp;
m_usedViews = new Dictionary<T_Tile, TileOpKind>();
GatherUnionedSubqueriesInUsedViews(rewriting);
}
// called for top query only
internal static bool TrySimplifyUnionRewriting(ref T_Tile rewriting, T_Tile toFill, T_Tile toAvoid, RewritingProcessor<T_Tile> qp)
{
RewritingSimplifier<T_Tile> simplifier = new RewritingSimplifier<T_Tile>(rewriting, toFill, toAvoid, qp);
// gather all unioned subqueries
T_Tile simplifiedRewriting;
if (simplifier.SimplifyRewriting(out simplifiedRewriting))
{
rewriting = simplifiedRewriting;
return true;
}
return false;
}
// modifies usedViews - removes all redundant views from it
internal static bool TrySimplifyJoinRewriting(ref T_Tile rewriting, T_Tile toAvoid, Dictionary<T_Tile, TileOpKind> usedViews, RewritingProcessor<T_Tile> qp)
{
RewritingSimplifier<T_Tile> simplifier = new RewritingSimplifier<T_Tile>(rewriting, toAvoid, usedViews, qp);
T_Tile simplifiedRewriting;
if (simplifier.SimplifyRewriting(out simplifiedRewriting))
{
rewriting = simplifiedRewriting;
return true;
}
return false;
}
private void GatherUnionedSubqueriesInUsedViews(T_Tile query)
{
if (query != null)
{
if (m_qp.GetOpKind(query) != TileOpKind.Union)
{
m_usedViews[query] = TileOpKind.Union;
}
else
{
GatherUnionedSubqueriesInUsedViews(m_qp.GetArg1(query));
GatherUnionedSubqueriesInUsedViews(m_qp.GetArg2(query));
}
}
}
// isExactAnswer: matters for Intersections/Differences only
private bool SimplifyRewriting(out T_Tile simplifiedRewriting)
{
bool compacted = false;
simplifiedRewriting = null;
T_Tile simplifiedOnce;
while (SimplifyRewritingOnce(out simplifiedOnce))
{
compacted = true;
simplifiedRewriting = simplifiedOnce;
}
return compacted;
}
// try removing one redundant view from intersected and subtracted views
// This method uses a dynamic divide-and-conquer algorithm that avoids recomputing many intersections/differences
private bool SimplifyRewritingOnce(out T_Tile simplifiedRewriting)
{
// check whether removing one or multiple views from intersected and subtracted views
// still (a) reduces extra tuples, and (b) has no missing tuples
// First, try removing a subtracted view
HashSet<T_Tile> remainingViews = new HashSet<T_Tile>(m_usedViews.Keys);
foreach (T_Tile usedView in m_usedViews.Keys)
{
// pick an intersected view, and nail it down
switch (m_usedViews[usedView])
{
case TileOpKind.Join:
case TileOpKind.Union:
remainingViews.Remove(usedView);
if (SimplifyRewritingOnce(usedView, remainingViews, out simplifiedRewriting))
{
return true;
}
remainingViews.Add(usedView);
break;
}
}
simplifiedRewriting = null;
return false;
}
// remainingViews may contain either unions only or intersections + differences
private bool SimplifyRewritingOnce(T_Tile newRewriting, HashSet<T_Tile> remainingViews,
out T_Tile simplifiedRewriting)
{
simplifiedRewriting = null;
if (remainingViews.Count == 0)
{
return false;
}
if (remainingViews.Count == 1)
{
// determine the remaining view
T_Tile remainingView = remainingViews.First();
// check whether rewriting obtained so far is good enough
// try disposing of this remaining view
bool isDisposable = false;
switch (m_usedViews[remainingView])
{
case TileOpKind.Union:
// check whether rewriting still covers toFill
isDisposable = m_qp.IsContainedIn(m_originalRewriting, newRewriting);
break;
default: // intersection
isDisposable = m_qp.IsContainedIn(m_originalRewriting, newRewriting) &&
m_qp.IsDisjointFrom(m_toAvoid, newRewriting);
break;
}
if (isDisposable)
{
// yes, the remaining view is disposable
simplifiedRewriting = newRewriting;
m_usedViews.Remove(remainingView);
return true;
}
return false; // no, can't trash the remaining view
}
// split remainingViews into two halves
// Compute rewriting for first half. Call recursively on second half.
// Then, compute rewriting for second half. Call recursively on first half.
int halfCount = remainingViews.Count / 2;
int count = 0;
T_Tile firstHalfRewriting = newRewriting;
T_Tile secondHalfRewriting = newRewriting;
HashSet<T_Tile> firstHalf = new HashSet<T_Tile>();
HashSet<T_Tile> secondHalf = new HashSet<T_Tile>();
foreach (T_Tile remainingView in remainingViews)
{
TileOpKind viewKind = m_usedViews[remainingView];
// add to first half
if (count++ < halfCount)
{
firstHalf.Add(remainingView);
firstHalfRewriting = GetRewritingHalf(firstHalfRewriting, remainingView, viewKind);
}
else // add to second half
{
secondHalf.Add(remainingView);
secondHalfRewriting = GetRewritingHalf(secondHalfRewriting, remainingView, viewKind);
}
}
// now, call recursively
return SimplifyRewritingOnce(firstHalfRewriting, secondHalf, out simplifiedRewriting)
|| SimplifyRewritingOnce(secondHalfRewriting, firstHalf, out simplifiedRewriting);
}
private T_Tile GetRewritingHalf(T_Tile halfRewriting, T_Tile remainingView, TileOpKind viewKind)
{
switch (viewKind)
{
case TileOpKind.Join:
halfRewriting = m_qp.Join(halfRewriting, remainingView); break;
case TileOpKind.AntiSemiJoin:
halfRewriting = m_qp.AntiSemiJoin(halfRewriting, remainingView); break;
case TileOpKind.Union:
halfRewriting = m_qp.Union(halfRewriting, remainingView); break;
default: Debug.Fail("unexpected"); break;
}
return halfRewriting;
}
}
}

View File

@ -0,0 +1,127 @@
//---------------------------------------------------------------------
// <copyright file="RoleBoolean.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//
// @owner [....]
// @backupOwner [....]
//---------------------------------------------------------------------
namespace System.Data.Mapping.ViewGeneration.Structures
{
using System.Collections.Generic;
using System.Data.Common.CommandTrees;
using System.Data.Entity;
using System.Data.Metadata.Edm;
using System.Diagnostics;
using System.Text;
/// <summary>
/// Denotes the fact that the key of the current tuple comes from a specific extent, or association role.
/// </summary>
internal sealed class RoleBoolean : TrueFalseLiteral
{
#region Constructor
internal RoleBoolean(EntitySetBase extent)
{
m_metadataItem = extent;
}
internal RoleBoolean(AssociationSetEnd end)
{
m_metadataItem = end;
}
#endregion
#region Fields
private readonly MetadataItem m_metadataItem;
#endregion
#region BoolLiteral members
/// <summary>
/// Not supported in this class.
/// </summary>
internal override StringBuilder AsEsql(StringBuilder builder, string blockAlias, bool skipIsNotNull)
{
Debug.Fail("Should not be called.");
return null; // To keep the compiler happy
}
/// <summary>
/// Not supported in this class.
/// </summary>
internal override DbExpression AsCqt(DbExpression row, bool skipIsNotNull)
{
Debug.Fail("Should not be called.");
return null; // To keep the compiler happy
}
internal override StringBuilder AsUserString(StringBuilder builder, string blockAlias, bool skipIsNotNull)
{
AssociationSetEnd end = m_metadataItem as AssociationSetEnd;
if (end != null)
{
builder.Append(Strings.ViewGen_AssociationSet_AsUserString(blockAlias, end.Name, end.ParentAssociationSet));
}
else
{
builder.Append(Strings.ViewGen_EntitySet_AsUserString(blockAlias, m_metadataItem.ToString()));
}
return builder;
}
internal override StringBuilder AsNegatedUserString(StringBuilder builder, string blockAlias, bool skipIsNotNull)
{
AssociationSetEnd end = m_metadataItem as AssociationSetEnd;
if (end != null)
{
builder.Append(Strings.ViewGen_AssociationSet_AsUserString_Negated(blockAlias, end.Name, end.ParentAssociationSet));
}
else
{
builder.Append(Strings.ViewGen_EntitySet_AsUserString_Negated(blockAlias, m_metadataItem.ToString()));
}
return builder;
}
internal override void GetRequiredSlots(MemberProjectionIndex projectedSlotMap, bool[] requiredSlots)
{
throw new NotImplementedException();
}
protected override bool IsEqualTo(BoolLiteral right)
{
RoleBoolean rightBoolean = right as RoleBoolean;
if (rightBoolean == null)
{
return false;
}
return m_metadataItem == rightBoolean.m_metadataItem;
}
public override int GetHashCode()
{
return m_metadataItem.GetHashCode();
}
internal override BoolLiteral RemapBool(Dictionary<MemberPath, MemberPath> remap)
{
return this;
}
#endregion
#region Other Methods
internal override void ToCompactString(StringBuilder builder)
{
AssociationSetEnd end = m_metadataItem as AssociationSetEnd;
if (end != null)
{
builder.Append("InEnd:" + end.ParentAssociationSet + "_" + end.Name);
}
else
{
builder.Append("InSet:" + m_metadataItem.ToString());
}
}
#endregion
}
}

View File

@ -0,0 +1,254 @@
//---------------------------------------------------------------------
// <copyright file="Tile.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//
// @owner [....]
// @backupOwner [....]
//---------------------------------------------------------------------
using System;
using System.Diagnostics;
using System.Collections.Generic;
using System.Text;
using System.Collections.ObjectModel;
using System.Linq;
using System.Globalization;
namespace System.Data.Mapping.ViewGeneration.QueryRewriting
{
internal enum TileOpKind
{
Union,
Join,
AntiSemiJoin,
// Project,
Named
}
internal interface ITileQuery
{
string Description { get; }
}
internal abstract class TileQueryProcessor<T_Query> where T_Query : ITileQuery
{
internal abstract T_Query Intersect(T_Query arg1, T_Query arg2);
internal abstract T_Query Difference(T_Query arg1, T_Query arg2);
internal abstract T_Query Union(T_Query arg1, T_Query arg2);
internal abstract bool IsSatisfiable(T_Query query);
internal abstract T_Query CreateDerivedViewBySelectingConstantAttributes(T_Query query);
}
internal class DefaultTileProcessor<T_Query> : TileProcessor<Tile<T_Query>> where T_Query : ITileQuery
{
private readonly TileQueryProcessor<T_Query> _tileQueryProcessor;
internal DefaultTileProcessor(TileQueryProcessor<T_Query> tileQueryProcessor)
{
_tileQueryProcessor = tileQueryProcessor;
}
internal TileQueryProcessor<T_Query> QueryProcessor
{
get { return _tileQueryProcessor; }
}
internal override bool IsEmpty(Tile<T_Query> tile)
{
return false == _tileQueryProcessor.IsSatisfiable(tile.Query);
}
internal override Tile<T_Query> Union(Tile<T_Query> arg1, Tile<T_Query> arg2)
{
return new TileBinaryOperator<T_Query>(arg1, arg2, TileOpKind.Union, _tileQueryProcessor.Union(arg1.Query, arg2.Query));
}
internal override Tile<T_Query> Join(Tile<T_Query> arg1, Tile<T_Query> arg2)
{
return new TileBinaryOperator<T_Query>(arg1, arg2, TileOpKind.Join, _tileQueryProcessor.Intersect(arg1.Query, arg2.Query));
}
internal override Tile<T_Query> AntiSemiJoin(Tile<T_Query> arg1, Tile<T_Query> arg2)
{
return new TileBinaryOperator<T_Query>(arg1, arg2, TileOpKind.AntiSemiJoin, _tileQueryProcessor.Difference(arg1.Query, arg2.Query));
}
internal override Tile<T_Query> GetArg1(Tile<T_Query> tile)
{
return tile.Arg1;
}
internal override Tile<T_Query> GetArg2(Tile<T_Query> tile)
{
return tile.Arg2;
}
internal override TileOpKind GetOpKind(Tile<T_Query> tile)
{
return tile.OpKind;
}
internal bool IsContainedIn(Tile<T_Query> arg1, Tile<T_Query> arg2)
{
return IsEmpty(AntiSemiJoin(arg1, arg2));
}
internal bool IsEquivalentTo(Tile<T_Query> arg1, Tile<T_Query> arg2)
{
return IsContainedIn(arg1, arg2) && IsContainedIn(arg2, arg1);
}
}
internal abstract class Tile<T_Query> where T_Query : ITileQuery
{
private readonly T_Query m_query;
private readonly TileOpKind m_opKind;
protected Tile(TileOpKind opKind, T_Query query)
{
m_opKind = opKind;
m_query = query;
}
public T_Query Query
{
get { return m_query; }
}
public abstract string Description { get; }
// multiple occurrences possible
public IEnumerable<T_Query> GetNamedQueries()
{
return GetNamedQueries(this);
}
private static IEnumerable<T_Query> GetNamedQueries(Tile<T_Query> rewriting)
{
if (rewriting != null)
{
if (rewriting.OpKind == TileOpKind.Named)
{
yield return ((TileNamed<T_Query>)rewriting).NamedQuery;
}
else
{
foreach (T_Query query in GetNamedQueries(rewriting.Arg1))
{
yield return query;
}
foreach (T_Query query in GetNamedQueries(rewriting.Arg2))
{
yield return query;
}
}
}
}
public override string ToString()
{
string formattedQuery = this.Description;
if (formattedQuery != null)
{
return String.Format(CultureInfo.InvariantCulture, "{0}: [{1}]", this.Description, this.Query);
}
else
{
return String.Format(CultureInfo.InvariantCulture, "[{0}]", this.Query);
}
}
public abstract Tile<T_Query> Arg1
{
get;
}
public abstract Tile<T_Query> Arg2
{
get;
}
public TileOpKind OpKind
{
get { return m_opKind; }
}
internal abstract Tile<T_Query> Replace(Tile<T_Query> oldTile, Tile<T_Query> newTile);
}
internal class TileNamed<T_Query> : Tile<T_Query> where T_Query : ITileQuery
{
public TileNamed(T_Query namedQuery)
: base(TileOpKind.Named, namedQuery)
{
Debug.Assert(namedQuery != null);
}
public T_Query NamedQuery
{
get { return this.Query; }
}
public override Tile<T_Query> Arg1 { get { return null; } }
public override Tile<T_Query> Arg2 { get { return null; } }
public override string Description
{
get { return this.Query.Description; }
}
public override string ToString()
{
return this.Query.ToString();
}
internal override Tile<T_Query> Replace(Tile<T_Query> oldTile, Tile<T_Query> newTile)
{
return (this == oldTile) ? newTile : this;
}
}
internal class TileBinaryOperator<T_Query> : Tile<T_Query> where T_Query : ITileQuery
{
private readonly Tile<T_Query> m_arg1;
private readonly Tile<T_Query> m_arg2;
public TileBinaryOperator(Tile<T_Query> arg1, Tile<T_Query> arg2, TileOpKind opKind, T_Query query)
: base(opKind, query)
{
Debug.Assert(arg1 != null && arg2 != null);
m_arg1 = arg1;
m_arg2 = arg2;
}
public override Tile<T_Query> Arg1 { get { return m_arg1; } }
public override Tile<T_Query> Arg2 { get { return m_arg2; } }
public override string Description
{
get
{
string descriptionFormat = null;
switch (OpKind)
{
case TileOpKind.Join: descriptionFormat = "({0} & {1})"; break;
case TileOpKind.AntiSemiJoin: descriptionFormat = "({0} - {1})"; break;
case TileOpKind.Union: descriptionFormat = "({0} | {1})"; break;
default: Debug.Fail("Unexpected binary operator"); break;
}
return String.Format(CultureInfo.InvariantCulture, descriptionFormat, this.Arg1.Description, this.Arg2.Description);
}
}
internal override Tile<T_Query> Replace(Tile<T_Query> oldTile, Tile<T_Query> newTile)
{
Tile<T_Query> newArg1 = Arg1.Replace(oldTile, newTile);
Tile<T_Query> newArg2 = Arg2.Replace(oldTile, newTile);
if (newArg1 != Arg1 || newArg2 != Arg2)
{
return new TileBinaryOperator<T_Query>(newArg1, newArg2, OpKind, Query);
}
return this;
}
}
}