2016-08-03 10:59:49 +00:00
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
// <copyright file="TdsParserHelperClasses.cs" company="Microsoft">
|
|
|
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
|
|
// </copyright>
|
2017-08-21 15:34:15 +00:00
|
|
|
// <owner current="true" primary="true">Microsoft</owner>
|
|
|
|
// <owner current="true" primary="false">Microsoft</owner>
|
2016-08-03 10:59:49 +00:00
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
namespace System.Data.SqlClient {
|
|
|
|
using System;
|
|
|
|
using System.Collections.Generic;
|
|
|
|
using System.Data;
|
|
|
|
using System.Data.Common;
|
|
|
|
using System.Data.ProviderBase;
|
|
|
|
using System.Data.Sql;
|
|
|
|
using System.Data.SqlTypes;
|
|
|
|
using System.Diagnostics;
|
|
|
|
using System.Reflection;
|
|
|
|
using System.Text;
|
|
|
|
using System.Threading;
|
|
|
|
using System.Security;
|
|
|
|
using System.Globalization;
|
|
|
|
|
|
|
|
using Microsoft.SqlServer.Server; // for SMI metadata
|
|
|
|
|
|
|
|
internal enum CallbackType {
|
|
|
|
Read = 0,
|
|
|
|
Write = 1
|
|
|
|
}
|
|
|
|
|
|
|
|
internal enum EncryptionOptions {
|
|
|
|
OFF,
|
|
|
|
ON,
|
|
|
|
NOT_SUP,
|
|
|
|
REQ,
|
|
|
|
LOGIN
|
|
|
|
}
|
|
|
|
|
|
|
|
internal enum PreLoginHandshakeStatus {
|
|
|
|
Successful,
|
|
|
|
InstanceFailure
|
|
|
|
}
|
|
|
|
|
|
|
|
internal enum PreLoginOptions {
|
|
|
|
VERSION,
|
|
|
|
ENCRYPT,
|
|
|
|
INSTANCE,
|
|
|
|
THREADID,
|
|
|
|
MARS,
|
|
|
|
TRACEID,
|
|
|
|
FEDAUTHREQUIRED,
|
|
|
|
NUMOPT,
|
|
|
|
LASTOPT = 255
|
|
|
|
}
|
|
|
|
|
|
|
|
internal enum RunBehavior {
|
|
|
|
UntilDone = 1, // 0001 binary
|
|
|
|
ReturnImmediately = 2, // 0010 binary
|
|
|
|
Clean = 5, // 0101 binary - Clean AND UntilDone
|
|
|
|
Attention = 13 // 1101 binary - Clean AND UntilDone AND Attention
|
|
|
|
}
|
|
|
|
|
|
|
|
internal enum TdsParserState {
|
|
|
|
Closed,
|
|
|
|
OpenNotLoggedIn,
|
|
|
|
OpenLoggedIn,
|
|
|
|
Broken,
|
|
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Struct encapsulating the data to be sent to the server as part of Federated Authentication Feature Extension.
|
|
|
|
/// </summary>
|
|
|
|
internal struct FederatedAuthenticationFeatureExtensionData
|
|
|
|
{
|
|
|
|
internal TdsEnums.FedAuthLibrary libraryType;
|
|
|
|
internal bool fedAuthRequiredPreLoginResponse;
|
|
|
|
internal SqlAuthenticationMethod authentication;
|
|
|
|
internal byte[] accessToken;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// <para> Represents a single encrypted value for a CEK. It contains the encrypted CEK,
|
|
|
|
/// the store type, name,the key path and encryption algorithm.</para>
|
|
|
|
/// </summary>
|
|
|
|
internal struct SqlEncryptionKeyInfo {
|
|
|
|
internal byte[] encryptedKey; // the encrypted "column encryption key"
|
|
|
|
internal int databaseId;
|
|
|
|
internal int cekId;
|
|
|
|
internal int cekVersion;
|
|
|
|
internal byte[] cekMdVersion;
|
|
|
|
internal string keyPath;
|
|
|
|
internal string keyStoreName;
|
|
|
|
internal string algorithmName;
|
|
|
|
internal byte normalizationRuleVersion;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// <para> Encapsulates one entry in the CipherInfo table sent as part of Colmetadata.
|
|
|
|
/// The same CEK is encrypted multiple times with different master keys (for master key
|
|
|
|
/// rotation scenario) We need to keep all these around until we can resolve the CEK
|
|
|
|
/// using the correct master key.</para>
|
|
|
|
/// </summary>
|
|
|
|
internal struct SqlTceCipherInfoEntry {
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// List of Column Encryption Key Information.
|
|
|
|
/// </summary>
|
|
|
|
private readonly List<SqlEncryptionKeyInfo> _columnEncryptionKeyValues;
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Key Ordinal.
|
|
|
|
/// </summary>
|
|
|
|
private readonly int _ordinal;
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Database ID
|
|
|
|
/// </summary>
|
|
|
|
private int _databaseId;
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Cek ID
|
|
|
|
/// </summary>
|
|
|
|
private int _cekId;
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Cek Version
|
|
|
|
/// </summary>
|
|
|
|
private int _cekVersion;
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Cek MD Version
|
|
|
|
/// </summary>
|
|
|
|
private byte[] _cekMdVersion;
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Return the ordinal.
|
|
|
|
/// </summary>
|
|
|
|
internal int Ordinal {
|
|
|
|
get {
|
|
|
|
return _ordinal;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Return the DatabaseID.
|
|
|
|
/// </summary>
|
|
|
|
internal int DatabaseId {
|
|
|
|
get {
|
|
|
|
return _databaseId;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Return the CEK ID.
|
|
|
|
/// </summary>
|
|
|
|
internal int CekId {
|
|
|
|
get {
|
|
|
|
return _cekId;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Return the CEK Version.
|
|
|
|
/// </summary>
|
|
|
|
internal int CekVersion {
|
|
|
|
get {
|
|
|
|
return _cekVersion;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Return the CEK MD Version.
|
|
|
|
/// </summary>
|
|
|
|
internal byte[] CekMdVersion {
|
|
|
|
get {
|
|
|
|
return _cekMdVersion;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Return the list of Column Encryption Key Values.
|
|
|
|
/// </summary>
|
|
|
|
internal List<SqlEncryptionKeyInfo> ColumnEncryptionKeyValues {
|
|
|
|
get {
|
|
|
|
return _columnEncryptionKeyValues;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Add an entry to the list of ColumnEncryptionKeyValues.
|
|
|
|
/// </summary>
|
|
|
|
/// <param name="encryptedKey"></param>
|
|
|
|
/// <param name="databaseId"></param>
|
|
|
|
/// <param name="cekId"></param>
|
|
|
|
/// <param name="cekVersion"></param>
|
|
|
|
/// <param name="cekMdVersion"></param>
|
|
|
|
/// <param name="keyPath"></param>
|
|
|
|
/// <param name="keyStoreName"></param>
|
|
|
|
/// <param name="algorithmName"></param>
|
|
|
|
internal void Add(byte[] encryptedKey, int databaseId, int cekId, int cekVersion, byte[] cekMdVersion, string keyPath, string keyStoreName, string algorithmName) {
|
|
|
|
|
|
|
|
Debug.Assert(_columnEncryptionKeyValues != null, "_columnEncryptionKeyValues should already be initialized.");
|
|
|
|
|
|
|
|
SqlEncryptionKeyInfo encryptionKey = new SqlEncryptionKeyInfo();
|
|
|
|
encryptionKey.encryptedKey = encryptedKey;
|
|
|
|
encryptionKey.databaseId = databaseId;
|
|
|
|
encryptionKey.cekId = cekId;
|
|
|
|
encryptionKey.cekVersion = cekVersion;
|
|
|
|
encryptionKey.cekMdVersion = cekMdVersion;
|
|
|
|
encryptionKey.keyPath = keyPath;
|
|
|
|
encryptionKey.keyStoreName = keyStoreName;
|
|
|
|
encryptionKey.algorithmName = algorithmName;
|
|
|
|
_columnEncryptionKeyValues.Add(encryptionKey);
|
|
|
|
|
|
|
|
if (0 == _databaseId) {
|
|
|
|
_databaseId = databaseId;
|
|
|
|
_cekId = cekId;
|
|
|
|
_cekVersion = cekVersion;
|
|
|
|
_cekMdVersion = cekMdVersion;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
Debug.Assert(_databaseId == databaseId);
|
|
|
|
Debug.Assert(_cekId == cekId);
|
|
|
|
Debug.Assert(_cekVersion == cekVersion);
|
|
|
|
Debug.Assert (_cekMdVersion != null && cekMdVersion != null && _cekMdVersion.Length == _cekMdVersion.Length);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Constructor.
|
|
|
|
/// </summary>
|
|
|
|
/// <param name="ordinal"></param>
|
|
|
|
internal SqlTceCipherInfoEntry(int ordinal = 0) : this() {
|
|
|
|
_ordinal = ordinal;
|
|
|
|
_databaseId = 0;
|
|
|
|
_cekId = 0;
|
|
|
|
_cekVersion = 0;
|
|
|
|
_cekMdVersion = null;
|
|
|
|
_columnEncryptionKeyValues = new List<SqlEncryptionKeyInfo>();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// <para> Represents a table with various CEKs used in a resultset. Each entry corresponds to one (unique) CEK. The CEK
|
|
|
|
/// may have been encrypted using multiple master keys (giving us multiple CEK values). All these values form one single
|
|
|
|
/// entry in this table.</para>
|
|
|
|
///</summary>
|
|
|
|
internal struct SqlTceCipherInfoTable {
|
|
|
|
private readonly SqlTceCipherInfoEntry [] keyList;
|
|
|
|
|
|
|
|
internal SqlTceCipherInfoTable (int tabSize) {
|
|
|
|
Debug.Assert (0 < tabSize, "Invalid Table Size");
|
|
|
|
keyList = new SqlTceCipherInfoEntry[tabSize];
|
|
|
|
}
|
|
|
|
|
|
|
|
internal SqlTceCipherInfoEntry this [int index] {
|
|
|
|
get {
|
|
|
|
Debug.Assert (index < keyList.Length, "Invalid index specified.");
|
|
|
|
return keyList[index];
|
|
|
|
}
|
|
|
|
set {
|
|
|
|
Debug.Assert (index < keyList.Length, "Invalid index specified.");
|
|
|
|
keyList[index] = value;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
internal int Size {
|
|
|
|
get {
|
|
|
|
return keyList.Length;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
sealed internal class SqlCollation {
|
|
|
|
// First 20 bits of info field represent the lcid, bits 21-25 are compare options
|
|
|
|
private const uint IgnoreCase = 1 << 20; // bit 21 - IgnoreCase
|
|
|
|
private const uint IgnoreNonSpace = 1 << 21; // bit 22 - IgnoreNonSpace / IgnoreAccent
|
|
|
|
private const uint IgnoreWidth = 1 << 22; // bit 23 - IgnoreWidth
|
|
|
|
private const uint IgnoreKanaType = 1 << 23; // bit 24 - IgnoreKanaType
|
|
|
|
private const uint BinarySort = 1 << 24; // bit 25 - BinarySort
|
|
|
|
|
|
|
|
internal const uint MaskLcid = 0xfffff;
|
|
|
|
private const int LcidVersionBitOffset = 28;
|
|
|
|
private const uint MaskLcidVersion = unchecked((uint)(0xf << LcidVersionBitOffset));
|
|
|
|
private const uint MaskCompareOpt = IgnoreCase | IgnoreNonSpace | IgnoreWidth | IgnoreKanaType | BinarySort;
|
|
|
|
|
|
|
|
internal uint info;
|
|
|
|
internal byte sortId;
|
|
|
|
|
|
|
|
static int FirstSupportedCollationVersion(int lcid)
|
|
|
|
{
|
|
|
|
// NOTE: switch-case works ~3 times faster in this case than search with Dictionary
|
|
|
|
switch (lcid)
|
|
|
|
{
|
|
|
|
case 1044: return 2; // Norwegian_100_BIN
|
|
|
|
case 1047: return 2; // Romansh_100_BIN
|
|
|
|
case 1056: return 2; // Urdu_100_BIN
|
|
|
|
case 1065: return 2; // Persian_100_BIN
|
|
|
|
case 1068: return 2; // Azeri_Latin_100_BIN
|
|
|
|
case 1070: return 2; // Upper_Sorbian_100_BIN
|
|
|
|
case 1071: return 1; // ----n_FYROM_90_BIN
|
|
|
|
case 1081: return 1; // Indic_General_90_BIN
|
|
|
|
case 1082: return 2; // Maltese_100_BIN
|
|
|
|
case 1083: return 2; // Sami_Norway_100_BIN
|
|
|
|
case 1087: return 1; // Kazakh_90_BIN
|
|
|
|
case 1090: return 2; // Turkmen_100_BIN
|
|
|
|
case 1091: return 1; // Uzbek_Latin_90_BIN
|
|
|
|
case 1092: return 1; // Tatar_90_BIN
|
|
|
|
case 1093: return 2; // Bengali_100_BIN
|
|
|
|
case 1101: return 2; // Assamese_100_BIN
|
|
|
|
case 1105: return 2; // Tibetan_100_BIN
|
|
|
|
case 1106: return 2; // Welsh_100_BIN
|
|
|
|
case 1107: return 2; // Khmer_100_BIN
|
|
|
|
case 1108: return 2; // Lao_100_BIN
|
|
|
|
case 1114: return 1; // Syriac_90_BIN
|
|
|
|
case 1121: return 2; // Nepali_100_BIN
|
|
|
|
case 1122: return 2; // Frisian_100_BIN
|
|
|
|
case 1123: return 2; // Pashto_100_BIN
|
|
|
|
case 1125: return 1; // Divehi_90_BIN
|
|
|
|
case 1133: return 2; // Bashkir_100_BIN
|
|
|
|
case 1146: return 2; // Mapudungan_100_BIN
|
|
|
|
case 1148: return 2; // Mohawk_100_BIN
|
|
|
|
case 1150: return 2; // Breton_100_BIN
|
|
|
|
case 1152: return 2; // Uighur_100_BIN
|
|
|
|
case 1153: return 2; // Maori_100_BIN
|
|
|
|
case 1155: return 2; // Corsican_100_BIN
|
|
|
|
case 1157: return 2; // Yakut_100_BIN
|
|
|
|
case 1164: return 2; // Dari_100_BIN
|
|
|
|
case 2074: return 2; // Serbian_Latin_100_BIN
|
|
|
|
case 2092: return 2; // Azeri_Cyrillic_100_BIN
|
|
|
|
case 2107: return 2; // Sami_Sweden_Finland_100_BIN
|
|
|
|
case 2143: return 2; // Tamazight_100_BIN
|
|
|
|
case 3076: return 1; // Chinese_Hong_Kong_Stroke_90_BIN
|
|
|
|
case 3098: return 2; // Serbian_Cyrillic_100_BIN
|
|
|
|
case 5124: return 2; // Chinese_Traditional_Pinyin_100_BIN
|
|
|
|
case 5146: return 2; // Bosnian_Latin_100_BIN
|
|
|
|
case 8218: return 2; // Bosnian_Cyrillic_100_BIN
|
|
|
|
|
|
|
|
default: return 0; // other LCIDs have collation with version 0
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
internal int LCID {
|
|
|
|
// First 20 bits of info field represent the lcid
|
|
|
|
get {
|
|
|
|
return unchecked((int)(info & MaskLcid));
|
|
|
|
}
|
|
|
|
set {
|
|
|
|
int lcid = value & (int)MaskLcid;
|
|
|
|
Debug.Assert(lcid == value, "invalid set_LCID value");
|
|
|
|
|
|
|
|
// VSTFDEVDIV 479474: some new Katmai LCIDs do not have collation with version = 0
|
|
|
|
// since user has no way to specify collation version, we set the first (minimal) supported version for these collations
|
|
|
|
int versionBits = FirstSupportedCollationVersion(lcid) << LcidVersionBitOffset;
|
|
|
|
Debug.Assert((versionBits & MaskLcidVersion) == versionBits, "invalid version returned by FirstSupportedCollationVersion");
|
|
|
|
|
|
|
|
// combine the current compare options with the new locale ID and its first supported version
|
|
|
|
info = (info & MaskCompareOpt) | unchecked((uint)lcid) | unchecked((uint)versionBits);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
internal SqlCompareOptions SqlCompareOptions {
|
|
|
|
get {
|
|
|
|
SqlCompareOptions options = SqlCompareOptions.None;
|
|
|
|
if (0 != (info & IgnoreCase))
|
|
|
|
options |= SqlCompareOptions.IgnoreCase;
|
|
|
|
if (0 != (info & IgnoreNonSpace))
|
|
|
|
options |= SqlCompareOptions.IgnoreNonSpace;
|
|
|
|
if (0 != (info & IgnoreWidth))
|
|
|
|
options |= SqlCompareOptions.IgnoreWidth;
|
|
|
|
if (0 != (info & IgnoreKanaType))
|
|
|
|
options |= SqlCompareOptions.IgnoreKanaType;
|
|
|
|
if (0 != (info & BinarySort))
|
|
|
|
options |= SqlCompareOptions.BinarySort;
|
|
|
|
return options;
|
|
|
|
}
|
|
|
|
set {
|
|
|
|
Debug.Assert((value & SqlString.x_iValidSqlCompareOptionMask) == value, "invalid set_SqlCompareOptions value");
|
|
|
|
uint tmp = 0;
|
|
|
|
if (0 != (value & SqlCompareOptions.IgnoreCase))
|
|
|
|
tmp |= IgnoreCase;
|
|
|
|
if (0 != (value & SqlCompareOptions.IgnoreNonSpace))
|
|
|
|
tmp |= IgnoreNonSpace;
|
|
|
|
if (0 != (value & SqlCompareOptions.IgnoreWidth))
|
|
|
|
tmp |= IgnoreWidth;
|
|
|
|
if (0 != (value & SqlCompareOptions.IgnoreKanaType))
|
|
|
|
tmp |= IgnoreKanaType;
|
|
|
|
if (0 != (value & SqlCompareOptions.BinarySort))
|
|
|
|
tmp |= BinarySort;
|
|
|
|
info = (info & MaskLcid) | tmp;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
internal string TraceString() {
|
|
|
|
return String.Format(/*IFormatProvider*/ null, "(LCID={0}, Opts={1})", this.LCID, (int)this.SqlCompareOptions);
|
|
|
|
}
|
|
|
|
|
|
|
|
static internal bool AreSame(SqlCollation a, SqlCollation b) {
|
|
|
|
if (a == null || b == null) {
|
|
|
|
return a == b;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return a.info == b.info && a.sortId == b.sortId;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
internal class RoutingInfo {
|
|
|
|
internal byte Protocol { get; private set; }
|
|
|
|
internal UInt16 Port { get; private set; }
|
|
|
|
internal string ServerName { get; private set; }
|
|
|
|
|
|
|
|
internal RoutingInfo(byte protocol, UInt16 port, string servername) {
|
|
|
|
Protocol = protocol;
|
|
|
|
Port = port;
|
|
|
|
ServerName = servername;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
sealed internal class SqlEnvChange {
|
|
|
|
internal byte type;
|
|
|
|
internal byte oldLength;
|
|
|
|
internal int newLength; // 7206 TDS changes makes this length an int
|
|
|
|
internal int length;
|
|
|
|
internal string newValue;
|
|
|
|
internal string oldValue;
|
|
|
|
internal byte[] newBinValue;
|
|
|
|
internal byte[] oldBinValue;
|
|
|
|
internal long newLongValue;
|
|
|
|
internal long oldLongValue;
|
|
|
|
internal SqlCollation newCollation;
|
|
|
|
internal SqlCollation oldCollation;
|
|
|
|
internal RoutingInfo newRoutingInfo;
|
|
|
|
}
|
|
|
|
|
|
|
|
sealed internal class SqlLogin {
|
|
|
|
internal SqlAuthenticationMethod authentication = SqlAuthenticationMethod.NotSpecified; // Authentication type
|
|
|
|
internal int timeout; // login timeout
|
|
|
|
internal bool userInstance = false; // user instance
|
|
|
|
internal string hostName = ""; // client machine name
|
|
|
|
internal string userName = ""; // user id
|
|
|
|
internal string password = ""; // password
|
|
|
|
internal string applicationName = ""; // application name
|
|
|
|
internal string serverName = ""; // server name
|
|
|
|
internal string language = ""; // initial language
|
|
|
|
internal string database = ""; // initial database
|
|
|
|
internal string attachDBFilename = ""; // DB filename to be attached
|
|
|
|
internal string newPassword = ""; // new password for reset password
|
|
|
|
internal bool useReplication = false; // user login for replication
|
|
|
|
internal bool useSSPI = false; // use integrated security
|
|
|
|
internal int packetSize = SqlConnectionString.DEFAULT.Packet_Size; // packet size
|
|
|
|
internal bool readOnlyIntent = false; // read-only intent
|
|
|
|
internal SqlCredential credential; // user id and password in SecureString
|
|
|
|
internal SecureString newSecurePassword; // new password in SecureString for resetting pasword
|
|
|
|
}
|
|
|
|
|
|
|
|
sealed internal class SqlLoginAck {
|
|
|
|
internal string programName;
|
|
|
|
internal byte majorVersion;
|
|
|
|
internal byte minorVersion;
|
|
|
|
internal short buildNum;
|
|
|
|
internal bool isVersion8;
|
|
|
|
internal UInt32 tdsVersion;
|
|
|
|
}
|
|
|
|
|
|
|
|
sealed internal class SqlFedAuthInfo {
|
|
|
|
internal string spn;
|
|
|
|
internal string stsurl;
|
|
|
|
public override string ToString() {
|
|
|
|
return String.Format(CultureInfo.InvariantCulture, "STSURL: {0}, SPN: {1}", stsurl ?? String.Empty, spn ?? String.Empty);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
sealed internal class SqlFedAuthToken {
|
|
|
|
internal UInt32 dataLen;
|
|
|
|
internal byte[] accessToken;
|
|
|
|
internal long expirationFileTime;
|
|
|
|
}
|
|
|
|
|
|
|
|
sealed internal class _SqlMetaData : SqlMetaDataPriv, ICloneable {
|
|
|
|
|
|
|
|
internal string column;
|
|
|
|
internal string baseColumn;
|
|
|
|
internal MultiPartTableName multiPartTableName;
|
|
|
|
internal readonly int ordinal;
|
|
|
|
internal byte updatability; // two bit field (0 is read only, 1 is updatable, 2 is updatability unknown)
|
|
|
|
internal byte tableNum;
|
|
|
|
internal bool isDifferentName;
|
|
|
|
internal bool isKey;
|
|
|
|
internal bool isHidden;
|
|
|
|
internal bool isExpression;
|
|
|
|
internal bool isIdentity;
|
|
|
|
internal bool isColumnSet;
|
|
|
|
internal byte op; // for altrow-columns only
|
|
|
|
internal ushort operand; // for altrow-columns only
|
|
|
|
|
|
|
|
internal _SqlMetaData(int ordinal) : base() {
|
|
|
|
this.ordinal = ordinal;
|
|
|
|
}
|
|
|
|
|
|
|
|
internal string serverName {
|
|
|
|
get {
|
|
|
|
return multiPartTableName.ServerName;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
internal string catalogName {
|
|
|
|
get {
|
|
|
|
return multiPartTableName.CatalogName;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
internal string schemaName {
|
|
|
|
get {
|
|
|
|
return multiPartTableName.SchemaName;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
internal string tableName {
|
|
|
|
get {
|
|
|
|
return multiPartTableName.TableName;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
internal bool IsNewKatmaiDateTimeType {
|
|
|
|
get {
|
|
|
|
return SqlDbType.Date == type || SqlDbType.Time == type || SqlDbType.DateTime2 == type || SqlDbType.DateTimeOffset == type;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
internal bool IsLargeUdt {
|
|
|
|
get {
|
|
|
|
return type == SqlDbType.Udt && length == Int32.MaxValue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public object Clone() {
|
|
|
|
_SqlMetaData result = new _SqlMetaData(ordinal);
|
|
|
|
result.CopyFrom(this);
|
|
|
|
result.column = column;
|
|
|
|
result.baseColumn = baseColumn;
|
|
|
|
result.multiPartTableName = multiPartTableName;
|
|
|
|
result.updatability = updatability;
|
|
|
|
result.tableNum = tableNum;
|
|
|
|
result.isDifferentName = isDifferentName;
|
|
|
|
result.isKey = isKey;
|
|
|
|
result.isHidden = isHidden;
|
|
|
|
result.isExpression = isExpression;
|
|
|
|
result.isIdentity = isIdentity;
|
|
|
|
result.isColumnSet = isColumnSet;
|
|
|
|
result.op = op;
|
|
|
|
result.operand = operand;
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
sealed internal class _SqlMetaDataSet : ICloneable {
|
|
|
|
internal ushort id; // for altrow-columns only
|
|
|
|
internal int[] indexMap;
|
|
|
|
internal int visibleColumns;
|
|
|
|
internal DataTable schemaTable;
|
|
|
|
internal readonly SqlTceCipherInfoTable? cekTable; // table of "column encryption keys" used for this metadataset
|
|
|
|
internal readonly _SqlMetaData[] metaDataArray;
|
|
|
|
|
|
|
|
internal _SqlMetaDataSet(int count, SqlTceCipherInfoTable? cipherTable) {
|
|
|
|
cekTable = cipherTable;
|
|
|
|
metaDataArray = new _SqlMetaData[count];
|
|
|
|
for(int i = 0; i < metaDataArray.Length; ++i) {
|
|
|
|
metaDataArray[i] = new _SqlMetaData(i);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private _SqlMetaDataSet(_SqlMetaDataSet original) {
|
|
|
|
this.id = original.id;
|
|
|
|
// although indexMap is not immutable, in practice it is initialized once and then passed around
|
|
|
|
this.indexMap = original.indexMap;
|
|
|
|
this.visibleColumns = original.visibleColumns;
|
|
|
|
this.schemaTable = original.schemaTable;
|
|
|
|
if (original.metaDataArray == null) {
|
|
|
|
metaDataArray = null;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
metaDataArray = new _SqlMetaData[original.metaDataArray.Length];
|
|
|
|
for (int idx=0; idx<metaDataArray.Length; idx++) {
|
|
|
|
metaDataArray[idx] = (_SqlMetaData)original.metaDataArray[idx].Clone();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
internal int Length {
|
|
|
|
get {
|
|
|
|
return metaDataArray.Length;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
internal _SqlMetaData this [int index] {
|
|
|
|
get {
|
|
|
|
return metaDataArray[index];
|
|
|
|
}
|
|
|
|
set {
|
|
|
|
Debug.Assert(null == value, "used only by SqlBulkCopy");
|
|
|
|
metaDataArray[index] = value;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public object Clone() {
|
|
|
|
return new _SqlMetaDataSet(this);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
sealed internal class _SqlMetaDataSetCollection : ICloneable {
|
|
|
|
private readonly List<_SqlMetaDataSet> altMetaDataSetArray;
|
|
|
|
internal _SqlMetaDataSet metaDataSet;
|
|
|
|
|
|
|
|
internal _SqlMetaDataSetCollection () {
|
|
|
|
altMetaDataSetArray = new List<_SqlMetaDataSet>();
|
|
|
|
}
|
|
|
|
|
|
|
|
internal void SetAltMetaData(_SqlMetaDataSet altMetaDataSet) {
|
|
|
|
// VSTFDEVDIV 479675: if altmetadata with same id is found, override it rather than adding a new one
|
|
|
|
int newId = altMetaDataSet.id;
|
|
|
|
for (int i = 0; i < altMetaDataSetArray.Count; i++) {
|
|
|
|
if (altMetaDataSetArray[i].id == newId) {
|
|
|
|
// override the existing metadata with the same id
|
|
|
|
altMetaDataSetArray[i] = altMetaDataSet;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// if we did not find metadata to override, add as new
|
|
|
|
altMetaDataSetArray.Add(altMetaDataSet);
|
|
|
|
}
|
|
|
|
|
|
|
|
internal _SqlMetaDataSet GetAltMetaData(int id) {
|
|
|
|
foreach (_SqlMetaDataSet altMetaDataSet in altMetaDataSetArray) {
|
|
|
|
if (altMetaDataSet.id == id) {
|
|
|
|
return altMetaDataSet;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Debug.Assert (false, "Can't match up altMetaDataSet with given id");
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
public object Clone()
|
|
|
|
{
|
|
|
|
_SqlMetaDataSetCollection result = new _SqlMetaDataSetCollection();
|
|
|
|
result.metaDataSet = metaDataSet == null ? null : (_SqlMetaDataSet)metaDataSet.Clone();
|
|
|
|
foreach (_SqlMetaDataSet set in altMetaDataSetArray) {
|
|
|
|
result.altMetaDataSetArray.Add((_SqlMetaDataSet)set.Clone());
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Represents Encryption related information of the cipher data.
|
|
|
|
/// </summary>
|
|
|
|
internal class SqlCipherMetadata {
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Cipher Info Entry.
|
|
|
|
/// </summary>
|
|
|
|
private SqlTceCipherInfoEntry? _sqlTceCipherInfoEntry;
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Encryption Algorithm Id.
|
|
|
|
/// </summary>
|
|
|
|
private readonly byte _cipherAlgorithmId;
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Encryption Algorithm Name.
|
|
|
|
/// </summary>
|
|
|
|
private readonly string _cipherAlgorithmName;
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Encryption Type.
|
|
|
|
/// </summary>
|
|
|
|
private readonly byte _encryptionType;
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Normalization Rule Version.
|
|
|
|
/// </summary>
|
|
|
|
private readonly byte _normalizationRuleVersion;
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Encryption Algorithm Handle.
|
|
|
|
/// </summary>
|
|
|
|
private SqlClientEncryptionAlgorithm _sqlClientEncryptionAlgorithm;
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Sql Encryption Key Info.
|
|
|
|
/// </summary>
|
|
|
|
private SqlEncryptionKeyInfo? _sqlEncryptionKeyInfo;
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Ordinal (into the Cek Table).
|
|
|
|
/// </summary>
|
|
|
|
private readonly ushort _ordinal;
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Return the Encryption Info Entry.
|
|
|
|
/// </summary>
|
|
|
|
internal SqlTceCipherInfoEntry? EncryptionInfo {
|
|
|
|
get {
|
|
|
|
return _sqlTceCipherInfoEntry;
|
|
|
|
}
|
|
|
|
set {
|
|
|
|
Debug.Assert(!_sqlTceCipherInfoEntry.HasValue, "We can only set the EncryptionInfo once.");
|
|
|
|
_sqlTceCipherInfoEntry = value;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Return the cipher's encryption algorithm id.
|
|
|
|
/// </summary>
|
|
|
|
internal byte CipherAlgorithmId {
|
|
|
|
get {
|
|
|
|
return _cipherAlgorithmId;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Return the cipher's encryption algorithm name (could be null).
|
|
|
|
/// </summary>
|
|
|
|
internal string CipherAlgorithmName {
|
|
|
|
get {
|
|
|
|
return _cipherAlgorithmName;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Return EncryptionType (Deterministic, Randomized, etc.)
|
|
|
|
/// </summary>
|
|
|
|
internal byte EncryptionType {
|
|
|
|
get {
|
|
|
|
return _encryptionType;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Return normalization rule version.
|
|
|
|
/// </summary>
|
|
|
|
internal byte NormalizationRuleVersion {
|
|
|
|
get {
|
|
|
|
return _normalizationRuleVersion;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Return the cipher encyrption algorithm handle.
|
|
|
|
/// </summary>
|
|
|
|
internal SqlClientEncryptionAlgorithm CipherAlgorithm {
|
|
|
|
get {
|
|
|
|
return _sqlClientEncryptionAlgorithm;
|
|
|
|
}
|
|
|
|
set {
|
|
|
|
Debug.Assert(_sqlClientEncryptionAlgorithm == null, "_sqlClientEncryptionAlgorithm should not be set more than once.");
|
|
|
|
_sqlClientEncryptionAlgorithm = value;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Return Encryption Key Info.
|
|
|
|
/// </summary>
|
|
|
|
internal SqlEncryptionKeyInfo? EncryptionKeyInfo {
|
|
|
|
get {
|
|
|
|
return _sqlEncryptionKeyInfo;
|
|
|
|
}
|
|
|
|
|
|
|
|
set {
|
|
|
|
Debug.Assert(!_sqlEncryptionKeyInfo.HasValue, "_sqlEncryptionKeyInfo should not be set more than once.");
|
|
|
|
_sqlEncryptionKeyInfo = value;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Return Ordinal into Cek Table.
|
|
|
|
/// </summary>
|
|
|
|
internal ushort CekTableOrdinal {
|
|
|
|
get {
|
|
|
|
return _ordinal;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Constructor.
|
|
|
|
/// </summary>
|
|
|
|
/// <param name="sqlTceCipherInfoEntry"></param>
|
|
|
|
/// <param name="sqlClientEncryptionAlgorithm"></param>
|
|
|
|
/// <param name="cipherAlgorithmId"></param>
|
|
|
|
/// <param name="encryptionType"></param>
|
|
|
|
/// <param name="normalizationRuleVersion"></param>
|
|
|
|
internal SqlCipherMetadata (SqlTceCipherInfoEntry? sqlTceCipherInfoEntry,
|
|
|
|
ushort ordinal,
|
|
|
|
byte cipherAlgorithmId,
|
|
|
|
string cipherAlgorithmName,
|
|
|
|
byte encryptionType,
|
|
|
|
byte normalizationRuleVersion) {
|
|
|
|
Debug.Assert(!sqlTceCipherInfoEntry.Equals(default(SqlTceCipherInfoEntry)), "sqlTceCipherInfoEntry should not be un-initialized.");
|
|
|
|
|
|
|
|
_sqlTceCipherInfoEntry = sqlTceCipherInfoEntry;
|
|
|
|
_ordinal = ordinal;
|
|
|
|
_cipherAlgorithmId = cipherAlgorithmId;
|
|
|
|
_cipherAlgorithmName = cipherAlgorithmName;
|
|
|
|
_encryptionType = encryptionType;
|
|
|
|
_normalizationRuleVersion = normalizationRuleVersion;
|
|
|
|
_sqlEncryptionKeyInfo = null;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Do we have an handle to the cipher encryption algorithm already ?
|
|
|
|
/// </summary>
|
|
|
|
/// <returns></returns>
|
|
|
|
internal bool IsAlgorithmInitialized() {
|
|
|
|
return (null != _sqlClientEncryptionAlgorithm) ? true : false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
internal class SqlMetaDataPriv {
|
|
|
|
internal SqlDbType type; // SqlDbType enum value
|
|
|
|
internal byte tdsType; // underlying tds type
|
|
|
|
internal byte precision = TdsEnums.UNKNOWN_PRECISION_SCALE; // give default of unknown (-1)
|
|
|
|
internal byte scale = TdsEnums.UNKNOWN_PRECISION_SCALE; // give default of unknown (-1)
|
|
|
|
internal int length;
|
|
|
|
internal SqlCollation collation;
|
|
|
|
internal int codePage;
|
|
|
|
internal Encoding encoding;
|
|
|
|
internal bool isNullable;
|
|
|
|
internal bool isMultiValued = false;
|
|
|
|
|
|
|
|
// UDT specific metadata
|
|
|
|
// server metadata info
|
|
|
|
// additional temporary UDT meta data
|
|
|
|
internal string udtDatabaseName;
|
|
|
|
internal string udtSchemaName;
|
|
|
|
internal string udtTypeName;
|
|
|
|
internal string udtAssemblyQualifiedName;
|
|
|
|
// on demand
|
|
|
|
internal Type udtType;
|
|
|
|
|
|
|
|
// Xml specific metadata
|
|
|
|
internal string xmlSchemaCollectionDatabase;
|
|
|
|
internal string xmlSchemaCollectionOwningSchema;
|
|
|
|
internal string xmlSchemaCollectionName;
|
|
|
|
internal MetaType metaType; // cached metaType
|
|
|
|
|
|
|
|
// Structured type-specific metadata
|
|
|
|
internal string structuredTypeDatabaseName;
|
|
|
|
internal string structuredTypeSchemaName;
|
|
|
|
internal string structuredTypeName;
|
|
|
|
internal IList<SmiMetaData> structuredFields;
|
|
|
|
|
|
|
|
internal bool isEncrypted; // TCE encrypted?
|
|
|
|
internal SqlMetaDataPriv baseTI; // for encrypted columns, represents the TYPE_INFO for plaintext value
|
|
|
|
internal SqlCipherMetadata cipherMD; // Cipher related metadata for encrypted columns.
|
|
|
|
internal SqlMetaDataPriv() {
|
|
|
|
}
|
|
|
|
|
|
|
|
internal virtual void CopyFrom(SqlMetaDataPriv original) {
|
|
|
|
this.type = original.type;
|
|
|
|
this.tdsType = original.tdsType;
|
|
|
|
this.precision = original.precision;
|
|
|
|
this.scale = original.scale;
|
|
|
|
this.length = original.length;
|
|
|
|
this.collation = original.collation;
|
|
|
|
this.codePage = original.codePage;
|
|
|
|
this.encoding = original.encoding;
|
|
|
|
this.isNullable = original.isNullable;
|
|
|
|
this.isMultiValued = original.isMultiValued;
|
|
|
|
this.udtDatabaseName = original.udtDatabaseName;
|
|
|
|
this.udtSchemaName = original.udtSchemaName;
|
|
|
|
this.udtTypeName = original.udtTypeName;
|
|
|
|
this.udtAssemblyQualifiedName = original.udtAssemblyQualifiedName;
|
|
|
|
this.udtType = original.udtType;
|
|
|
|
this.xmlSchemaCollectionDatabase = original.xmlSchemaCollectionDatabase;
|
|
|
|
this.xmlSchemaCollectionOwningSchema = original.xmlSchemaCollectionOwningSchema;
|
|
|
|
this.xmlSchemaCollectionName = original.xmlSchemaCollectionName;
|
|
|
|
this.metaType = original.metaType;
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
|
|
this.structuredTypeDatabaseName = original.structuredTypeDatabaseName;
|
|
|
|
this.structuredTypeSchemaName = original.structuredTypeSchemaName;
|
|
|
|
this.structuredTypeName = original.structuredTypeName;
|
|
|
|
this.structuredFields = original.structuredFields;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Is the algorithm handle for the cipher encryption initialized ?
|
|
|
|
/// </summary>
|
|
|
|
/// <returns></returns>
|
|
|
|
internal bool IsAlgorithmInitialized() {
|
|
|
|
if (null != cipherMD) {
|
|
|
|
return cipherMD.IsAlgorithmInitialized();
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Returns the normalization rule version byte.
|
|
|
|
/// </summary>
|
|
|
|
/// <returns></returns>
|
|
|
|
internal byte NormalizationRuleVersion {
|
|
|
|
get {
|
|
|
|
if (null != cipherMD){
|
|
|
|
return cipherMD.NormalizationRuleVersion;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0x00;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Class encapsulating additional information when sending encrypted input parameters.
|
|
|
|
/// </summary>
|
|
|
|
sealed internal class SqlColumnEncryptionInputParameterInfo
|
|
|
|
{
|
|
|
|
/// <summary>
|
|
|
|
/// Metadata of the parameter to write the TYPE_INFO of the unencrypted column data type.
|
|
|
|
/// </summary>
|
|
|
|
private readonly SmiParameterMetaData _smiParameterMetadata;
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Column encryption related metadata.
|
|
|
|
/// </summary>
|
|
|
|
private readonly SqlCipherMetadata _cipherMetadata;
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Serialized format for a subset of members.
|
|
|
|
/// Does not include _smiParameterMetadata's serialization.
|
|
|
|
/// </summary>
|
|
|
|
private readonly byte[] _serializedWireFormat;
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Return the SMI Parameter Metadata.
|
|
|
|
/// </summary>
|
|
|
|
internal SmiParameterMetaData ParameterMetadata {
|
|
|
|
get {
|
|
|
|
return _smiParameterMetadata;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Return the serialized format for some members.
|
|
|
|
/// This is pre-calculated and cached since members are immutable.
|
|
|
|
/// Does not include _smiParameterMetadata's serialization.
|
|
|
|
/// </summary>
|
|
|
|
internal byte[] SerializedWireFormat
|
|
|
|
{
|
|
|
|
get {
|
|
|
|
return _serializedWireFormat;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Constructor.
|
|
|
|
/// </summary>
|
|
|
|
/// <param name="smiParameterMetadata"></param>
|
|
|
|
/// <param name="cipherMetadata"></param>
|
|
|
|
internal SqlColumnEncryptionInputParameterInfo(SmiParameterMetaData smiParameterMetadata, SqlCipherMetadata cipherMetadata) {
|
|
|
|
Debug.Assert(smiParameterMetadata != null, "smiParameterMetadata should not be null.");
|
|
|
|
Debug.Assert(cipherMetadata != null, "cipherMetadata should not be null");
|
|
|
|
Debug.Assert(cipherMetadata.EncryptionKeyInfo.HasValue, "cipherMetadata.EncryptionKeyInfo.HasValue should be true.");
|
|
|
|
|
|
|
|
_smiParameterMetadata = smiParameterMetadata;
|
|
|
|
_cipherMetadata = cipherMetadata;
|
|
|
|
_serializedWireFormat = SerializeToWriteFormat();
|
|
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Serializes some data members to wire format.
|
|
|
|
/// </summary>
|
|
|
|
private byte[] SerializeToWriteFormat() {
|
|
|
|
int totalLength = 0;
|
|
|
|
|
|
|
|
// CipherAlgorithmId.
|
|
|
|
totalLength += sizeof(byte);
|
|
|
|
|
|
|
|
// Encryption Type.
|
|
|
|
totalLength += sizeof(byte);
|
|
|
|
|
|
|
|
// Database id of the encryption key.
|
|
|
|
totalLength += sizeof(int);
|
|
|
|
|
|
|
|
// Id of the encryption key.
|
|
|
|
totalLength += sizeof(int);
|
|
|
|
|
|
|
|
// Version of the encryption key.
|
|
|
|
totalLength += sizeof(int);
|
|
|
|
|
|
|
|
// Metadata version of the encryption key.
|
|
|
|
totalLength += _cipherMetadata.EncryptionKeyInfo.Value.cekMdVersion.Length;
|
|
|
|
|
|
|
|
// Normalization Rule Version.
|
|
|
|
totalLength += sizeof(byte);
|
|
|
|
|
|
|
|
byte[] serializedWireFormat = new byte[totalLength];
|
|
|
|
|
|
|
|
// No:of bytes consumed till now. Running variable.
|
|
|
|
int consumedBytes = 0;
|
|
|
|
|
|
|
|
// 1 - Write Cipher Algorithm Id.
|
|
|
|
serializedWireFormat[consumedBytes++] = _cipherMetadata.CipherAlgorithmId;
|
|
|
|
|
|
|
|
// 2 - Write Encryption Type.
|
|
|
|
serializedWireFormat[consumedBytes++] = _cipherMetadata.EncryptionType;
|
|
|
|
|
|
|
|
// 3 - Write the database id of the encryption key.
|
|
|
|
SerializeIntIntoBuffer(_cipherMetadata.EncryptionKeyInfo.Value.databaseId, serializedWireFormat, ref consumedBytes);
|
|
|
|
|
|
|
|
// 4 - Write the id of the encryption key.
|
|
|
|
SerializeIntIntoBuffer(_cipherMetadata.EncryptionKeyInfo.Value.cekId, serializedWireFormat, ref consumedBytes);
|
|
|
|
|
|
|
|
// 5 - Write the version of the encryption key.
|
|
|
|
SerializeIntIntoBuffer(_cipherMetadata.EncryptionKeyInfo.Value.cekVersion, serializedWireFormat, ref consumedBytes);
|
|
|
|
|
|
|
|
// 6 - Write the metadata version of the encryption key.
|
|
|
|
Buffer.BlockCopy(_cipherMetadata.EncryptionKeyInfo.Value.cekMdVersion, 0, serializedWireFormat, consumedBytes, _cipherMetadata.EncryptionKeyInfo.Value.cekMdVersion.Length);
|
|
|
|
consumedBytes += _cipherMetadata.EncryptionKeyInfo.Value.cekMdVersion.Length;
|
|
|
|
|
|
|
|
// 7 - Write Normalization Rule Version.
|
|
|
|
serializedWireFormat[consumedBytes++] = _cipherMetadata.NormalizationRuleVersion;
|
|
|
|
|
|
|
|
return serializedWireFormat;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Serializes an int into the provided buffer and offset.
|
|
|
|
/// </summary>
|
|
|
|
private void SerializeIntIntoBuffer(int value, byte[] buffer, ref int offset) {
|
|
|
|
buffer[offset++] = (byte)(value & 0xff);
|
|
|
|
buffer[offset++] = (byte)((value >> 8) & 0xff);
|
|
|
|
buffer[offset++] = (byte)((value >> 16) & 0xff);
|
|
|
|
buffer[offset++] = (byte)((value >> 24) & 0xff);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
sealed internal class _SqlRPC {
|
|
|
|
internal string rpcName;
|
|
|
|
internal string databaseName; // Used for UDTs
|
|
|
|
internal ushort ProcID; // Used instead of name
|
|
|
|
internal ushort options;
|
|
|
|
internal SqlParameter[] parameters;
|
|
|
|
internal byte[] paramoptions;
|
|
|
|
|
|
|
|
internal int? recordsAffected;
|
|
|
|
internal int cumulativeRecordsAffected;
|
|
|
|
|
|
|
|
internal int errorsIndexStart;
|
|
|
|
internal int errorsIndexEnd;
|
|
|
|
internal SqlErrorCollection errors;
|
|
|
|
|
|
|
|
internal int warningsIndexStart;
|
|
|
|
internal int warningsIndexEnd;
|
|
|
|
internal SqlErrorCollection warnings;
|
|
|
|
internal bool needsFetchParameterEncryptionMetadata;
|
|
|
|
internal string GetCommandTextOrRpcName() {
|
|
|
|
if (TdsEnums.RPC_PROCID_EXECUTESQL == ProcID) {
|
|
|
|
// Param 0 is the actual sql executing
|
|
|
|
return (string)parameters[0].Value;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return rpcName;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
sealed internal class SqlReturnValue : SqlMetaDataPriv {
|
|
|
|
|
|
|
|
internal ushort parmIndex; //Yukon or later only
|
|
|
|
internal string parameter;
|
|
|
|
internal readonly SqlBuffer value;
|
|
|
|
|
|
|
|
internal SqlReturnValue() : base() {
|
|
|
|
value = new SqlBuffer();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
internal struct MultiPartTableName {
|
|
|
|
private string _multipartName;
|
|
|
|
private string _serverName;
|
|
|
|
private string _catalogName;
|
|
|
|
private string _schemaName;
|
|
|
|
private string _tableName;
|
|
|
|
|
|
|
|
internal MultiPartTableName(string[] parts) {
|
|
|
|
_multipartName = null;
|
|
|
|
_serverName = parts[0];
|
|
|
|
_catalogName = parts[1];
|
|
|
|
_schemaName = parts[2];
|
|
|
|
_tableName = parts[3];
|
|
|
|
}
|
|
|
|
|
|
|
|
internal MultiPartTableName(string multipartName) {
|
|
|
|
_multipartName = multipartName;
|
|
|
|
_serverName = null;
|
|
|
|
_catalogName = null;
|
|
|
|
_schemaName = null;
|
|
|
|
_tableName = null;
|
|
|
|
}
|
|
|
|
|
|
|
|
internal string ServerName {
|
|
|
|
get {
|
|
|
|
ParseMultipartName();
|
|
|
|
return _serverName;
|
|
|
|
}
|
|
|
|
set { _serverName = value; }
|
|
|
|
}
|
|
|
|
internal string CatalogName {
|
|
|
|
get {
|
|
|
|
ParseMultipartName();
|
|
|
|
return _catalogName;
|
|
|
|
}
|
|
|
|
set { _catalogName = value; }
|
|
|
|
}
|
|
|
|
internal string SchemaName {
|
|
|
|
get {
|
|
|
|
ParseMultipartName();
|
|
|
|
return _schemaName;
|
|
|
|
}
|
|
|
|
set { _schemaName = value; }
|
|
|
|
}
|
|
|
|
internal string TableName {
|
|
|
|
get {
|
|
|
|
ParseMultipartName();
|
|
|
|
return _tableName;
|
|
|
|
}
|
|
|
|
set { _tableName = value; }
|
|
|
|
}
|
|
|
|
|
|
|
|
private void ParseMultipartName() {
|
|
|
|
if (null != _multipartName) {
|
|
|
|
string[] parts = MultipartIdentifier.ParseMultipartIdentifier(_multipartName, "[\"", "]\"", Res.SQL_TDSParserTableName, false);
|
|
|
|
_serverName = parts[0];
|
|
|
|
_catalogName = parts[1];
|
|
|
|
_schemaName = parts[2];
|
|
|
|
_tableName = parts[3];
|
|
|
|
_multipartName = null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
internal static readonly MultiPartTableName Null = new MultiPartTableName(new string[] {null, null, null, null});
|
|
|
|
}
|
|
|
|
}
|