Bump corefx
[mono.git] / mcs / class / referencesource / System.Data / System / Data / Sql / SqlDataSourceEnumerator.cs
1 //------------------------------------------------------------------------------
2 // <copyright file="SqlDataSourceEnumerator.cs" company="Microsoft">
3 //     Copyright (c) Microsoft Corporation.  All rights reserved.
4 // </copyright>
5 // <owner current="true" primary="true">Microsoft</owner>
6 // <owner current="true" primary="false">Microsoft</owner>
7 //------------------------------------------------------------------------------
8
9 namespace System.Data.Sql {
10
11     using System;
12     using System.Data;
13     using System.Data.Common;
14     using System.Data.SqlClient;
15     using System.Diagnostics;
16     using System.Globalization;
17     using System.Runtime.CompilerServices;
18     using System.Runtime.InteropServices;
19     using System.Security;
20     using System.Text;
21
22     public sealed class SqlDataSourceEnumerator : DbDataSourceEnumerator {
23
24         private static readonly SqlDataSourceEnumerator SingletonInstance = new SqlDataSourceEnumerator();
25         internal const string ServerName     = "ServerName";
26         internal const string InstanceName   = "InstanceName";
27         internal const string IsClustered    = "IsClustered";
28         internal const string Version        = "Version";
29 #if !MONO
30         private  const int    timeoutSeconds = ADP.DefaultCommandTimeout;
31 #endif
32         private long timeoutTime;                                // variable used for timeout computations, holds the value of the hi-res performance counter at which this request should expire
33
34         private SqlDataSourceEnumerator() : base() {
35         }
36
37         public static SqlDataSourceEnumerator Instance {
38             get { 
39                 return SqlDataSourceEnumerator.SingletonInstance;
40             }
41         }
42
43         override public DataTable GetDataSources() {
44 #if MONO
45             timeoutTime = 0;
46             throw new NotImplementedException ();
47 #else
48             (new NamedPermissionSet("FullTrust")).Demand(); // SQLBUDT 244304
49             char[] buffer = null;
50             StringBuilder strbldr = new StringBuilder();
51
52             Int32  bufferSize = 1024;
53             Int32  readLength = 0;
54             buffer            = new char[bufferSize];
55                         bool   more       = true;
56             bool   failure    = false;
57             IntPtr handle     = ADP.PtrZero;
58
59                         RuntimeHelpers.PrepareConstrainedRegions();
60             try {
61                 timeoutTime = TdsParserStaticMethods.GetTimeoutSeconds(timeoutSeconds);
62                 RuntimeHelpers.PrepareConstrainedRegions();
63                 try {} finally {
64                     handle = SNINativeMethodWrapper.SNIServerEnumOpen();
65                 }
66
67                 if (ADP.PtrZero != handle) {
68                     while (more && !TdsParserStaticMethods.TimeoutHasExpired(timeoutTime)) {
69                                     readLength = SNINativeMethodWrapper.SNIServerEnumRead(handle, buffer, bufferSize, ref more);
70                         if (readLength > bufferSize) {
71                             failure = true;
72                             more = false;
73                         }
74                         else if (0 < readLength) {
75                                                         strbldr.Append(buffer, 0, readLength);
76                                                 }    
77                     }
78                 }
79             }
80             finally {
81                 if (ADP.PtrZero != handle) {
82                     SNINativeMethodWrapper.SNIServerEnumClose(handle);
83                 }
84             }
85
86             if (failure) {
87                 Debug.Assert(false, "GetDataSources:SNIServerEnumRead returned bad length");
88                 Bid.Trace("<sc.SqlDataSourceEnumerator.GetDataSources|ERR> GetDataSources:SNIServerEnumRead returned bad length, requested %d, received %d", bufferSize, readLength);
89                 throw ADP.ArgumentOutOfRange("readLength");
90             }
91
92             return ParseServerEnumString(strbldr.ToString());
93 #endif
94         }
95         
96         private static string _Version = "Version:";
97         private static string _Cluster = "Clustered:";
98         private static int _clusterLength = _Cluster.Length;
99         private static int _versionLength =_Version.Length;
100
101         static private DataTable ParseServerEnumString(string serverInstances) {
102             DataTable dataTable = new DataTable("SqlDataSources");
103             dataTable.Locale = CultureInfo.InvariantCulture;
104             dataTable.Columns.Add(ServerName, typeof(string));
105             dataTable.Columns.Add(InstanceName, typeof(string));
106             dataTable.Columns.Add(IsClustered, typeof(string));
107             dataTable.Columns.Add(Version, typeof(string));
108             DataRow dataRow = null;
109             string serverName = null;
110             string instanceName = null;
111             string isClustered = null;
112             string version = null;
113             
114             // Every row comes in the format "serverName\instanceName;Clustered:[Yes|No];Version:.." 
115             // Every row is terminated by a null character.
116             // Process one row at a time
117             foreach (string instance in serverInstances.Split('\0')) {
118                 string value = instance.Trim('\0'); // MDAC 91934
119                 if (0 == value.Length) {
120                     continue;
121                 }
122                                 foreach (string instance2 in value.Split(';')) {                                        
123                                         if (serverName == null) {
124                         foreach(string instance3 in instance2.Split('\\')) {                                                    
125                                                         if (serverName == null) {
126                                 serverName = instance3;
127                                 continue;
128                             }
129                             Debug.Assert(instanceName == null);
130                             instanceName = instance3;
131                         }
132                         continue;
133                     }
134                     if (isClustered == null) {
135                         Debug.Assert(String.Compare(_Cluster, 0, instance2, 0, _clusterLength, StringComparison.OrdinalIgnoreCase) == 0);
136                         isClustered = instance2.Substring(_clusterLength);
137                         continue;
138                     }
139                     Debug.Assert(version == null);
140                     Debug.Assert(String.Compare(_Version, 0, instance2, 0, _versionLength, StringComparison.OrdinalIgnoreCase) == 0);
141                     version =  instance2.Substring(_versionLength);
142                 }
143
144                 string query = "ServerName='"+serverName+"'";
145
146                 if (!ADP.IsEmpty(instanceName)) { // SQL BU DT 20006584: only append instanceName if present.
147                     query += " AND InstanceName='"+instanceName+"'";
148                 }
149
150                 // SNI returns dupes - do not add them.  SQL BU DT 290323
151                 if (dataTable.Select(query).Length == 0) {
152                     dataRow = dataTable.NewRow();
153                     dataRow[0] = serverName;
154                     dataRow[1] = instanceName;
155                     dataRow[2] = isClustered;
156                     dataRow[3] = version;
157                     dataTable.Rows.Add(dataRow);
158                 }
159                 serverName = null;
160                 instanceName = null;
161                 isClustered = null;
162                 version = null;
163             }
164             foreach(DataColumn column in dataTable.Columns) {
165                 column.ReadOnly = true;
166             }
167             return dataTable;
168         }
169     }
170 }