File: DbProviderFactories.cs

package info (click to toggle)
mono 6.14.1%2Bds2-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 1,282,732 kB
  • sloc: cs: 11,182,461; xml: 2,850,281; ansic: 699,123; cpp: 122,919; perl: 58,604; javascript: 30,841; asm: 21,845; makefile: 19,602; sh: 10,973; python: 4,772; pascal: 925; sql: 859; sed: 16; php: 1
file content (346 lines) | stat: -rw-r--r-- 19,628 bytes parent folder | download | duplicates (5)
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
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
//------------------------------------------------------------------------------
// <copyright file="DbProviderFactories.cs" company="Microsoft">
//      Copyright (c) Microsoft Corporation.  All rights reserved.
// </copyright>
// <owner current="true" primary="true">Microsoft</owner>
// <owner current="true" primary="false">Microsoft</owner>
//------------------------------------------------------------------------------

namespace System.Data.Common {

    using System;
    using System.Collections;
    using System.Collections.Concurrent;
    using System.Collections.Generic;
    using System.Configuration;
    using System.Data;
    using System.Diagnostics;
    using System.Globalization;
    using System.Xml;
    using System.Linq;
    using System.Reflection;

    public static class DbProviderFactories {

        private const string AssemblyQualifiedName = "AssemblyQualifiedName";
        private const string Instance = "Instance";
        private const string InvariantName = "InvariantName";
        private const string Name = "Name";
        private const string Description = "Description";
        private const string InstanceFieldName = "Instance";


        private static ConcurrentDictionary<string, ProviderRegistration> _registeredFactories = new ConcurrentDictionary<string, ProviderRegistration>();
        private static ConnectionState _initState; // closed, connecting, open
        private static DataTable _providerTable;
        private static object _lockobj = new object();

        static public DbProviderFactory GetFactory(string providerInvariantName) => GetFactory(providerInvariantName, true);

        static public DbProviderFactory GetFactory(string providerInvariantName, bool throwOnError) {
            if (throwOnError)
                ADP.CheckArgumentLength(providerInvariantName, "providerInvariantName");
            // NOTES: Include the Framework Providers and any other Providers listed in the config file.
            DataTable providerTable = GetProviderTable();
            if (null != providerTable) {
                // we don't need to copy the DataTable because its used in a controlled fashion
                // also we don't need to create a blank datatable because we know the information won't exist

#if DEBUG
                DataColumn[] pkey = providerTable.PrimaryKey;
                Debug.Assert(null != providerTable.Columns[InvariantName], "missing primary key column");
                Debug.Assert((null != pkey) && (1 == pkey.Length) && (InvariantName == pkey[0].ColumnName), "bad primary key");
#endif
                DataRow providerRow = providerTable.Rows.Find(providerInvariantName);
                if (null != providerRow) {
                    return DbProviderFactories.GetFactory(providerRow);
                }
            }

            if (throwOnError)
                throw ADP.ConfigProviderNotFound();
            return null;
        }

        static public DbProviderFactory GetFactory(DataRow providerRow) {
            ADP.CheckArgumentNull(providerRow, "providerRow");
            
            // fail with ConfigProviderMissing rather than ColumnNotInTheTable exception
            DataColumn column = providerRow.Table.Columns[AssemblyQualifiedName];
            if (null != column) { 
                // column value may not be a string
                string assemblyQualifiedName = providerRow[column] as string;
                if (!ADP.IsEmpty(assemblyQualifiedName)) {

    // FXCop is concerned about the following line call to Get Type,
    // If this code is deemed safe during our security review we should add this warning to our exclusion list.
    // FXCop Message, pertaining to the call to GetType.
    //
    // Secure late-binding methods,System.Data.dll!System.Data.Common.DbProviderFactories.GetFactory(System.Data.DataRow):System.Data.Common.DbProviderFactory,
                    Type providerType = Type.GetType(assemblyQualifiedName);
                    if (null != providerType) {

                        System.Reflection.FieldInfo providerInstance = providerType.GetField(Instance, System.Reflection.BindingFlags.DeclaredOnly|System.Reflection.BindingFlags.Public|System.Reflection.BindingFlags.Static);
                        if (null != providerInstance) {
                            Debug.Assert(providerInstance.IsPublic, "field not public");
                            Debug.Assert(providerInstance.IsStatic, "field not static");

                             if (providerInstance.FieldType.IsSubclassOf(typeof(DbProviderFactory))) {

                                object factory = providerInstance.GetValue(null);
                                if (null != factory) {
                                    return (DbProviderFactory)factory;
                                }
                                // else throw ConfigProviderInvalid
                            }
                            // else throw ConfigProviderInvalid
                        }
                        throw ADP.ConfigProviderInvalid();
                    }
                    throw ADP.ConfigProviderNotInstalled();
                }
                // else throw ConfigProviderMissing
            }
            throw ADP.ConfigProviderMissing();
        }

        static public DbProviderFactory GetFactory(DbConnection connection) {
            ADP.CheckArgumentNull(connection, "connection");

            return connection.ProviderFactory;
        }
            
        static public DataTable GetFactoryClasses() { // V1.2.3300
            // NOTES: Include the Framework Providers and any other Providers listed in the config file.
            DataTable dataTable = GetProviderTable();
            if (null != dataTable) {
                dataTable = dataTable.Copy();
            }
            else {
                dataTable = DbProviderFactoriesConfigurationHandler.CreateProviderDataTable();
            }
            return dataTable;
        }

        // VSTFDevDiv # 624213: System.Data.Common.DbProviderFactories.GetFactoryClasses() still gets OracleClient provider in ClientSku environment.
        static private DataTable IncludeFrameworkFactoryClasses(DataTable configDataTable)
        {
            DataTable dataTable = DbProviderFactoriesConfigurationHandler.CreateProviderDataTable();

            // NOTES: Adding the following Framework DbProviderFactories
            //  <add name="Odbc Data Provider" invariant="System.Data.Odbc" description=".Net Framework Data Provider for Odbc" type="System.Data.Odbc.OdbcFactory, System.Data, Version=%ASSEMBLY_VERSION%, Culture=neutral, PublicKeyToken=%ECMA_PUBLICKEY%"/>
            //  <add name="OleDb Data Provider" invariant="System.Data.OleDb" description=".Net Framework Data Provider for OleDb" type="System.Data.OleDb.OleDbFactory, System.Data, Version=%ASSEMBLY_VERSION%, Culture=neutral, PublicKeyToken=%ECMA_PUBLICKEY%"/>
            //  <add name="OracleClient Data Provider" invariant="System.Data.OracleClient" description=".Net Framework Data Provider for Oracle" type="System.Data.OracleClient.OracleClientFactory, System.Data.OracleClient, Version=%ASSEMBLY_VERSION%, Culture=neutral, PublicKeyToken=%ECMA_PUBLICKEY%"/>
            //  <add name="SqlClient Data Provider" invariant="System.Data.SqlClient" description=".Net Framework Data Provider for SqlServer" type="System.Data.SqlClient.SqlClientFactory, System.Data, Version=%ASSEMBLY_VERSION%, Culture=neutral, PublicKeyToken=%ECMA_PUBLICKEY%"/>
            Type sysDataType = typeof(System.Data.SqlClient.SqlClientFactory);
            string asmQualName = sysDataType.AssemblyQualifiedName.ToString().Replace(DbProviderFactoriesConfigurationHandler.sqlclientPartialAssemblyQualifiedName, DbProviderFactoriesConfigurationHandler.oracleclientPartialAssemblyQualifiedName);
            DbProviderFactoryConfigSection[] dbFactoriesConfigSection = new DbProviderFactoryConfigSection[(int)DbProvidersIndex.DbProvidersIndexCount];
            dbFactoriesConfigSection[(int)DbProvidersIndex.Odbc] = new DbProviderFactoryConfigSection(typeof(System.Data.Odbc.OdbcFactory), DbProviderFactoriesConfigurationHandler.odbcProviderName, DbProviderFactoriesConfigurationHandler.odbcProviderDescription);
            dbFactoriesConfigSection[(int)DbProvidersIndex.OleDb] = new DbProviderFactoryConfigSection(typeof(System.Data.OleDb.OleDbFactory), DbProviderFactoriesConfigurationHandler.oledbProviderName, DbProviderFactoriesConfigurationHandler.oledbProviderDescription);
            dbFactoriesConfigSection[(int)DbProvidersIndex.OracleClient] = new DbProviderFactoryConfigSection(DbProviderFactoriesConfigurationHandler.oracleclientProviderName, DbProviderFactoriesConfigurationHandler.oracleclientProviderNamespace, DbProviderFactoriesConfigurationHandler.oracleclientProviderDescription, asmQualName);
            dbFactoriesConfigSection[(int)DbProvidersIndex.SqlClient] = new DbProviderFactoryConfigSection(typeof(System.Data.SqlClient.SqlClientFactory), DbProviderFactoriesConfigurationHandler.sqlclientProviderName, DbProviderFactoriesConfigurationHandler.sqlclientProviderDescription);

            for (int i = 0; i < dbFactoriesConfigSection.Length; i++)
            {
                if (dbFactoriesConfigSection[i].IsNull() == false)
                {
                    bool flagIncludeToTable = false;

                    if (i == ((int)DbProvidersIndex.OracleClient)) // OracleClient Provider: Include only if it installed
                    {
                        Type providerType = Type.GetType(dbFactoriesConfigSection[i].AssemblyQualifiedName);
                        if (providerType != null)
                        {
                            // NOTES: Try and create a instance; If it fails, it will throw a System.NullReferenceException exception;
                            System.Reflection.FieldInfo providerInstance = providerType.GetField(Instance, System.Reflection.BindingFlags.DeclaredOnly | System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static);
                            if ((null != providerInstance) && (providerInstance.FieldType.IsSubclassOf(typeof(DbProviderFactory))))
                            {
                                Debug.Assert(providerInstance.IsPublic, "field not public");
                                Debug.Assert(providerInstance.IsStatic, "field not static");

                                object factory = providerInstance.GetValue(null);
                                if (null != factory)
                                {
                                    flagIncludeToTable = true;
                                } // Else ignore and don't add to table
                            } // Else ignore and don't add to table
                        }
                    }
                    else
                    {
                        flagIncludeToTable = true;
                    }

                    if (flagIncludeToTable == true)
                    {
                        DataRow row = dataTable.NewRow();
                        row[Name] = dbFactoriesConfigSection[i].Name;
                        row[InvariantName] = dbFactoriesConfigSection[i].InvariantName;
                        row[Description] = dbFactoriesConfigSection[i].Description;
                        row[AssemblyQualifiedName] = dbFactoriesConfigSection[i].AssemblyQualifiedName;
                        dataTable.Rows.Add(row);
                    } // Else Ignore and do not include to table;
                }
            }

            // NOTES: Additional step added here to maintain the sequence order of the providers listed.
            // The Framework Providers get listed first and is followed the custom providers.
            for (int i = 0; (configDataTable != null) && (i < configDataTable.Rows.Count); i++)
            {
                try
                {
                    bool flagIncludeToTable = false;

                    // OracleClient Provider: Include only if it installed
                    if (configDataTable.Rows[i][AssemblyQualifiedName].ToString().ToLowerInvariant().Contains(DbProviderFactoriesConfigurationHandler.oracleclientProviderNamespace.ToString().ToLowerInvariant()))
                    {
                        Type providerType = Type.GetType(configDataTable.Rows[i][AssemblyQualifiedName].ToString());
                        if (providerType != null)
                        {
                            // NOTES: Try and create a instance; If it fails, it will throw a System.NullReferenceException exception;
                            System.Reflection.FieldInfo providerInstance = providerType.GetField(Instance, System.Reflection.BindingFlags.DeclaredOnly | System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static);
                            if ((null != providerInstance) && (providerInstance.FieldType.IsSubclassOf(typeof(DbProviderFactory))))
                            {
                                Debug.Assert(providerInstance.IsPublic, "field not public");
                                Debug.Assert(providerInstance.IsStatic, "field not static");

                                object factory = providerInstance.GetValue(null);
                                if (null != factory)
                                {
                                    flagIncludeToTable = true;
                                } // Else ignore and don't add to table
                            } // Else ignore and don't add to table
                        }
                    }
                    else
                    {
                        flagIncludeToTable = true;
                    }

                    if(flagIncludeToTable == true)
                    {
                        // NOTES: If it already exist in the configTable, it raises a ConstraintException;
                        dataTable.Rows.Add(configDataTable.Rows[i].ItemArray);
                    }
                }
                catch (System.Data.ConstraintException) 
                {
                    // NOTES: Ignore item; Already exist in the configTable, hence the ConstraintException; Move to the next item;
                }
            }

            return dataTable;
        }

        static private DataTable GetProviderTable() {
            Initialize();
            return _providerTable;
        }

        static private void Initialize() {
            if (ConnectionState.Open != _initState) {
                lock (_lockobj) {
                    switch(_initState) {
                    case ConnectionState.Closed:
                        _initState = ConnectionState.Connecting; // used for preventing recursion
                        try {
                            DataSet configTable = PrivilegedConfigurationManager.GetSection(DbProviderFactoriesConfigurationHandler.sectionName) as DataSet;
                            _providerTable = (null != configTable) ? IncludeFrameworkFactoryClasses(configTable.Tables[DbProviderFactoriesConfigurationHandler.providerGroup]) : IncludeFrameworkFactoryClasses(null);
                        }
                        finally {
                            _initState = ConnectionState.Open;
                        }
                        break;
                    case ConnectionState.Connecting:
                    case ConnectionState.Open:
                        break;
                    default:
                        Debug.Assert(false, "unexpected state");
                        break;
                    }
                }
            }
        }

#if MONO
        public static bool TryGetFactory(string providerInvariantName, out DbProviderFactory factory)
        {
            factory = GetFactory(providerInvariantName, throwOnError: false);
            return factory != null;
        }

        public static IEnumerable<string> GetProviderInvariantNames()
        {
            return _registeredFactories.Keys.ToList();
        }

        public static void RegisterFactory(string providerInvariantName, string factoryTypeAssemblyQualifiedName)
        {
            ADP.CheckArgumentLength(providerInvariantName, nameof(providerInvariantName));
            ADP.CheckArgumentLength(factoryTypeAssemblyQualifiedName, nameof(factoryTypeAssemblyQualifiedName));
            
            // this method performs a deferred registration: the type name specified is checked when the factory is requested for the first time. 
            _registeredFactories[providerInvariantName] = new ProviderRegistration(factoryTypeAssemblyQualifiedName, null);
        }

        private static DbProviderFactory GetFactoryInstance(Type providerFactoryClass)
        {
            ADP.CheckArgumentNull(providerFactoryClass, nameof(providerFactoryClass));
            if (!providerFactoryClass.IsSubclassOf(typeof(DbProviderFactory)))
            {
                throw ADP.Argument(SR.Format(SR.ADP_DbProviderFactories_NotAFactoryType, providerFactoryClass.FullName));
            }

            FieldInfo providerInstance = providerFactoryClass.GetField(InstanceFieldName, BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.Static);
            if (null == providerInstance)
            {
                throw ADP.InvalidOperation(SR.ADP_DbProviderFactories_NoInstance);
            }
            if (!providerInstance.FieldType.IsSubclassOf(typeof(DbProviderFactory)))
            {
                throw ADP.InvalidOperation(SR.ADP_DbProviderFactories_NoInstance);
            }
            object factory = providerInstance.GetValue(null);
            if (null == factory)
            {
                throw ADP.InvalidOperation(SR.ADP_DbProviderFactories_NoInstance);
            }
            return (DbProviderFactory)factory;
        }

        public static void RegisterFactory(string providerInvariantName, Type providerFactoryClass)
        {
            RegisterFactory(providerInvariantName, GetFactoryInstance(providerFactoryClass));
        }

        public static void RegisterFactory(string providerInvariantName, DbProviderFactory factory)
        {
            ADP.CheckArgumentLength(providerInvariantName, nameof(providerInvariantName));
            ADP.CheckArgumentNull(factory, nameof(factory));

            _registeredFactories[providerInvariantName] = new ProviderRegistration(factory.GetType().AssemblyQualifiedName, factory);
        }
        
        public static bool UnregisterFactory(string providerInvariantName)
        {
            return !string.IsNullOrWhiteSpace(providerInvariantName) && _registeredFactories.TryRemove(providerInvariantName, out _);
        }

        private struct ProviderRegistration
        {
            internal ProviderRegistration(string factoryTypeAssemblyQualifiedName, DbProviderFactory factoryInstance)
            {
                this.FactoryTypeAssemblyQualifiedName = factoryTypeAssemblyQualifiedName;
                this.FactoryInstance = factoryInstance;
            }

            internal string FactoryTypeAssemblyQualifiedName { get; }
            /// <summary>
            /// The cached instance of the type in <see cref="FactoryTypeAssemblyQualifiedName"/>. If null, this registation is seen as a deferred registration
            /// and <see cref="FactoryTypeAssemblyQualifiedName"/> is checked the first time when this registration is requested through GetFactory().
            /// </summary>
            internal DbProviderFactory FactoryInstance { get; }
        }
#endif
    }
}