1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151
|
//---------------------------------------------------------------------
// <copyright file="CodeGen.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//
// @owner Microsoft
// @backupOwner Microsoft
//---------------------------------------------------------------------
using System;
using System.Collections.Generic;
//using System.Diagnostics; // Please use PlanCompiler.Assert instead of Debug.Assert in this class...
// It is fine to use Debug.Assert in cases where you assert an obvious thing that is supposed
// to prevent from simple mistakes during development (e.g. method argument validation
// in cases where it was you who created the variables or the variables had already been validated or
// in "else" clauses where due to code changes (e.g. adding a new value to an enum type) the default
// "else" block is chosen why the new condition should be treated separately). This kind of asserts are
// (can be) helpful when developing new code to avoid simple mistakes but have no or little value in
// the shipped product.
// PlanCompiler.Assert *MUST* be used to verify conditions in the trees. These would be assumptions
// about how the tree was built etc. - in these cases we probably want to throw an exception (this is
// what PlanCompiler.Assert does when the condition is not met) if either the assumption is not correct
// or the tree was built/rewritten not the way we thought it was.
// Use your judgment - if you rather remove an assert than ship it use Debug.Assert otherwise use
// PlanCompiler.Assert.
using System.Globalization;
using md = System.Data.Metadata.Edm;
using System.Data.Common.CommandTrees;
using System.Data.Query.InternalTrees;
using System.Data.Query.PlanCompiler;
//
// The CodeGen module is responsible for translating the ITree finally into a query
// We assume that various tree transformations have taken place, and the tree
// is finally ready to be executed. The CodeGen module
// * converts the Itree into one or more CTrees (in S space)
// * produces a ColumnMap to facilitate result assembly
// * and wraps up everything in a plan object
//
//
namespace System.Data.Query.PlanCompiler
{
internal class CodeGen
{
#region public methods
/// <summary>
/// This involves
/// * Converting the ITree into a set of ProviderCommandInfo objects
/// * Creating a column map to enable result assembly
/// Currently, we only produce a single ITree, and correspondingly, the
/// following steps are trivial
/// </summary>
/// <param name="compilerState">current compiler state</param>
/// <param name="childCommands">CQTs for each store command</param>
/// <param name="resultColumnMap">column map to help in result assembly</param>
internal static void Process(PlanCompiler compilerState, out List<ProviderCommandInfo> childCommands, out ColumnMap resultColumnMap, out int columnCount)
{
CodeGen codeGen = new CodeGen(compilerState);
codeGen.Process(out childCommands, out resultColumnMap, out columnCount);
}
#endregion
#region constructors
private CodeGen(PlanCompiler compilerState)
{
m_compilerState = compilerState;
}
#endregion
#region private methods
/// <summary>
/// The real driver. This routine walks the tree, converts each subcommand
/// into a CTree, and converts the columnmap into a real column map.
/// Finally, it produces a "real" plan that can be used by the bridge execution, and
/// returns this plan
///
/// The root of the tree must be a PhysicalProjectOp. Each child of this Op
/// represents a command to be executed, and the ColumnMap of this Op represents
/// the eventual columnMap to be used for result assembly
/// </summary>
/// <param name="childCommands">CQTs for store commands</param>
/// <param name="resultColumnMap">column map for result assembly</param>
private void Process(out List<ProviderCommandInfo> childCommands, out ColumnMap resultColumnMap, out int columnCount)
{
PhysicalProjectOp projectOp = (PhysicalProjectOp)this.Command.Root.Op;
this.m_subCommands = new List<Node>(new Node[] { this.Command.Root });
childCommands = new List<ProviderCommandInfo>(new ProviderCommandInfo[] {
ProviderCommandInfoUtils.Create(
this.Command,
this.Command.Root // input node
)});
// Build the final column map, and count the columns we expect for it.
resultColumnMap = BuildResultColumnMap(projectOp);
columnCount = projectOp.Outputs.Count;
}
private ColumnMap BuildResultColumnMap(PhysicalProjectOp projectOp)
{
// convert the column map into a real column map
// build up a dictionary mapping Vars to their real positions in the commands
Dictionary<Var, KeyValuePair<int, int>> varMap = BuildVarMap();
ColumnMap realColumnMap = ColumnMapTranslator.Translate(projectOp.ColumnMap, varMap);
return realColumnMap;
}
/// <summary>
/// For each subcommand, build up a "location-map" for each top-level var that
/// is projected out. This location map will ultimately be used to convert VarRefColumnMap
/// into SimpleColumnMap
/// </summary>
private Dictionary<Var, KeyValuePair<int, int>> BuildVarMap()
{
Dictionary<Var, KeyValuePair<int, int>> varMap =
new Dictionary<Var, KeyValuePair<int, int>>();
int commandId = 0;
foreach (Node subCommand in m_subCommands)
{
PhysicalProjectOp projectOp = (PhysicalProjectOp)subCommand.Op;
int columnPos = 0;
foreach (Var v in projectOp.Outputs)
{
KeyValuePair<int, int> varLocation = new KeyValuePair<int, int>(commandId, columnPos);
varMap[v] = varLocation;
columnPos++;
}
commandId++;
}
return varMap;
}
#endregion
#region private state
private PlanCompiler m_compilerState;
private Command Command { get { return m_compilerState.Command; } }
private List<Node> m_subCommands;
#endregion
}
}
|