File: oledbconnectionstring.cs

package info (click to toggle)
mono 6.12.0.199%2Bdfsg-6
  • links: PTS, VCS
  • area: main
  • in suites: 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 (424 lines) | stat: -rw-r--r-- 19,699 bytes parent folder | download | duplicates (2)
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
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
//------------------------------------------------------------------------------
// <copyright file="oledbconnectionstring.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.OleDb {

    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.Collections.Specialized;
    using System.Data;
    using System.Data.Common;
    using System.Diagnostics;
    using System.Globalization;
    using System.IO;
    using System.Security;
    using System.Security.Permissions;
    using System.Text;
    using Microsoft.Win32;
    using System.Runtime.Versioning;

    internal struct SchemaSupport {
        internal Guid _schemaRowset;
        internal int  _restrictions;
    }

    internal sealed class OleDbConnectionString : DbConnectionOptions {
        // instances of this class are intended to be immutable, i.e readonly
        // used by pooling classes so it is much easier to verify correctness
        // when not worried about the class being modified during execution

        internal static class KEY {
            internal const string Asynchronous_Processing = "asynchronous processing";
            internal const string Connect_Timeout         = "connect timeout";
            internal const string Data_Provider           = "data provider";
            internal const string Data_Source             = "data source";
            internal const string Extended_Properties     = "extended properties";
            internal const string File_Name               = "file name";
            internal const string Initial_Catalog         = "initial catalog";
            internal const string Ole_DB_Services         = "ole db services";
            internal const string Persist_Security_Info   = "persist security info";
            internal const string Prompt                  = "prompt";
            internal const string Provider                = "provider";
            internal const string RemoteProvider          = "remote provider";
            internal const string WindowHandle            = "window handle";
        }

        // registry key and dword value entry for udl pooling
        private static class UDL {
            internal const string Header   = "\xfeff[oledb]\r\n; Everything after this line is an OLE DB initstring\r\n";
            internal const string Location = "SOFTWARE\\Microsoft\\DataAccess\\Udl Pooling";
            internal const string Pooling  = "Cache Size";

            static internal volatile bool      _PoolSizeInit;
            static internal int                _PoolSize;

            static internal volatile Dictionary<string,string> _Pool;
            static internal object             _PoolLock = new object();
        }

        private static class VALUES {
            internal const string NoPrompt = "noprompt";
        }

        // set during ctor
        internal readonly bool PossiblePrompt;
        internal readonly string ActualConnectionString; // cached value passed to GetDataSource

        private readonly string _expandedConnectionString;

        internal SchemaSupport[] _schemaSupport;

        internal int _sqlSupport;
        internal bool _supportMultipleResults;
        internal bool _supportIRow;
        internal bool _hasSqlSupport;
        internal bool _hasSupportMultipleResults, _hasSupportIRow;

        private int _oledbServices;

        // these are cached delegates (per unique connectionstring)
        internal UnsafeNativeMethods.IUnknownQueryInterface        DangerousDataSourceIUnknownQueryInterface;
        internal UnsafeNativeMethods.IDBInitializeInitialize       DangerousIDBInitializeInitialize;
        internal UnsafeNativeMethods.IDBCreateSessionCreateSession DangerousIDBCreateSessionCreateSession;
        internal UnsafeNativeMethods.IDBCreateCommandCreateCommand DangerousIDBCreateCommandCreateCommand;

        // since IDBCreateCommand interface may not be supported for a particular provider (only IOpenRowset)
        // we cache that fact rather than call QueryInterface on every call to Open
        internal bool HaveQueriedForCreateCommand;

        // SxS: if user specifies a value for "File Name=" (UDL) in connection string, OleDbConnectionString will load the connection string
        // from the UDL file. The UDL file is opened as FileMode.Open, FileAccess.Read, FileShare.Read, allowing concurrent access to it.
        [ResourceExposure(ResourceScope.None)]
        [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
        internal OleDbConnectionString(string connectionString, bool validate) : base(connectionString) {
            string prompt = this[KEY.Prompt];
            PossiblePrompt = ((!ADP.IsEmpty(prompt) && (0 != String.Compare(prompt, VALUES.NoPrompt, StringComparison.OrdinalIgnoreCase)))
                              || !ADP.IsEmpty(this[KEY.WindowHandle]));

            if (!IsEmpty) {
                string udlConnectionString = null;
                if (!validate) {
                    int position = 0;
                    string udlFileName = null;
                    _expandedConnectionString = ExpandDataDirectories(ref udlFileName, ref position);

                    if (!ADP.IsEmpty(udlFileName)) { // fail via new FileStream vs. GetFullPath
                        udlFileName = ADP.GetFullPath(udlFileName); // MDAC 82833
                    }
                    if (null != udlFileName) {
                        udlConnectionString = LoadStringFromStorage(udlFileName);

                        if (!ADP.IsEmpty(udlConnectionString)) {
                            _expandedConnectionString = _expandedConnectionString.Substring(0, position) + udlConnectionString + ';' + _expandedConnectionString.Substring(position);
                        }
                    }
                }
                if (validate || ADP.IsEmpty(udlConnectionString)) {
                    ActualConnectionString = ValidateConnectionString(connectionString);
                }
            }
        }

        internal int ConnectTimeout {
            get { return base.ConvertValueToInt32(KEY.Connect_Timeout, ADP.DefaultConnectionTimeout); }
        }

        internal string DataSource {
            get { return base.ConvertValueToString(KEY.Data_Source, ADP.StrEmpty); }
        }

        internal string InitialCatalog {
            get { return base.ConvertValueToString(KEY.Initial_Catalog, ADP.StrEmpty); }
        }

        internal string Provider {
            get {
                Debug.Assert(!ADP.IsEmpty(this[KEY.Provider]), "no Provider");
                return this[KEY.Provider];
            }
        }

        internal int OleDbServices {
            get {
                return _oledbServices;
            }
        }

        internal SchemaSupport[] SchemaSupport { // OleDbConnection.GetSchemaRowsetInformation
            get { return _schemaSupport; }
            set { _schemaSupport = value; }
        }

        protected internal override System.Security.PermissionSet CreatePermissionSet() {
            System.Security.PermissionSet permissionSet;
            if (PossiblePrompt) {
                permissionSet = new NamedPermissionSet("FullTrust");
            }
            else {
                permissionSet = new System.Security.PermissionSet(System.Security.Permissions.PermissionState.None);
                permissionSet.AddPermission(new OleDbPermission(this));
            }
            return permissionSet;
        }

        protected internal override string Expand() {
            if (null != _expandedConnectionString) {
                return _expandedConnectionString;
            }
            else {
                return base.Expand();
            }
        }

        internal int GetSqlSupport(OleDbConnection connection) {
            int sqlSupport = _sqlSupport;
            if (!_hasSqlSupport) {
                object value = connection.GetDataSourcePropertyValue(OleDbPropertySetGuid.DataSourceInfo, ODB.DBPROP_SQLSUPPORT);
                if (value is Int32) { // not OleDbPropertyStatus
                    sqlSupport = (int) value;
                }
                _sqlSupport = sqlSupport;
                _hasSqlSupport = true;
            }
            return sqlSupport;
        }

        internal bool GetSupportIRow(OleDbConnection connection, OleDbCommand command) {
            bool supportIRow = _supportIRow;
            if (!_hasSupportIRow) {
                object value = command.GetPropertyValue(OleDbPropertySetGuid.Rowset, ODB.DBPROP_IRow);

                // SQLOLEDB always returns VARIANT_FALSE for DBPROP_IROW, so base the answer on existence
                supportIRow = !(value is OleDbPropertyStatus);
                _supportIRow = supportIRow;
                _hasSupportIRow = true;
            }
            return supportIRow;
        }

        internal bool GetSupportMultipleResults(OleDbConnection connection) {
            bool supportMultipleResults = _supportMultipleResults;
            if (!_hasSupportMultipleResults) {
                object value = connection.GetDataSourcePropertyValue(OleDbPropertySetGuid.DataSourceInfo, ODB.DBPROP_MULTIPLERESULTS);
                if (value is Int32) {// not OleDbPropertyStatus
                    supportMultipleResults = (ODB.DBPROPVAL_MR_NOTSUPPORTED != (int) value);
                }
                _supportMultipleResults = supportMultipleResults;
                _hasSupportMultipleResults = true;
            }
            return supportMultipleResults;
        }

        static private int UdlPoolSize { // MDAC 69925
            // SxS: UdpPoolSize reads registry value to get the pool size
            [ResourceExposure(ResourceScope.None)]
            [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
            get {
                int poolsize = UDL._PoolSize;
                if (!UDL._PoolSizeInit) {
                    object value = ADP.LocalMachineRegistryValue(UDL.Location, UDL.Pooling);
                    if (value is Int32) {
                        poolsize = (int) value;
                        poolsize = ((0 < poolsize) ? poolsize : 0);
                        UDL._PoolSize = poolsize;
                    }
                    UDL._PoolSizeInit = true;
                }
                return poolsize;
            }
        }

        [ResourceExposure(ResourceScope.Machine)]
        [ResourceConsumption(ResourceScope.Machine)]
        static private string LoadStringFromStorage(string udlfilename) {
            string udlConnectionString = null;
            Dictionary<string,string> udlcache = UDL._Pool;

            if ((null == udlcache) || !udlcache.TryGetValue(udlfilename, out udlConnectionString)) {
                udlConnectionString = LoadStringFromFileStorage(udlfilename);
                if (null != udlConnectionString) {
                    Debug.Assert(!ADP.IsEmpty(udlfilename), "empty filename didn't fail");

                    if (0 < UdlPoolSize) {
                        Debug.Assert(udlfilename == ADP.GetFullPath(udlfilename), "only cache full path filenames"); // MDAC 82833

                        if (null == udlcache) {
                            udlcache = new Dictionary<string,string>();
                            udlcache[udlfilename] = udlConnectionString;

                            lock(UDL._PoolLock) {
                                if (null != UDL._Pool) {
                                    udlcache = UDL._Pool;
                                }
                                else {
                                    UDL._Pool = udlcache;
                                    udlcache = null;
                                }
                            }
                        }
                        if (null != udlcache) {
                            lock(udlcache) {
                                udlcache[udlfilename] = udlConnectionString;
                            }
                        }
                    }
                }
            }
            return udlConnectionString;
        }

        [ResourceExposure(ResourceScope.Machine)]
        [ResourceConsumption(ResourceScope.Machine)]
        static private string LoadStringFromFileStorage(string udlfilename) {
            // Microsoft Data Link File Format
            // The first two lines of a .udl file must have exactly the following contents in order to work properly:
            //  [oledb]
            //  ; Everything after this line is an OLE DB initstring
            //
            string connectionString = null;
            Exception failure = null;
            try {
                int hdrlength = ADP.CharSize*UDL.Header.Length;
                using(FileStream fstream = new FileStream(udlfilename, FileMode.Open, FileAccess.Read, FileShare.Read)) {
                    long length = fstream.Length;
                    if (length < hdrlength || (0 != length%ADP.CharSize)) {
                        failure = ADP.InvalidUDL();
                    }
                    else {
                        byte[] bytes = new Byte[hdrlength];
                        int count = fstream.Read(bytes, 0, bytes.Length);
                        if (count < hdrlength) {
                            failure = ADP.InvalidUDL();
                        }
                        else if (System.Text.Encoding.Unicode.GetString(bytes, 0, hdrlength) != UDL.Header) {
                            failure = ADP.InvalidUDL();
                        }
                        else { // please verify header before allocating memory block for connection string
                            bytes = new Byte[length - hdrlength];
                            count = fstream.Read(bytes, 0, bytes.Length);
                            connectionString = System.Text.Encoding.Unicode.GetString(bytes, 0, count);
                        }
                    }
                }
            }
            catch(Exception e) {
                // 
                if (!ADP.IsCatchableExceptionType(e)) {
                    throw;
                }

                throw ADP.UdlFileError(e);
            }
            if (null != failure) {
                throw failure;
            }
            return connectionString.Trim();
        }

        [ResourceExposure(ResourceScope.None)] // reads OleDbServices value for the provider
        [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
        private string ValidateConnectionString(string connectionString) {
            if (ConvertValueToBoolean(KEY.Asynchronous_Processing, false)) {
                throw ODB.AsynchronousNotSupported();
            }

            int connectTimeout = ConvertValueToInt32(KEY.Connect_Timeout, 0);
            if (connectTimeout < 0) {
                throw ADP.InvalidConnectTimeoutValue();
            }

            string progid = ConvertValueToString(KEY.Data_Provider, null); // MDAC 71923
            if (null != progid) {
                progid = progid.Trim();
                if (0 < progid.Length) { // don't fail on empty 'Data Provider' value
                    ValidateProvider(progid);
                }
            }
            progid = ConvertValueToString(KEY.RemoteProvider, null); // MDAC 71923
            if (null != progid) {
                progid = progid.Trim();
                if (0 < progid.Length) { // don't fail on empty 'Data Provider' value
                    ValidateProvider(progid);
                }
            }
            progid = ConvertValueToString(KEY.Provider, ADP.StrEmpty).Trim();
            ValidateProvider(progid); // will fail on empty 'Provider' value

            // SQLBU VSTS 59322: initialize to default
            // If the value is not provided in connection string and OleDbServices registry key has not been set by the provider,
            // the default for the provider is -1 (all services are ON).
            // our default is -13, we turn off ODB.DBPROPVAL_OS_AGR_AFTERSESSION and ODB.DBPROPVAL_OS_CLIENTCURSOR flags
            _oledbServices = DbConnectionStringDefaults.OleDbServices;

            bool hasOleDBServices = (base.ContainsKey(KEY.Ole_DB_Services) && !ADP.IsEmpty((string)base[KEY.Ole_DB_Services]));
            if (!hasOleDBServices) { // don't touch registry if they have OLE DB Services
                string classid = (string) ADP.ClassesRootRegistryValue(progid + "\\CLSID", String.Empty);
                if ((null != classid) && (0 < classid.Length)) {
                    // CLSID detection of 'Microsoft OLE DB Provider for ODBC Drivers'
                    Guid classidProvider = new Guid(classid);
                    if (ODB.CLSID_MSDASQL == classidProvider) {
                        throw ODB.MSDASQLNotSupported();
                    }
                    object tmp = ADP.ClassesRootRegistryValue("CLSID\\{" + classidProvider.ToString("D", CultureInfo.InvariantCulture) + "}", ODB.OLEDB_SERVICES);
                    if (null != tmp) {

                        // @devnote: some providers like MSDataShape don't have the OLEDB_SERVICES value
                        // the MSDataShape provider doesn't support the 'Ole Db Services' keyword
                        // hence, if the value doesn't exist - don't prepend to string
                        try {
                            _oledbServices = (int)tmp;
                        }
                        catch(InvalidCastException e) {
                            ADP.TraceExceptionWithoutRethrow(e);
                        }
                        _oledbServices &= ~(ODB.DBPROPVAL_OS_AGR_AFTERSESSION | ODB.DBPROPVAL_OS_CLIENTCURSOR); // NT 347436, MDAC 58606

                        StringBuilder builder = new StringBuilder();
                        builder.Append(KEY.Ole_DB_Services);
                        builder.Append("=");
                        builder.Append(_oledbServices.ToString(CultureInfo.InvariantCulture));
                        builder.Append(";");
                        builder.Append(connectionString);
                        connectionString = builder.ToString();
                    }
                }
            }
            else {
                // SQLBU VSTS 59322: parse the Ole Db Services value from connection string
                _oledbServices = ConvertValueToInt32(KEY.Ole_DB_Services, DbConnectionStringDefaults.OleDbServices);
            }

            return connectionString;
        }

        internal static bool IsMSDASQL(string progid) {
            return (("msdasql" == progid) || progid.StartsWith("msdasql.", StringComparison.Ordinal) || ("microsoft ole db provider for odbc drivers" == progid));
        }

        static private void ValidateProvider(string progid) {
            if (ADP.IsEmpty(progid)) {
                throw ODB.NoProviderSpecified();
            }
            if (ODB.MaxProgIdLength <= progid.Length) { // MDAC 63151
                throw ODB.InvalidProviderSpecified();
            }
            progid = progid.ToLower(CultureInfo.InvariantCulture);
            if (IsMSDASQL(progid)) {
                // fail msdasql even if not on the machine.
                throw ODB.MSDASQLNotSupported();
            }
        }
        
        static internal void ReleaseObjectPool() {
            UDL._PoolSizeInit = false;
            UDL._Pool = null;
        }
    }
}