Jo Shields 3c1f479b9d Imported Upstream version 4.0.0~alpha1
Former-commit-id: 806294f5ded97629b74c85c09952f2a74fe182d9
2015-04-07 09:35:12 +01:00

375 lines
16 KiB
C#

//---------------------------------------------------------------------
// <copyright file="Validator.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//
// @owner [....]
// @backupOwner [....]
//---------------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.Globalization;
using md = System.Data.Metadata.Edm;
using System.Data.Query.InternalTrees;
using System.Data.Query.PlanCompiler;
using System.Data.Query.ResultAssembly;
using System.Diagnostics;
using System.Text;
namespace System.Data.Query.PlanCompiler
{
#if DEBUG
/// <summary>
/// The Validator class extends the BasicValidator and enforces that the ITree is valid
/// through varying stages of the plan compilation process. At each stage, certain operators
/// are illegal - and this validator is largely intended to tackle that
/// </summary>
internal class Validator : BasicValidator
{
#region public surface
internal static void Validate(PlanCompiler compilerState, Node n)
{
Validator validator = new Validator(compilerState);
validator.Validate(n);
}
internal static void Validate(PlanCompiler compilerState)
{
Validate(compilerState, compilerState.Command.Root);
}
#endregion
#region constructors
private Validator(PlanCompiler compilerState)
: base(compilerState.Command)
{
m_compilerState = compilerState;
}
private static BitVec InitializeOpTypes()
{
BitVec validOpTypes = new BitVec(((int)OpType.MaxMarker + 1) * ((int)PlanCompilerPhase.MaxMarker + 1));
AddAllEntry(validOpTypes, OpType.Aggregate);
AddAllEntry(validOpTypes, OpType.And);
AddAllEntry(validOpTypes, OpType.Case);
AddAllEntry(validOpTypes, OpType.Cast);
AddEntry(validOpTypes, OpType.Collect,
PlanCompilerPhase.PreProcessor,
PlanCompilerPhase.AggregatePushdown,
PlanCompilerPhase.Normalization,
PlanCompilerPhase.NTE,
PlanCompilerPhase.ProjectionPruning,
PlanCompilerPhase.NestPullup);
AddAllEntry(validOpTypes, OpType.Constant);
AddAllEntry(validOpTypes, OpType.ConstantPredicate);
AddAllEntry(validOpTypes, OpType.ConstrainedSort);
AddAllEntry(validOpTypes, OpType.CrossApply);
AddAllEntry(validOpTypes, OpType.CrossJoin);
AddEntry(validOpTypes, OpType.Deref, PlanCompilerPhase.PreProcessor);
AddAllEntry(validOpTypes, OpType.Distinct);
AddAllEntry(validOpTypes, OpType.Divide);
AddEntry(validOpTypes, OpType.Element,
PlanCompilerPhase.PreProcessor,
PlanCompilerPhase.Transformations,
PlanCompilerPhase.JoinElimination,
PlanCompilerPhase.ProjectionPruning,
PlanCompilerPhase.CodeGen,
PlanCompilerPhase.PostCodeGen);
AddAllEntry(validOpTypes, OpType.EQ);
AddAllEntry(validOpTypes, OpType.Except);
AddAllEntry(validOpTypes, OpType.Exists);
AddAllEntry(validOpTypes, OpType.Filter);
AddAllEntry(validOpTypes, OpType.FullOuterJoin);
AddAllEntry(validOpTypes, OpType.Function);
AddAllEntry(validOpTypes, OpType.GE);
AddEntry(validOpTypes, OpType.GetEntityRef,
PlanCompilerPhase.PreProcessor,
PlanCompilerPhase.AggregatePushdown,
PlanCompilerPhase.Normalization,
PlanCompilerPhase.NTE);
AddEntry(validOpTypes, OpType.GetRefKey,
PlanCompilerPhase.PreProcessor,
PlanCompilerPhase.AggregatePushdown,
PlanCompilerPhase.Normalization,
PlanCompilerPhase.NTE);
AddAllEntry(validOpTypes, OpType.GroupBy);
AddEntry(validOpTypes, OpType.GroupByInto,
PlanCompilerPhase.PreProcessor,
PlanCompilerPhase.AggregatePushdown,
PlanCompilerPhase.Normalization,
PlanCompilerPhase.NTE,
PlanCompilerPhase.ProjectionPruning,
PlanCompilerPhase.NestPullup);
AddAllEntry(validOpTypes, OpType.GT);
AddAllEntry(validOpTypes, OpType.InnerJoin);
AddAllEntry(validOpTypes, OpType.InternalConstant);
AddAllEntry(validOpTypes, OpType.Intersect);
AddAllEntry(validOpTypes, OpType.IsNull);
AddEntry(validOpTypes, OpType.IsOf,
PlanCompilerPhase.PreProcessor,
PlanCompilerPhase.AggregatePushdown,
PlanCompilerPhase.Normalization,
PlanCompilerPhase.NTE);
AddAllEntry(validOpTypes, OpType.LE);
AddAllEntry(validOpTypes, OpType.LeftOuterJoin);
AddAllEntry(validOpTypes, OpType.Like);
AddAllEntry(validOpTypes, OpType.LT);
AddAllEntry(validOpTypes, OpType.Minus);
AddAllEntry(validOpTypes, OpType.Modulo);
AddAllEntry(validOpTypes, OpType.Multiply);
AddEntry(validOpTypes, OpType.Navigate, PlanCompilerPhase.PreProcessor);
AddAllEntry(validOpTypes, OpType.NE);
AddEntry(validOpTypes, OpType.NewEntity,
PlanCompilerPhase.PreProcessor,
PlanCompilerPhase.AggregatePushdown,
PlanCompilerPhase.Normalization,
PlanCompilerPhase.NTE);
AddEntry(validOpTypes, OpType.NewInstance,
PlanCompilerPhase.PreProcessor,
PlanCompilerPhase.AggregatePushdown,
PlanCompilerPhase.Normalization,
PlanCompilerPhase.NTE);
AddEntry(validOpTypes, OpType.DiscriminatedNewEntity,
PlanCompilerPhase.PreProcessor,
PlanCompilerPhase.AggregatePushdown,
PlanCompilerPhase.Normalization,
PlanCompilerPhase.NTE);
AddEntry(validOpTypes, OpType.NewMultiset, PlanCompilerPhase.PreProcessor);
AddEntry(validOpTypes, OpType.NewRecord,
PlanCompilerPhase.PreProcessor,
PlanCompilerPhase.AggregatePushdown,
PlanCompilerPhase.Normalization,
PlanCompilerPhase.NTE);
AddAllEntry(validOpTypes, OpType.Not);
AddAllEntry(validOpTypes, OpType.Null);
AddAllEntry(validOpTypes, OpType.NullSentinel);
AddAllEntry(validOpTypes, OpType.Or);
AddAllEntry(validOpTypes, OpType.OuterApply);
AddAllEntry(validOpTypes, OpType.PhysicalProject);
AddAllEntry(validOpTypes, OpType.Plus);
AddAllEntry(validOpTypes, OpType.Project);
// Since, we don't support UDTs anymore - we shouldn't see PropertyOp after this
AddEntry(validOpTypes, OpType.Property,
PlanCompilerPhase.PreProcessor,
PlanCompilerPhase.AggregatePushdown,
PlanCompilerPhase.Normalization,
PlanCompilerPhase.NTE);
AddEntry(validOpTypes, OpType.Ref,
PlanCompilerPhase.PreProcessor,
PlanCompilerPhase.AggregatePushdown,
PlanCompilerPhase.Normalization,
PlanCompilerPhase.NTE);
AddEntry(validOpTypes, OpType.RelProperty,
PlanCompilerPhase.PreProcessor,
PlanCompilerPhase.AggregatePushdown,
PlanCompilerPhase.Normalization,
PlanCompilerPhase.NTE);
AddAllEntry(validOpTypes, OpType.ScanTable);
AddEntry(validOpTypes, OpType.ScanView,
PlanCompilerPhase.PreProcessor,
PlanCompilerPhase.AggregatePushdown,
PlanCompilerPhase.Normalization,
PlanCompilerPhase.NTE);
AddAllEntry(validOpTypes, OpType.SingleRow);
AddAllEntry(validOpTypes, OpType.SingleRowTable);
AddAllEntry(validOpTypes, OpType.SoftCast);
AddAllEntry(validOpTypes, OpType.Sort);
AddEntry(validOpTypes, OpType.Treat,
PlanCompilerPhase.PreProcessor,
PlanCompilerPhase.AggregatePushdown,
PlanCompilerPhase.Normalization,
PlanCompilerPhase.NTE);
AddAllEntry(validOpTypes, OpType.UnaryMinus);
AddAllEntry(validOpTypes, OpType.UnionAll);
AddAllEntry(validOpTypes, OpType.Unnest);
AddAllEntry(validOpTypes, OpType.VarDef);
AddAllEntry(validOpTypes, OpType.VarDefList);
AddAllEntry(validOpTypes, OpType.VarRef);
return validOpTypes;
}
#endregion
#region private methods
#region Initializers
private static int ComputeHash(OpType opType, PlanCompilerPhase phase)
{
int hash = ((int)opType * (int)PlanCompilerPhase.MaxMarker) + (int)phase;
return hash;
}
private static void AddSingleEntry(BitVec opVector, OpType opType, PlanCompilerPhase phase)
{
int hash = ComputeHash(opType, phase);
opVector.Set(hash);
}
private static void AddEntry(BitVec opVector, OpType opType, params PlanCompilerPhase[] phases)
{
foreach (PlanCompilerPhase phase in phases)
{
AddSingleEntry(opVector, opType, phase);
}
}
private static void AddAllEntry(BitVec opVector, OpType opType)
{
foreach (PlanCompilerPhase phase in s_PlanCompilerPhases)
{
AddSingleEntry(opVector, opType, phase);
}
}
private static bool CheckEntry(OpType opType, PlanCompilerPhase phase)
{
int hash = ComputeHash(opType, phase);
return s_ValidOpTypes.IsSet(hash);
}
#endregion
#region Visitors
protected override void VisitDefault(Node n)
{
base.VisitDefault(n);
Assert(CheckEntry(n.Op.OpType, m_compilerState.Phase),
"Unxpected Op {0} in Phase {1}", n.Op.OpType, m_compilerState.Phase);
}
#region ScalarOps
public override void Visit(NewEntityOp op, Node n)
{
base.Visit(op, n);
if (m_compilerState.Phase > PlanCompilerPhase.PreProcessor && op.Type.EdmType.BuiltInTypeKind == md.BuiltInTypeKind.EntityType)
{
Assert(op.Scoped, "NewEntityOp for an entity type {0} is not scoped. All entity type constructors must be scoped after PreProcessor phase.", op.Type.EdmType.FullName);
}
}
#endregion
#region PhysicalOps
#endregion
#region RelOps
#endregion
#region AncillaryOps
#endregion
#endregion
#endregion
#region private state
private PlanCompiler m_compilerState;
private static PlanCompilerPhase[] s_PlanCompilerPhases = { PlanCompilerPhase.PreProcessor ,
PlanCompilerPhase.AggregatePushdown ,
PlanCompilerPhase.Normalization ,
PlanCompilerPhase.NTE ,
PlanCompilerPhase.ProjectionPruning ,
PlanCompilerPhase.NestPullup ,
PlanCompilerPhase.Transformations ,
PlanCompilerPhase.JoinElimination ,
PlanCompilerPhase.CodeGen ,
PlanCompilerPhase.PostCodeGen };
private static BitVec s_ValidOpTypes = InitializeOpTypes();
#endregion
/// <summary>
/// BitVector helper class; used to keep track of the used columns
/// in the result assembly.
/// </summary>
/// <remarks>
/// BitVec can be a struct because it contains a readonly reference to an int[].
/// This code is a copy of System.Collections.BitArray so that we can have an efficient implementation of Minus.
/// </remarks>
internal struct BitVec
{
private readonly int[] m_array;
private readonly int m_length;
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal BitVec(int length)
{
Debug.Assert(0 < length, "zero length");
m_array = new int[(length + 31) / 32];
m_length = length;
}
internal int Count
{
get { return m_length; }
}
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal void Set(int index)
{
Debug.Assert(unchecked((uint)index < (uint)m_length), "index out of range");
m_array[index / 32] |= (1 << (index % 32));
}
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal void ClearAll()
{
for (int i = 0; i < m_array.Length; i++)
{
m_array[i] = 0;
}
}
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal bool IsEmpty()
{
for (int i = 0; i < m_array.Length; i++)
{
if (0 != m_array[i])
{
return false;
}
}
return true;
}
internal bool IsSet(int index)
{
Debug.Assert(unchecked((uint)index < (uint)m_length), "index out of range");
return (m_array[index / 32] & (1 << (index % 32))) != 0;
}
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal void Or(BitVec value)
{
Debug.Assert(m_length == value.m_length, "unequal sized bitvec");
for (int i = 0; i < m_array.Length; i++)
{
m_array[i] |= value.m_array[i];
}
}
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal void Minus(BitVec value)
{
Debug.Assert(m_length == value.m_length, "unequal sized bitvec");
for (int i = 0; i < m_array.Length; i++)
{
m_array[i] &= ~value.m_array[i];
}
}
public override string ToString()
{
StringBuilder sb = new StringBuilder(3 * Count);
string separator = string.Empty;
for (int i = 0; i < Count; i++)
{
if (IsSet(i))
{
sb.Append(separator);
sb.Append(i);
separator = ",";
}
}
return sb.ToString();
}
}
}
#endif // DEBUG
}