//--------------------------------------------------------------------- // // Copyright (c) Microsoft Corporation. All rights reserved. // // // @owner [....] // @backupOwner [....] //--------------------------------------------------------------------- using System; using System.Collections.Generic; using System.Diagnostics; using System.Data.Common; using System.Data.Metadata.Edm; using System.Data.Common.CommandTrees; namespace System.Data.Common.CommandTrees.Internal { /// /// Writes a description of a given expression, in a format determined by the specific implementation of a derived type /// internal abstract class ExpressionDumper : DbExpressionVisitor { #region Constructors internal ExpressionDumper() { } #endregion #region (Pseudo) Public API /// /// Begins a new Dump block with the specified name /// /// The name of the block internal void Begin(string name) { Begin(name, (Dictionary)null); } /// /// Begins a new Dump block with the specified name and specified attributes /// /// The name of the block /// The named attributes of the block. May be null internal abstract void Begin(string name, Dictionary attrs); /// /// Ends the Dump block with the specified name. /// The caller should not assumer that this name will be verified /// against the last name used in a Begin call. /// /// The name of the block internal abstract void End(string name); /// /// Dumps a DbExpression by visiting it. /// /// The DbExpression to dump internal void Dump(DbExpression target) { target.Accept(this); } /// /// Dumps a DbExpression with the specified block name preceeding and succeeding (decorating) it. /// /// The DbExpression to dump /// The decorating block name internal void Dump(DbExpression e, string name) { Begin(name); Dump(e); End(name); } /// /// Dumps a DbExpressionBinding with the specified decoration /// /// The DbExpressionBinding to dump /// The decorating block name internal void Dump(DbExpressionBinding binding, string name) { Begin(name); Dump(binding); End(name); } /// /// Dumps a DbExpressionBinding including its VariableName and DbExpression /// /// The DbExpressionBinding to dump internal void Dump(DbExpressionBinding binding) { Begin("DbExpressionBinding", "VariableName", binding.VariableName); Begin("Expression"); Dump(binding.Expression); End("Expression"); End("DbExpressionBinding"); } /// /// Dumps a DbGroupExpressionBinding with the specified decoration /// /// The DbGroupExpressionBinding to dump /// The decorating block name internal void Dump(DbGroupExpressionBinding binding, string name) { Begin(name); Dump(binding); End(name); } /// /// Dumps a DbGroupExpressionBinding including its VariableName, GroupVariableName and DbExpression /// /// The DbGroupExpressionBinding to dump internal void Dump(DbGroupExpressionBinding binding) { Begin("DbGroupExpressionBinding", "VariableName", binding.VariableName, "GroupVariableName", binding.GroupVariableName); Begin("Expression"); Dump(binding.Expression); End("Expression"); End("DbGroupExpressionBinding"); } /// /// Dumps each DbExpression in the specified enumerable. The entire output is decorated with the 'pluralName' /// block name while each element DbExpression is decorated with the 'singularName' block name. /// If the list is empty only the pluralName decoration start/end will appear. /// /// The enumerable list of Expressions to dump /// The overall list decoration block name /// The decoration block name that will be applied to each element DbExpression internal void Dump(IEnumerable exprs, string pluralName, string singularName) { Begin(pluralName); foreach (DbExpression expr in exprs) { Begin(singularName); this.Dump(expr); End(singularName); } End(pluralName); } /// /// Dumps each Parameter metadata in the specified enumerable. The entire output is decorated with the "Parameters" /// block name while each metadata element is decorated with the "Parameter" block name. /// If the list is empty only the "Parameters" decoration start/end will appear. /// /// The enumerable list of Parameter metadata to dump internal void Dump(IEnumerable paramList) { Begin("Parameters"); foreach (FunctionParameter param in paramList) { Begin("Parameter", "Name", param.Name); Dump(param.TypeUsage, "ParameterType"); End("Parameter"); } End("Parameters"); } /// /// Dumps the specified Type metadata instance with the specified decoration /// /// The Type metadata to dump /// The decorating block name internal void Dump(TypeUsage type, string name) { Begin(name); Dump(type); End(name); } /// /// Dumps the specified Type metadata instance /// /// The Type metadata to dump internal void Dump(TypeUsage type) { Dictionary facetInfo = new Dictionary(); foreach (Facet facet in type.Facets) { facetInfo.Add(facet.Name, facet.Value); } Begin("TypeUsage", facetInfo); Dump(type.EdmType); End("TypeUsage"); } /// /// Dumps the specified EDM type metadata instance with the specified decoration /// /// The type metadata to dump /// The decorating block name internal void Dump(EdmType type, string name) { Begin(name); Dump(type); End(name); } /// /// Dumps the specified type metadata instance /// /// The type metadata to dump internal void Dump(EdmType type) { Begin("EdmType", "BuiltInTypeKind", Enum.GetName(typeof(BuiltInTypeKind), type.BuiltInTypeKind), "Namespace", type.NamespaceName, "Name", type.Name); End("EdmType"); } /// /// Dumps the specified Relation metadata instance with the specified decoration /// /// The Relation metadata to dump /// The decorating block name internal void Dump(RelationshipType type, string name) { Begin(name); Dump(type); End(name); } /// /// Dumps the specified Relation metadata instance /// /// The Relation metadata to dump internal void Dump(RelationshipType type) { Begin( "RelationshipType", "Namespace", type.NamespaceName, "Name", type.Name ); End("RelationshipType"); } /// /// Dumps the specified EdmFunction metadata instance /// /// The EdmFunction metadata to dump. internal void Dump(EdmFunction function) { Begin("Function", "Name", function.Name, "Namespace", function.NamespaceName); Dump(function.Parameters); if (function.ReturnParameters.Count == 1) { Dump(function.ReturnParameters[0].TypeUsage, "ReturnType"); } else { Begin("ReturnTypes"); foreach (var returnParameter in function.ReturnParameters) { Dump(returnParameter.TypeUsage, returnParameter.Name); } End("ReturnTypes"); } End("Function"); } /// /// Dumps the specified EdmProperty metadata instance /// /// The EdmProperty metadata to dump internal void Dump(EdmProperty prop) { Begin("Property", "Name", prop.Name, "Nullable", prop.Nullable); Dump(prop.DeclaringType, "DeclaringType"); Dump(prop.TypeUsage, "PropertyType"); End("Property"); } /// /// Dumps the specified Relation End EdmMember metadata instance with the specified decoration /// /// The Relation End metadata to dump /// The decorating block name internal void Dump(RelationshipEndMember end, string name) { Begin(name); Begin( "RelationshipEndMember", "Name", end.Name, //"IsParent", end.IsParent, "RelationshipMultiplicity", Enum.GetName(typeof(RelationshipMultiplicity), end.RelationshipMultiplicity) ); Dump(end.DeclaringType, "DeclaringRelation"); Dump(end.TypeUsage, "EndType"); End("RelationshipEndMember"); End(name); } /// /// Dumps the specified Navigation Property EdmMember metadata instance with the specified decoration /// /// The Navigation Property metadata to dump /// The decorating block name internal void Dump(NavigationProperty navProp, string name) { Begin(name); Begin( "NavigationProperty", "Name", navProp.Name, //"IsParent", end.IsParent, "RelationshipTypeName", navProp.RelationshipType.FullName, "ToEndMemberName", navProp.ToEndMember.Name ); Dump(navProp.DeclaringType, "DeclaringType"); Dump(navProp.TypeUsage, "PropertyType"); End("NavigationProperty"); End(name); } #if METHOD_EXPRESSION /// /// Dumps the specified Method metadata instance /// /// The Method metadata to dump internal void Dump(MethodMetadata meth) { Begin("MethodMetadata", "Name", meth.Name, "IsStatic", meth.IsStatic); Dump(meth.DefiningType, "DeclaringType"); Dump(meth.Parameters); Dump(meth.Type, "ReturnType"); End("MethodMetadata"); } #endif /// /// Dumps the specified DbLambda instance /// /// The DbLambda to dump. internal void Dump(DbLambda lambda) { Begin("DbLambda"); Dump(System.Linq.Enumerable.Cast(lambda.Variables), "Variables", "Variable"); Dump(lambda.Body, "Body"); End("DbLambda"); } #endregion #region Private Implementation private void Begin(DbExpression expr) { Begin(expr, new Dictionary()); } private void Begin(DbExpression expr, Dictionary attrs) { attrs.Add("DbExpressionKind", Enum.GetName(typeof(DbExpressionKind), expr.ExpressionKind)); Begin(expr.GetType().Name, attrs); Dump(expr.ResultType, "ResultType"); } private void Begin(DbExpression expr, string attributeName, object attributeValue) { Dictionary attrs = new Dictionary(); attrs.Add(attributeName, attributeValue); Begin(expr, attrs); } private void Begin(string expr, string attributeName, object attributeValue) { Dictionary attrs = new Dictionary(); attrs.Add(attributeName, attributeValue); Begin(expr, attrs); } private void Begin(string expr, string attributeName1, object attributeValue1, string attributeName2, object attributeValue2) { Dictionary attrs = new Dictionary(); attrs.Add(attributeName1, attributeValue1); attrs.Add(attributeName2, attributeValue2); Begin(expr, attrs); } private void Begin(string expr, string attributeName1, object attributeValue1, string attributeName2, object attributeValue2, string attributeName3, object attributeValue3) { Dictionary attrs = new Dictionary(); attrs.Add(attributeName1, attributeValue1); attrs.Add(attributeName2, attributeValue2); attrs.Add(attributeName3, attributeValue3); Begin(expr, attrs); } private void End(DbExpression expr) { End(expr.GetType().Name); } private void BeginUnary(DbUnaryExpression e) { Begin(e); Begin("Argument"); Dump(e.Argument); End("Argument"); } private void BeginBinary(DbBinaryExpression e) { Begin(e); Begin("Left"); Dump(e.Left); End("Left"); Begin("Right"); Dump(e.Right); End("Right"); } #endregion #region DbExpressionVisitor Members public override void Visit(DbExpression e) { Begin(e); End(e); } public override void Visit(DbConstantExpression e) { Dictionary attrs = new Dictionary(); attrs.Add("Value", e.Value); Begin(e, attrs); End(e); } public override void Visit(DbNullExpression e) { Begin(e); End(e); } public override void Visit(DbVariableReferenceExpression e) { Dictionary attrs = new Dictionary(); attrs.Add("VariableName", e.VariableName); Begin(e, attrs); End(e); } public override void Visit(DbParameterReferenceExpression e) { Dictionary attrs = new Dictionary(); attrs.Add("ParameterName", e.ParameterName); Begin(e, attrs); End(e); } public override void Visit(DbFunctionExpression e) { Begin(e); Dump(e.Function); Dump(e.Arguments, "Arguments", "Argument"); End(e); } public override void Visit(DbLambdaExpression expression) { Begin(expression); Dump(expression.Lambda); Dump(expression.Arguments, "Arguments", "Argument"); End(expression); } #if METHOD_EXPRESSION public override void Visit(MethodExpression e) { Begin(e); Dump(e.Method); Dump(e.Arguments, "Arguments", "Argument"); if (e.Instance != null) { Dump(e.Instance, "Instance"); } End(e); } #endif public override void Visit(DbPropertyExpression e) { // // Currently the DbPropertyExpression.EdmProperty member property may only be either: // - EdmProperty // - RelationshipEndMember // - NavigationProperty // Begin(e); RelationshipEndMember end = e.Property as RelationshipEndMember; if (end != null) { Dump(end, "Property"); } else if (Helper.IsNavigationProperty(e.Property)) { Dump((NavigationProperty)e.Property, "Property"); } else { Dump((EdmProperty)e.Property); } if (e.Instance != null) { Dump(e.Instance, "Instance"); } End(e); } public override void Visit(DbComparisonExpression e) { BeginBinary(e); End(e); } public override void Visit(DbLikeExpression e) { Begin(e); Dump(e.Argument, "Argument"); Dump(e.Pattern, "Pattern"); Dump(e.Escape, "Escape"); End(e); } public override void Visit(DbLimitExpression e) { Begin(e, "WithTies", e.WithTies); Dump(e.Argument, "Argument"); Dump(e.Limit, "Limit"); End(e); } public override void Visit(DbIsNullExpression e) { BeginUnary(e); End(e); } public override void Visit(DbArithmeticExpression e) { Begin(e); Dump(e.Arguments, "Arguments", "Argument"); End(e); } public override void Visit(DbAndExpression e) { BeginBinary(e); End(e); } public override void Visit(DbOrExpression e) { BeginBinary(e); End(e); } public override void Visit(DbNotExpression e) { BeginUnary(e); End(e); } public override void Visit(DbDistinctExpression e) { BeginUnary(e); End(e); } public override void Visit(DbElementExpression e) { BeginUnary(e); End(e); } public override void Visit(DbIsEmptyExpression e) { BeginUnary(e); End(e); } public override void Visit(DbUnionAllExpression e) { BeginBinary(e); End(e); } public override void Visit(DbIntersectExpression e) { BeginBinary(e); End(e); } public override void Visit(DbExceptExpression e) { BeginBinary(e); End(e); } public override void Visit(DbTreatExpression e) { BeginUnary(e); End(e); } public override void Visit(DbIsOfExpression e) { BeginUnary(e); Dump(e.OfType, "OfType") ; End(e); } public override void Visit(DbCastExpression e) { BeginUnary(e); End(e); } public override void Visit(DbCaseExpression e) { Begin(e); Dump(e.When, "Whens", "When"); Dump(e.Then, "Thens", "Then"); Dump(e.Else, "Else"); } public override void Visit(DbOfTypeExpression e) { BeginUnary(e); Dump(e.OfType, "OfType"); End(e); } public override void Visit(DbNewInstanceExpression e) { Begin(e); Dump(e.Arguments, "Arguments", "Argument"); if (e.HasRelatedEntityReferences) { Begin("RelatedEntityReferences"); foreach (DbRelatedEntityRef relatedRef in e.RelatedEntityReferences) { Begin("DbRelatedEntityRef"); Dump(relatedRef.SourceEnd, "SourceEnd"); Dump(relatedRef.TargetEnd, "TargetEnd"); Dump(relatedRef.TargetEntityReference, "TargetEntityReference"); End("DbRelatedEntityRef"); } End("RelatedEntityReferences"); } End(e); } public override void Visit(DbRelationshipNavigationExpression e) { Begin(e); Dump(e.NavigateFrom, "NavigateFrom"); Dump(e.NavigateTo, "NavigateTo"); Dump(e.Relationship, "Relationship"); Dump(e.NavigationSource, "NavigationSource"); End(e); } public override void Visit(DbRefExpression e) { BeginUnary(e); End(e); } public override void Visit(DbDerefExpression e) { BeginUnary(e); End(e); } public override void Visit(DbRefKeyExpression e) { BeginUnary(e); End(e); } public override void Visit(DbEntityRefExpression e) { BeginUnary(e); End(e); } public override void Visit(DbScanExpression e) { Begin(e); Begin("Target", "Name", e.Target.Name, "Container", e.Target.EntityContainer.Name); Dump(e.Target.ElementType, "TargetElementType"); End("Target"); End(e); } public override void Visit(DbFilterExpression e) { Begin(e); Dump(e.Input, "Input"); Dump(e.Predicate, "Predicate"); End(e); } public override void Visit(DbProjectExpression e) { Begin(e); Dump(e.Input, "Input"); Dump(e.Projection, "Projection"); End(e); } public override void Visit(DbCrossJoinExpression e) { Begin(e); Begin("Inputs"); foreach (DbExpressionBinding binding in e.Inputs) { Dump(binding, "Input"); } End("Inputs"); End(e); } public override void Visit(DbJoinExpression e) { Begin(e); Dump(e.Left, "Left"); Dump(e.Right, "Right"); Dump(e.JoinCondition, "JoinCondition"); End(e); } public override void Visit(DbApplyExpression e) { Begin(e); Dump(e.Input, "Input"); Dump(e.Apply, "Apply"); End(e); } public override void Visit(DbGroupByExpression e) { Begin(e); Dump(e.Input, "Input"); Dump(e.Keys, "Keys", "Key"); Begin("Aggregates"); foreach (DbAggregate agg in e.Aggregates) { DbFunctionAggregate funcAgg = agg as DbFunctionAggregate; if (funcAgg != null) { Begin("DbFunctionAggregate"); Dump(funcAgg.Function); Dump(funcAgg.Arguments, "Arguments", "Argument"); End("DbFunctionAggregate"); } else { DbGroupAggregate groupAgg = agg as DbGroupAggregate; Debug.Assert(groupAgg != null, "Invalid DbAggregate"); Begin("DbGroupAggregate"); Dump(groupAgg.Arguments, "Arguments", "Argument"); End("DbGroupAggregate"); } } End("Aggregates"); End(e); } protected virtual void Dump(IList sortOrder) { Begin("SortOrder"); foreach (DbSortClause clause in sortOrder) { string collStr = clause.Collation; if (null == collStr) { collStr = ""; } Begin("DbSortClause", "Ascending", clause.Ascending, "Collation", collStr); Dump(clause.Expression, "Expression"); End("DbSortClause"); } End("SortOrder"); } public override void Visit(DbSkipExpression e) { Begin(e); Dump(e.Input, "Input"); Dump(e.SortOrder); Dump(e.Count, "Count"); End(e); } public override void Visit(DbSortExpression e) { Begin(e); Dump(e.Input, "Input"); Dump(e.SortOrder); End(e); } public override void Visit(DbQuantifierExpression e) { Begin(e); Dump(e.Input, "Input"); Dump(e.Predicate, "Predicate"); End(e); } #endregion } }