1 //------------------------------------------------------------------------------
2 // <copyright file="SqlMetaDataFactory.cs" company="Microsoft">
3 // Copyright (c) Microsoft Corporation. All rights reserved.
6 // <owner current="true" primary="true">Microsoft</owner>
7 // <owner current="true" primary="false">Mugunm</owner>
9 //------------------------------------------------------------------------------
11 namespace System.Data.SqlClient{
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;
24 using System.Xml.Schema;
27 internal sealed class SqlMetaDataFactory : DbMetaDataFactory{ // V1.2.3300
29 private const string _serverVersionNormalized90 = "09.00.0000";
30 private const string _serverVersionNormalized90782 = "09.00.0782";
31 private const string _serverVersionNormalized10 = "10.00.0000";
34 public SqlMetaDataFactory(Stream XMLStream,
36 string serverVersionNormalized):
37 base(XMLStream, serverVersion, serverVersionNormalized) {
42 private void addUDTsToDataTypesTable(DataTable dataTypesTable, SqlConnection connection , String ServerVersion) {
44 const string sqlCommand =
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, " +
57 "from sys.assemblies as assemblies join sys.assembly_types as types " +
58 "on assemblies.assembly_id = types.assembly_id ";
60 // pre 9.0/Yukon servers do not have UDTs
61 if (0 > string.Compare(ServerVersion, _serverVersionNormalized90, StringComparison.OrdinalIgnoreCase)){
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];
78 if ((providerDbtype == null) ||
79 (columnSize == null) ||
80 (isFixedLength == null) ||
81 (isSearchable == null) ||
82 (isLiteralSupported == null) ||
84 (isNullable == null)) {
85 throw ADP.InvalidXml();
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;
101 using (IDataReader reader = command.ExecuteReader()) {
103 object[] values = new object[11];
104 while (reader.Read()) {
106 reader.GetValues(values);
107 newRow = dataTypesTable.NewRow();
109 newRow[providerDbtype] = SqlDbType.Udt;
111 if (values[columnSizeIndex] != DBNull.Value) {
112 newRow[columnSize] = values[columnSizeIndex];
115 if (values[isFixedLengthIndex] != DBNull.Value) {
116 newRow[isFixedLength] = values[isFixedLengthIndex];
119 newRow[isSearchable] = true;
120 newRow[isLiteralSupported] = false;
121 if (values[isNullableIndex] != DBNull.Value) {
122 newRow[isNullable] = values[isNullableIndex];
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)) {
132 StringBuilder nameString = new StringBuilder();
133 nameString.Append(values[assemblyClassIndex].ToString());
134 nameString.Append(", ");
135 nameString.Append(values[assemblyNameIndex].ToString());
136 nameString.Append(", Version=");
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());
146 if (values[cultureInfoIndex] != DBNull.Value) {
147 nameString.Append(", Culture=");
148 nameString.Append(values[cultureInfoIndex].ToString());
151 if (values[publicKeyIndex] != DBNull.Value) {
153 nameString.Append(", PublicKeyToken=");
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));
160 nameString.Append(resultString.ToString());
163 newRow[typeName] = nameString.ToString();
164 dataTypesTable.Rows.Add(newRow);
165 newRow.AcceptChanges();
166 } // if assembly name
172 private void AddTVPsToDataTypesTable(DataTable dataTypesTable, SqlConnection connection , String ServerVersion) {
174 const string sqlCommand =
180 "where is_table_type = 1";
184 if (0 > string.Compare(ServerVersion, _serverVersionNormalized10, StringComparison.OrdinalIgnoreCase)){
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];
200 if ((providerDbtype == null) ||
201 (columnSize == null) ||
202 (isSearchable == null) ||
203 (isLiteralSupported == null) ||
204 (typeName == null) ||
205 (isNullable == null)) {
206 throw ADP.InvalidXml();
209 const int columnSizeIndex = 2;
210 const int isNullableIndex = 1;
211 const int typeNameIndex = 0;
213 using (IDataReader reader = command.ExecuteReader()) {
215 object[] values = new object[11];
216 while (reader.Read()) {
218 reader.GetValues(values);
219 newRow = dataTypesTable.NewRow();
221 newRow[providerDbtype] = SqlDbType.Structured;
223 if (values[columnSizeIndex] != DBNull.Value) {
224 newRow[columnSize] = values[columnSizeIndex];
227 newRow[isSearchable] = false;
228 newRow[isLiteralSupported] = false;
229 if (values[isNullableIndex] != DBNull.Value) {
230 newRow[isNullable] = values[isNullableIndex];
233 if (values[typeNameIndex] != DBNull.Value) {
234 newRow[typeName] = values[typeNameIndex];
235 dataTypesTable.Rows.Add(newRow);
236 newRow.AcceptChanges();
242 private DataTable GetDataTypesTable(SqlConnection connection){
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);
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);
254 addUDTsToDataTypesTable(dataTypesTable, connection, ServerVersionNormalized);
255 AddTVPsToDataTypesTable(dataTypesTable, connection, ServerVersionNormalized);
257 dataTypesTable.AcceptChanges();
258 return dataTypesTable;
262 protected override DataTable PrepareCollection(String collectionName, String[] restrictions, DbConnection connection){
264 SqlConnection sqlConnection = (SqlConnection) connection;
265 DataTable resultTable = null;
267 if (collectionName == DbMetaDataCollectionNames.DataTypes){
268 if (ADP.IsEmptyArray(restrictions) == false) {
269 throw ADP.TooManyRestrictions(DbMetaDataCollectionNames.DataTypes);
271 resultTable = GetDataTypesTable(sqlConnection);
274 if (resultTable == null){
275 throw ADP.UnableToBuildCollection(collectionName);