1 //------------------------------------------------------------------------------
2 // <copyright file="SqlMetaDataFactory.cs" company="Microsoft">
3 //     Copyright (c) Microsoft Corporation.  All rights reserved.
4 // </copyright>
5 //
6 // <owner current="true" primary="true">Microsoft</owner>
7 // <owner current="true" primary="false">Mugunm</owner>
8 //
9 //------------------------------------------------------------------------------
10 
11 namespace System.Data.SqlClient{
12 
13     using System;
14     using System.Data;
15     using System.IO;
16     using System.Collections;
17     using System.Data.ProviderBase;
18     using System.Data.Common;
19     using System.Data.SqlClient;
20     using System.Diagnostics;
21     using System.Globalization;
22     using System.Text;
23     using System.Xml;
24     using System.Xml.Schema;
25 
26 
27     internal sealed class SqlMetaDataFactory : DbMetaDataFactory{ // V1.2.3300
28 
29         private const string _serverVersionNormalized90 = "09.00.0000";
30         private const string _serverVersionNormalized90782 = "09.00.0782";
31         private const string _serverVersionNormalized10 = "10.00.0000";
32 
33 
SqlMetaDataFactory(Stream XMLStream, string serverVersion, string serverVersionNormalized)34         public SqlMetaDataFactory(Stream XMLStream,
35                                     string serverVersion,
36                                     string serverVersionNormalized):
37                 base(XMLStream, serverVersion, serverVersionNormalized) {
38 
39 
40         }
41 
addUDTsToDataTypesTable(DataTable dataTypesTable, SqlConnection connection , String ServerVersion)42         private void addUDTsToDataTypesTable(DataTable dataTypesTable, SqlConnection connection , String  ServerVersion) {
43 
44             const string sqlCommand =
45                 "select " +
46                     "assemblies.name, " +
47                     "types.assembly_class, " +
48                     "ASSEMBLYPROPERTY(assemblies.name, 'VersionMajor') as version_major, " +
49                     "ASSEMBLYPROPERTY(assemblies.name, 'VersionMinor') as version_minor, " +
50                     "ASSEMBLYPROPERTY(assemblies.name, 'VersionBuild') as version_build, " +
51                     "ASSEMBLYPROPERTY(assemblies.name, 'VersionRevision') as version_revision, " +
52                     "ASSEMBLYPROPERTY(assemblies.name, 'CultureInfo') as culture_info, " +
53                     "ASSEMBLYPROPERTY(assemblies.name, 'PublicKey') as public_key, " +
54                     "is_nullable, " +
55                     "is_fixed_length, " +
56                     "max_length " +
57                 "from sys.assemblies as assemblies  join sys.assembly_types as types " +
58                 "on assemblies.assembly_id = types.assembly_id ";
59 
60             // pre 9.0/Yukon servers do not have UDTs
61             if (0 > string.Compare(ServerVersion,  _serverVersionNormalized90, StringComparison.OrdinalIgnoreCase)){
62                 return;
63             }
64 
65 
66             // Execute the SELECT statement
67             SqlCommand command = connection.CreateCommand();
68             command.CommandText = sqlCommand;
69             DataRow newRow = null;
70             DataColumn providerDbtype = dataTypesTable.Columns[DbMetaDataColumnNames.ProviderDbType];
71             DataColumn columnSize = dataTypesTable.Columns[DbMetaDataColumnNames.ColumnSize];
72             DataColumn isFixedLength = dataTypesTable.Columns[DbMetaDataColumnNames.IsFixedLength];
73             DataColumn isSearchable = dataTypesTable.Columns[DbMetaDataColumnNames.IsSearchable];
74             DataColumn isLiteralSupported = dataTypesTable.Columns[DbMetaDataColumnNames.IsLiteralSupported];
75             DataColumn typeName = dataTypesTable.Columns[DbMetaDataColumnNames.TypeName];
76             DataColumn isNullable = dataTypesTable.Columns[DbMetaDataColumnNames.IsNullable];
77 
78             if ((providerDbtype == null) ||
79                 (columnSize == null) ||
80                 (isFixedLength == null) ||
81                 (isSearchable == null) ||
82                 (isLiteralSupported == null) ||
83                 (typeName == null) ||
84                 (isNullable == null)) {
85                 throw ADP.InvalidXml();
86             }
87 
88             const int columnSizeIndex = 10;
89             const int isFixedLengthIndex = 9;
90             const int isNullableIndex = 8;
91             const int assemblyNameIndex = 0;
92             const int assemblyClassIndex = 1;
93             const int versionMajorIndex = 2;
94             const int versionMinorIndex = 3;
95             const int versionBuildIndex = 4;
96             const int versionRevisionIndex = 5;
97             const int cultureInfoIndex = 6;
98             const int publicKeyIndex = 7;
99 
100 
101             using (IDataReader reader = command.ExecuteReader()) {
102 
103                 object[] values = new object[11];
104                 while (reader.Read()) {
105 
106                     reader.GetValues(values);
107                     newRow = dataTypesTable.NewRow();
108 
109                     newRow[providerDbtype] = SqlDbType.Udt;
110 
111                     if (values[columnSizeIndex] != DBNull.Value) {
112                         newRow[columnSize] = values[columnSizeIndex];
113                     }
114 
115                     if (values[isFixedLengthIndex] != DBNull.Value) {
116                         newRow[isFixedLength] = values[isFixedLengthIndex];
117                     }
118 
119                     newRow[isSearchable] = true;
120                     newRow[isLiteralSupported] = false;
121                     if (values[isNullableIndex] != DBNull.Value) {
122                         newRow[isNullable] = values[isNullableIndex];
123                     }
124 
125                     if ((values[assemblyNameIndex] != DBNull.Value) &&
126                         (values[assemblyClassIndex] != DBNull.Value) &&
127                         (values[versionMajorIndex] != DBNull.Value) &&
128                         (values[versionMinorIndex] != DBNull.Value) &&
129                         (values[versionBuildIndex] != DBNull.Value) &&
130                         (values[versionRevisionIndex] != DBNull.Value)) {
131 
132                         StringBuilder nameString = new StringBuilder();
133                         nameString.Append(values[assemblyClassIndex].ToString());
134                         nameString.Append(", ");
135                         nameString.Append(values[assemblyNameIndex].ToString());
136                         nameString.Append(", Version=");
137 
138                         nameString.Append(values[versionMajorIndex].ToString());
139                         nameString.Append(".");
140                         nameString.Append(values[versionMinorIndex].ToString());
141                         nameString.Append(".");
142                         nameString.Append(values[versionBuildIndex].ToString());
143                         nameString.Append(".");
144                         nameString.Append(values[versionRevisionIndex].ToString());
145 
146                         if (values[cultureInfoIndex] != DBNull.Value) {
147                             nameString.Append(", Culture=");
148                             nameString.Append(values[cultureInfoIndex].ToString());
149                         }
150 
151                         if (values[publicKeyIndex] != DBNull.Value) {
152 
153                             nameString.Append(", PublicKeyToken=");
154 
155                             StringBuilder resultString = new StringBuilder();
156                             Byte[] byteArrayValue = (Byte[])values[publicKeyIndex];
157                             foreach (byte b in byteArrayValue) {
158                                 resultString.Append(String.Format((IFormatProvider)null, "{0,-2:x2}", b));
159                             }
160                             nameString.Append(resultString.ToString());
161                         }
162 
163                         newRow[typeName] = nameString.ToString();
164                         dataTypesTable.Rows.Add(newRow);
165                         newRow.AcceptChanges();
166                     } // if assembly name
167 
168                 }//end while
169             } // end using
170         }
171 
AddTVPsToDataTypesTable(DataTable dataTypesTable, SqlConnection connection , String ServerVersion)172         private void AddTVPsToDataTypesTable(DataTable dataTypesTable, SqlConnection connection , String  ServerVersion) {
173 
174             const string sqlCommand =
175                 "select " +
176                     "name, " +
177                     "is_nullable, " +
178                     "max_length " +
179                 "from sys.types " +
180                 "where is_table_type = 1";
181 
182             //
183 
184             if (0 > string.Compare(ServerVersion,  _serverVersionNormalized10, StringComparison.OrdinalIgnoreCase)){
185                 return;
186             }
187 
188 
189             // Execute the SELECT statement
190             SqlCommand command = connection.CreateCommand();
191             command.CommandText = sqlCommand;
192             DataRow newRow = null;
193             DataColumn providerDbtype = dataTypesTable.Columns[DbMetaDataColumnNames.ProviderDbType];
194             DataColumn columnSize = dataTypesTable.Columns[DbMetaDataColumnNames.ColumnSize];
195             DataColumn isSearchable = dataTypesTable.Columns[DbMetaDataColumnNames.IsSearchable];
196             DataColumn isLiteralSupported = dataTypesTable.Columns[DbMetaDataColumnNames.IsLiteralSupported];
197             DataColumn typeName = dataTypesTable.Columns[DbMetaDataColumnNames.TypeName];
198             DataColumn isNullable = dataTypesTable.Columns[DbMetaDataColumnNames.IsNullable];
199 
200             if ((providerDbtype == null) ||
201                 (columnSize == null) ||
202                 (isSearchable == null) ||
203                 (isLiteralSupported == null) ||
204                 (typeName == null) ||
205                 (isNullable == null)) {
206                 throw ADP.InvalidXml();
207             }
208 
209             const int columnSizeIndex = 2;
210             const int isNullableIndex = 1;
211             const int typeNameIndex = 0;
212 
213             using (IDataReader reader = command.ExecuteReader()) {
214 
215                 object[] values = new object[11];
216                 while (reader.Read()) {
217 
218                     reader.GetValues(values);
219                     newRow = dataTypesTable.NewRow();
220 
221                     newRow[providerDbtype] = SqlDbType.Structured;
222 
223                     if (values[columnSizeIndex] != DBNull.Value) {
224                         newRow[columnSize] = values[columnSizeIndex];
225                     }
226 
227                     newRow[isSearchable] = false;
228                     newRow[isLiteralSupported] = false;
229                     if (values[isNullableIndex] != DBNull.Value) {
230                         newRow[isNullable] = values[isNullableIndex];
231                     }
232 
233                     if (values[typeNameIndex] != DBNull.Value) {
234                         newRow[typeName] = values[typeNameIndex];
235                         dataTypesTable.Rows.Add(newRow);
236                         newRow.AcceptChanges();
237                     } // if type name
238                 }//end while
239             } // end using
240         }
241 
GetDataTypesTable(SqlConnection connection)242         private DataTable GetDataTypesTable(SqlConnection connection){
243 
244 
245             // verify the existance of the table in the data set
246             DataTable dataTypesTable = CollectionDataSet.Tables[DbMetaDataCollectionNames.DataTypes];
247             if (dataTypesTable == null){
248                 throw ADP.UnableToBuildCollection(DbMetaDataCollectionNames.DataTypes);
249             }
250 
251              // copy the table filtering out any rows that don't apply to tho current version of the prrovider
252             dataTypesTable = CloneAndFilterCollection(DbMetaDataCollectionNames.DataTypes, null);
253 
254             addUDTsToDataTypesTable(dataTypesTable, connection, ServerVersionNormalized);
255             AddTVPsToDataTypesTable(dataTypesTable, connection, ServerVersionNormalized);
256 
257             dataTypesTable.AcceptChanges();
258             return  dataTypesTable;
259 
260         }
261 
PrepareCollection(String collectionName, String[] restrictions, DbConnection connection)262         protected override DataTable PrepareCollection(String collectionName, String[] restrictions, DbConnection connection){
263 
264             SqlConnection sqlConnection = (SqlConnection) connection;
265             DataTable resultTable = null;
266 
267             if (collectionName == DbMetaDataCollectionNames.DataTypes){
268                 if (ADP.IsEmptyArray(restrictions) == false) {
269                     throw ADP.TooManyRestrictions(DbMetaDataCollectionNames.DataTypes);
270                 }
271                 resultTable = GetDataTypesTable(sqlConnection);
272             }
273 
274             if (resultTable == null){
275                throw ADP.UnableToBuildCollection(collectionName);
276             }
277 
278             return resultTable;
279 
280         }
281 
282 
283 
284     }
285 }
286 
287 
288 
289