| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424 |
- //------------------------------------------------------------------------------
- // <copyright file="oledbconnectionstring.cs" company="Microsoft">
- // Copyright (c) Microsoft Corporation. All rights reserved.
- // </copyright>
- // <owner current="true" primary="true">[....]</owner>
- // <owner current="true" primary="false">[....]</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 existance
- 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;
- }
- }
- }
|