1 //---------------------------------------------------------------------
2 // <copyright file="ProviderCommandInfoUtils.cs" company="Microsoft">
3 // Copyright (c) Microsoft Corporation. All rights reserved.
7 // @backupOwner Microsoft
8 //---------------------------------------------------------------------
11 using System.Collections.Generic;
12 //using System.Diagnostics; // Please use PlanCompiler.Assert instead of Debug.Assert in this class...
14 // It is fine to use Debug.Assert in cases where you assert an obvious thing that is supposed
15 // to prevent from simple mistakes during development (e.g. method argument validation
16 // in cases where it was you who created the variables or the variables had already been validated or
17 // in "else" clauses where due to code changes (e.g. adding a new value to an enum type) the default
18 // "else" block is chosen why the new condition should be treated separately). This kind of asserts are
19 // (can be) helpful when developing new code to avoid simple mistakes but have no or little value in
20 // the shipped product.
21 // PlanCompiler.Assert *MUST* be used to verify conditions in the trees. These would be assumptions
22 // about how the tree was built etc. - in these cases we probably want to throw an exception (this is
23 // what PlanCompiler.Assert does when the condition is not met) if either the assumption is not correct
24 // or the tree was built/rewritten not the way we thought it was.
25 // Use your judgment - if you rather remove an assert than ship it use Debug.Assert otherwise use
26 // PlanCompiler.Assert.
28 using System.Data.Common.CommandTrees;
29 using System.Data.Common;
30 using md = System.Data.Metadata.Edm;
31 using System.Data.Query.InternalTrees;
32 using System.Data.Query.PlanCompiler;
34 namespace System.Data.Query.PlanCompiler
37 /// Helper class for creating a ProviderCommandInfo given an Iqt Node.
39 internal static class ProviderCommandInfoUtils
41 #region Public Methods
44 /// Creates a ProviderCommandInfo for the given node.
45 /// This method should be called when the keys, foreign keys and sort keys are known ahead of time.
46 /// Typically it is used when the original command is factored into multiple commands.
48 /// <param name="command">The owning command, used for creating VarVecs, etc</param>
49 /// <param name="node">The root of the sub-command for which a ProviderCommandInfo should be generated</param>
50 /// <param name="children">A list of ProviderCommandInfos that were created for the child sub-commands.</param>
51 /// <returns>The resulting ProviderCommandInfo</returns>
52 internal static ProviderCommandInfo Create(
55 List<ProviderCommandInfo> children)
57 PhysicalProjectOp projectOp = node.Op as PhysicalProjectOp;
58 PlanCompiler.Assert(projectOp != null, "Expected root Op to be a physical Project");
61 DbCommandTree ctree = CTreeGenerator.Generate(command, node);
62 DbQueryCommandTree cqtree = ctree as DbQueryCommandTree;
63 PlanCompiler.Assert(cqtree != null, "null query command tree");
65 // Get the rowtype for the result cqt
66 md.CollectionType collType = TypeHelpers.GetEdmType<md.CollectionType>(cqtree.Query.ResultType);
67 PlanCompiler.Assert(md.TypeSemantics.IsRowType(collType.TypeUsage), "command rowtype is not a record");
69 // Build up a mapping from Vars to the corresponding output property/column
70 Dictionary<Var, md.EdmProperty> outputVarMap = BuildOutputVarMap(projectOp, collType.TypeUsage);
72 return new ProviderCommandInfo(ctree, children);
76 /// Creates a ProviderCommandInfo for the given node.
77 /// This method should be called when the keys and the sort keys are not known ahead of time.
78 /// Typically it is used when there is only one command, that is no query factoring is done.
79 /// This method also has the option of pulling up keys and sort information.
81 /// <param name="command">The owning command, used for creating VarVecs, etc</param>
82 /// <param name="node">The root of the sub-command for which a ProviderCommandInfo should be generated</param>
83 /// <returns>The resulting ProviderCommandInfo</returns>
84 internal static ProviderCommandInfo Create(
91 new List<ProviderCommandInfo>() //children
96 #region Private Methods
98 /// Build up a mapping from Vars to the corresponding property of the output row type
100 /// <param name="projectOp">the physical projectOp</param>
101 /// <param name="outputType">output type</param>
102 /// <returns>a map from Vars to the output type member</returns>
103 private static Dictionary<Var, md.EdmProperty> BuildOutputVarMap(PhysicalProjectOp projectOp, md.TypeUsage outputType)
105 Dictionary<Var, md.EdmProperty> outputVarMap = new Dictionary<Var, md.EdmProperty>();
107 PlanCompiler.Assert(md.TypeSemantics.IsRowType(outputType), "PhysicalProjectOp result type is not a RowType?");
109 IEnumerator<md.EdmProperty> propertyEnumerator = TypeHelpers.GetEdmType<md.RowType>(outputType).Properties.GetEnumerator();
110 IEnumerator<Var> varEnumerator = projectOp.Outputs.GetEnumerator();
113 bool foundProp = propertyEnumerator.MoveNext();
114 bool foundVar = varEnumerator.MoveNext();
115 if (foundProp != foundVar)
117 throw EntityUtil.InternalError(EntityUtil.InternalErrorCode.ColumnCountMismatch, 1);
123 outputVarMap[varEnumerator.Current] = propertyEnumerator.Current;