33// See the LICENSE file in the project root for more information.
44
55using System ;
6+ using System . Collections . Concurrent ;
67using System . Collections . Generic ;
78using System . ComponentModel ;
89using System . Data ;
@@ -40,7 +41,45 @@ public sealed partial class SqlCommand : DbCommand, ICloneable
4041 #endregion
4142
4243 #region Fields
43-
44+ #region Test-Only Behavior Overrides
45+ #if DEBUG
46+ /// <summary>
47+ /// Force the client to sleep during sp_describe_parameter_encryption in the function TryFetchInputParameterEncryptionInfo.
48+ /// </summary>
49+ private static bool _sleepDuringTryFetchInputParameterEncryptionInfo = false ;
50+
51+ /// <summary>
52+ /// Force the client to sleep during sp_describe_parameter_encryption in the function RunExecuteReaderTds.
53+ /// </summary>
54+ private static bool _sleepDuringRunExecuteReaderTdsForSpDescribeParameterEncryption = false ;
55+
56+ /// <summary>
57+ /// Force the client to sleep during sp_describe_parameter_encryption after ReadDescribeEncryptionParameterResults.
58+ /// </summary>
59+ private static bool _sleepAfterReadDescribeEncryptionParameterResults = false ;
60+
61+ /// <summary>
62+ /// Internal flag for testing purposes that forces all queries to internally end async calls.
63+ /// </summary>
64+ private static bool _forceInternalEndQuery = false ;
65+
66+ /// <summary>
67+ /// Internal flag for testing purposes that forces one RetryableEnclaveQueryExecutionException during GenerateEnclavePackage
68+ /// </summary>
69+ private static bool _forceRetryableEnclaveQueryExecutionExceptionDuringGenerateEnclavePackage = false ;
70+ #endif
71+ #endregion
72+
73+ // @TODO: Make property - non-private fields are bad
74+ // @TODO: Rename to match naming convention _enclavePackage
75+ internal EnclavePackage enclavePackage = null ;
76+
77+ // @TODO: Make property - non-private fields are bad (this should be read-only externally)
78+ internal ConcurrentDictionary < int , SqlTceCipherInfoEntry > keysToBeSentToEnclave ;
79+
80+ // @TODO: Make property - non-private fields are bad (this can be read-only externally)
81+ internal bool requiresEnclaveComputations = false ;
82+
4483 // @TODO: Make property - non-private fields are bad
4584 internal SqlDependency _sqlDep ;
4685
@@ -75,7 +114,7 @@ public sealed partial class SqlCommand : DbCommand, ICloneable
75114 /// false. This may also be used to set other behavior which overrides connection level
76115 /// setting.
77116 /// </summary>
78- // @TODO: Make auto-property
117+ // @TODO: Make auto-property, also make nullable.
79118 private SqlCommandColumnEncryptionSetting _columnEncryptionSetting =
80119 SqlCommandColumnEncryptionSetting . UseConnectionSetting ;
81120
@@ -94,6 +133,25 @@ public sealed partial class SqlCommand : DbCommand, ICloneable
94133 /// </summary>
95134 private CommandType _commandType ;
96135
136+ /// <summary>
137+ /// This variable is used to keep track of which RPC batch's results are being read when reading the results of
138+ /// describe parameter encryption RPC requests in BatchRPCMode.
139+ /// </summary>
140+ // @TODO: Rename to match naming conventions
141+ private int _currentlyExecutingDescribeParameterEncryptionRPC ;
142+
143+ /// <summary>
144+ /// Per-command custom providers. It can be provided by the user and can be set more than
145+ /// once.
146+ /// </summary>
147+ private IReadOnlyDictionary < string , SqlColumnEncryptionKeyStoreProvider > _customColumnEncryptionKeyStoreProviders ;
148+
149+ // @TODO: Rename to indicate that this is for enclave stuff, I think...
150+ private byte [ ] customData = null ;
151+
152+ // @TODO: Rename to indicate that this is for enclave stuff. Or just get rid of it and use the length of customData if possible.
153+ private int customDataLength = 0 ;
154+
97155 /// <summary>
98156 /// By default, the cmd object is visible on the design surface (i.e. VS7 Server Tray) to
99157 /// limit the number of components that clutter the design surface, when the DataAdapter
@@ -102,20 +160,23 @@ public sealed partial class SqlCommand : DbCommand, ICloneable
102160 /// </summary>
103161 // @TODO: Make auto-property
104162 private bool _designTimeInvisible ;
105-
106- /// <summary>
107- /// Current state of preparation of the command.
108- /// By default, assume the user is not sharing a connection so the command has not been prepared.
109- /// </summary>
110- private EXECTYPE _execType = EXECTYPE . UNPREPARED ;
111163
112164 /// <summary>
113165 /// True if the user changes the command text or number of parameters after the command has
114166 /// already prepared.
115167 /// </summary>
116168 // @TODO: Consider renaming "_IsUserDirty"
117169 private bool _dirty = false ;
118-
170+
171+ /// <summary>
172+ /// Current state of preparation of the command.
173+ /// By default, assume the user is not sharing a connection so the command has not been prepared.
174+ /// </summary>
175+ private EXECTYPE _execType = EXECTYPE . UNPREPARED ;
176+
177+ // @TODO: Rename to match naming conventions _enclaveAttestationParameters
178+ private SqlEnclaveAttestationParameters enclaveAttestationParameters = null ;
179+
119180 /// <summary>
120181 /// On 8.0 and above the Prepared state cannot be left. Once a command is prepared it will
121182 /// always be prepared. A change in parameters, command text, etc (IsDirty) automatically
@@ -183,6 +244,22 @@ public sealed partial class SqlCommand : DbCommand, ICloneable
183244 // @TODO: Use int? and replace -1 usage with null
184245 private int _rowsAffected = - 1 ;
185246
247+ /// <summary>
248+ /// number of rows affected by sp_describe_parameter_encryption.
249+ /// </summary>
250+ // @TODO: Use int? and replace -1 usage with null
251+ // @TODO: This is only used for debug asserts?
252+ // @TODO: Rename to drop Sp
253+ private int _rowsAffectedBySpDescribeParameterEncryption = - 1 ;
254+
255+ /// <summary>
256+ /// RPC for tracking execution of sp_describe_parameter_encryption.
257+ /// </summary>
258+ private _SqlRPC _rpcForEncryption = null ;
259+
260+ // @TODO: Rename to match naming convention
261+ private _SqlRPC [ ] _sqlRPCParameterEncryptionReqArray ;
262+
186263 /// <summary>
187264 /// TDS session the current instance is using.
188265 /// </summary>
@@ -204,7 +281,14 @@ public sealed partial class SqlCommand : DbCommand, ICloneable
204281 /// DbDataAdapter.
205282 /// </summary>
206283 private UpdateRowSource _updatedRowSource = UpdateRowSource . Both ;
207-
284+
285+ /// <summary>
286+ /// Indicates if the column encryption setting was set at-least once in the batch rpc mode,
287+ /// when using AddBatchCommand.
288+ /// </summary>
289+ // @TODO: can be replaced by using nullable for _columnEncryptionSetting.
290+ private bool _wasBatchModeColumnEncryptionSettingSetOnce ;
291+
208292 #endregion
209293
210294 #region Constructors
@@ -624,9 +708,15 @@ public override UpdateRowSource UpdatedRowSource
624708 #endregion
625709
626710 #region Internal/Protected/Private Properties
627-
711+
712+ internal bool HasColumnEncryptionKeyStoreProvidersRegistered
713+ {
714+ get => _customColumnEncryptionKeyStoreProviders ? . Count > 0 ;
715+ }
716+
628717 internal bool InPrepare => _inPrepare ;
629718
719+ // @TODO: Rename RowsAffectedInternal or
630720 internal int InternalRecordsAffected
631721 {
632722 get => _rowsAffected ;
@@ -643,9 +733,36 @@ internal int InternalRecordsAffected
643733 }
644734 }
645735
736+ /// <summary>
737+ /// A flag to indicate if we have in-progress describe parameter encryption RPC requests.
738+ /// Reset to false when completed.
739+ /// </summary>
740+ // @TODO: Rename to match naming conventions
741+ internal bool IsDescribeParameterEncryptionRPCCurrentlyInProgress { get ; private set ; }
742+
646743 // @TODO: Rename to match conventions.
647744 internal int ObjectID { get ; } = Interlocked . Increment ( ref _objectTypeCount ) ;
648745
746+ /// <summary>
747+ /// Get or add to the number of records affected by SpDescribeParameterEncryption.
748+ /// The below line is used only for debug asserts and not exposed publicly or impacts functionality otherwise.
749+ /// </summary>
750+ internal int RowsAffectedByDescribeParameterEncryption
751+ {
752+ get => _rowsAffectedBySpDescribeParameterEncryption ;
753+ set
754+ {
755+ if ( _rowsAffectedBySpDescribeParameterEncryption == - 1 )
756+ {
757+ _rowsAffectedBySpDescribeParameterEncryption = value ;
758+ }
759+ else if ( value > 0 )
760+ {
761+ _rowsAffectedBySpDescribeParameterEncryption += value ;
762+ }
763+ }
764+ }
765+
649766 internal SqlStatistics Statistics
650767 {
651768 get
@@ -768,6 +885,20 @@ private bool IsDirty
768885 private bool IsSimpleTextQuery => CommandType is CommandType . Text &&
769886 ( _parameters is null || _parameters . Count == 0 ) ;
770887
888+ private bool ShouldCacheEncryptionMetadata
889+ {
890+ // @TODO: Should we check for null on _activeConnection?
891+ get => ! requiresEnclaveComputations || _activeConnection . Parser . AreEnclaveRetriesSupported ;
892+ }
893+
894+ private bool ShouldUseEnclaveBasedWorkflow
895+ {
896+ // @TODO: I'm pretty sure the or'd condition is used in several places. We could factor that out.
897+ get => ( ! string . IsNullOrWhiteSpace ( _activeConnection . EnclaveAttestationUrl ) ||
898+ _activeConnection . AttestationProtocol is SqlConnectionAttestationProtocol . None ) &&
899+ IsColumnEncryptionEnabled ;
900+ }
901+
771902 #endregion
772903
773904 #region Public/Internal Methods
0 commit comments