Update Reference Sources to .NET Framework 4.6.1
[mono.git] / mcs / class / referencesource / System.Data / System / Data / SqlClient / TdsParserHelperClasses.cs
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
9 namespace System.Data.SqlClient {
10     using System;
11     using System.Collections.Generic;
12     using System.Data;
13     using System.Data.Common;
14     using System.Data.ProviderBase;
15     using System.Data.Sql;
16     using System.Data.SqlTypes;
17     using System.Diagnostics;
18     using System.Reflection;
19     using System.Text;
20     using System.Threading;
21     using System.Security;
22     using System.Globalization;
23
24     using Microsoft.SqlServer.Server; // for SMI metadata
25
26     internal enum CallbackType {
27         Read  = 0,
28         Write = 1
29     }
30
31     internal enum EncryptionOptions {
32         OFF,
33         ON,
34         NOT_SUP,
35         REQ,
36         LOGIN
37     }
38
39     internal enum PreLoginHandshakeStatus {
40         Successful,
41         InstanceFailure
42     }
43
44     internal enum PreLoginOptions {
45         VERSION,
46         ENCRYPT,
47         INSTANCE,
48         THREADID,
49         MARS,
50         TRACEID,
51         FEDAUTHREQUIRED,
52         NUMOPT,
53         LASTOPT = 255
54     }
55
56     internal enum RunBehavior {
57         UntilDone         =  1, // 0001 binary
58         ReturnImmediately =  2, // 0010 binary
59         Clean             =  5, // 0101 binary - Clean AND UntilDone
60         Attention         = 13  // 1101 binary - Clean AND UntilDone AND Attention
61     }
62
63     internal enum TdsParserState {
64         Closed,
65         OpenNotLoggedIn,
66         OpenLoggedIn,
67         Broken,
68     }
69
70     /// <summary>
71     /// Struct encapsulating the data to be sent to the server as part of Federated Authentication Feature Extension.
72     /// </summary>
73     internal struct FederatedAuthenticationFeatureExtensionData
74     {
75         internal TdsEnums.FedAuthLibrary libraryType;
76         internal bool fedAuthRequiredPreLoginResponse;
77         internal SqlAuthenticationMethod authentication;
78         internal byte[] accessToken;
79     }
80
81     /// <summary>
82     /// <para> Represents a single encrypted value for a CEK. It contains the encrypted CEK,
83     ///  the store type, name,the key path and encryption algorithm.</para>
84     /// </summary>
85     internal struct SqlEncryptionKeyInfo {
86         internal byte[] encryptedKey; // the encrypted "column encryption key"
87         internal int databaseId;
88         internal int cekId;
89         internal int cekVersion;
90         internal byte[] cekMdVersion;
91         internal string keyPath;
92         internal string keyStoreName;
93         internal string algorithmName;
94         internal byte normalizationRuleVersion;
95     }
96
97     /// <summary>
98     /// <para> Encapsulates one entry in the CipherInfo table sent as part of Colmetadata.
99     /// The same CEK is encrypted multiple times with different master keys (for master key
100     /// rotation scenario) We need to keep all these around until we can resolve the CEK
101     /// using the correct master key.</para>
102     /// </summary>
103     internal struct SqlTceCipherInfoEntry {
104
105         /// <summary>
106         /// List of Column Encryption Key Information.
107         /// </summary>
108         private readonly List<SqlEncryptionKeyInfo> _columnEncryptionKeyValues;
109
110         /// <summary>
111         /// Key Ordinal.
112         /// </summary>
113         private readonly int _ordinal;
114
115         /// <summary>
116         /// Database ID
117         /// </summary>
118         private int _databaseId;
119
120         /// <summary>
121         /// Cek ID
122         /// </summary>
123         private int _cekId;
124
125         /// <summary>
126         /// Cek Version
127         /// </summary>
128         private int _cekVersion;
129
130         /// <summary>
131         /// Cek MD Version
132         /// </summary>
133         private byte[] _cekMdVersion;
134
135         /// <summary>
136         /// Return the ordinal.
137         /// </summary>
138         internal int Ordinal {
139             get {
140                 return _ordinal;
141             }
142         }
143
144         /// <summary>
145         /// Return the DatabaseID.
146         /// </summary>
147         internal int DatabaseId {
148             get {
149                 return _databaseId;
150             }
151         }
152
153         /// <summary>
154         /// Return the CEK ID.
155         /// </summary>
156         internal int CekId {
157             get {
158                 return _cekId;
159             }
160         }
161
162         /// <summary>
163         /// Return the CEK Version.
164         /// </summary>
165         internal int CekVersion {
166             get {
167                 return _cekVersion;
168             }
169         }
170
171         /// <summary>
172         /// Return the CEK MD Version.
173         /// </summary>
174         internal byte[] CekMdVersion {
175             get {
176                 return _cekMdVersion;
177             }
178         }
179
180         /// <summary>
181         /// Return the list of Column Encryption Key Values.
182         /// </summary>
183         internal List<SqlEncryptionKeyInfo> ColumnEncryptionKeyValues {
184             get {
185                 return _columnEncryptionKeyValues;
186             }
187         }
188
189         /// <summary>
190         /// Add an entry to the list of ColumnEncryptionKeyValues.
191         /// </summary>
192         /// <param name="encryptedKey"></param>
193         /// <param name="databaseId"></param>
194         /// <param name="cekId"></param>
195         /// <param name="cekVersion"></param>
196         /// <param name="cekMdVersion"></param>
197         /// <param name="keyPath"></param>
198         /// <param name="keyStoreName"></param>
199         /// <param name="algorithmName"></param>
200         internal void Add(byte[] encryptedKey, int databaseId, int cekId, int cekVersion, byte[] cekMdVersion, string keyPath, string keyStoreName, string algorithmName) {
201
202             Debug.Assert(_columnEncryptionKeyValues != null, "_columnEncryptionKeyValues should already be initialized.");
203
204             SqlEncryptionKeyInfo encryptionKey = new SqlEncryptionKeyInfo();
205             encryptionKey.encryptedKey = encryptedKey;
206             encryptionKey.databaseId = databaseId;
207             encryptionKey.cekId = cekId;
208             encryptionKey.cekVersion = cekVersion;
209             encryptionKey.cekMdVersion = cekMdVersion;
210             encryptionKey.keyPath = keyPath;
211             encryptionKey.keyStoreName = keyStoreName;
212             encryptionKey.algorithmName = algorithmName;
213             _columnEncryptionKeyValues.Add(encryptionKey);
214
215             if (0 == _databaseId) {
216                 _databaseId = databaseId;
217                 _cekId = cekId;
218                 _cekVersion = cekVersion;
219                 _cekMdVersion = cekMdVersion;
220             }
221             else {
222                 Debug.Assert(_databaseId == databaseId);
223                 Debug.Assert(_cekId == cekId);
224                 Debug.Assert(_cekVersion == cekVersion);
225                 Debug.Assert (_cekMdVersion != null && cekMdVersion != null && _cekMdVersion.Length == _cekMdVersion.Length);
226             }
227         }
228
229         /// <summary>
230         /// Constructor.
231         /// </summary>
232         /// <param name="ordinal"></param>
233         internal SqlTceCipherInfoEntry(int ordinal = 0) : this() {
234             _ordinal = ordinal;
235             _databaseId = 0;
236             _cekId = 0;
237             _cekVersion = 0;
238             _cekMdVersion = null;
239             _columnEncryptionKeyValues = new List<SqlEncryptionKeyInfo>();
240         }
241     }
242
243     /// <summary> 
244     /// <para> Represents a table with various CEKs used in a resultset. Each entry corresponds to one (unique) CEK. The CEK
245     /// may have been encrypted using multiple master keys (giving us multiple CEK values). All these values form one single
246     /// entry in this table.</para>
247     ///</summary>
248     internal struct SqlTceCipherInfoTable {
249         private readonly SqlTceCipherInfoEntry [] keyList;
250
251         internal SqlTceCipherInfoTable (int tabSize) {
252             Debug.Assert (0 < tabSize, "Invalid Table Size");
253             keyList = new SqlTceCipherInfoEntry[tabSize];
254         }
255
256         internal SqlTceCipherInfoEntry this [int index] {
257             get {
258                 Debug.Assert (index < keyList.Length, "Invalid index specified.");
259                 return keyList[index];
260             }
261             set {
262                 Debug.Assert (index < keyList.Length, "Invalid index specified.");
263                 keyList[index] = value;
264             }
265         }
266
267         internal int Size {
268             get {
269                 return keyList.Length;
270             }
271         }
272     }
273
274     sealed internal class SqlCollation {
275         // First 20 bits of info field represent the lcid, bits 21-25 are compare options
276         private const uint IgnoreCase     = 1 << 20; // bit 21 - IgnoreCase
277         private const uint IgnoreNonSpace = 1 << 21; // bit 22 - IgnoreNonSpace / IgnoreAccent
278         private const uint IgnoreWidth    = 1 << 22; // bit 23 - IgnoreWidth
279         private const uint IgnoreKanaType = 1 << 23; // bit 24 - IgnoreKanaType
280         private const uint BinarySort     = 1 << 24; // bit 25 - BinarySort
281
282         internal const uint MaskLcid           = 0xfffff;
283         private const int LcidVersionBitOffset = 28;
284         private const uint MaskLcidVersion     = unchecked((uint)(0xf << LcidVersionBitOffset));
285         private const uint MaskCompareOpt = IgnoreCase | IgnoreNonSpace | IgnoreWidth | IgnoreKanaType | BinarySort;
286
287         internal uint info;
288         internal byte sortId;
289
290         static int FirstSupportedCollationVersion(int lcid)
291         {
292             // NOTE: switch-case works ~3 times faster in this case than search with Dictionary
293             switch (lcid)
294             {
295                 case 1044: return 2; // Norwegian_100_BIN
296                 case 1047: return 2; // Romansh_100_BIN
297                 case 1056: return 2; // Urdu_100_BIN
298                 case 1065: return 2; // Persian_100_BIN
299                 case 1068: return 2; // Azeri_Latin_100_BIN
300                 case 1070: return 2; // Upper_Sorbian_100_BIN
301                 case 1071: return 1; // ----n_FYROM_90_BIN
302                 case 1081: return 1; // Indic_General_90_BIN
303                 case 1082: return 2; // Maltese_100_BIN
304                 case 1083: return 2; // Sami_Norway_100_BIN
305                 case 1087: return 1; // Kazakh_90_BIN
306                 case 1090: return 2; // Turkmen_100_BIN
307                 case 1091: return 1; // Uzbek_Latin_90_BIN
308                 case 1092: return 1; // Tatar_90_BIN
309                 case 1093: return 2; // Bengali_100_BIN
310                 case 1101: return 2; // Assamese_100_BIN
311                 case 1105: return 2; // Tibetan_100_BIN
312                 case 1106: return 2; // Welsh_100_BIN
313                 case 1107: return 2; // Khmer_100_BIN
314                 case 1108: return 2; // Lao_100_BIN
315                 case 1114: return 1; // Syriac_90_BIN
316                 case 1121: return 2; // Nepali_100_BIN
317                 case 1122: return 2; // Frisian_100_BIN
318                 case 1123: return 2; // Pashto_100_BIN
319                 case 1125: return 1; // Divehi_90_BIN
320                 case 1133: return 2; // Bashkir_100_BIN
321                 case 1146: return 2; // Mapudungan_100_BIN
322                 case 1148: return 2; // Mohawk_100_BIN
323                 case 1150: return 2; // Breton_100_BIN
324                 case 1152: return 2; // Uighur_100_BIN
325                 case 1153: return 2; // Maori_100_BIN
326                 case 1155: return 2; // Corsican_100_BIN
327                 case 1157: return 2; // Yakut_100_BIN
328                 case 1164: return 2; // Dari_100_BIN
329                 case 2074: return 2; // Serbian_Latin_100_BIN
330                 case 2092: return 2; // Azeri_Cyrillic_100_BIN
331                 case 2107: return 2; // Sami_Sweden_Finland_100_BIN
332                 case 2143: return 2; // Tamazight_100_BIN
333                 case 3076: return 1; // Chinese_Hong_Kong_Stroke_90_BIN
334                 case 3098: return 2; // Serbian_Cyrillic_100_BIN
335                 case 5124: return 2; // Chinese_Traditional_Pinyin_100_BIN
336                 case 5146: return 2; // Bosnian_Latin_100_BIN
337                 case 8218: return 2; // Bosnian_Cyrillic_100_BIN
338
339                 default: return 0;   // other LCIDs have collation with version 0
340             }
341         }
342
343         internal int LCID {
344             // First 20 bits of info field represent the lcid
345             get {
346                 return unchecked((int)(info & MaskLcid));
347             }
348             set {
349                 int lcid = value & (int)MaskLcid;
350                 Debug.Assert(lcid == value, "invalid set_LCID value");
351
352                 // VSTFDEVDIV 479474: some new Katmai LCIDs do not have collation with version = 0
353                 // since user has no way to specify collation version, we set the first (minimal) supported version for these collations
354                 int versionBits = FirstSupportedCollationVersion(lcid) << LcidVersionBitOffset;
355                 Debug.Assert((versionBits & MaskLcidVersion) == versionBits, "invalid version returned by FirstSupportedCollationVersion");
356
357                 // combine the current compare options with the new locale ID and its first supported version
358                 info = (info & MaskCompareOpt) | unchecked((uint)lcid) | unchecked((uint)versionBits);
359             }
360         }
361
362         internal SqlCompareOptions SqlCompareOptions {
363             get {
364                 SqlCompareOptions options = SqlCompareOptions.None;
365                 if (0 != (info & IgnoreCase))
366                     options |= SqlCompareOptions.IgnoreCase;
367                 if (0 != (info & IgnoreNonSpace))
368                     options |= SqlCompareOptions.IgnoreNonSpace;
369                 if (0 != (info & IgnoreWidth))
370                     options |= SqlCompareOptions.IgnoreWidth;
371                 if (0 != (info & IgnoreKanaType))
372                     options |= SqlCompareOptions.IgnoreKanaType;
373                 if (0 != (info & BinarySort))
374                     options |= SqlCompareOptions.BinarySort;
375                 return options;
376             }
377             set {
378                 Debug.Assert((value & SqlString.x_iValidSqlCompareOptionMask) == value, "invalid set_SqlCompareOptions value");
379                 uint tmp = 0;
380                 if (0 != (value & SqlCompareOptions.IgnoreCase))
381                     tmp |= IgnoreCase;
382                 if (0 != (value & SqlCompareOptions.IgnoreNonSpace))
383                     tmp |= IgnoreNonSpace;
384                 if (0 != (value & SqlCompareOptions.IgnoreWidth))
385                     tmp |= IgnoreWidth;
386                 if (0 != (value & SqlCompareOptions.IgnoreKanaType))
387                     tmp |= IgnoreKanaType;
388                 if (0 != (value & SqlCompareOptions.BinarySort))
389                     tmp |= BinarySort;
390                 info = (info & MaskLcid) | tmp;
391             }
392         }
393
394         internal string TraceString() {
395             return String.Format(/*IFormatProvider*/ null, "(LCID={0}, Opts={1})", this.LCID, (int)this.SqlCompareOptions);
396         }
397
398         static internal bool AreSame(SqlCollation a, SqlCollation b) {
399             if (a == null || b == null) {
400                 return a == b;
401             }
402             else {
403                 return a.info == b.info && a.sortId == b.sortId;
404             }
405
406         }
407       
408     }
409
410     internal class RoutingInfo {
411         internal byte Protocol { get; private set; }
412         internal UInt16 Port { get; private set; }
413         internal string ServerName { get; private set; }
414
415         internal RoutingInfo(byte protocol, UInt16 port, string servername) {
416             Protocol = protocol;
417             Port = port;
418             ServerName = servername;
419         }
420     }
421
422     sealed internal class SqlEnvChange {
423         internal byte         type;
424         internal byte         oldLength;
425         internal int          newLength; // 7206 TDS changes makes this length an int
426         internal int          length;
427         internal string       newValue;
428         internal string       oldValue;
429         internal byte[]       newBinValue;
430         internal byte[]       oldBinValue;
431         internal long         newLongValue;
432         internal long         oldLongValue;
433         internal SqlCollation newCollation;
434         internal SqlCollation oldCollation;
435         internal RoutingInfo  newRoutingInfo;
436     }
437
438     sealed internal class SqlLogin {
439         internal SqlAuthenticationMethod authentication = SqlAuthenticationMethod.NotSpecified;               // Authentication type
440         internal int timeout;                                                       // login timeout
441         internal bool   userInstance     = false;                                   // user instance
442         internal string hostName         = "";                                      // client machine name
443         internal string userName         = "";                                      // user id
444         internal string password         = "";                                      // password
445         internal string applicationName  = "";                                      // application name
446         internal string serverName       = "";                                      // server name
447         internal string language         = "";                                      // initial language
448         internal string database         = "";                                      // initial database
449         internal string attachDBFilename = "";                                      // DB filename to be attached
450         internal string newPassword      = "";                                      // new password for reset password
451         internal bool   useReplication   = false;                                   // user login for replication
452         internal bool   useSSPI          = false;                                   // use integrated security
453         internal int    packetSize       = SqlConnectionString.DEFAULT.Packet_Size; // packet size
454         internal bool   readOnlyIntent   = false;                                   // read-only intent
455         internal SqlCredential credential;                                          // user id and password in SecureString
456         internal SecureString newSecurePassword;                                    // new password in SecureString for resetting pasword
457     }
458
459     sealed internal class SqlLoginAck {
460         internal string programName;
461         internal byte   majorVersion;
462         internal byte   minorVersion;
463         internal short  buildNum;
464         internal bool   isVersion8;
465         internal UInt32 tdsVersion;
466     }
467
468     sealed internal class SqlFedAuthInfo {
469         internal string spn;
470         internal string stsurl;
471         public override string ToString() {
472             return String.Format(CultureInfo.InvariantCulture, "STSURL: {0}, SPN: {1}", stsurl ?? String.Empty, spn ?? String.Empty);
473         }
474     }
475
476     sealed internal class SqlFedAuthToken {
477         internal UInt32 dataLen;
478         internal byte[] accessToken;
479         internal long expirationFileTime;
480     }
481
482     sealed internal class _SqlMetaData : SqlMetaDataPriv, ICloneable {
483
484         internal string             column;
485         internal string             baseColumn;
486         internal MultiPartTableName multiPartTableName;
487         internal readonly int       ordinal;
488         internal byte               updatability;     // two bit field (0 is read only, 1 is updatable, 2 is updatability unknown)
489         internal byte               tableNum;
490         internal bool               isDifferentName;
491         internal bool               isKey;
492         internal bool               isHidden;
493         internal bool               isExpression;
494         internal bool               isIdentity;
495         internal bool               isColumnSet;
496         internal byte               op;       // for altrow-columns only
497         internal ushort             operand;  // for altrow-columns only
498
499         internal _SqlMetaData(int ordinal) : base() {
500             this.ordinal = ordinal;
501         }
502
503         internal string serverName {
504             get {
505                 return multiPartTableName.ServerName;
506             }
507         }
508         internal string catalogName {
509             get {
510                 return multiPartTableName.CatalogName;
511             }
512         }
513         internal string schemaName {
514             get {
515                 return multiPartTableName.SchemaName;
516             }
517         }
518         internal string tableName {
519             get {
520                 return multiPartTableName.TableName;
521             }
522         }
523
524         internal bool IsNewKatmaiDateTimeType {
525             get {
526                 return SqlDbType.Date == type || SqlDbType.Time == type || SqlDbType.DateTime2 == type || SqlDbType.DateTimeOffset == type;
527             }
528         }
529
530         internal bool IsLargeUdt {
531             get {
532                 return type == SqlDbType.Udt && length == Int32.MaxValue;
533             }
534         }
535
536         public object Clone() {
537             _SqlMetaData result = new _SqlMetaData(ordinal);
538             result.CopyFrom(this);
539             result.column = column;
540             result.baseColumn = baseColumn;
541             result.multiPartTableName = multiPartTableName;
542             result.updatability = updatability;
543             result.tableNum = tableNum;
544             result.isDifferentName = isDifferentName;
545             result.isKey = isKey;
546             result.isHidden = isHidden;
547             result.isExpression = isExpression;
548             result.isIdentity = isIdentity;
549             result.isColumnSet = isColumnSet;
550             result.op = op;
551             result.operand = operand;
552             return result;
553         }
554     }
555
556     sealed internal class _SqlMetaDataSet : ICloneable {
557         internal ushort         id;             // for altrow-columns only
558         internal int[]          indexMap;
559         internal int            visibleColumns;
560         internal DataTable      schemaTable;
561         internal readonly SqlTceCipherInfoTable? cekTable; // table of "column encryption keys" used for this metadataset
562         internal readonly _SqlMetaData[] metaDataArray;
563
564         internal _SqlMetaDataSet(int count, SqlTceCipherInfoTable? cipherTable) {
565             cekTable = cipherTable;
566             metaDataArray = new _SqlMetaData[count];
567             for(int i = 0; i < metaDataArray.Length; ++i) {
568                 metaDataArray[i] = new _SqlMetaData(i);
569             }
570         }
571
572         private _SqlMetaDataSet(_SqlMetaDataSet original) {
573             this.id = original.id;
574             // although indexMap is not immutable, in practice it is initialized once and then passed around
575             this.indexMap = original.indexMap;
576             this.visibleColumns = original.visibleColumns;
577             this.schemaTable = original.schemaTable;
578             if (original.metaDataArray == null) {
579                 metaDataArray = null;
580             }
581             else {
582                 metaDataArray = new _SqlMetaData[original.metaDataArray.Length];
583                 for (int idx=0; idx<metaDataArray.Length; idx++) {
584                     metaDataArray[idx] = (_SqlMetaData)original.metaDataArray[idx].Clone();
585                 }
586             }
587         }
588
589         internal int Length {
590             get {
591                 return metaDataArray.Length;
592             }
593         }
594
595         internal _SqlMetaData this [int index] {
596             get {
597                 return metaDataArray[index];
598             }
599             set {
600                 Debug.Assert(null == value, "used only by SqlBulkCopy");
601                 metaDataArray[index] = value;
602             }
603         }
604
605         public object Clone() {
606             return new _SqlMetaDataSet(this);
607         }
608     }
609
610     sealed internal class _SqlMetaDataSetCollection : ICloneable {
611         private readonly List<_SqlMetaDataSet> altMetaDataSetArray;
612         internal _SqlMetaDataSet metaDataSet;
613
614         internal _SqlMetaDataSetCollection () {
615             altMetaDataSetArray = new List<_SqlMetaDataSet>();
616         }
617
618         internal void SetAltMetaData(_SqlMetaDataSet altMetaDataSet) {
619             // VSTFDEVDIV 479675: if altmetadata with same id is found, override it rather than adding a new one
620             int newId = altMetaDataSet.id;
621             for (int i = 0; i < altMetaDataSetArray.Count; i++) {
622                 if (altMetaDataSetArray[i].id == newId) {
623                     // override the existing metadata with the same id
624                     altMetaDataSetArray[i] = altMetaDataSet;
625                     return;
626                 }
627             }
628
629             // if we did not find metadata to override, add as new
630             altMetaDataSetArray.Add(altMetaDataSet);
631         }
632
633         internal _SqlMetaDataSet GetAltMetaData(int id) {
634             foreach (_SqlMetaDataSet altMetaDataSet in altMetaDataSetArray) {
635                 if (altMetaDataSet.id == id) {
636                     return altMetaDataSet;
637                 }
638             }
639             Debug.Assert (false, "Can't match up altMetaDataSet with given id");
640             return null;
641         }
642
643         public object Clone()
644         {
645             _SqlMetaDataSetCollection result = new _SqlMetaDataSetCollection();
646             result.metaDataSet = metaDataSet == null ? null : (_SqlMetaDataSet)metaDataSet.Clone();
647             foreach (_SqlMetaDataSet set in altMetaDataSetArray) {
648                 result.altMetaDataSetArray.Add((_SqlMetaDataSet)set.Clone());
649             }
650             return result;
651         }
652     }
653
654     /// <summary>
655     /// Represents Encryption related information of the cipher data.
656     /// </summary>
657     internal class SqlCipherMetadata {
658
659         /// <summary>
660         /// Cipher Info Entry.
661         /// </summary>
662         private SqlTceCipherInfoEntry? _sqlTceCipherInfoEntry;
663
664         /// <summary>
665         /// Encryption Algorithm Id.
666         /// </summary>
667         private readonly byte _cipherAlgorithmId;
668
669         /// <summary>
670         /// Encryption Algorithm Name.
671         /// </summary>
672         private readonly string _cipherAlgorithmName;
673
674         /// <summary>
675         /// Encryption Type.
676         /// </summary>
677         private readonly byte _encryptionType;
678
679         /// <summary>
680         /// Normalization Rule Version.
681         /// </summary>
682         private readonly byte _normalizationRuleVersion;
683         
684         /// <summary>
685         /// Encryption Algorithm Handle.
686         /// </summary>
687         private SqlClientEncryptionAlgorithm _sqlClientEncryptionAlgorithm;
688
689         /// <summary>
690         /// Sql Encryption Key Info.
691         /// </summary>
692         private SqlEncryptionKeyInfo? _sqlEncryptionKeyInfo;
693
694         /// <summary>
695         /// Ordinal (into the Cek Table).
696         /// </summary>
697         private readonly ushort _ordinal;
698
699         /// <summary>
700         /// Return the Encryption Info Entry.
701         /// </summary>
702         internal SqlTceCipherInfoEntry? EncryptionInfo {
703             get {
704                 return _sqlTceCipherInfoEntry;
705             }
706             set {
707                 Debug.Assert(!_sqlTceCipherInfoEntry.HasValue, "We can only set the EncryptionInfo once.");
708                 _sqlTceCipherInfoEntry = value;
709             }
710         }
711
712         /// <summary>
713         /// Return the cipher's encryption algorithm id.
714         /// </summary>
715         internal byte CipherAlgorithmId {
716             get {
717                 return _cipherAlgorithmId;
718             }
719         }
720
721         /// <summary>
722         /// Return the cipher's encryption algorithm name (could be null).
723         /// </summary>
724         internal string CipherAlgorithmName {
725             get {
726                 return _cipherAlgorithmName;
727             }
728         }
729
730         /// <summary>
731         /// Return EncryptionType (Deterministic, Randomized, etc.)
732         /// </summary>
733         internal byte EncryptionType {
734             get {
735                 return _encryptionType;
736             }
737         }
738
739         /// <summary>
740         /// Return normalization rule version.
741         /// </summary>
742         internal byte NormalizationRuleVersion {
743             get {
744                 return _normalizationRuleVersion;
745             }
746         }
747
748         /// <summary>
749         /// Return the cipher encyrption algorithm handle.
750         /// </summary>
751         internal SqlClientEncryptionAlgorithm CipherAlgorithm {
752             get {
753                 return _sqlClientEncryptionAlgorithm;
754             }
755             set {
756                 Debug.Assert(_sqlClientEncryptionAlgorithm == null, "_sqlClientEncryptionAlgorithm should not be set more than once.");
757                  _sqlClientEncryptionAlgorithm = value;
758             }
759         }
760
761         /// <summary>
762         /// Return Encryption Key Info.
763         /// </summary>
764         internal SqlEncryptionKeyInfo? EncryptionKeyInfo {
765             get {
766                 return _sqlEncryptionKeyInfo;
767             }
768
769             set {
770                 Debug.Assert(!_sqlEncryptionKeyInfo.HasValue, "_sqlEncryptionKeyInfo should not be set more than once.");
771                 _sqlEncryptionKeyInfo = value;
772             }
773         }
774
775         /// <summary>
776         /// Return Ordinal into Cek Table.
777         /// </summary>
778         internal ushort CekTableOrdinal {
779             get {
780                 return _ordinal;
781             }
782         }
783
784         /// <summary>
785         /// Constructor.
786         /// </summary>
787         /// <param name="sqlTceCipherInfoEntry"></param>
788         /// <param name="sqlClientEncryptionAlgorithm"></param>
789         /// <param name="cipherAlgorithmId"></param>
790         /// <param name="encryptionType"></param>
791         /// <param name="normalizationRuleVersion"></param>
792         internal SqlCipherMetadata (SqlTceCipherInfoEntry? sqlTceCipherInfoEntry,
793                                     ushort ordinal,
794                                     byte cipherAlgorithmId,
795                                     string cipherAlgorithmName,
796                                     byte encryptionType,
797                                     byte normalizationRuleVersion) {
798             Debug.Assert(!sqlTceCipherInfoEntry.Equals(default(SqlTceCipherInfoEntry)), "sqlTceCipherInfoEntry should not be un-initialized.");
799
800             _sqlTceCipherInfoEntry = sqlTceCipherInfoEntry;
801             _ordinal = ordinal;
802             _cipherAlgorithmId = cipherAlgorithmId;
803             _cipherAlgorithmName = cipherAlgorithmName;
804             _encryptionType = encryptionType;
805             _normalizationRuleVersion = normalizationRuleVersion;
806             _sqlEncryptionKeyInfo = null;
807         }
808
809         /// <summary>
810         /// Do we have an handle to the cipher encryption algorithm already ?
811         /// </summary>
812         /// <returns></returns>
813         internal bool IsAlgorithmInitialized() {
814             return (null != _sqlClientEncryptionAlgorithm) ? true : false;
815         }
816     }
817
818     internal class SqlMetaDataPriv {
819         internal SqlDbType    type;    // SqlDbType enum value
820         internal byte         tdsType; // underlying tds type
821         internal byte         precision = TdsEnums.UNKNOWN_PRECISION_SCALE; // give default of unknown (-1)
822         internal byte         scale     = TdsEnums.UNKNOWN_PRECISION_SCALE; // give default of unknown (-1)
823         internal int          length;
824         internal SqlCollation collation;
825         internal int          codePage;
826         internal Encoding     encoding;
827         internal bool         isNullable;
828         internal bool         isMultiValued = false;
829
830         // UDT specific metadata
831         // server metadata info
832         // additional temporary UDT meta data
833         internal string                 udtDatabaseName;
834         internal string                 udtSchemaName;
835         internal string                 udtTypeName;
836         internal string                 udtAssemblyQualifiedName;
837         // on demand
838         internal Type                   udtType;
839
840         // Xml specific metadata
841         internal string       xmlSchemaCollectionDatabase;
842         internal string       xmlSchemaCollectionOwningSchema;
843         internal string       xmlSchemaCollectionName;
844         internal MetaType     metaType; // cached metaType
845
846         // Structured type-specific metadata
847         internal string                 structuredTypeDatabaseName;
848         internal string                 structuredTypeSchemaName;
849         internal string                 structuredTypeName;
850         internal IList<SmiMetaData>     structuredFields;
851
852         internal bool                    isEncrypted; // TCE encrypted?
853         internal SqlMetaDataPriv         baseTI;   // for encrypted columns, represents the TYPE_INFO for plaintext value
854         internal SqlCipherMetadata       cipherMD; // Cipher related metadata for encrypted columns.
855         internal SqlMetaDataPriv() {
856         }
857
858         internal virtual void CopyFrom(SqlMetaDataPriv original) {
859             this.type = original.type;
860             this.tdsType = original.tdsType;
861             this.precision = original.precision;
862             this.scale = original.scale;
863             this.length = original.length;
864             this.collation = original.collation;
865             this.codePage = original.codePage;
866             this.encoding = original.encoding;
867             this.isNullable = original.isNullable;
868             this.isMultiValued = original.isMultiValued;
869             this.udtDatabaseName = original.udtDatabaseName;
870             this.udtSchemaName = original.udtSchemaName;
871             this.udtTypeName = original.udtTypeName;
872             this.udtAssemblyQualifiedName = original.udtAssemblyQualifiedName;
873             this.udtType = original.udtType;
874             this.xmlSchemaCollectionDatabase = original.xmlSchemaCollectionDatabase;
875             this.xmlSchemaCollectionOwningSchema = original.xmlSchemaCollectionOwningSchema;
876             this.xmlSchemaCollectionName = original.xmlSchemaCollectionName;
877             this.metaType = original.metaType;
878             // 
879
880
881             this.structuredTypeDatabaseName = original.structuredTypeDatabaseName;
882             this.structuredTypeSchemaName = original.structuredTypeSchemaName;
883             this.structuredTypeName = original.structuredTypeName;
884             this.structuredFields = original.structuredFields;
885         }
886
887         /// <summary>
888         /// Is the algorithm handle for the cipher encryption initialized ?
889         /// </summary>
890         /// <returns></returns>
891         internal bool IsAlgorithmInitialized() {
892             if (null != cipherMD) {
893                 return cipherMD.IsAlgorithmInitialized(); 
894             }
895
896             return false;
897         }
898
899         /// <summary>
900         /// Returns the normalization rule version byte.
901         /// </summary>
902         /// <returns></returns>
903         internal byte NormalizationRuleVersion {
904             get {
905                 if (null != cipherMD){
906                     return cipherMD.NormalizationRuleVersion; 
907                 }
908
909                 return 0x00;
910             }
911         }
912     }
913
914     /// <summary>
915     /// Class encapsulating additional information when sending encrypted input parameters.
916     /// </summary>
917     sealed internal class SqlColumnEncryptionInputParameterInfo
918     {
919         /// <summary>
920         /// Metadata of the parameter to write the TYPE_INFO of the unencrypted column data type.
921         /// </summary>
922         private readonly SmiParameterMetaData _smiParameterMetadata;
923
924         /// <summary>
925         /// Column encryption related metadata.
926         /// </summary>
927         private readonly SqlCipherMetadata _cipherMetadata;
928
929         /// <summary>
930         /// Serialized format for a subset of members.
931         /// Does not include _smiParameterMetadata's serialization.
932         /// </summary>
933         private readonly byte[] _serializedWireFormat;
934
935         /// <summary>
936         /// Return the SMI Parameter Metadata.
937         /// </summary>
938         internal SmiParameterMetaData ParameterMetadata {
939             get {
940                 return _smiParameterMetadata;
941             }
942         }
943
944         /// <summary>
945         /// Return the serialized format for some members.
946         /// This is pre-calculated and cached since members are immutable.
947         /// Does not include _smiParameterMetadata's serialization.
948         /// </summary>
949         internal byte[] SerializedWireFormat
950         {
951             get {
952                 return _serializedWireFormat;
953             }
954         }
955
956         /// <summary>
957         /// Constructor.
958         /// </summary>
959         /// <param name="smiParameterMetadata"></param>
960         /// <param name="cipherMetadata"></param>
961         internal SqlColumnEncryptionInputParameterInfo(SmiParameterMetaData smiParameterMetadata, SqlCipherMetadata cipherMetadata) {
962             Debug.Assert(smiParameterMetadata != null, "smiParameterMetadata should not be null.");
963             Debug.Assert(cipherMetadata != null, "cipherMetadata should not be null");
964             Debug.Assert(cipherMetadata.EncryptionKeyInfo.HasValue, "cipherMetadata.EncryptionKeyInfo.HasValue should be true.");
965
966             _smiParameterMetadata = smiParameterMetadata;
967             _cipherMetadata = cipherMetadata;
968             _serializedWireFormat = SerializeToWriteFormat();
969         }
970
971         /// <summary>
972         /// Serializes some data members to wire format.
973         /// </summary>
974         private byte[] SerializeToWriteFormat() {
975             int totalLength = 0;
976
977             // CipherAlgorithmId.
978             totalLength += sizeof(byte);
979
980             // Encryption Type.
981             totalLength += sizeof(byte);
982
983             // Database id of the encryption key.
984             totalLength += sizeof(int);
985
986             // Id of the encryption key.
987             totalLength += sizeof(int);
988
989             // Version of the encryption key.
990             totalLength += sizeof(int);
991
992             // Metadata version of the encryption key.
993             totalLength += _cipherMetadata.EncryptionKeyInfo.Value.cekMdVersion.Length;
994
995             // Normalization Rule Version.
996             totalLength += sizeof(byte);
997
998             byte[] serializedWireFormat = new byte[totalLength];
999
1000             // No:of bytes consumed till now. Running variable.
1001             int consumedBytes = 0;
1002
1003             // 1 - Write Cipher Algorithm Id.
1004             serializedWireFormat[consumedBytes++] = _cipherMetadata.CipherAlgorithmId;
1005
1006             // 2 - Write Encryption Type.
1007             serializedWireFormat[consumedBytes++] = _cipherMetadata.EncryptionType;
1008
1009             // 3 - Write the database id of the encryption key.
1010             SerializeIntIntoBuffer(_cipherMetadata.EncryptionKeyInfo.Value.databaseId, serializedWireFormat, ref consumedBytes);
1011
1012             // 4 - Write the id of the encryption key.
1013             SerializeIntIntoBuffer(_cipherMetadata.EncryptionKeyInfo.Value.cekId, serializedWireFormat, ref consumedBytes);
1014
1015             // 5 - Write the version of the encryption key.
1016             SerializeIntIntoBuffer(_cipherMetadata.EncryptionKeyInfo.Value.cekVersion, serializedWireFormat, ref consumedBytes);
1017
1018             // 6 - Write the metadata version of the encryption key.
1019             Buffer.BlockCopy(_cipherMetadata.EncryptionKeyInfo.Value.cekMdVersion, 0, serializedWireFormat, consumedBytes, _cipherMetadata.EncryptionKeyInfo.Value.cekMdVersion.Length);
1020             consumedBytes += _cipherMetadata.EncryptionKeyInfo.Value.cekMdVersion.Length;
1021
1022             // 7 - Write Normalization Rule Version.
1023             serializedWireFormat[consumedBytes++] = _cipherMetadata.NormalizationRuleVersion;
1024
1025             return serializedWireFormat;
1026         }
1027
1028         /// <summary>
1029         /// Serializes an int into the provided buffer and offset.
1030         /// </summary>
1031         private void SerializeIntIntoBuffer(int value, byte[] buffer, ref int offset) {
1032             buffer[offset++] = (byte)(value & 0xff);
1033             buffer[offset++] = (byte)((value >> 8) & 0xff);
1034             buffer[offset++] = (byte)((value >> 16) & 0xff);
1035             buffer[offset++] = (byte)((value >> 24) & 0xff);
1036         }
1037     }
1038
1039     sealed internal class _SqlRPC {
1040         internal string         rpcName;
1041         internal string         databaseName; // Used for UDTs
1042         internal ushort         ProcID;       // Used instead of name
1043         internal ushort         options;
1044         internal SqlParameter[] parameters;
1045         internal byte[]         paramoptions;
1046
1047         internal int?           recordsAffected;
1048         internal int            cumulativeRecordsAffected;
1049
1050         internal int            errorsIndexStart;
1051         internal int            errorsIndexEnd;
1052         internal SqlErrorCollection errors;
1053         
1054         internal int            warningsIndexStart;
1055         internal int            warningsIndexEnd;
1056         internal SqlErrorCollection warnings;
1057         internal bool           needsFetchParameterEncryptionMetadata;
1058         internal string GetCommandTextOrRpcName() {
1059             if (TdsEnums.RPC_PROCID_EXECUTESQL == ProcID) {
1060                 // Param 0 is the actual sql executing
1061                 return (string)parameters[0].Value;
1062             }
1063             else {
1064                 return rpcName;
1065             }
1066         }
1067     }
1068
1069     sealed internal class SqlReturnValue : SqlMetaDataPriv {
1070
1071         internal ushort    parmIndex;      //Yukon or later only
1072         internal string    parameter;
1073         internal readonly  SqlBuffer value;
1074
1075         internal SqlReturnValue() : base() {
1076             value = new SqlBuffer();
1077         }
1078     }
1079
1080     internal struct MultiPartTableName {
1081         private string _multipartName;
1082         private string _serverName;
1083         private string _catalogName;
1084         private string _schemaName;
1085         private string _tableName;
1086
1087         internal MultiPartTableName(string[] parts) {
1088             _multipartName = null;
1089             _serverName = parts[0];
1090             _catalogName = parts[1];
1091             _schemaName = parts[2];
1092             _tableName = parts[3];
1093         }
1094
1095         internal MultiPartTableName(string multipartName) {
1096             _multipartName = multipartName;
1097             _serverName = null;
1098             _catalogName = null;
1099             _schemaName = null;
1100             _tableName = null;
1101         }
1102
1103         internal string ServerName {
1104             get {
1105                 ParseMultipartName();
1106                 return _serverName;
1107             }
1108             set { _serverName = value; }
1109         }
1110         internal string CatalogName {
1111             get {
1112                 ParseMultipartName();
1113                 return _catalogName;
1114             }
1115             set { _catalogName = value; }
1116         }
1117         internal string SchemaName {
1118             get {
1119                 ParseMultipartName();
1120                 return _schemaName;
1121             }
1122             set { _schemaName = value; }
1123         }
1124         internal string TableName {
1125             get {
1126                 ParseMultipartName();
1127                 return _tableName;
1128             }
1129             set { _tableName = value; }
1130         }
1131
1132         private void ParseMultipartName() {
1133             if (null != _multipartName) {
1134                 string[] parts = MultipartIdentifier.ParseMultipartIdentifier(_multipartName, "[\"", "]\"", Res.SQL_TDSParserTableName, false);
1135                 _serverName = parts[0];
1136                 _catalogName = parts[1];
1137                 _schemaName = parts[2];
1138                 _tableName = parts[3];
1139                 _multipartName = null;
1140             }
1141         }
1142
1143         internal static readonly MultiPartTableName Null = new MultiPartTableName(new string[] {null, null, null, null});
1144     }
1145 }