2015-04-07 09:35:12 +01:00
//---------------------------------------------------------------------
// <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
}