//---------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//
// @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
{
///
/// Types of variable
///
internal enum VarType
{
///
/// a parameter
///
Parameter,
///
/// Column of a table
///
Column,
///
/// A Computed var
///
Computed,
///
/// Var for SetOps (Union, Intersect, Except)
///
SetOp,
///
/// NotValid
///
NotValid
}
///
/// Same as a ValRef in SqlServer. I just like changing names :-)
///
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;
}
///
/// Id of this var
///
internal int Id { get { return m_id; } }
///
/// Kind of Var
///
internal VarType VarType { get { return m_varType; } }
///
/// Datatype of this Var
///
internal TypeUsage Type { get { return m_type; } }
///
/// Try to get the name of this Var.
///
///
///
internal virtual bool TryGetName(out string name)
{
name = null;
return false;
}
///
/// Debugging support
///
///
public override string ToString()
{
return String.Format(CultureInfo.InvariantCulture, "{0}", this.Id); ;
}
}
///
/// Describes a query parameter
///
internal sealed class ParameterVar : Var
{
string m_paramName;
internal ParameterVar(int id, TypeUsage type, string paramName)
: base(id, VarType.Parameter, type)
{
m_paramName = paramName;
}
///
/// Name of the parameter
///
internal string ParameterName { get { return m_paramName; } }
///
/// Get the name of this Var
///
///
///
internal override bool TryGetName(out string name)
{
name = this.ParameterName;
return true;
}
}
///
/// Describes a column of a table
///
internal sealed class ColumnVar : Var
{
ColumnMD m_columnMetadata;
Table m_table;
///
/// Constructor
///
///
///
///
internal ColumnVar(int id, Table table, ColumnMD columnMetadata)
: base(id, VarType.Column, columnMetadata.Type)
{
m_table = table;
m_columnMetadata = columnMetadata;
}
///
/// The table instance containing this column reference
///
internal Table Table { get { return m_table; } }
///
/// The column metadata for this column
///
internal ColumnMD ColumnMetadata { get { return m_columnMetadata; } }
///
/// Get the name of this column var
///
///
///
internal override bool TryGetName(out string name)
{
name = m_columnMetadata.Name;
return true;
}
}
///
/// A computed expression. Defined by a VarDefOp
///
internal sealed class ComputedVar : Var
{
internal ComputedVar(int id, TypeUsage type) : base(id, VarType.Computed, type)
{
}
}
///
/// A SetOp Var - used as the output var for set operations (Union, Intersect, Except)
///
internal sealed class SetOpVar : Var
{
internal SetOpVar(int id, TypeUsage type) : base(id, VarType.SetOp, type) { }
}
//
///
/// 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.
///
///
internal class VarVec : IEnumerable
{
#region Nested Classes
///
/// A VarVec enumerator is a specialized enumerator for a VarVec.
///
internal class VarVecEnumerator : IEnumerator, IDisposable
{
#region private state
private int m_position;
private Command m_command;
private BitArray m_bitArray;
#endregion
#region Constructors
///
/// Constructs a new enumerator for the specified Vec
///
///
internal VarVecEnumerator(VarVec vec)
{
Init(vec);
}
#endregion
#region public surface
///
/// Initialize the enumerator to enumerate over the supplied Vec
///
///
internal void Init(VarVec vec)
{
m_position = -1;
m_command = vec.m_command;
m_bitArray = vec.m_bitVector;
}
#endregion
#region IEnumerator Members
///
/// Get the Var at the current position
///
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;}
}
///
/// Move to the next position
///
///
public bool MoveNext()
{
m_position++;
for (; m_position < m_bitArray.Count; m_position++)
{
if (m_bitArray[m_position])
{
return true;
}
}
return false;
}
///
/// Reset enumerator to start off again
///
public void Reset()
{
m_position = -1;
}
#endregion
#region IDisposable Members
///
/// Dispose of the current enumerator - return it to the Command
///
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);
}
///
/// Computes (this Minus other) by performing (this And (Not(other)))
/// A temp VarVec is used and released at the end of the operation
///
///
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);
}
///
/// Does this have a non-zero overlap with the other vec
///
///
///
internal bool Overlaps(VarVec other)
{
VarVec otherCopy = m_command.CreateVarVec(other);
otherCopy.And(this);
bool overlaps = !otherCopy.IsEmpty;
m_command.ReleaseVarVec(otherCopy);
return overlaps;
}
///
/// Does this Vec include every var in the other vec?
/// Written this way deliberately under the assumption that "other"
/// is a relatively small vec
///
///
///
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 other)
{
InitFrom(other, false);
}
internal void InitFrom(IEnumerable other, bool ignoreParameters)
{
this.Clear();
foreach (Var v in other)
{
if (!ignoreParameters || (v.VarType != VarType.Parameter))
{
this.Set(v);
}
}
}
///
/// The enumerator pattern
///
///
public IEnumerator GetEnumerator()
{
return m_command.GetVarVecEnumerator(this);
}
IEnumerator IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
///
/// Number of vars in this set
///
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);
}
///
/// Is this Vec empty?
///
internal bool IsEmpty
{
get { return this.First == null;}
}
///
/// Get me the first var that is set
///
internal Var First
{
get
{
foreach (Var v in this)
{
return v;
}
return null;
}
}
///
/// Walk through the input varVec, replace any vars that have been "renamed" based
/// on the input varMap, and return the new VarVec
///
/// dictionary of renamed vars
/// a new VarVec
internal VarVec Remap(Dictionary 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;
}
}
///
/// Debugging support
/// provide a string representation for debugging.
///
///
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
///
/// Create a clone of this vec
///
///
public VarVec Clone()
{
VarVec newVec = m_command.CreateVarVec();
newVec.InitFrom(this);
return newVec;
}
#endregion
}
///
/// An ordered list of Vars. Use this when you need an ordering.
///
[DebuggerDisplay("{{{ToString()}}}")]
internal class VarList : List
{
#region constructors
///
/// Trivial constructor
///
internal VarList() : base() { }
///
/// Not so trivial constructor
///
///
internal VarList(IEnumerable vars) : base(vars) { }
#endregion
#region public methods
///
/// Debugging support
/// provide a string representation for debugging.
///
///
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
///
/// Helps map one variable to the next.
///
internal class VarMap: Dictionary
{
#region public surfaces
internal VarMap GetReverseMap()
{
VarMap reverseMap = new VarMap();
foreach (KeyValuePair 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
}