TdsParserHelperClasses.cs 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594
  1. //------------------------------------------------------------------------------
  2. // <copyright file="TdsParserHelperClasses.cs" company="Microsoft">
  3. // Copyright (c) Microsoft Corporation. All rights reserved.
  4. // </copyright>
  5. // <owner current="true" primary="true">[....]</owner>
  6. // <owner current="true" primary="false">[....]</owner>
  7. //------------------------------------------------------------------------------
  8. namespace System.Data.SqlClient {
  9. using System;
  10. using System.Collections.Generic;
  11. using System.Data;
  12. using System.Data.Common;
  13. using System.Data.ProviderBase;
  14. using System.Data.Sql;
  15. using System.Data.SqlTypes;
  16. using System.Diagnostics;
  17. using System.Reflection;
  18. using System.Text;
  19. using System.Threading;
  20. using System.Security;
  21. using Microsoft.SqlServer.Server; // for SMI metadata
  22. internal enum CallbackType {
  23. Read = 0,
  24. Write = 1
  25. }
  26. internal enum EncryptionOptions {
  27. OFF,
  28. ON,
  29. NOT_SUP,
  30. REQ,
  31. LOGIN
  32. }
  33. internal enum PreLoginHandshakeStatus {
  34. Successful,
  35. InstanceFailure
  36. }
  37. internal enum PreLoginOptions {
  38. VERSION,
  39. ENCRYPT,
  40. INSTANCE,
  41. THREADID,
  42. MARS,
  43. TRACEID,
  44. NUMOPT,
  45. LASTOPT = 255
  46. }
  47. internal enum RunBehavior {
  48. UntilDone = 1, // 0001 binary
  49. ReturnImmediately = 2, // 0010 binary
  50. Clean = 5, // 0101 binary - Clean AND UntilDone
  51. Attention = 13 // 1101 binary - Clean AND UntilDone AND Attention
  52. }
  53. internal enum TdsParserState {
  54. Closed,
  55. OpenNotLoggedIn,
  56. OpenLoggedIn,
  57. Broken,
  58. }
  59. sealed internal class SqlCollation {
  60. // First 20 bits of info field represent the lcid, bits 21-25 are compare options
  61. private const uint IgnoreCase = 1 << 20; // bit 21 - IgnoreCase
  62. private const uint IgnoreNonSpace = 1 << 21; // bit 22 - IgnoreNonSpace / IgnoreAccent
  63. private const uint IgnoreWidth = 1 << 22; // bit 23 - IgnoreWidth
  64. private const uint IgnoreKanaType = 1 << 23; // bit 24 - IgnoreKanaType
  65. private const uint BinarySort = 1 << 24; // bit 25 - BinarySort
  66. internal const uint MaskLcid = 0xfffff;
  67. private const int LcidVersionBitOffset = 28;
  68. private const uint MaskLcidVersion = unchecked((uint)(0xf << LcidVersionBitOffset));
  69. private const uint MaskCompareOpt = IgnoreCase | IgnoreNonSpace | IgnoreWidth | IgnoreKanaType | BinarySort;
  70. internal uint info;
  71. internal byte sortId;
  72. static int FirstSupportedCollationVersion(int lcid)
  73. {
  74. // NOTE: switch-case works ~3 times faster in this case than search with Dictionary
  75. switch (lcid)
  76. {
  77. case 1044: return 2; // Norwegian_100_BIN
  78. case 1047: return 2; // Romansh_100_BIN
  79. case 1056: return 2; // Urdu_100_BIN
  80. case 1065: return 2; // Persian_100_BIN
  81. case 1068: return 2; // Azeri_Latin_100_BIN
  82. case 1070: return 2; // Upper_Sorbian_100_BIN
  83. case 1071: return 1; // ----n_FYROM_90_BIN
  84. case 1081: return 1; // Indic_General_90_BIN
  85. case 1082: return 2; // Maltese_100_BIN
  86. case 1083: return 2; // Sami_Norway_100_BIN
  87. case 1087: return 1; // Kazakh_90_BIN
  88. case 1090: return 2; // Turkmen_100_BIN
  89. case 1091: return 1; // Uzbek_Latin_90_BIN
  90. case 1092: return 1; // Tatar_90_BIN
  91. case 1093: return 2; // Bengali_100_BIN
  92. case 1101: return 2; // Assamese_100_BIN
  93. case 1105: return 2; // Tibetan_100_BIN
  94. case 1106: return 2; // Welsh_100_BIN
  95. case 1107: return 2; // Khmer_100_BIN
  96. case 1108: return 2; // Lao_100_BIN
  97. case 1114: return 1; // Syriac_90_BIN
  98. case 1121: return 2; // Nepali_100_BIN
  99. case 1122: return 2; // Frisian_100_BIN
  100. case 1123: return 2; // Pashto_100_BIN
  101. case 1125: return 1; // Divehi_90_BIN
  102. case 1133: return 2; // Bashkir_100_BIN
  103. case 1146: return 2; // Mapudungan_100_BIN
  104. case 1148: return 2; // Mohawk_100_BIN
  105. case 1150: return 2; // Breton_100_BIN
  106. case 1152: return 2; // Uighur_100_BIN
  107. case 1153: return 2; // Maori_100_BIN
  108. case 1155: return 2; // Corsican_100_BIN
  109. case 1157: return 2; // Yakut_100_BIN
  110. case 1164: return 2; // Dari_100_BIN
  111. case 2074: return 2; // Serbian_Latin_100_BIN
  112. case 2092: return 2; // Azeri_Cyrillic_100_BIN
  113. case 2107: return 2; // Sami_Sweden_Finland_100_BIN
  114. case 2143: return 2; // Tamazight_100_BIN
  115. case 3076: return 1; // Chinese_Hong_Kong_Stroke_90_BIN
  116. case 3098: return 2; // Serbian_Cyrillic_100_BIN
  117. case 5124: return 2; // Chinese_Traditional_Pinyin_100_BIN
  118. case 5146: return 2; // Bosnian_Latin_100_BIN
  119. case 8218: return 2; // Bosnian_Cyrillic_100_BIN
  120. default: return 0; // other LCIDs have collation with version 0
  121. }
  122. }
  123. internal int LCID {
  124. // First 20 bits of info field represent the lcid
  125. get {
  126. return unchecked((int)(info & MaskLcid));
  127. }
  128. set {
  129. int lcid = value & (int)MaskLcid;
  130. Debug.Assert(lcid == value, "invalid set_LCID value");
  131. // VSTFDEVDIV 479474: some new Katmai LCIDs do not have collation with version = 0
  132. // since user has no way to specify collation version, we set the first (minimal) supported version for these collations
  133. int versionBits = FirstSupportedCollationVersion(lcid) << LcidVersionBitOffset;
  134. Debug.Assert((versionBits & MaskLcidVersion) == versionBits, "invalid version returned by FirstSupportedCollationVersion");
  135. // combine the current compare options with the new locale ID and its first supported version
  136. info = (info & MaskCompareOpt) | unchecked((uint)lcid) | unchecked((uint)versionBits);
  137. }
  138. }
  139. internal SqlCompareOptions SqlCompareOptions {
  140. get {
  141. SqlCompareOptions options = SqlCompareOptions.None;
  142. if (0 != (info & IgnoreCase))
  143. options |= SqlCompareOptions.IgnoreCase;
  144. if (0 != (info & IgnoreNonSpace))
  145. options |= SqlCompareOptions.IgnoreNonSpace;
  146. if (0 != (info & IgnoreWidth))
  147. options |= SqlCompareOptions.IgnoreWidth;
  148. if (0 != (info & IgnoreKanaType))
  149. options |= SqlCompareOptions.IgnoreKanaType;
  150. if (0 != (info & BinarySort))
  151. options |= SqlCompareOptions.BinarySort;
  152. return options;
  153. }
  154. set {
  155. Debug.Assert((value & SqlString.x_iValidSqlCompareOptionMask) == value, "invalid set_SqlCompareOptions value");
  156. uint tmp = 0;
  157. if (0 != (value & SqlCompareOptions.IgnoreCase))
  158. tmp |= IgnoreCase;
  159. if (0 != (value & SqlCompareOptions.IgnoreNonSpace))
  160. tmp |= IgnoreNonSpace;
  161. if (0 != (value & SqlCompareOptions.IgnoreWidth))
  162. tmp |= IgnoreWidth;
  163. if (0 != (value & SqlCompareOptions.IgnoreKanaType))
  164. tmp |= IgnoreKanaType;
  165. if (0 != (value & SqlCompareOptions.BinarySort))
  166. tmp |= BinarySort;
  167. info = (info & MaskLcid) | tmp;
  168. }
  169. }
  170. internal string TraceString() {
  171. return String.Format(/*IFormatProvider*/ null, "(LCID={0}, Opts={1})", this.LCID, (int)this.SqlCompareOptions);
  172. }
  173. static internal bool AreSame(SqlCollation a, SqlCollation b) {
  174. if (a == null || b == null) {
  175. return a == b;
  176. }
  177. else {
  178. return a.info == b.info && a.sortId == b.sortId;
  179. }
  180. }
  181. }
  182. internal class RoutingInfo {
  183. internal byte Protocol { get; private set; }
  184. internal UInt16 Port { get; private set; }
  185. internal string ServerName { get; private set; }
  186. internal RoutingInfo(byte protocol, UInt16 port, string servername) {
  187. Protocol = protocol;
  188. Port = port;
  189. ServerName = servername;
  190. }
  191. }
  192. sealed internal class SqlEnvChange {
  193. internal byte type;
  194. internal byte oldLength;
  195. internal int newLength; // 7206 TDS changes makes this length an int
  196. internal int length;
  197. internal string newValue;
  198. internal string oldValue;
  199. internal byte[] newBinValue;
  200. internal byte[] oldBinValue;
  201. internal long newLongValue;
  202. internal long oldLongValue;
  203. internal SqlCollation newCollation;
  204. internal SqlCollation oldCollation;
  205. internal RoutingInfo newRoutingInfo;
  206. }
  207. sealed internal class SqlLogin {
  208. internal int timeout; // login timeout
  209. internal bool userInstance = false; // user instance
  210. internal string hostName = ""; // client machine name
  211. internal string userName = ""; // user id
  212. internal string password = ""; // password
  213. internal string applicationName = ""; // application name
  214. internal string serverName = ""; // server name
  215. internal string language = ""; // initial language
  216. internal string database = ""; // initial database
  217. internal string attachDBFilename = ""; // DB filename to be attached
  218. internal string newPassword = ""; // new password for reset password
  219. internal bool useReplication = false; // user login for replication
  220. internal bool useSSPI = false; // use integrated security
  221. internal int packetSize = SqlConnectionString.DEFAULT.Packet_Size; // packet size
  222. internal bool readOnlyIntent = false; // read-only intent
  223. internal SqlCredential credential; // user id and password in SecureString
  224. internal SecureString newSecurePassword; // new password in SecureString for resetting pasword
  225. }
  226. sealed internal class SqlLoginAck {
  227. internal string programName;
  228. internal byte majorVersion;
  229. internal byte minorVersion;
  230. internal short buildNum;
  231. internal bool isVersion8;
  232. internal UInt32 tdsVersion;
  233. }
  234. sealed internal class _SqlMetaData : SqlMetaDataPriv, ICloneable {
  235. internal string column;
  236. internal string baseColumn;
  237. internal MultiPartTableName multiPartTableName;
  238. internal readonly int ordinal;
  239. internal byte updatability; // two bit field (0 is read only, 1 is updatable, 2 is updatability unknown)
  240. internal byte tableNum;
  241. internal bool isDifferentName;
  242. internal bool isKey;
  243. internal bool isHidden;
  244. internal bool isExpression;
  245. internal bool isIdentity;
  246. internal bool isColumnSet;
  247. internal byte op; // for altrow-columns only
  248. internal ushort operand; // for altrow-columns only
  249. internal _SqlMetaData(int ordinal) : base() {
  250. this.ordinal = ordinal;
  251. }
  252. internal string serverName {
  253. get {
  254. return multiPartTableName.ServerName;
  255. }
  256. }
  257. internal string catalogName {
  258. get {
  259. return multiPartTableName.CatalogName;
  260. }
  261. }
  262. internal string schemaName {
  263. get {
  264. return multiPartTableName.SchemaName;
  265. }
  266. }
  267. internal string tableName {
  268. get {
  269. return multiPartTableName.TableName;
  270. }
  271. }
  272. internal bool IsNewKatmaiDateTimeType {
  273. get {
  274. return SqlDbType.Date == type || SqlDbType.Time == type || SqlDbType.DateTime2 == type || SqlDbType.DateTimeOffset == type;
  275. }
  276. }
  277. internal bool IsLargeUdt {
  278. get {
  279. return type == SqlDbType.Udt && length == Int32.MaxValue;
  280. }
  281. }
  282. public object Clone() {
  283. _SqlMetaData result = new _SqlMetaData(ordinal);
  284. result.CopyFrom(this);
  285. result.column = column;
  286. result.baseColumn = baseColumn;
  287. result.multiPartTableName = multiPartTableName;
  288. result.updatability = updatability;
  289. result.tableNum = tableNum;
  290. result.isDifferentName = isDifferentName;
  291. result.isKey = isKey;
  292. result.isHidden = isHidden;
  293. result.isExpression = isExpression;
  294. result.isIdentity = isIdentity;
  295. result.isColumnSet = isColumnSet;
  296. result.op = op;
  297. result.operand = operand;
  298. return result;
  299. }
  300. }
  301. sealed internal class _SqlMetaDataSet : ICloneable {
  302. internal ushort id; // for altrow-columns only
  303. internal int[] indexMap;
  304. internal int visibleColumns;
  305. internal DataTable schemaTable;
  306. private readonly _SqlMetaData[] metaDataArray;
  307. internal _SqlMetaDataSet(int count) {
  308. metaDataArray = new _SqlMetaData[count];
  309. for(int i = 0; i < metaDataArray.Length; ++i) {
  310. metaDataArray[i] = new _SqlMetaData(i);
  311. }
  312. }
  313. private _SqlMetaDataSet(_SqlMetaDataSet original) {
  314. this.id = original.id;
  315. // although indexMap is not immutable, in practice it is initialized once and then passed around
  316. this.indexMap = original.indexMap;
  317. this.visibleColumns = original.visibleColumns;
  318. this.schemaTable = original.schemaTable;
  319. if (original.metaDataArray == null) {
  320. metaDataArray = null;
  321. }
  322. else {
  323. metaDataArray = new _SqlMetaData[original.metaDataArray.Length];
  324. for (int idx=0; idx<metaDataArray.Length; idx++) {
  325. metaDataArray[idx] = (_SqlMetaData)original.metaDataArray[idx].Clone();
  326. }
  327. }
  328. }
  329. internal int Length {
  330. get {
  331. return metaDataArray.Length;
  332. }
  333. }
  334. internal _SqlMetaData this [int index] {
  335. get {
  336. return metaDataArray[index];
  337. }
  338. set {
  339. Debug.Assert(null == value, "used only by SqlBulkCopy");
  340. metaDataArray[index] = value;
  341. }
  342. }
  343. public object Clone() {
  344. return new _SqlMetaDataSet(this);
  345. }
  346. }
  347. sealed internal class _SqlMetaDataSetCollection : ICloneable {
  348. private readonly List<_SqlMetaDataSet> altMetaDataSetArray;
  349. internal _SqlMetaDataSet metaDataSet;
  350. internal _SqlMetaDataSetCollection () {
  351. altMetaDataSetArray = new List<_SqlMetaDataSet>();
  352. }
  353. internal void SetAltMetaData(_SqlMetaDataSet altMetaDataSet) {
  354. // VSTFDEVDIV 479675: if altmetadata with same id is found, override it rather than adding a new one
  355. int newId = altMetaDataSet.id;
  356. for (int i = 0; i < altMetaDataSetArray.Count; i++) {
  357. if (altMetaDataSetArray[i].id == newId) {
  358. // override the existing metadata with the same id
  359. altMetaDataSetArray[i] = altMetaDataSet;
  360. return;
  361. }
  362. }
  363. // if we did not find metadata to override, add as new
  364. altMetaDataSetArray.Add(altMetaDataSet);
  365. }
  366. internal _SqlMetaDataSet GetAltMetaData(int id) {
  367. foreach (_SqlMetaDataSet altMetaDataSet in altMetaDataSetArray) {
  368. if (altMetaDataSet.id == id) {
  369. return altMetaDataSet;
  370. }
  371. }
  372. Debug.Assert (false, "Can't match up altMetaDataSet with given id");
  373. return null;
  374. }
  375. public object Clone()
  376. {
  377. _SqlMetaDataSetCollection result = new _SqlMetaDataSetCollection();
  378. result.metaDataSet = metaDataSet == null ? null : (_SqlMetaDataSet)metaDataSet.Clone();
  379. foreach (_SqlMetaDataSet set in altMetaDataSetArray) {
  380. result.altMetaDataSetArray.Add((_SqlMetaDataSet)set.Clone());
  381. }
  382. return result;
  383. }
  384. }
  385. internal class SqlMetaDataPriv {
  386. internal SqlDbType type; // SqlDbType enum value
  387. internal byte tdsType; // underlying tds type
  388. internal byte precision = TdsEnums.UNKNOWN_PRECISION_SCALE; // give default of unknown (-1)
  389. internal byte scale = TdsEnums.UNKNOWN_PRECISION_SCALE; // give default of unknown (-1)
  390. internal int length;
  391. internal SqlCollation collation;
  392. internal int codePage;
  393. internal Encoding encoding;
  394. internal bool isNullable;
  395. internal bool isMultiValued = false;
  396. // UDT specific metadata
  397. // server metadata info
  398. // additional temporary UDT meta data
  399. internal string udtDatabaseName;
  400. internal string udtSchemaName;
  401. internal string udtTypeName;
  402. internal string udtAssemblyQualifiedName;
  403. // on demand
  404. internal Type udtType;
  405. // Xml specific metadata
  406. internal string xmlSchemaCollectionDatabase;
  407. internal string xmlSchemaCollectionOwningSchema;
  408. internal string xmlSchemaCollectionName;
  409. internal MetaType metaType; // cached metaType
  410. // Structured type-specific metadata
  411. internal string structuredTypeDatabaseName;
  412. internal string structuredTypeSchemaName;
  413. internal string structuredTypeName;
  414. internal IList<SmiMetaData> structuredFields;
  415. internal SqlMetaDataPriv() {
  416. }
  417. internal virtual void CopyFrom(SqlMetaDataPriv original) {
  418. this.type = original.type;
  419. this.tdsType = original.tdsType;
  420. this.precision = original.precision;
  421. this.scale = original.scale;
  422. this.length = original.length;
  423. this.collation = original.collation;
  424. this.codePage = original.codePage;
  425. this.encoding = original.encoding;
  426. this.isNullable = original.isNullable;
  427. this.isMultiValued = original.isMultiValued;
  428. this.udtDatabaseName = original.udtDatabaseName;
  429. this.udtSchemaName = original.udtSchemaName;
  430. this.udtTypeName = original.udtTypeName;
  431. this.udtAssemblyQualifiedName = original.udtAssemblyQualifiedName;
  432. this.udtType = original.udtType;
  433. this.xmlSchemaCollectionDatabase = original.xmlSchemaCollectionDatabase;
  434. this.xmlSchemaCollectionOwningSchema = original.xmlSchemaCollectionOwningSchema;
  435. this.xmlSchemaCollectionName = original.xmlSchemaCollectionName;
  436. this.metaType = original.metaType;
  437. //
  438. this.structuredTypeDatabaseName = original.structuredTypeDatabaseName;
  439. this.structuredTypeSchemaName = original.structuredTypeSchemaName;
  440. this.structuredTypeName = original.structuredTypeName;
  441. this.structuredFields = original.structuredFields;
  442. }
  443. }
  444. sealed internal class _SqlRPC {
  445. internal string rpcName;
  446. internal string databaseName; // Used for UDTs
  447. internal ushort ProcID; // Used instead of name
  448. internal ushort options;
  449. internal SqlParameter[] parameters;
  450. internal byte[] paramoptions;
  451. internal int? recordsAffected;
  452. internal int cumulativeRecordsAffected;
  453. internal int errorsIndexStart;
  454. internal int errorsIndexEnd;
  455. internal SqlErrorCollection errors;
  456. internal int warningsIndexStart;
  457. internal int warningsIndexEnd;
  458. internal SqlErrorCollection warnings;
  459. }
  460. sealed internal class SqlReturnValue : SqlMetaDataPriv {
  461. internal ushort parmIndex; //Yukon or later only
  462. internal string parameter;
  463. internal readonly SqlBuffer value;
  464. internal SqlReturnValue() : base() {
  465. value = new SqlBuffer();
  466. }
  467. }
  468. internal struct MultiPartTableName {
  469. private string _multipartName;
  470. private string _serverName;
  471. private string _catalogName;
  472. private string _schemaName;
  473. private string _tableName;
  474. internal MultiPartTableName(string[] parts) {
  475. _multipartName = null;
  476. _serverName = parts[0];
  477. _catalogName = parts[1];
  478. _schemaName = parts[2];
  479. _tableName = parts[3];
  480. }
  481. internal MultiPartTableName(string multipartName) {
  482. _multipartName = multipartName;
  483. _serverName = null;
  484. _catalogName = null;
  485. _schemaName = null;
  486. _tableName = null;
  487. }
  488. internal string ServerName {
  489. get {
  490. ParseMultipartName();
  491. return _serverName;
  492. }
  493. set { _serverName = value; }
  494. }
  495. internal string CatalogName {
  496. get {
  497. ParseMultipartName();
  498. return _catalogName;
  499. }
  500. set { _catalogName = value; }
  501. }
  502. internal string SchemaName {
  503. get {
  504. ParseMultipartName();
  505. return _schemaName;
  506. }
  507. set { _schemaName = value; }
  508. }
  509. internal string TableName {
  510. get {
  511. ParseMultipartName();
  512. return _tableName;
  513. }
  514. set { _tableName = value; }
  515. }
  516. private void ParseMultipartName() {
  517. if (null != _multipartName) {
  518. string[] parts = MultipartIdentifier.ParseMultipartIdentifier(_multipartName, "[\"", "]\"", Res.SQL_TDSParserTableName, false);
  519. _serverName = parts[0];
  520. _catalogName = parts[1];
  521. _schemaName = parts[2];
  522. _tableName = parts[3];
  523. _multipartName = null;
  524. }
  525. }
  526. internal static readonly MultiPartTableName Null = new MultiPartTableName(new string[] {null, null, null, null});
  527. }
  528. }