1 //---------------------------------------------------------------------
2 // <copyright file="Tile.cs" company="Microsoft">
3 // Copyright (c) Microsoft Corporation. All rights reserved.
7 // @backupOwner Microsoft
8 //---------------------------------------------------------------------
11 using System.Diagnostics;
12 using System.Collections.Generic;
14 using System.Collections.ObjectModel;
16 using System.Globalization;
18 namespace System.Data.Mapping.ViewGeneration.QueryRewriting
20 internal enum TileOpKind
29 internal interface ITileQuery
31 string Description { get; }
34 internal abstract class TileQueryProcessor<T_Query> where T_Query : ITileQuery
36 internal abstract T_Query Intersect(T_Query arg1, T_Query arg2);
37 internal abstract T_Query Difference(T_Query arg1, T_Query arg2);
38 internal abstract T_Query Union(T_Query arg1, T_Query arg2);
39 internal abstract bool IsSatisfiable(T_Query query);
40 internal abstract T_Query CreateDerivedViewBySelectingConstantAttributes(T_Query query);
43 internal class DefaultTileProcessor<T_Query> : TileProcessor<Tile<T_Query>> where T_Query : ITileQuery
45 private readonly TileQueryProcessor<T_Query> _tileQueryProcessor;
47 internal DefaultTileProcessor(TileQueryProcessor<T_Query> tileQueryProcessor)
49 _tileQueryProcessor = tileQueryProcessor;
52 internal TileQueryProcessor<T_Query> QueryProcessor
54 get { return _tileQueryProcessor; }
57 internal override bool IsEmpty(Tile<T_Query> tile)
59 return false == _tileQueryProcessor.IsSatisfiable(tile.Query);
62 internal override Tile<T_Query> Union(Tile<T_Query> arg1, Tile<T_Query> arg2)
64 return new TileBinaryOperator<T_Query>(arg1, arg2, TileOpKind.Union, _tileQueryProcessor.Union(arg1.Query, arg2.Query));
67 internal override Tile<T_Query> Join(Tile<T_Query> arg1, Tile<T_Query> arg2)
69 return new TileBinaryOperator<T_Query>(arg1, arg2, TileOpKind.Join, _tileQueryProcessor.Intersect(arg1.Query, arg2.Query));
72 internal override Tile<T_Query> AntiSemiJoin(Tile<T_Query> arg1, Tile<T_Query> arg2)
74 return new TileBinaryOperator<T_Query>(arg1, arg2, TileOpKind.AntiSemiJoin, _tileQueryProcessor.Difference(arg1.Query, arg2.Query));
77 internal override Tile<T_Query> GetArg1(Tile<T_Query> tile)
82 internal override Tile<T_Query> GetArg2(Tile<T_Query> tile)
87 internal override TileOpKind GetOpKind(Tile<T_Query> tile)
92 internal bool IsContainedIn(Tile<T_Query> arg1, Tile<T_Query> arg2)
94 return IsEmpty(AntiSemiJoin(arg1, arg2));
97 internal bool IsEquivalentTo(Tile<T_Query> arg1, Tile<T_Query> arg2)
99 return IsContainedIn(arg1, arg2) && IsContainedIn(arg2, arg1);
103 internal abstract class Tile<T_Query> where T_Query : ITileQuery
105 private readonly T_Query m_query;
106 private readonly TileOpKind m_opKind;
108 protected Tile(TileOpKind opKind, T_Query query)
116 get { return m_query; }
119 public abstract string Description { get; }
121 // multiple occurrences possible
122 public IEnumerable<T_Query> GetNamedQueries()
124 return GetNamedQueries(this);
126 private static IEnumerable<T_Query> GetNamedQueries(Tile<T_Query> rewriting)
128 if (rewriting != null)
130 if (rewriting.OpKind == TileOpKind.Named)
132 yield return ((TileNamed<T_Query>)rewriting).NamedQuery;
136 foreach (T_Query query in GetNamedQueries(rewriting.Arg1))
140 foreach (T_Query query in GetNamedQueries(rewriting.Arg2))
148 public override string ToString()
150 string formattedQuery = this.Description;
151 if (formattedQuery != null)
153 return String.Format(CultureInfo.InvariantCulture, "{0}: [{1}]", this.Description, this.Query);
157 return String.Format(CultureInfo.InvariantCulture, "[{0}]", this.Query);
161 public abstract Tile<T_Query> Arg1
166 public abstract Tile<T_Query> Arg2
171 public TileOpKind OpKind
173 get { return m_opKind; }
176 internal abstract Tile<T_Query> Replace(Tile<T_Query> oldTile, Tile<T_Query> newTile);
179 internal class TileNamed<T_Query> : Tile<T_Query> where T_Query : ITileQuery
181 public TileNamed(T_Query namedQuery)
182 : base(TileOpKind.Named, namedQuery)
184 Debug.Assert(namedQuery != null);
187 public T_Query NamedQuery
189 get { return this.Query; }
192 public override Tile<T_Query> Arg1 { get { return null; } }
193 public override Tile<T_Query> Arg2 { get { return null; } }
195 public override string Description
197 get { return this.Query.Description; }
200 public override string ToString()
202 return this.Query.ToString();
205 internal override Tile<T_Query> Replace(Tile<T_Query> oldTile, Tile<T_Query> newTile)
207 return (this == oldTile) ? newTile : this;
211 internal class TileBinaryOperator<T_Query> : Tile<T_Query> where T_Query : ITileQuery
213 private readonly Tile<T_Query> m_arg1;
214 private readonly Tile<T_Query> m_arg2;
216 public TileBinaryOperator(Tile<T_Query> arg1, Tile<T_Query> arg2, TileOpKind opKind, T_Query query)
217 : base(opKind, query)
219 Debug.Assert(arg1 != null && arg2 != null);
224 public override Tile<T_Query> Arg1 { get { return m_arg1; } }
225 public override Tile<T_Query> Arg2 { get { return m_arg2; } }
227 public override string Description
231 string descriptionFormat = null;
234 case TileOpKind.Join: descriptionFormat = "({0} & {1})"; break;
235 case TileOpKind.AntiSemiJoin: descriptionFormat = "({0} - {1})"; break;
236 case TileOpKind.Union: descriptionFormat = "({0} | {1})"; break;
237 default: Debug.Fail("Unexpected binary operator"); break;
239 return String.Format(CultureInfo.InvariantCulture, descriptionFormat, this.Arg1.Description, this.Arg2.Description);
243 internal override Tile<T_Query> Replace(Tile<T_Query> oldTile, Tile<T_Query> newTile)
245 Tile<T_Query> newArg1 = Arg1.Replace(oldTile, newTile);
246 Tile<T_Query> newArg2 = Arg2.Replace(oldTile, newTile);
247 if (newArg1 != Arg1 || newArg2 != Arg2)
249 return new TileBinaryOperator<T_Query>(newArg1, newArg2, OpKind, Query);