1 //---------------------------------------------------------------------
2 // <copyright file="Vars.cs" company="Microsoft">
3 // Copyright (c) Microsoft Corporation. All rights reserved.
7 // @backupOwner Microsoft
8 //---------------------------------------------------------------------
11 using System.Collections;
12 using System.Collections.Generic;
13 using System.Data.Metadata.Edm;
14 using System.Diagnostics;
15 using System.Globalization;
18 namespace System.Data.Query.InternalTrees
41 /// Var for SetOps (Union, Intersect, Except)
52 /// Same as a ValRef in SqlServer. I just like changing names :-)
54 internal abstract class Var
60 internal Var(int id, VarType varType, TypeUsage type)
70 internal int Id { get { return m_id; } }
75 internal VarType VarType { get { return m_varType; } }
78 /// Datatype of this Var
80 internal TypeUsage Type { get { return m_type; } }
83 /// Try to get the name of this Var.
85 /// <param name="name"></param>
86 /// <returns></returns>
87 internal virtual bool TryGetName(out string name)
96 /// <returns></returns>
97 public override string ToString()
99 return String.Format(CultureInfo.InvariantCulture, "{0}", this.Id); ;
104 /// Describes a query parameter
106 internal sealed class ParameterVar : Var
110 internal ParameterVar(int id, TypeUsage type, string paramName)
111 : base(id, VarType.Parameter, type)
113 m_paramName = paramName;
117 /// Name of the parameter
119 internal string ParameterName { get { return m_paramName; } }
122 /// Get the name of this Var
124 /// <param name="name"></param>
125 /// <returns></returns>
126 internal override bool TryGetName(out string name)
128 name = this.ParameterName;
134 /// Describes a column of a table
136 internal sealed class ColumnVar : Var
138 ColumnMD m_columnMetadata;
144 /// <param name="id"></param>
145 /// <param name="table"></param>
146 /// <param name="columnMetadata"></param>
147 internal ColumnVar(int id, Table table, ColumnMD columnMetadata)
148 : base(id, VarType.Column, columnMetadata.Type)
151 m_columnMetadata = columnMetadata;
155 /// The table instance containing this column reference
157 internal Table Table { get { return m_table; } }
160 /// The column metadata for this column
162 internal ColumnMD ColumnMetadata { get { return m_columnMetadata; } }
165 /// Get the name of this column var
167 /// <param name="name"></param>
168 /// <returns></returns>
169 internal override bool TryGetName(out string name)
171 name = m_columnMetadata.Name;
177 /// A computed expression. Defined by a VarDefOp
179 internal sealed class ComputedVar : Var
181 internal ComputedVar(int id, TypeUsage type) : base(id, VarType.Computed, type)
187 /// A SetOp Var - used as the output var for set operations (Union, Intersect, Except)
189 internal sealed class SetOpVar : Var
191 internal SetOpVar(int id, TypeUsage type) : base(id, VarType.SetOp, type) { }
197 /// A VarVec is a compressed representation of a set of variables - with no duplicates
200 /// A VarVec should be used in many places where we expect a number of vars to be
201 /// passed around; and we don't care particularly about the ordering of the vars
203 /// This is obviously not suitable for representing sort keys, but is still
204 /// reasonable for representing group by keys, and a variety of others.
207 internal class VarVec : IEnumerable<Var>
209 #region Nested Classes
211 /// A VarVec enumerator is a specialized enumerator for a VarVec.
213 internal class VarVecEnumerator : IEnumerator<Var>, IDisposable
215 #region private state
216 private int m_position;
217 private Command m_command;
218 private BitArray m_bitArray;
223 /// Constructs a new enumerator for the specified Vec
225 /// <param name="vec"></param>
226 internal VarVecEnumerator(VarVec vec)
232 #region public surface
234 /// Initialize the enumerator to enumerate over the supplied Vec
236 /// <param name="vec"></param>
237 internal void Init(VarVec vec)
240 m_command = vec.m_command;
241 m_bitArray = vec.m_bitVector;
245 #region IEnumerator<Var> Members
247 /// Get the Var at the current position
251 get { return (m_position >= 0 && m_position < m_bitArray.Count) ? m_command.GetVar(m_position) : (Var)null; }
255 #region IEnumerator Members
256 object IEnumerator.Current
258 get { return Current;}
262 /// Move to the next position
264 /// <returns></returns>
265 public bool MoveNext()
268 for (; m_position < m_bitArray.Count; m_position++)
270 if (m_bitArray[m_position])
279 /// Reset enumerator to start off again
287 #region IDisposable Members
289 /// Dispose of the current enumerator - return it to the Command
291 public void Dispose()
293 // Technically, calling GC.SuppressFinalize is not required because the class does not
294 // have a finalizer, but it does no harm, protects against the case where a finalizer is added
295 // in the future, and prevents an FxCop warning.
296 GC.SuppressFinalize(this);
298 m_command.ReleaseVarVecEnumerator(this);
305 #region public methods
306 internal void Clear()
308 m_bitVector.Length = 0;
311 internal void And(VarVec other)
314 m_bitVector.And(other.m_bitVector);
317 internal void Or(VarVec other)
320 m_bitVector.Or(other.m_bitVector);
324 /// Computes (this Minus other) by performing (this And (Not(other)))
325 /// A temp VarVec is used and released at the end of the operation
327 /// <param name="other"></param>
328 internal void Minus(VarVec other)
330 VarVec tmp = m_command.CreateVarVec(other);
331 tmp.m_bitVector.Length = m_bitVector.Length;
332 tmp.m_bitVector.Not();
334 m_command.ReleaseVarVec(tmp);
338 /// Does this have a non-zero overlap with the other vec
340 /// <param name="other"></param>
341 /// <returns></returns>
342 internal bool Overlaps(VarVec other)
344 VarVec otherCopy = m_command.CreateVarVec(other);
346 bool overlaps = !otherCopy.IsEmpty;
347 m_command.ReleaseVarVec(otherCopy);
352 /// Does this Vec include every var in the other vec?
353 /// Written this way deliberately under the assumption that "other"
354 /// is a relatively small vec
356 /// <param name="other"></param>
357 /// <returns></returns>
358 internal bool Subsumes(VarVec other)
360 for (int i = 0; i < other.m_bitVector.Count; i++)
362 if (other.m_bitVector[i] &&
363 ((i >= this.m_bitVector.Count) || !this.m_bitVector[i]))
371 internal void InitFrom(VarVec other)
374 this.m_bitVector.Length = other.m_bitVector.Length;
375 this.m_bitVector.Or(other.m_bitVector);
378 internal void InitFrom(IEnumerable<Var> other)
380 InitFrom(other, false);
383 internal void InitFrom(IEnumerable<Var> other, bool ignoreParameters)
386 foreach (Var v in other)
388 if (!ignoreParameters || (v.VarType != VarType.Parameter))
396 /// The enumerator pattern
398 /// <returns></returns>
399 public IEnumerator<Var> GetEnumerator()
401 return m_command.GetVarVecEnumerator(this);
404 IEnumerator IEnumerable.GetEnumerator()
406 return this.GetEnumerator();
410 /// Number of vars in this set
417 foreach (Var v in this)
423 internal bool IsSet(Var v)
426 return m_bitVector.Get(v.Id);
428 internal void Set(Var v)
431 m_bitVector.Set(v.Id, true);
433 internal void Clear(Var v)
436 m_bitVector.Set(v.Id, false);
440 /// Is this Vec empty?
442 internal bool IsEmpty
444 get { return this.First == null;}
448 /// Get me the first var that is set
454 foreach (Var v in this)
463 /// Walk through the input varVec, replace any vars that have been "renamed" based
464 /// on the input varMap, and return the new VarVec
466 /// <param name="varMap">dictionary of renamed vars</param>
467 /// <returns>a new VarVec</returns>
468 internal VarVec Remap(Dictionary<Var, Var> varMap)
470 VarVec newVec = m_command.CreateVarVec();
471 foreach (Var v in this)
474 if (!varMap.TryGetValue(v, out newVar))
486 internal VarVec(Command command)
488 m_bitVector = new BitArray(64);
493 #region private methods
494 private void Align(VarVec other)
496 if (other.m_bitVector.Count == this.m_bitVector.Count)
498 if (other.m_bitVector.Count > this.m_bitVector.Count)
500 this.m_bitVector.Length = other.m_bitVector.Count;
504 other.m_bitVector.Length = this.m_bitVector.Count;
507 private void Align(int idx)
509 if (idx >= m_bitVector.Count)
511 m_bitVector.Length = idx + 1;
516 /// Debugging support
517 /// provide a string representation for debugging.
518 /// <returns></returns>
520 public override string ToString()
522 StringBuilder sb = new StringBuilder();
523 string separator = String.Empty;
525 foreach (Var v in this)
527 sb.AppendFormat(CultureInfo.InvariantCulture, "{0}{1}", separator, v.Id);
530 return sb.ToString();
534 #region private state
535 private BitArray m_bitVector;
536 private Command m_command;
541 /// Create a clone of this vec
543 /// <returns></returns>
544 public VarVec Clone()
546 VarVec newVec = m_command.CreateVarVec();
547 newVec.InitFrom(this);
555 /// An ordered list of Vars. Use this when you need an ordering.
557 [DebuggerDisplay("{{{ToString()}}}")]
558 internal class VarList : List<Var>
562 /// Trivial constructor
564 internal VarList() : base() { }
567 /// Not so trivial constructor
569 /// <param name="vars"></param>
570 internal VarList(IEnumerable<Var> vars) : base(vars) { }
573 #region public methods
576 /// Debugging support
577 /// provide a string representation for debugging.
578 /// <returns></returns>
580 public override string ToString()
582 StringBuilder sb = new StringBuilder();
583 string separator = String.Empty;
585 foreach (Var v in this)
587 sb.AppendFormat(CultureInfo.InvariantCulture, "{0}{1}", separator, v.Id);
590 return sb.ToString();
599 /// Helps map one variable to the next.
601 internal class VarMap: Dictionary<Var, Var>
603 #region public surfaces
605 internal VarMap GetReverseMap()
607 VarMap reverseMap = new VarMap();
608 foreach (KeyValuePair<Var, Var> kv in this)
611 // On the odd chance that a var is in the varMap more than once, the first one
612 // is going to be the one we want to use, because it might be the discriminator
614 if (!reverseMap.TryGetValue(kv.Value, out x))
616 reverseMap[kv.Value] = kv.Key;
622 public override string ToString()
624 StringBuilder sb = new StringBuilder();
625 string separator = string.Empty;
627 foreach (Var v in this.Keys)
629 sb.AppendFormat(CultureInfo.InvariantCulture, "{0}({1},{2})", separator, v.Id, this[v].Id);
632 return sb.ToString();
638 internal VarMap() : base() { }