sqlmetadatafactory.cs 12 KB

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