File: ProviderCommandInfoUtils.cs

package info (click to toggle)
mono 6.12.0.199%2Bdfsg-6
  • links: PTS, VCS
  • area: main
  • in suites: sid, trixie
  • size: 1,296,836 kB
  • sloc: cs: 11,181,803; xml: 2,850,076; ansic: 699,709; cpp: 123,344; perl: 59,361; javascript: 30,841; asm: 21,853; makefile: 20,405; sh: 15,009; python: 4,839; pascal: 925; sql: 859; sed: 16; php: 1
file content (130 lines) | stat: -rw-r--r-- 6,409 bytes parent folder | download | duplicates (8)
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
//---------------------------------------------------------------------
// <copyright file="ProviderCommandInfoUtils.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.Data.Common.CommandTrees;
using System.Data.Common;
using md = System.Data.Metadata.Edm;
using System.Data.Query.InternalTrees;
using System.Data.Query.PlanCompiler;

namespace System.Data.Query.PlanCompiler
{
    /// <summary>
    /// Helper class for creating a ProviderCommandInfo given an Iqt Node. 
    /// </summary>
    internal static class ProviderCommandInfoUtils
    {
        #region Public Methods

        /// <summary>
        /// Creates a ProviderCommandInfo for the given node. 
        /// This method should be called when the keys, foreign keys and sort keys are known ahead of time.
        /// Typically it is used when the original command is factored into multiple commands. 
        /// </summary>
        /// <param name="command">The owning command, used for creating VarVecs, etc</param>
        /// <param name="node">The root of the sub-command for which a ProviderCommandInfo should be generated</param>
        /// <param name="children">A list of ProviderCommandInfos that were created for the child sub-commands.</param>
        /// <returns>The resulting ProviderCommandInfo</returns>
        internal static ProviderCommandInfo Create(
            Command command,
            Node node, 
            List<ProviderCommandInfo> children)
        {
            PhysicalProjectOp projectOp = node.Op as PhysicalProjectOp;
            PlanCompiler.Assert(projectOp != null, "Expected root Op to be a physical Project");

            // build up the CQT
            DbCommandTree ctree = CTreeGenerator.Generate(command, node);
            DbQueryCommandTree cqtree = ctree as DbQueryCommandTree;
            PlanCompiler.Assert(cqtree != null, "null query command tree");

            // Get the rowtype for the result cqt
            md.CollectionType collType = TypeHelpers.GetEdmType<md.CollectionType>(cqtree.Query.ResultType);
            PlanCompiler.Assert(md.TypeSemantics.IsRowType(collType.TypeUsage), "command rowtype is not a record");

            // Build up a mapping from Vars to the corresponding output property/column
            Dictionary<Var, md.EdmProperty> outputVarMap = BuildOutputVarMap(projectOp, collType.TypeUsage);

            return new ProviderCommandInfo(ctree, children);
        }

        /// <summary>
        /// Creates a ProviderCommandInfo for the given node. 
        /// This method should be called when the keys and the sort keys are not known ahead of time.
        /// Typically it is used when there is only one command, that is no query factoring is done.
        /// This method also has the option of pulling up keys and sort information. 
        /// </summary>
        /// <param name="command">The owning command, used for creating VarVecs, etc</param>
        /// <param name="node">The root of the sub-command for which a ProviderCommandInfo should be generated</param>
        /// <returns>The resulting ProviderCommandInfo</returns>
        internal static ProviderCommandInfo Create(
            Command command,
            Node node)
        {   
            return Create(
                command, 
                node, 
                new List<ProviderCommandInfo>() //children 
                );
        }
        #endregion

        #region Private Methods
        /// <summary>
        /// Build up a mapping from Vars to the corresponding property of the output row type
        /// </summary>
        /// <param name="projectOp">the physical projectOp</param>
        /// <param name="outputType">output type</param>
        /// <returns>a map from Vars to the output type member</returns>
        private static Dictionary<Var, md.EdmProperty> BuildOutputVarMap(PhysicalProjectOp projectOp, md.TypeUsage outputType)
        {
            Dictionary<Var, md.EdmProperty> outputVarMap = new Dictionary<Var, md.EdmProperty>();

            PlanCompiler.Assert(md.TypeSemantics.IsRowType(outputType), "PhysicalProjectOp result type is not a RowType?");

            IEnumerator<md.EdmProperty> propertyEnumerator = TypeHelpers.GetEdmType<md.RowType>(outputType).Properties.GetEnumerator();
            IEnumerator<Var> varEnumerator = projectOp.Outputs.GetEnumerator();
            while (true)
            {
                bool foundProp = propertyEnumerator.MoveNext();
                bool foundVar = varEnumerator.MoveNext();
                if (foundProp != foundVar)
                {
                    throw EntityUtil.InternalError(EntityUtil.InternalErrorCode.ColumnCountMismatch, 1);
                }
                if (!foundProp)
                {
                    break;
                }
                outputVarMap[varEnumerator.Current] = propertyEnumerator.Current;
            }
            return outputVarMap;
        }

        #endregion
    }
}