|
//---------------------------------------------------------------------
// <copyright file="Vars.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//
// @owner Microsoft
// @backupOwner Microsoft
//---------------------------------------------------------------------
using System;
using System.Collections;
using System.Collections.Generic;
using System.Data.Metadata.Edm;
using System.Diagnostics;
using System.Globalization;
using System.Text;
namespace System.Data.Query.InternalTrees
{
/// <summary>
/// Types of variable
/// </summary>
internal enum VarType
{
/// <summary>
/// a parameter
/// </summary>
Parameter,
/// <summary>
/// Column of a table
/// </summary>
Column,
/// <summary>
/// A Computed var
/// </summary>
Computed,
/// <summary>
/// Var for SetOps (Union, Intersect, Except)
/// </summary>
SetOp,
/// <summary>
/// NotValid
/// </summary>
NotValid
}
/// <summary>
/// Same as a ValRef in SqlServer. I just like changing names :-)
/// </summary>
internal abstract class Var
{
int m_id;
VarType m_varType;
TypeUsage m_type;
internal Var(int id, VarType varType, TypeUsage type)
{
m_id = id;
m_varType = varType;
m_type = type;
}
/// <summary>
/// Id of this var
/// </summary>
internal int Id { get { return m_id; } }
/// <summary>
/// Kind of Var
/// </summary>
internal VarType VarType { get { return m_varType; } }
/// <summary>
/// Datatype of this Var
/// </summary>
internal TypeUsage Type { get { return m_type; } }
/// <summary>
/// Try to get the name of this Var.
/// </summary>
/// <param name="name"></param>
/// <returns></returns>
internal virtual bool TryGetName(out string name)
{
name = null;
return false;
}
/// <summary>
/// Debugging support
/// </summary>
/// <returns></returns>
public override string ToString()
{
return String.Format(CultureInfo.InvariantCulture, "{0}", this.Id); ;
}
}
/// <summary>
/// Describes a query parameter
/// </summary>
internal sealed class ParameterVar : Var
{
string m_paramName;
internal ParameterVar(int id, TypeUsage type, string paramName)
: base(id, VarType.Parameter, type)
{
m_paramName = paramName;
}
/// <summary>
/// Name of the parameter
/// </summary>
internal string ParameterName { get { return m_paramName; } }
/// <summary>
/// Get the name of this Var
/// </summary>
/// <param name="name"></param>
/// <returns></returns>
internal override bool TryGetName(out string name)
{
name = this.ParameterName;
return true;
}
}
/// <summary>
/// Describes a column of a table
/// </summary>
internal sealed class ColumnVar : Var
{
ColumnMD m_columnMetadata;
Table m_table;
/// <summary>
/// Constructor
/// </summary>
/// <param name="id"></param>
/// <param name="table"></param>
/// <param name="columnMetadata"></param>
internal ColumnVar(int id, Table table, ColumnMD columnMetadata)
: base(id, VarType.Column, columnMetadata.Type)
{
m_table = table;
m_columnMetadata = columnMetadata;
}
/// <summary>
/// The table instance containing this column reference
/// </summary>
internal Table Table { get { return m_table; } }
/// <summary>
/// The column metadata for this column
/// </summary>
internal ColumnMD ColumnMetadata { get { return m_columnMetadata; } }
/// <summary>
/// Get the name of this column var
/// </summary>
/// <param name="name"></param>
/// <returns></returns>
internal override bool TryGetName(out string name)
{
name = m_columnMetadata.Name;
return true;
}
}
/// <summary>
/// A computed expression. Defined by a VarDefOp
/// </summary>
internal sealed class ComputedVar : Var
{
internal ComputedVar(int id, TypeUsage type) : base(id, VarType.Computed, type)
{
}
}
/// <summary>
/// A SetOp Var - used as the output var for set operations (Union, Intersect, Except)
/// </summary>
internal sealed class SetOpVar : Var
{
internal SetOpVar(int id, TypeUsage type) : base(id, VarType.SetOp, type) { }
}
//
/// <summary>
/// A VarVec is a compressed representation of a set of variables - with no duplicates
/// and no ordering
///
/// A VarVec should be used in many places where we expect a number of vars to be
/// passed around; and we don't care particularly about the ordering of the vars
///
/// This is obviously not suitable for representing sort keys, but is still
/// reasonable for representing group by keys, and a variety of others.
///
/// </summary>
internal class VarVec : IEnumerable<Var>
{
#region Nested Classes
/// <summary>
/// A VarVec enumerator is a specialized enumerator for a VarVec.
/// </summary>
internal class VarVecEnumerator : IEnumerator<Var>, IDisposable
{
#region private state
private int m_position;
private Command m_command;
private BitArray m_bitArray;
#endregion
#region Constructors
/// <summary>
/// Constructs a new enumerator for the specified Vec
/// </summary>
/// <param name="vec"></param>
internal VarVecEnumerator(VarVec vec)
{
Init(vec);
}
#endregion
#region public surface
/// <summary>
/// Initialize the enumerator to enumerate over the supplied Vec
/// </summary>
/// <param name="vec"></param>
internal void Init(VarVec vec)
{
m_position = -1;
m_command = vec.m_command;
m_bitArray = vec.m_bitVector;
}
#endregion
#region IEnumerator<Var> Members
/// <summary>
/// Get the Var at the current position
/// </summary>
public Var Current
{
get { return (m_position >= 0 && m_position < m_bitArray.Count) ? m_command.GetVar(m_position) : (Var)null; }
}
#endregion
#region IEnumerator Members
object IEnumerator.Current
{
get { return Current;}
}
/// <summary>
/// Move to the next position
/// </summary>
/// <returns></returns>
public bool MoveNext()
{
m_position++;
for (; m_position < m_bitArray.Count; m_position++)
{
if (m_bitArray[m_position])
{
return true;
}
}
return false;
}
/// <summary>
/// Reset enumerator to start off again
/// </summary>
public void Reset()
{
m_position = -1;
}
#endregion
#region IDisposable Members
/// <summary>
/// Dispose of the current enumerator - return it to the Command
/// </summary>
public void Dispose()
{
// Technically, calling GC.SuppressFinalize is not required because the class does not
// have a finalizer, but it does no harm, protects against the case where a finalizer is added
// in the future, and prevents an FxCop warning.
GC.SuppressFinalize(this);
m_bitArray = null;
m_command.ReleaseVarVecEnumerator(this);
}
#endregion
}
#endregion
#region public methods
internal void Clear()
{
m_bitVector.Length = 0;
}
internal void And(VarVec other)
{
Align(other);
m_bitVector.And(other.m_bitVector);
}
internal void Or(VarVec other)
{
Align(other);
m_bitVector.Or(other.m_bitVector);
}
/// <summary>
/// Computes (this Minus other) by performing (this And (Not(other)))
/// A temp VarVec is used and released at the end of the operation
/// </summary>
/// <param name="other"></param>
internal void Minus(VarVec other)
{
VarVec tmp = m_command.CreateVarVec(other);
tmp.m_bitVector.Length = m_bitVector.Length;
tmp.m_bitVector.Not();
this.And(tmp);
m_command.ReleaseVarVec(tmp);
}
/// <summary>
/// Does this have a non-zero overlap with the other vec
/// </summary>
/// <param name="other"></param>
/// <returns></returns>
internal bool Overlaps(VarVec other)
{
VarVec otherCopy = m_command.CreateVarVec(other);
otherCopy.And(this);
bool overlaps = !otherCopy.IsEmpty;
m_command.ReleaseVarVec(otherCopy);
return overlaps;
}
/// <summary>
/// Does this Vec include every var in the other vec?
/// Written this way deliberately under the assumption that "other"
/// is a relatively small vec
/// </summary>
/// <param name="other"></param>
/// <returns></returns>
internal bool Subsumes(VarVec other)
{
for (int i = 0; i < other.m_bitVector.Count; i++)
{
if (other.m_bitVector[i] &&
((i >= this.m_bitVector.Count) || !this.m_bitVector[i]))
{
return false;
}
}
return true;
}
internal void InitFrom(VarVec other)
{
this.Clear();
this.m_bitVector.Length = other.m_bitVector.Length;
this.m_bitVector.Or(other.m_bitVector);
}
internal void InitFrom(IEnumerable<Var> other)
{
InitFrom(other, false);
}
internal void InitFrom(IEnumerable<Var> other, bool ignoreParameters)
{
this.Clear();
foreach (Var v in other)
{
if (!ignoreParameters || (v.VarType != VarType.Parameter))
{
this.Set(v);
}
}
}
/// <summary>
/// The enumerator pattern
/// </summary>
/// <returns></returns>
public IEnumerator<Var> GetEnumerator()
{
return m_command.GetVarVecEnumerator(this);
}
IEnumerator IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
/// <summary>
/// Number of vars in this set
/// </summary>
internal int Count
{
get
{
int count = 0;
foreach (Var v in this)
count++;
return count;
}
}
internal bool IsSet(Var v)
{
Align(v.Id);
return m_bitVector.Get(v.Id);
}
internal void Set(Var v)
{
Align(v.Id);
m_bitVector.Set(v.Id, true);
}
internal void Clear(Var v)
{
Align(v.Id);
m_bitVector.Set(v.Id, false);
}
/// <summary>
/// Is this Vec empty?
/// </summary>
internal bool IsEmpty
{
get { return this.First == null;}
}
/// <summary>
/// Get me the first var that is set
/// </summary>
internal Var First
{
get
{
foreach (Var v in this)
{
return v;
}
return null;
}
}
/// <summary>
/// Walk through the input varVec, replace any vars that have been "renamed" based
/// on the input varMap, and return the new VarVec
/// </summary>
/// <param name="varMap">dictionary of renamed vars</param>
/// <returns>a new VarVec</returns>
internal VarVec Remap(Dictionary<Var, Var> varMap)
{
VarVec newVec = m_command.CreateVarVec();
foreach (Var v in this)
{
Var newVar;
if (!varMap.TryGetValue(v, out newVar))
{
newVar = v;
}
newVec.Set(newVar);
}
return newVec;
}
#endregion
#region constructors
internal VarVec(Command command)
{
m_bitVector = new BitArray(64);
m_command = command;
}
#endregion
#region private methods
private void Align(VarVec other)
{
if (other.m_bitVector.Count == this.m_bitVector.Count)
return;
if (other.m_bitVector.Count > this.m_bitVector.Count)
{
this.m_bitVector.Length = other.m_bitVector.Count;
}
else
{
other.m_bitVector.Length = this.m_bitVector.Count;
}
}
private void Align(int idx)
{
if (idx >= m_bitVector.Count)
{
m_bitVector.Length = idx + 1;
}
}
/// <summary>
/// Debugging support
/// provide a string representation for debugging.
/// <returns></returns>
/// </summary>
public override string ToString()
{
StringBuilder sb = new StringBuilder();
string separator = String.Empty;
foreach (Var v in this)
{
sb.AppendFormat(CultureInfo.InvariantCulture, "{0}{1}", separator, v.Id);
separator = ",";
}
return sb.ToString();
}
#endregion
#region private state
private BitArray m_bitVector;
private Command m_command;
#endregion
#region Clone
/// <summary>
/// Create a clone of this vec
/// </summary>
/// <returns></returns>
public VarVec Clone()
{
VarVec newVec = m_command.CreateVarVec();
newVec.InitFrom(this);
return newVec;
}
#endregion
}
/// <summary>
/// An ordered list of Vars. Use this when you need an ordering.
/// </summary>
[DebuggerDisplay("{{{ToString()}}}")]
internal class VarList : List<Var>
{
#region constructors
/// <summary>
/// Trivial constructor
/// </summary>
internal VarList() : base() { }
/// <summary>
/// Not so trivial constructor
/// </summary>
/// <param name="vars"></param>
internal VarList(IEnumerable<Var> vars) : base(vars) { }
#endregion
#region public methods
/// <summary>
/// Debugging support
/// provide a string representation for debugging.
/// <returns></returns>
/// </summary>
public override string ToString()
{
StringBuilder sb = new StringBuilder();
string separator = String.Empty;
foreach (Var v in this)
{
sb.AppendFormat(CultureInfo.InvariantCulture, "{0}{1}", separator, v.Id);
separator = ",";
}
return sb.ToString();
}
#endregion
}
#region VarMap
/// <summary>
/// Helps map one variable to the next.
/// </summary>
internal class VarMap: Dictionary<Var, Var>
{
#region public surfaces
internal VarMap GetReverseMap()
{
VarMap reverseMap = new VarMap();
foreach (KeyValuePair<Var, Var> kv in this)
{
Var x;
// On the odd chance that a var is in the varMap more than once, the first one
// is going to be the one we want to use, because it might be the discriminator
// var;
if (!reverseMap.TryGetValue(kv.Value, out x))
{
reverseMap[kv.Value] = kv.Key;
}
}
return reverseMap;
}
public override string ToString()
{
StringBuilder sb = new StringBuilder();
string separator = string.Empty;
foreach (Var v in this.Keys)
{
sb.AppendFormat(CultureInfo.InvariantCulture, "{0}({1},{2})", separator, v.Id, this[v].Id);
separator = ",";
}
return sb.ToString();
}
#endregion
#region constructors
internal VarMap() : base() { }
#endregion
}
#endregion
}
|