Updates referencesource to .NET 4.7
[mono.git] / mcs / class / referencesource / System.Data.Entity / System / Data / Common / CommandTrees / DbCommandTree.cs
1 //---------------------------------------------------------------------
2 // <copyright file="DbCommandTree.cs" company="Microsoft">
3 //      Copyright (c) Microsoft Corporation.  All rights reserved.
4 // </copyright>
5 //
6 // @owner  Microsoft
7 // @backupOwner Microsoft
8 //---------------------------------------------------------------------
9
10 namespace System.Data.Common.CommandTrees
11 {
12     using System.Collections.Generic;
13     using System.Data.Common.CommandTrees.Internal;
14     using System.Data.Common.Utils;
15     using System.Data.Metadata.Edm;
16     using System.IO;
17     using System.Linq;
18     using System.Text.RegularExpressions;
19
20     /// <summary>
21     /// Describes the different "kinds" (classes) of command trees.
22     /// </summary>
23     internal enum DbCommandTreeKind
24     {
25         Query,
26         Update,
27         Insert,
28         Delete,
29         Function,
30     }
31
32     /// <summary>
33     /// DbCommandTree is the abstract base type for the Delete, Query, Insert and Update DbCommandTree types.
34     /// </summary>
35     [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "Db")]
36     public abstract class DbCommandTree
37     {      
38         // Metadata collection
39         private readonly MetadataWorkspace _metadata;
40         private readonly DataSpace _dataSpace;
41                 
42         /// <summary>
43         /// Initializes a new command tree with a given metadata workspace.
44         /// </summary>
45         /// <param name="metadata">The metadata workspace against which the command tree should operate.</param>
46         /// <param name="dataSpace">The logical 'space' that metadata in the expressions used in this command tree must belong to.</param>
47         internal DbCommandTree(MetadataWorkspace metadata, DataSpace dataSpace)
48         {
49             // Ensure the metadata workspace is non-null
50             EntityUtil.CheckArgumentNull(metadata, "metadata");
51
52             // Ensure that the data space value is valid
53             if (!DbCommandTree.IsValidDataSpace(dataSpace))
54             {
55                 throw EntityUtil.Argument(System.Data.Entity.Strings.Cqt_CommandTree_InvalidDataSpace, "dataSpace");
56             }
57
58             //
59             // Create the tree's metadata workspace and initalize commonly used types.
60             //
61             MetadataWorkspace effectiveMetadata = new MetadataWorkspace();
62                 
63             //While EdmItemCollection and StorageitemCollections are required
64             //ObjectItemCollection may or may not be registered on the workspace yet.
65             //So register the ObjectItemCollection if it exists.
66             ItemCollection objectItemCollection;
67             if (metadata.TryGetItemCollection(DataSpace.OSpace, out objectItemCollection))
68             {
69                 effectiveMetadata.RegisterItemCollection(objectItemCollection);
70             }                
71             effectiveMetadata.RegisterItemCollection(metadata.GetItemCollection(DataSpace.CSpace));
72             effectiveMetadata.RegisterItemCollection(metadata.GetItemCollection(DataSpace.CSSpace));
73             effectiveMetadata.RegisterItemCollection(metadata.GetItemCollection(DataSpace.SSpace));
74
75             this._metadata = effectiveMetadata;
76             this._dataSpace = dataSpace;
77         }
78                                         
79         /// <summary>
80         /// Gets the name and corresponding type of each parameter that can be referenced within this command tree.
81         /// </summary>
82         public IEnumerable<KeyValuePair<string, TypeUsage>> Parameters
83         {
84             get
85             {
86                 return this.GetParameters();
87             }
88         }
89                 
90         #region Internal Implementation
91         
92         /// <summary>
93         /// Gets the kind of this command tree.
94         /// </summary>
95         internal abstract DbCommandTreeKind CommandTreeKind { get; }
96
97         /// <summary>
98         /// Gets the name and type of each parameter declared on the command tree.
99         /// </summary>
100         /// <returns></returns>
101         internal abstract IEnumerable<KeyValuePair<string, TypeUsage>> GetParameters();
102         
103         /// <summary>
104         /// Gets the metadata workspace used by this command tree.
105         /// </summary>
106         internal MetadataWorkspace MetadataWorkspace { get { return _metadata; } }
107
108         /// <summary>
109         /// Gets the data space in which metadata used by this command tree must reside.
110         /// </summary>
111         internal DataSpace DataSpace { get { return _dataSpace; } }
112                 
113         #region Dump/Print Support
114
115         internal void Dump(ExpressionDumper dumper)
116         {
117             //
118             // Dump information about this command tree to the specified ExpressionDumper
119             //
120             // First dump standard information - the DataSpace of the command tree and its parameters
121             //
122             Dictionary<string, object> attrs = new Dictionary<string, object>();
123             attrs.Add("DataSpace", this.DataSpace);
124             dumper.Begin(this.GetType().Name, attrs);
125
126             //
127             // The name and type of each Parameter in turn is added to the output
128             //
129             dumper.Begin("Parameters", null);
130             foreach (KeyValuePair<string, TypeUsage> param in this.Parameters)
131             {
132                 Dictionary<string, object> paramAttrs = new Dictionary<string, object>();
133                 paramAttrs.Add("Name", param.Key);
134                 dumper.Begin("Parameter", paramAttrs);
135                 dumper.Dump(param.Value, "ParameterType");
136                 dumper.End("Parameter");
137             }
138             dumper.End("Parameters");
139
140             //
141             // Delegate to the derived type's implementation that dumps the structure of the command tree
142             //
143             this.DumpStructure(dumper);
144
145             //
146             // Matching call to End to correspond with the call to Begin above
147             //
148             dumper.End(this.GetType().Name);
149         }
150
151         internal abstract void DumpStructure(ExpressionDumper dumper);
152
153         internal string DumpXml()
154         {
155             //
156             // This is a convenience method that dumps the command tree in an XML format.
157             // This is intended primarily as a debugging aid to allow inspection of the tree structure.
158             //
159             // Create a new MemoryStream that the XML dumper should write to.
160             //
161             MemoryStream stream = new MemoryStream();
162
163             //
164             // Create the dumper
165             //
166             XmlExpressionDumper dumper = new XmlExpressionDumper(stream);
167
168             //
169             // Dump this tree and then close the XML dumper so that the end document tag is written
170             // and the output is flushed to the stream.
171             //
172             this.Dump(dumper);
173             dumper.Close();
174
175             //
176             // Construct a string from the resulting memory stream and return it to the caller
177             //
178             return XmlExpressionDumper.DefaultEncoding.GetString(stream.ToArray());
179         }
180
181         internal string Print()
182         {
183             return this.PrintTree(new ExpressionPrinter());
184         }
185
186         internal abstract string PrintTree(ExpressionPrinter printer);
187
188         #endregion
189
190         internal static bool IsValidDataSpace(DataSpace dataSpace)
191         {
192             return (DataSpace.OSpace == dataSpace ||
193                     DataSpace.CSpace == dataSpace ||
194                     DataSpace.SSpace == dataSpace);
195         }
196
197         internal static bool IsValidParameterName(string name)
198         {
199             return (!StringUtil.IsNullOrEmptyOrWhiteSpace(name) &&
200                     _paramNameRegex.IsMatch(name));
201         }
202         private static readonly Regex _paramNameRegex = new Regex("^([A-Za-z])([A-Za-z0-9_])*$");
203                 
204         #endregion
205     }
206 }