OleDbMetaDataFactory.cs 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639
  1. //------------------------------------------------------------------------------
  2. // <copyright file="OleDbMetaDataFactory.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.OleDb{
  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.Diagnostics;
  18. using System.Globalization;
  19. using System.Text;
  20. using System.Xml;
  21. using System.Xml.Schema;
  22. internal sealed class OleDbMetaDataFactory : DbMetaDataFactory{ // V1.2.3300
  23. private struct SchemaRowsetName {
  24. internal SchemaRowsetName(string schemaName, Guid schemaRowset) {
  25. _schemaName = schemaName;
  26. _schemaRowset = schemaRowset;
  27. }
  28. internal readonly string _schemaName;
  29. internal readonly Guid _schemaRowset;
  30. }
  31. private const string _collectionName = "CollectionName";
  32. private const string _populationMechanism = "PopulationMechanism";
  33. private const string _prepareCollection = "PrepareCollection";
  34. private readonly SchemaRowsetName[] _schemaMapping;
  35. internal OleDbMetaDataFactory(Stream XMLStream,
  36. string serverVersion,
  37. string serverVersionNormalized,
  38. SchemaSupport[] schemaSupport):
  39. base(XMLStream, serverVersion, serverVersionNormalized) {
  40. // set up the colletion mane schema rowset guid mapping
  41. _schemaMapping = new SchemaRowsetName[] {
  42. new SchemaRowsetName(DbMetaDataCollectionNames.DataTypes,OleDbSchemaGuid.Provider_Types),
  43. new SchemaRowsetName(OleDbMetaDataCollectionNames.Catalogs,OleDbSchemaGuid.Catalogs),
  44. new SchemaRowsetName(OleDbMetaDataCollectionNames.Collations,OleDbSchemaGuid.Collations),
  45. new SchemaRowsetName(OleDbMetaDataCollectionNames.Columns,OleDbSchemaGuid.Columns),
  46. new SchemaRowsetName(OleDbMetaDataCollectionNames.Indexes,OleDbSchemaGuid.Indexes),
  47. new SchemaRowsetName(OleDbMetaDataCollectionNames.Procedures,OleDbSchemaGuid.Procedures),
  48. new SchemaRowsetName(OleDbMetaDataCollectionNames.ProcedureColumns,OleDbSchemaGuid.Procedure_Columns),
  49. new SchemaRowsetName(OleDbMetaDataCollectionNames.ProcedureParameters,OleDbSchemaGuid.Procedure_Parameters),
  50. new SchemaRowsetName(OleDbMetaDataCollectionNames.Tables,OleDbSchemaGuid.Tables),
  51. new SchemaRowsetName(OleDbMetaDataCollectionNames.Views,OleDbSchemaGuid.Views)};
  52. // verify the existance of the table in the data set
  53. DataTable metaDataCollectionsTable = CollectionDataSet.Tables[DbMetaDataCollectionNames.MetaDataCollections];
  54. if (metaDataCollectionsTable == null){
  55. throw ADP.UnableToBuildCollection(DbMetaDataCollectionNames.MetaDataCollections);
  56. }
  57. // copy the table filtering out any rows that don't apply to the current version of the provider
  58. metaDataCollectionsTable = CloneAndFilterCollection(DbMetaDataCollectionNames.MetaDataCollections, null);
  59. // verify the existance of the table in the data set
  60. DataTable restrictionsTable = CollectionDataSet.Tables[DbMetaDataCollectionNames.Restrictions];
  61. if (restrictionsTable != null){
  62. // copy the table filtering out any rows that don't apply to the current version of the provider
  63. restrictionsTable= CloneAndFilterCollection(DbMetaDataCollectionNames.Restrictions, null);
  64. }
  65. // need to filter out any of the collections where
  66. // 1) it is populated using prepare collection
  67. // 2) it is in the collection to schema rowset mapping above
  68. // 3) the provider does not support the necessary schema rowset
  69. DataColumn populationMechanism = metaDataCollectionsTable.Columns[_populationMechanism];
  70. if ((null == populationMechanism) || (typeof(System.String) != populationMechanism.DataType)) {
  71. throw ADP.InvalidXmlMissingColumn(DbMetaDataCollectionNames.MetaDataCollections,_populationMechanism);
  72. }
  73. DataColumn collectionName = metaDataCollectionsTable.Columns[_collectionName];
  74. if ((null == collectionName) || (typeof(System.String) != collectionName.DataType)) {
  75. throw ADP.InvalidXmlMissingColumn(DbMetaDataCollectionNames.MetaDataCollections,_collectionName);
  76. }
  77. DataColumn restrictionCollectionName = null;
  78. if (restrictionsTable != null){
  79. restrictionCollectionName = restrictionsTable.Columns[_collectionName];
  80. if ((null == restrictionCollectionName) || (typeof(System.String) != restrictionCollectionName.DataType)) {
  81. throw ADP.InvalidXmlMissingColumn(DbMetaDataCollectionNames.Restrictions,_collectionName);
  82. }
  83. }
  84. foreach (DataRow collection in metaDataCollectionsTable.Rows){
  85. string populationMechanismValue = collection[populationMechanism] as string;
  86. if (ADP.IsEmpty(populationMechanismValue )) {
  87. throw ADP.InvalidXmlInvalidValue(DbMetaDataCollectionNames.MetaDataCollections,_populationMechanism);
  88. }
  89. string collectionNameValue = collection[collectionName] as string;
  90. if (ADP.IsEmpty(collectionNameValue)) {
  91. throw ADP.InvalidXmlInvalidValue(DbMetaDataCollectionNames.MetaDataCollections,_collectionName);
  92. }
  93. if (populationMechanismValue == _prepareCollection) {
  94. // is the collection in the mapping
  95. int mapping = -1;
  96. for (int i = 0; i < _schemaMapping.Length; i++){
  97. if (_schemaMapping[i]._schemaName == collectionNameValue){
  98. mapping = i;
  99. break;
  100. }
  101. }
  102. // no go on to the next collection
  103. if (mapping == -1) {
  104. continue;
  105. }
  106. // does the provider support the necessary schema rowset
  107. bool isSchemaRowsetSupported = false;
  108. if (schemaSupport != null){
  109. for (int i = 0; i < schemaSupport.Length; i++){
  110. if (_schemaMapping[mapping]._schemaRowset == schemaSupport[i]._schemaRowset){
  111. isSchemaRowsetSupported = true;
  112. break;
  113. }
  114. }
  115. }
  116. // if not delete the row from the table
  117. if (isSchemaRowsetSupported == false){
  118. // but first delete any related restrictions
  119. if (restrictionsTable != null) {
  120. foreach (DataRow restriction in restrictionsTable.Rows) {
  121. string restrictionCollectionNameValue = restriction[restrictionCollectionName] as string;
  122. if (ADP.IsEmpty(restrictionCollectionNameValue)) {
  123. throw ADP.InvalidXmlInvalidValue(DbMetaDataCollectionNames.Restrictions,_collectionName);
  124. }
  125. if (collectionNameValue == restrictionCollectionNameValue) {
  126. restriction.Delete();
  127. }
  128. }
  129. restrictionsTable.AcceptChanges();
  130. }
  131. collection.Delete();
  132. }
  133. }
  134. }
  135. // replace the original table with the updated one
  136. metaDataCollectionsTable.AcceptChanges();
  137. CollectionDataSet.Tables.Remove(CollectionDataSet.Tables[DbMetaDataCollectionNames.MetaDataCollections]);
  138. CollectionDataSet.Tables.Add(metaDataCollectionsTable);
  139. if (restrictionsTable != null) {
  140. CollectionDataSet.Tables.Remove(CollectionDataSet.Tables[DbMetaDataCollectionNames.Restrictions]);
  141. CollectionDataSet.Tables.Add(restrictionsTable);
  142. }
  143. }
  144. private String BuildRegularExpression(string invalidChars, string invalidStartingChars){
  145. StringBuilder regularExpression = new StringBuilder("[^");
  146. ADP.EscapeSpecialCharacters(invalidStartingChars,regularExpression);
  147. regularExpression.Append("][^");
  148. ADP.EscapeSpecialCharacters(invalidChars,regularExpression);
  149. regularExpression.Append("]*");
  150. return regularExpression.ToString();
  151. }
  152. private DataTable GetDataSourceInformationTable(OleDbConnection connection, OleDbConnectionInternal internalConnection){
  153. // verify that the data source information table is in the data set
  154. DataTable dataSourceInformationTable = CollectionDataSet.Tables[DbMetaDataCollectionNames.DataSourceInformation];
  155. if (dataSourceInformationTable == null){
  156. throw ADP.UnableToBuildCollection(DbMetaDataCollectionNames.DataSourceInformation);
  157. }
  158. // copy the table filtering out any rows that don't apply to tho current version of the prrovider
  159. dataSourceInformationTable = CloneAndFilterCollection(DbMetaDataCollectionNames.DataSourceInformation, null);
  160. // after filtering there better be just one row
  161. if (dataSourceInformationTable.Rows.Count != 1){
  162. throw ADP.IncorrectNumberOfDataSourceInformationRows();
  163. }
  164. DataRow dataSourceInformation = dataSourceInformationTable.Rows[0];
  165. // update the identifier separator
  166. string catalogSeparatorPattern = internalConnection.GetLiteralInfo(ODB.DBLITERAL_CATALOG_SEPARATOR);
  167. string schemaSeparatorPattern = internalConnection.GetLiteralInfo(ODB.DBLITERAL_SCHEMA_SEPARATOR);
  168. if (catalogSeparatorPattern != null) {
  169. StringBuilder compositeSeparatorPattern = new StringBuilder();
  170. StringBuilder patternEscaped = new StringBuilder();
  171. ADP.EscapeSpecialCharacters(catalogSeparatorPattern,patternEscaped);
  172. compositeSeparatorPattern.Append(patternEscaped.ToString());
  173. if ((schemaSeparatorPattern != null) && (schemaSeparatorPattern != catalogSeparatorPattern)) {
  174. compositeSeparatorPattern.Append("|");
  175. patternEscaped.Length = 0;
  176. ADP.EscapeSpecialCharacters(schemaSeparatorPattern,patternEscaped);
  177. compositeSeparatorPattern.Append(patternEscaped.ToString());
  178. }
  179. dataSourceInformation[DbMetaDataColumnNames.CompositeIdentifierSeparatorPattern] = compositeSeparatorPattern.ToString();
  180. }
  181. else if (schemaSeparatorPattern != null){
  182. StringBuilder patternEscaped = new StringBuilder();
  183. ADP.EscapeSpecialCharacters(schemaSeparatorPattern, patternEscaped);
  184. dataSourceInformation[DbMetaDataColumnNames.CompositeIdentifierSeparatorPattern] = patternEscaped.ToString();;
  185. }
  186. // update the DataSourceProductName
  187. object property;
  188. property = connection.GetDataSourcePropertyValue(OleDbPropertySetGuid.DataSourceInfo,ODB.DBPROP_DBMSNAME);
  189. if (property != null) {
  190. dataSourceInformation[DbMetaDataColumnNames.DataSourceProductName] = (string) property;
  191. }
  192. // update the server version strings
  193. dataSourceInformation[DbMetaDataColumnNames.DataSourceProductVersion] = ServerVersion;
  194. dataSourceInformation[DbMetaDataColumnNames.DataSourceProductVersionNormalized] = ServerVersionNormalized;
  195. // values that are the same for all OLE DB Providers. See SQLBU 308529
  196. dataSourceInformation[DbMetaDataColumnNames.ParameterMarkerFormat] = "?";
  197. dataSourceInformation[DbMetaDataColumnNames.ParameterMarkerPattern] = "\\?";
  198. dataSourceInformation[DbMetaDataColumnNames.ParameterNameMaxLength] = 0;
  199. property = connection.GetDataSourcePropertyValue(OleDbPropertySetGuid.DataSourceInfo,ODB.DBPROP_GROUPBY);
  200. GroupByBehavior groupByBehavior = GroupByBehavior.Unknown;
  201. if (property != null) {
  202. switch ((int)property) {
  203. case ODB.DBPROPVAL_GB_CONTAINS_SELECT:
  204. groupByBehavior = GroupByBehavior.MustContainAll;
  205. break;
  206. case ODB.DBPROPVAL_GB_EQUALS_SELECT:
  207. groupByBehavior = GroupByBehavior.ExactMatch;
  208. break;
  209. case ODB.DBPROPVAL_GB_NO_RELATION:
  210. groupByBehavior = GroupByBehavior.Unrelated;
  211. break;
  212. case ODB.DBPROPVAL_GB_NOT_SUPPORTED:
  213. groupByBehavior = GroupByBehavior.NotSupported;
  214. break;
  215. }
  216. }
  217. dataSourceInformation[DbMetaDataColumnNames.GroupByBehavior] = groupByBehavior;
  218. SetIdentifierCase(DbMetaDataColumnNames.IdentifierCase,ODB.DBPROP_IDENTIFIERCASE,dataSourceInformation, connection);
  219. SetIdentifierCase(DbMetaDataColumnNames.QuotedIdentifierCase,ODB.DBPROP_QUOTEDIDENTIFIERCASE,dataSourceInformation, connection);
  220. property = connection.GetDataSourcePropertyValue(OleDbPropertySetGuid.DataSourceInfo,ODB.DBPROP_ORDERBYCOLUNSINSELECT);
  221. if (property != null) {
  222. dataSourceInformation[DbMetaDataColumnNames.OrderByColumnsInSelect] = (bool) property;
  223. }
  224. DataTable infoLiterals = internalConnection.BuildInfoLiterals();
  225. if (infoLiterals != null){
  226. DataRow[] tableNameRow = infoLiterals.Select("Literal = " + ODB.DBLITERAL_TABLE_NAME.ToString(CultureInfo.InvariantCulture));
  227. if (tableNameRow != null) {
  228. object invalidCharsObject = tableNameRow[0]["InvalidChars"];
  229. if (invalidCharsObject.GetType() == typeof(string)) {
  230. string invalidChars = (string)invalidCharsObject;
  231. object invalidStartingCharsObject = tableNameRow[0]["InvalidStartingChars"];
  232. string invalidStartingChars;
  233. if (invalidStartingCharsObject.GetType() == typeof(string)) {
  234. invalidStartingChars = (string)invalidStartingCharsObject;
  235. }
  236. else {
  237. invalidStartingChars = invalidChars;
  238. }
  239. dataSourceInformation[DbMetaDataColumnNames.IdentifierPattern] =
  240. BuildRegularExpression(invalidChars,invalidStartingChars);
  241. }
  242. }
  243. }
  244. // build the QuotedIdentifierPattern using the quote prefix and suffix from the provider and
  245. // assuming that the quote suffix is escaped via repetion (i.e " becomes "")
  246. string quotePrefix;
  247. string quoteSuffix;
  248. connection.GetLiteralQuotes(ADP.GetSchema, out quotePrefix, out quoteSuffix);
  249. if (quotePrefix != null){
  250. // if the quote suffix is null assume that it is the same as the prefix (See OLEDB spec
  251. // IDBInfo::GetLiteralInfo DBLITERAL_QUOTE_SUFFIX.)
  252. if (quoteSuffix == null) {
  253. quoteSuffix = quotePrefix;
  254. }
  255. // only know how to build the parttern if the suffix is 1 character
  256. // in all other cases just leave the field null
  257. if (quoteSuffix.Length == 1) {
  258. StringBuilder scratchStringBuilder = new StringBuilder();
  259. ADP.EscapeSpecialCharacters(quoteSuffix,scratchStringBuilder );
  260. string escapedQuoteSuffixString = scratchStringBuilder.ToString();
  261. scratchStringBuilder.Length = 0;
  262. ADP.EscapeSpecialCharacters(quotePrefix, scratchStringBuilder);
  263. scratchStringBuilder.Append("(([^");
  264. scratchStringBuilder.Append(escapedQuoteSuffixString);
  265. scratchStringBuilder.Append("]|");
  266. scratchStringBuilder.Append(escapedQuoteSuffixString);
  267. scratchStringBuilder.Append(escapedQuoteSuffixString);
  268. scratchStringBuilder.Append(")*)");
  269. scratchStringBuilder.Append(escapedQuoteSuffixString);
  270. dataSourceInformation[DbMetaDataColumnNames.QuotedIdentifierPattern] = scratchStringBuilder.ToString();
  271. }
  272. }
  273. dataSourceInformationTable.AcceptChanges();
  274. return dataSourceInformationTable;
  275. }
  276. private DataTable GetDataTypesTable(OleDbConnection connection){
  277. // verify the existance of the table in the data set
  278. DataTable dataTypesTable = CollectionDataSet.Tables[DbMetaDataCollectionNames.DataTypes];
  279. if (dataTypesTable == null){
  280. throw ADP.UnableToBuildCollection(DbMetaDataCollectionNames.DataTypes);
  281. }
  282. // copy the table filtering out any rows that don't apply to tho current version of the prrovider
  283. dataTypesTable = CloneAndFilterCollection(DbMetaDataCollectionNames.DataTypes, null);
  284. DataTable providerTypesTable = connection.GetOleDbSchemaTable(OleDbSchemaGuid.Provider_Types,null);
  285. DataColumn[] targetColumns = new DataColumn[] {
  286. dataTypesTable.Columns[DbMetaDataColumnNames.TypeName],
  287. dataTypesTable.Columns[DbMetaDataColumnNames.ColumnSize],
  288. dataTypesTable.Columns[DbMetaDataColumnNames.CreateParameters],
  289. dataTypesTable.Columns[DbMetaDataColumnNames.IsAutoIncrementable],
  290. dataTypesTable.Columns[DbMetaDataColumnNames.IsCaseSensitive],
  291. dataTypesTable.Columns[DbMetaDataColumnNames.IsFixedLength],
  292. dataTypesTable.Columns[DbMetaDataColumnNames.IsFixedPrecisionScale],
  293. dataTypesTable.Columns[DbMetaDataColumnNames.IsLong],
  294. dataTypesTable.Columns[DbMetaDataColumnNames.IsNullable],
  295. dataTypesTable.Columns[DbMetaDataColumnNames.IsUnsigned],
  296. dataTypesTable.Columns[DbMetaDataColumnNames.MaximumScale],
  297. dataTypesTable.Columns[DbMetaDataColumnNames.MinimumScale],
  298. dataTypesTable.Columns[DbMetaDataColumnNames.LiteralPrefix],
  299. dataTypesTable.Columns[DbMetaDataColumnNames.LiteralSuffix],
  300. dataTypesTable.Columns[OleDbMetaDataColumnNames.NativeDataType]};
  301. DataColumn[] sourceColumns = new DataColumn[] {
  302. providerTypesTable.Columns["TYPE_NAME"],
  303. providerTypesTable.Columns["COLUMN_SIZE"],
  304. providerTypesTable.Columns["CREATE_PARAMS"],
  305. providerTypesTable.Columns["AUTO_UNIQUE_VALUE"],
  306. providerTypesTable.Columns["CASE_SENSITIVE"],
  307. providerTypesTable.Columns["IS_FIXEDLENGTH"],
  308. providerTypesTable.Columns["FIXED_PREC_SCALE"],
  309. providerTypesTable.Columns["IS_LONG"],
  310. providerTypesTable.Columns["IS_NULLABLE"],
  311. providerTypesTable.Columns["UNSIGNED_ATTRIBUTE"],
  312. providerTypesTable.Columns["MAXIMUM_SCALE"],
  313. providerTypesTable.Columns["MINIMUM_SCALE"],
  314. providerTypesTable.Columns["LITERAL_PREFIX"],
  315. providerTypesTable.Columns["LITERAL_SUFFIX"],
  316. providerTypesTable.Columns["DATA_TYPE"]};
  317. Debug.Assert(sourceColumns.Length == targetColumns.Length);
  318. DataColumn isSearchable = dataTypesTable.Columns[DbMetaDataColumnNames.IsSearchable];
  319. DataColumn isSearchableWithLike = dataTypesTable.Columns[DbMetaDataColumnNames.IsSearchableWithLike];
  320. DataColumn providerDbType = dataTypesTable.Columns[DbMetaDataColumnNames.ProviderDbType];
  321. DataColumn clrType = dataTypesTable.Columns[DbMetaDataColumnNames.DataType];
  322. DataColumn isLong = dataTypesTable.Columns[DbMetaDataColumnNames.IsLong];
  323. DataColumn isFixed = dataTypesTable.Columns[DbMetaDataColumnNames.IsFixedLength];
  324. DataColumn sourceOleDbType = providerTypesTable.Columns["DATA_TYPE"];
  325. DataColumn searchable = providerTypesTable.Columns["SEARCHABLE"];
  326. foreach (DataRow sourceRow in providerTypesTable.Rows) {
  327. DataRow newRow = dataTypesTable.NewRow();
  328. for (int i = 0; i < sourceColumns.Length; i++) {
  329. if ((sourceColumns[i] != null) && (targetColumns[i] != null)){
  330. newRow[targetColumns[i]] = sourceRow[sourceColumns[i]];
  331. }
  332. }
  333. short nativeDataType = (short) Convert.ChangeType(sourceRow[sourceOleDbType],typeof(short), CultureInfo.InvariantCulture);
  334. NativeDBType nativeType = NativeDBType.FromDBType(nativeDataType,(bool)newRow[isLong], (bool)newRow[isFixed]);
  335. newRow[clrType] = nativeType.dataType.FullName;
  336. newRow[providerDbType] = nativeType.enumOleDbType;
  337. // searchable has to be special cased becasue it is not an eaxct mapping
  338. if ((isSearchable != null) && (isSearchableWithLike != null) && (searchable != null)) {
  339. newRow[isSearchable] = DBNull.Value;
  340. newRow[isSearchableWithLike] = DBNull.Value;
  341. if ( DBNull.Value != sourceRow[searchable]){
  342. Int64 searchableValue = (Int64)(sourceRow[searchable]);
  343. switch (searchableValue){
  344. case ODB.DB_UNSEARCHABLE:
  345. newRow[isSearchable] = false;
  346. newRow[isSearchableWithLike] = false;
  347. break;
  348. case ODB.DB_LIKE_ONLY:
  349. newRow[isSearchable] = false;
  350. newRow[isSearchableWithLike] = true;
  351. break;
  352. case ODB.DB_ALL_EXCEPT_LIKE:
  353. newRow[isSearchable] = true;
  354. newRow[isSearchableWithLike] = false;
  355. break;
  356. case ODB.DB_SEARCHABLE:
  357. newRow[isSearchable] = true;
  358. newRow[isSearchableWithLike] = true;
  359. break;
  360. }
  361. }
  362. }
  363. dataTypesTable.Rows.Add(newRow);
  364. }
  365. dataTypesTable.AcceptChanges();
  366. return dataTypesTable;
  367. }
  368. private DataTable GetReservedWordsTable(OleDbConnectionInternal internalConnection){
  369. // verify the existance of the table in the data set
  370. DataTable reservedWordsTable = CollectionDataSet.Tables[DbMetaDataCollectionNames.ReservedWords];
  371. if (null == reservedWordsTable){
  372. throw ADP.UnableToBuildCollection(DbMetaDataCollectionNames.ReservedWords);
  373. }
  374. // copy the table filtering out any rows that don't apply to tho current version of the prrovider
  375. reservedWordsTable = CloneAndFilterCollection(DbMetaDataCollectionNames.ReservedWords, null);
  376. DataColumn reservedWordColumn = reservedWordsTable.Columns[DbMetaDataColumnNames.ReservedWord];
  377. if (null == reservedWordColumn){
  378. throw ADP.UnableToBuildCollection(DbMetaDataCollectionNames.ReservedWords);
  379. }
  380. if (!internalConnection.AddInfoKeywordsToTable(reservedWordsTable, reservedWordColumn)){
  381. throw ODB.IDBInfoNotSupported();
  382. }
  383. return reservedWordsTable;
  384. }
  385. protected override DataTable PrepareCollection(String collectionName, String[] restrictions, DbConnection connection){
  386. OleDbConnection oleDbConnection = (OleDbConnection) connection;
  387. OleDbConnectionInternal oleDbInternalConnection = (OleDbConnectionInternal) (oleDbConnection.InnerConnection);
  388. DataTable resultTable = null;
  389. if (collectionName == DbMetaDataCollectionNames.DataSourceInformation){
  390. if (ADP.IsEmptyArray(restrictions) == false){
  391. throw ADP.TooManyRestrictions(DbMetaDataCollectionNames.DataSourceInformation);
  392. }
  393. resultTable = GetDataSourceInformationTable(oleDbConnection, oleDbInternalConnection);
  394. }
  395. else if (collectionName == DbMetaDataCollectionNames.DataTypes){
  396. if (ADP.IsEmptyArray(restrictions) == false){
  397. throw ADP.TooManyRestrictions(DbMetaDataCollectionNames.DataTypes);
  398. }
  399. resultTable = GetDataTypesTable(oleDbConnection);
  400. }
  401. else if (collectionName == DbMetaDataCollectionNames.ReservedWords){
  402. if (ADP.IsEmptyArray(restrictions) == false){
  403. throw ADP.TooManyRestrictions(DbMetaDataCollectionNames.ReservedWords);
  404. }
  405. resultTable = GetReservedWordsTable(oleDbInternalConnection);
  406. }
  407. else {
  408. for (int i=0; i < _schemaMapping.Length; i++){
  409. if (_schemaMapping[i]._schemaName== collectionName) {
  410. // need to special case the oledb schema rowset restrictions on columns that are not
  411. // string tpyes
  412. object[] mungedRestrictions = restrictions;;
  413. if (restrictions != null){
  414. //verify that there are not too many restrictions
  415. DataTable metaDataCollectionsTable = CollectionDataSet.Tables[DbMetaDataCollectionNames.MetaDataCollections];
  416. int numberOfSupportedRestictions = -1;
  417. // prepare colletion is called with the exact collection name so
  418. // we can do an exact string comparision here
  419. foreach (DataRow row in metaDataCollectionsTable.Rows){
  420. string candidateCollectionName = ((string)row[DbMetaDataColumnNames.CollectionName,DataRowVersion.Current]);
  421. if (collectionName == candidateCollectionName) {
  422. numberOfSupportedRestictions = (int)row[DbMetaDataColumnNames.NumberOfRestrictions];
  423. if (numberOfSupportedRestictions < restrictions.Length){
  424. throw ADP.TooManyRestrictions(collectionName);
  425. }
  426. break;
  427. }
  428. }
  429. Debug.Assert(numberOfSupportedRestictions != -1, "PrepareCollection was called for an collection that is not supported.");
  430. // the 4th restrictionon the indexes schema rowset(type) is an I2 - enum
  431. const int indexRestrictionTypeSlot = 3;
  432. if ((collectionName == OleDbMetaDataCollectionNames.Indexes) &&
  433. (restrictions.Length >= indexRestrictionTypeSlot+1) &&
  434. (restrictions[indexRestrictionTypeSlot] != null)){
  435. mungedRestrictions = new object[restrictions.Length];
  436. for (int j = 0; j <restrictions.Length; j++){
  437. mungedRestrictions[j] = restrictions[j];
  438. }
  439. UInt16 indexTypeValue;
  440. if ((restrictions[indexRestrictionTypeSlot] == "DBPROPVAL_IT_BTREE") ||
  441. (restrictions[indexRestrictionTypeSlot] == "1")){
  442. indexTypeValue = 1;
  443. }
  444. else if ((restrictions[indexRestrictionTypeSlot] == "DBPROPVAL_IT_HASH") ||
  445. (restrictions[indexRestrictionTypeSlot] == "2")){
  446. indexTypeValue = 2;
  447. }
  448. else if ((restrictions[indexRestrictionTypeSlot] == "DBPROPVAL_IT_CONTENT") ||
  449. (restrictions[indexRestrictionTypeSlot] == "3")){
  450. indexTypeValue = 3;
  451. }
  452. else if ((restrictions[indexRestrictionTypeSlot] == "DBPROPVAL_IT_OTHER") ||
  453. (restrictions[indexRestrictionTypeSlot] == "4")){
  454. indexTypeValue = 4;
  455. }
  456. else {
  457. throw ADP.InvalidRestrictionValue(collectionName,"TYPE",restrictions[indexRestrictionTypeSlot]);
  458. }
  459. mungedRestrictions[indexRestrictionTypeSlot] = indexTypeValue;
  460. }
  461. // the 4th restrictionon the procedures schema rowset(type) is an I2 - enum
  462. const int procedureRestrictionTypeSlot = 3;
  463. if ((collectionName == OleDbMetaDataCollectionNames.Procedures) &&
  464. (restrictions.Length >= procedureRestrictionTypeSlot+1) &&
  465. (restrictions[procedureRestrictionTypeSlot] != null)){
  466. mungedRestrictions = new object[restrictions.Length];
  467. for (int j = 0; j <restrictions.Length; j++){
  468. mungedRestrictions[j] = restrictions[j];
  469. }
  470. Int16 procedureTypeValue;
  471. if ((restrictions[procedureRestrictionTypeSlot] == "DB_PT_UNKNOWN") ||
  472. (restrictions[procedureRestrictionTypeSlot] == "1")){
  473. procedureTypeValue = 1;
  474. }
  475. else if ((restrictions[procedureRestrictionTypeSlot] == "DB_PT_PROCEDURE")||
  476. (restrictions[procedureRestrictionTypeSlot] == "2")){
  477. procedureTypeValue = 2;
  478. }
  479. else if ((restrictions[procedureRestrictionTypeSlot] == "DB_PT_FUNCTION")||
  480. (restrictions[procedureRestrictionTypeSlot] == "3")){
  481. procedureTypeValue = 3;
  482. }
  483. else {
  484. throw ADP.InvalidRestrictionValue(collectionName,"PROCEDURE_TYPE",restrictions[procedureRestrictionTypeSlot]);
  485. }
  486. mungedRestrictions[procedureRestrictionTypeSlot] = procedureTypeValue;
  487. }
  488. }
  489. resultTable = oleDbConnection.GetOleDbSchemaTable((System.Guid)_schemaMapping[i]._schemaRowset,mungedRestrictions);
  490. break;
  491. }
  492. }
  493. }
  494. if (resultTable == null){
  495. throw ADP.UnableToBuildCollection(collectionName);
  496. }
  497. return resultTable;
  498. }
  499. private void SetIdentifierCase(string columnName, int propertyID, DataRow row, OleDbConnection connection) {
  500. object property = connection.GetDataSourcePropertyValue(OleDbPropertySetGuid.DataSourceInfo,propertyID);
  501. IdentifierCase identifierCase = IdentifierCase.Unknown;
  502. if (property != null) {
  503. int propertyValue = (int)property;
  504. switch (propertyValue) {
  505. case ODB.DBPROPVAL_IC_UPPER:
  506. case ODB.DBPROPVAL_IC_LOWER:
  507. case ODB.DBPROPVAL_IC_MIXED:
  508. identifierCase = IdentifierCase.Insensitive;
  509. break;
  510. case ODB.DBPROPVAL_IC_SENSITIVE:
  511. identifierCase = IdentifierCase.Sensitive;
  512. break;
  513. }
  514. }
  515. row[columnName] = identifierCase;
  516. }
  517. }
  518. }