1 //------------------------------------------------------------------------------
2 // <copyright file="SqlDataSourceEnumerator.cs" company="Microsoft">
3 // Copyright (c) Microsoft Corporation. All rights reserved.
5 // <owner current="true" primary="true">Microsoft</owner>
6 // <owner current="true" primary="false">Microsoft</owner>
7 //------------------------------------------------------------------------------
9 namespace System.Data.Sql {
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;
22 public sealed class SqlDataSourceEnumerator : DbDataSourceEnumerator {
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";
30 private const int timeoutSeconds = ADP.DefaultCommandTimeout;
32 private long timeoutTime; // variable used for timeout computations, holds the value of the hi-res performance counter at which this request should expire
34 private SqlDataSourceEnumerator() : base() {
37 public static SqlDataSourceEnumerator Instance {
39 return SqlDataSourceEnumerator.SingletonInstance;
43 override public DataTable GetDataSources() {
46 throw new NotImplementedException ();
48 (new NamedPermissionSet("FullTrust")).Demand(); // SQLBUDT 244304
50 StringBuilder strbldr = new StringBuilder();
52 Int32 bufferSize = 1024;
54 buffer = new char[bufferSize];
57 IntPtr handle = ADP.PtrZero;
59 RuntimeHelpers.PrepareConstrainedRegions();
61 timeoutTime = TdsParserStaticMethods.GetTimeoutSeconds(timeoutSeconds);
62 RuntimeHelpers.PrepareConstrainedRegions();
64 handle = SNINativeMethodWrapper.SNIServerEnumOpen();
67 if (ADP.PtrZero != handle) {
68 while (more && !TdsParserStaticMethods.TimeoutHasExpired(timeoutTime)) {
69 readLength = SNINativeMethodWrapper.SNIServerEnumRead(handle, buffer, bufferSize, ref more);
70 if (readLength > bufferSize) {
74 else if (0 < readLength) {
75 strbldr.Append(buffer, 0, readLength);
81 if (ADP.PtrZero != handle) {
82 SNINativeMethodWrapper.SNIServerEnumClose(handle);
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");
92 return ParseServerEnumString(strbldr.ToString());
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;
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;
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) {
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;
129 Debug.Assert(instanceName == null);
130 instanceName = instance3;
134 if (isClustered == null) {
135 Debug.Assert(String.Compare(_Cluster, 0, instance2, 0, _clusterLength, StringComparison.OrdinalIgnoreCase) == 0);
136 isClustered = instance2.Substring(_clusterLength);
139 Debug.Assert(version == null);
140 Debug.Assert(String.Compare(_Version, 0, instance2, 0, _versionLength, StringComparison.OrdinalIgnoreCase) == 0);
141 version = instance2.Substring(_versionLength);
144 string query = "ServerName='"+serverName+"'";
146 if (!ADP.IsEmpty(instanceName)) { // SQL BU DT 20006584: only append instanceName if present.
147 query += " AND InstanceName='"+instanceName+"'";
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);
164 foreach(DataColumn column in dataTable.Columns) {
165 column.ReadOnly = true;