Updates referencesource to .NET 4.7
[mono.git] / mcs / class / referencesource / System.Data.Entity.Design / System / Data / Entity / Design / SSDLGenerator / FunctionDetailsReader.cs
1 //---------------------------------------------------------------------
2 // <copyright file="FunctionDetailsReader.cs" company="Microsoft">
3 //      Copyright (c) Microsoft Corporation.  All rights reserved.
4 // </copyright>
5 //
6 // @owner       Microsoft
7 // @backupOwner Microsoft
8 //---------------------------------------------------------------------
9 using System;
10 using System.Collections.Generic;
11 using System.Text;
12 using System.Data.Common;
13 using System.Data.EntityClient;
14 using System.Diagnostics;
15 using System.Data.Metadata.Edm;
16
17 namespace System.Data.Entity.Design.SsdlGenerator
18 {
19     /// <summary>
20     /// The purpose of this class is to give us strongly typed access to the results of the reader.
21     /// NOTE: this class will dispose of the command when the reader is disposed.
22     /// </summary>
23     internal abstract class FunctionDetailsReader : IDisposable
24     {
25         private DbDataReader _reader;
26         private EntityCommand _command;
27         private EntityConnection _connection;
28         private object[] _currentRow;
29
30         public static FunctionDetailsReader Create(EntityConnection connection, IEnumerable<EntityStoreSchemaFilterEntry> filters, Version storeSchemaModelVersion)
31         {
32             Debug.Assert(connection != null, "the parameter connection is null");
33             Debug.Assert(connection.State == ConnectionState.Open, "the connection is not Open");
34
35             if (storeSchemaModelVersion >= EntityFrameworkVersions.Version3)
36             {
37                 return new FunctionDetailsReaderV3(connection, filters);
38             }
39             else
40             {
41                 return new FunctionDetailsReaderV1(connection, filters);
42             }
43         }
44
45         protected void InitializeReader(EntityConnection connection, IEnumerable<EntityStoreSchemaFilterEntry> filters)
46         {
47             _connection = connection;
48
49             _command = EntityStoreSchemaGeneratorDatabaseSchemaLoader.CreateFilteredCommand(
50                         _connection,
51                         FunctionDetailSql,
52                         FunctionOrderByClause,
53                         EntityStoreSchemaFilterObjectTypes.Function,
54                         new List<EntityStoreSchemaFilterEntry>(filters),
55                         new string[] { FunctionDetailAlias });
56             _reader = _command.ExecuteReader(CommandBehavior.SequentialAccess);
57         }
58
59         internal bool Read()
60         {
61             Debug.Assert(_reader != null, "don't Read() when it is created from a memento");
62             bool haveRow = _reader.Read();
63             if (haveRow)
64             {
65                 if (_currentRow == null)
66                 {
67                     _currentRow = new object[ColumnCount];
68                 }
69                 _reader.GetValues(_currentRow);
70             }
71             else
72             {
73                 _currentRow = null;
74             }
75             return haveRow;
76         }
77
78         public void Dispose()
79         {
80             // Technically, calling GC.SuppressFinalize is not required because the class does not
81             // have a finalizer, but it does no harm, protects against the case where a finalizer is added
82             // in the future, and prevents an FxCop warning.
83             GC.SuppressFinalize(this);
84             Debug.Assert(_reader != null, "don't Dispose() when it is created from a memento");
85             _reader.Dispose();
86             _command.Dispose();
87         }
88
89         internal abstract int ColumnCount { get; }
90
91         public abstract string Catalog { get; }
92
93         public abstract string Schema { get; }
94
95         public abstract string ProcedureName { get; }
96
97         public abstract string ReturnType { get; }
98
99         public abstract bool IsIsAggregate { get; }
100
101         public abstract bool IsBuiltIn { get; }
102
103         public abstract bool IsComposable { get; }
104
105         public abstract bool IsNiladic { get; }
106
107         public abstract bool IsTvf { get; }
108
109         public abstract string ParameterName { get; }
110
111         public abstract bool IsParameterNameNull { get; }
112
113         public abstract string ParameterType { get; }
114
115         public abstract bool IsParameterTypeNull { get; }
116
117         public abstract string ProcParameterMode { get; }
118
119         public abstract bool IsParameterModeNull { get; }
120
121         public bool TryGetParameterMode(out ParameterMode mode)
122         {
123             if (IsParameterModeNull)
124             {
125                 mode = (ParameterMode)(-1);
126                 return false;
127             }
128
129             switch (ProcParameterMode)
130             {
131                 case "IN":
132                     mode = ParameterMode.In;
133                     return true;
134                 case "OUT":
135                     mode = ParameterMode.Out;
136                     return true;
137                 case "INOUT":
138                     mode = ParameterMode.InOut;
139                     return true;
140                 default:
141                     mode = (ParameterMode)(-1);
142                     return false;
143             }
144         }
145
146         internal EntityStoreSchemaGenerator.DbObjectKey CreateDbObjectKey()
147         {
148             Debug.Assert(_currentRow != null, "don't call this method when you not reading");
149             return new EntityStoreSchemaGenerator.DbObjectKey(this.Catalog, this.Schema, this.ProcedureName, EntityStoreSchemaGenerator.DbObjectType.Function);
150         }
151
152         protected static T ConvertDBNull<T>(object value)
153         {
154             return Convert.IsDBNull(value) ? default(T) : (T)value;
155         }
156
157         public abstract void Attach(Memento memento);
158
159         public abstract Memento CreateMemento();
160
161         private static readonly string FunctionDetailAlias = "sp";
162         protected abstract string FunctionDetailSql { get; }
163         private static readonly string FunctionOrderByClause = @" 
164             ORDER BY
165                 sp.SchemaName
166             ,   sp.Name
167             ,   sp.Ordinal
168             ";
169
170         internal sealed class FunctionDetailsReaderV1 : FunctionDetailsReader
171         {
172             internal FunctionDetailsReaderV1(MementoV1 memento)
173             {
174                 _currentRow = memento.Values;
175             }
176
177             public FunctionDetailsReaderV1(EntityConnection connection, IEnumerable<EntityStoreSchemaFilterEntry> filters)
178             {
179                 InitializeReader(connection, filters);
180             }
181
182             public override void Attach(Memento memento)
183             {
184                 Debug.Assert(memento != null, "the parameter memento is null");
185                 Debug.Assert(memento.Values != null, "the values in the memento are null");
186                 Debug.Assert(memento is MementoV1, "the memento is for a different version");
187                 Debug.Assert(_reader == null, "don't attach to a real reader");
188                 _currentRow = memento.Values;
189             }
190
191             public override Memento CreateMemento()
192             {
193                 Debug.Assert(_currentRow != null, "don't call this method when you not reading");
194                 return new MementoV1((object[])_currentRow.Clone());
195             }
196
197             const int PROC_SCHEMA_INDEX = 0;
198             const int PROC_NAME_INDEX = 1;
199             const int PROC_RET_TYPE_INDEX = 2;
200             const int PROC_ISAGGREGATE_INDEX = 3;
201             const int PROC_ISCOMPOSABLE_INDEX = 4;
202             const int PROC_ISBUILTIN_INDEX = 5;
203             const int PROC_ISNILADIC_INDEX = 6;
204             const int PARAM_NAME_INDEX = 7;
205             const int PARAM_TYPE_INDEX = 8;
206             const int PARAM_DIRECTION_INDEX = 9;
207
208             internal override int ColumnCount { get { return 10; } }
209
210             public override string Catalog { get { return null; } }
211
212             public override string Schema
213             {
214                 get { return ConvertDBNull<string>(_currentRow[PROC_SCHEMA_INDEX]); }
215             }
216
217             public override string ProcedureName
218             {
219                 get { return ConvertDBNull<string>(_currentRow[PROC_NAME_INDEX]); }
220             }
221
222             public override string ReturnType
223             {
224                 get { return ConvertDBNull<string>(_currentRow[PROC_RET_TYPE_INDEX]); }
225             }
226
227             public override bool IsIsAggregate
228             {
229                 get { return ConvertDBNull<bool>(_currentRow[PROC_ISAGGREGATE_INDEX]); }
230             }
231
232             public override bool IsBuiltIn
233             {
234                 get { return ConvertDBNull<bool>(_currentRow[PROC_ISBUILTIN_INDEX]); }
235             }
236
237             public override bool IsComposable
238             {
239                 get { return ConvertDBNull<bool>(_currentRow[PROC_ISCOMPOSABLE_INDEX]); }
240             }
241
242             public override bool IsNiladic
243             {
244                 get { return ConvertDBNull<bool>(_currentRow[PROC_ISNILADIC_INDEX]); }
245             }
246
247             public override bool IsTvf { get { return false; } }
248
249             public override string ParameterName
250             {
251                 get { return (string)_currentRow[PARAM_NAME_INDEX]; }
252             }
253
254             public override bool IsParameterNameNull
255             {
256                 get { return Convert.IsDBNull(_currentRow[PARAM_NAME_INDEX]); }
257             }
258
259             public override string ParameterType
260             {
261                 get { return (string)_currentRow[PARAM_TYPE_INDEX]; }
262             }
263
264             public override bool IsParameterTypeNull
265             {
266                 get { return Convert.IsDBNull(_currentRow[PARAM_TYPE_INDEX]); }
267             }
268
269             public override string ProcParameterMode
270             {
271                 get { return (string)_currentRow[PARAM_DIRECTION_INDEX]; }
272             }
273
274             public override bool IsParameterModeNull
275             {
276                 get { return Convert.IsDBNull(_currentRow[PARAM_DIRECTION_INDEX]); }
277             }
278
279             protected override string FunctionDetailSql
280             {
281                 get
282                 {
283                     return @"
284             SELECT
285                   sp.SchemaName
286                 , sp.Name 
287                 , sp.ReturnTypeName
288                 , sp.IsAggregate
289                 , sp.IsComposable
290                 , sp.IsBuiltIn
291                 , sp.IsNiladic
292                 , sp.ParameterName
293                 , sp.ParameterType
294                 , sp.Mode
295             FROM (  
296             (SELECT
297                   r.CatalogName as CatalogName
298               ,   r.SchemaName as SchemaName
299               ,   r.Name as Name
300               ,   r.ReturnType.TypeName as ReturnTypeName
301               ,   r.IsAggregate as IsAggregate
302               ,   true as IsComposable
303               ,   r.IsBuiltIn as IsBuiltIn
304               ,   r.IsNiladic as IsNiladic
305               ,   p.Name as ParameterName
306               ,   p.ParameterType.TypeName as ParameterType
307               ,   p.Mode as Mode
308               ,   p.Ordinal as Ordinal
309             FROM
310                 OfType(SchemaInformation.Functions, Store.ScalarFunction) as r 
311                  OUTER APPLY
312                 r.Parameters as p)
313             UNION ALL
314             (SELECT
315                   r.CatalogName as CatalogName
316               ,   r.SchemaName as SchemaName
317               ,   r.Name as Name
318               ,   CAST(NULL as string) as ReturnTypeName
319               ,   false as IsAggregate
320               ,   false as IsComposable
321               ,   false as IsBuiltIn
322               ,   false as IsNiladic
323               ,   p.Name as ParameterName
324               ,   p.ParameterType.TypeName as ParameterType
325               ,   p.Mode as Mode
326               ,   p.Ordinal as Ordinal
327             FROM
328                 SchemaInformation.Procedures as r 
329                  OUTER APPLY
330                 r.Parameters as p)) as sp
331             ";
332                 }
333             }
334         }
335
336         internal sealed class FunctionDetailsReaderV3 : FunctionDetailsReader
337         {
338             internal FunctionDetailsReaderV3(MementoV3 memento)
339             {
340                 _currentRow = memento.Values;
341             }
342
343             public FunctionDetailsReaderV3(EntityConnection connection, IEnumerable<EntityStoreSchemaFilterEntry> filters)
344             {
345                 InitializeReader(connection, filters);
346             }
347
348             public override void Attach(Memento memento)
349             {
350                 Debug.Assert(memento != null, "the parameter memento is null");
351                 Debug.Assert(memento.Values != null, "the values in the memento are null");
352                 Debug.Assert(memento is MementoV3, "the memento is for a different version");
353                 Debug.Assert(_reader == null, "don't attach to a real reader");
354                 _currentRow = memento.Values;
355             }
356
357             public override Memento CreateMemento()
358             {
359                 Debug.Assert(_currentRow != null, "don't call this method when you not reading");
360                 return new MementoV3((object[])_currentRow.Clone());
361             }
362
363             const int PROC_CATALOG_INDEX = 0;
364             const int PROC_SCHEMA_INDEX = 1;
365             const int PROC_NAME_INDEX = 2;
366             const int PROC_RET_TYPE_INDEX = 3;
367             const int PROC_ISAGGREGATE_INDEX = 4;
368             const int PROC_ISCOMPOSABLE_INDEX = 5;
369             const int PROC_ISBUILTIN_INDEX = 6;
370             const int PROC_ISNILADIC_INDEX = 7;
371             const int PROC_ISTVF_INDEX = 8;
372             const int PARAM_NAME_INDEX = 9;
373             const int PARAM_TYPE_INDEX = 10;
374             const int PARAM_DIRECTION_INDEX = 11;
375
376             internal override int ColumnCount { get { return 12; } }
377
378             public override string Catalog
379             {
380                 get { return ConvertDBNull<string>(_currentRow[PROC_CATALOG_INDEX]); }
381             }
382
383             public override string Schema
384             {
385                 get { return ConvertDBNull<string>(_currentRow[PROC_SCHEMA_INDEX]); }
386             }
387
388             public override string ProcedureName
389             {
390                 get { return ConvertDBNull<string>(_currentRow[PROC_NAME_INDEX]); }
391             }
392
393             public override string ReturnType
394             {
395                 get { return ConvertDBNull<string>(_currentRow[PROC_RET_TYPE_INDEX]); }
396             }
397
398             public override bool IsIsAggregate
399             {
400                 get { return ConvertDBNull<bool>(_currentRow[PROC_ISAGGREGATE_INDEX]); }
401             }
402
403             public override bool IsBuiltIn
404             {
405                 get { return ConvertDBNull<bool>(_currentRow[PROC_ISBUILTIN_INDEX]); }
406             }
407
408             public override bool IsComposable
409             {
410                 get { return ConvertDBNull<bool>(_currentRow[PROC_ISCOMPOSABLE_INDEX]); }
411             }
412
413             public override bool IsNiladic
414             {
415                 get { return ConvertDBNull<bool>(_currentRow[PROC_ISNILADIC_INDEX]); }
416             }
417
418             public override bool IsTvf
419             {
420                 get { return ConvertDBNull<bool>(_currentRow[PROC_ISTVF_INDEX]); }
421             }
422
423             public override string ParameterName
424             {
425                 get { return (string)_currentRow[PARAM_NAME_INDEX]; }
426             }
427
428             public override bool IsParameterNameNull
429             {
430                 get { return Convert.IsDBNull(_currentRow[PARAM_NAME_INDEX]); }
431             }
432
433             public override string ParameterType
434             {
435                 get { return (string)_currentRow[PARAM_TYPE_INDEX]; }
436             }
437
438             public override bool IsParameterTypeNull
439             {
440                 get { return Convert.IsDBNull(_currentRow[PARAM_TYPE_INDEX]); }
441             }
442
443             public override string ProcParameterMode
444             {
445                 get { return (string)_currentRow[PARAM_DIRECTION_INDEX]; }
446             }
447
448             public override bool IsParameterModeNull
449             {
450                 get { return Convert.IsDBNull(_currentRow[PARAM_DIRECTION_INDEX]); }
451             }
452
453             protected override string FunctionDetailSql
454             {
455                 get
456                 {
457                     return @"
458             Function IsTvf(f Store.Function) as (f is of (Store.TableValuedFunction))
459             SELECT
460                   sp.CatalogName
461                 , sp.SchemaName
462                 , sp.Name 
463                 , sp.ReturnTypeName
464                 , sp.IsAggregate
465                 , sp.IsComposable
466                 , sp.IsBuiltIn
467                 , sp.IsNiladic
468                 , sp.IsTvf
469                 , sp.ParameterName
470                 , sp.ParameterType
471                 , sp.Mode
472             FROM (  
473             (SELECT
474                   r.CatalogName as CatalogName
475               ,   r.SchemaName as SchemaName
476               ,   r.Name as Name
477               ,   TREAT(r as Store.ScalarFunction).ReturnType.TypeName as ReturnTypeName
478               ,   TREAT(r as Store.ScalarFunction).IsAggregate as IsAggregate
479               ,   true as IsComposable
480               ,   r.IsBuiltIn as IsBuiltIn
481               ,   r.IsNiladic as IsNiladic
482               ,   IsTvf(r) as IsTvf
483               ,   p.Name as ParameterName
484               ,   p.ParameterType.TypeName as ParameterType
485               ,   p.Mode as Mode
486               ,   p.Ordinal as Ordinal
487             FROM
488                 SchemaInformation.Functions as r 
489                  OUTER APPLY
490                 r.Parameters as p)
491             UNION ALL
492             (SELECT
493                   r.CatalogName as CatalogName
494               ,   r.SchemaName as SchemaName
495               ,   r.Name as Name
496               ,   CAST(NULL as string) as ReturnTypeName
497               ,   false as IsAggregate
498               ,   false as IsComposable
499               ,   false as IsBuiltIn
500               ,   false as IsNiladic
501               ,   false as IsTvf
502               ,   p.Name as ParameterName
503               ,   p.ParameterType.TypeName as ParameterType
504               ,   p.Mode as Mode
505               ,   p.Ordinal as Ordinal
506             FROM
507                 SchemaInformation.Procedures as r 
508                  OUTER APPLY
509                 r.Parameters as p)) as sp
510             ";
511                 }
512             }
513         }
514
515         internal abstract class Memento
516         {
517             protected object[] _values;
518
519             internal object[] Values
520             {
521                 get { return _values; }
522             }
523
524             public abstract FunctionDetailsReader CreateReader();
525         }
526
527         internal sealed class MementoV1 : Memento
528         {
529             internal MementoV1(object[] values)
530             {
531                 _values = values;
532             }
533
534             public override FunctionDetailsReader CreateReader()
535             {
536                 return new FunctionDetailsReaderV1(this);
537             }
538         }
539
540         internal sealed class MementoV3 : Memento
541         {
542             internal MementoV3(object[] values)
543             {
544                 _values = values;
545             }
546
547             public override FunctionDetailsReader CreateReader()
548             {
549                 return new FunctionDetailsReaderV3(this);
550             }
551         }
552     }
553 }