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