SqlConnection.cs 95 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248
  1. //------------------------------------------------------------------------------
  2. // <copyright file="SqlConnection.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. [assembly: System.Runtime.CompilerServices.InternalsVisibleTo("System.Data.DataSetExtensions, PublicKey="+AssemblyRef.EcmaPublicKeyFull)] // DevDiv Bugs 92166
  9. namespace System.Data.SqlClient
  10. {
  11. using System;
  12. using System.Collections;
  13. using System.Configuration.Assemblies;
  14. using System.ComponentModel;
  15. using System.Data;
  16. using System.Data.Common;
  17. using System.Data.ProviderBase;
  18. using System.Data.Sql;
  19. using System.Data.SqlTypes;
  20. using System.Diagnostics;
  21. using System.Globalization;
  22. using System.IO;
  23. using System.Runtime.CompilerServices;
  24. using System.Runtime.ConstrainedExecution;
  25. using System.Runtime.InteropServices;
  26. using System.Runtime.Remoting;
  27. using System.Runtime.Serialization.Formatters;
  28. using System.Text;
  29. using System.Threading;
  30. using System.Threading.Tasks;
  31. using System.Security;
  32. using System.Security.Permissions;
  33. using System.Reflection;
  34. using System.Runtime.Versioning;
  35. using Microsoft.SqlServer.Server;
  36. using System.Security.Principal;
  37. using System.Diagnostics.CodeAnalysis;
  38. [DefaultEvent("InfoMessage")]
  39. public sealed partial class SqlConnection: DbConnection, ICloneable {
  40. static private readonly object EventInfoMessage = new object();
  41. private SqlDebugContext _sdc; // SQL Debugging support
  42. private bool _AsyncCommandInProgress;
  43. // SQLStatistics support
  44. internal SqlStatistics _statistics;
  45. private bool _collectstats;
  46. private bool _fireInfoMessageEventOnUserErrors; // False by default
  47. // root task associated with current async invocation
  48. Tuple<TaskCompletionSource<DbConnectionInternal>, Task> _currentCompletion;
  49. private SqlCredential _credential; // SQL authentication password stored in SecureString
  50. private string _connectionString;
  51. private int _connectRetryCount;
  52. // connection resiliency
  53. private object _reconnectLock = new object();
  54. internal Task _currentReconnectionTask;
  55. private Task _asyncWaitingForReconnection; // current async task waiting for reconnection in non-MARS connections
  56. private Guid _originalConnectionId = Guid.Empty;
  57. private CancellationTokenSource _reconnectionCancellationSource;
  58. internal SessionData _recoverySessionData;
  59. internal WindowsIdentity _lastIdentity;
  60. internal WindowsIdentity _impersonateIdentity;
  61. private int _reconnectCount;
  62. public SqlConnection(string connectionString) : this(connectionString, null) {
  63. }
  64. public SqlConnection(string connectionString, SqlCredential credential) : this() {
  65. ConnectionString = connectionString; // setting connection string first so that ConnectionOption is available
  66. if (credential != null)
  67. {
  68. // The following checks are necessary as setting Credential property will call CheckAndThrowOnInvalidCombinationOfConnectionStringAndSqlCredential
  69. // CheckAndThrowOnInvalidCombinationOfConnectionStringAndSqlCredential it will throw InvalidOperationException rather than Arguemtn exception
  70. // Need to call setter on Credential property rather than setting _credential directly as pool groups need to be checked
  71. SqlConnectionString connectionOptions = (SqlConnectionString) ConnectionOptions;
  72. if (UsesClearUserIdOrPassword(connectionOptions))
  73. {
  74. throw ADP.InvalidMixedArgumentOfSecureAndClearCredential();
  75. }
  76. if (UsesIntegratedSecurity(connectionOptions))
  77. {
  78. throw ADP.InvalidMixedArgumentOfSecureCredentialAndIntegratedSecurity();
  79. }
  80. if (UsesContextConnection(connectionOptions))
  81. {
  82. throw ADP.InvalidMixedArgumentOfSecureCredentialAndContextConnection();
  83. }
  84. Credential = credential;
  85. }
  86. // else
  87. // credential == null: we should not set "Credential" as this will do additional validation check and
  88. // checking pool groups which is not necessary. All necessary operation is already done by calling "ConnectionString = connectionString"
  89. CacheConnectionStringProperties();
  90. }
  91. private SqlConnection(SqlConnection connection) { // Clone
  92. GC.SuppressFinalize(this);
  93. CopyFrom(connection);
  94. _connectionString = connection._connectionString;
  95. if (connection._credential != null)
  96. {
  97. SecureString password = connection._credential.Password.Copy();
  98. password.MakeReadOnly();
  99. _credential = new SqlCredential(connection._credential.UserId, password);
  100. }
  101. CacheConnectionStringProperties();
  102. }
  103. // This method will be called once connection string is set or changed.
  104. private void CacheConnectionStringProperties() {
  105. SqlConnectionString connString = ConnectionOptions as SqlConnectionString;
  106. if (connString != null) {
  107. _connectRetryCount = connString.ConnectRetryCount;
  108. }
  109. }
  110. //
  111. // PUBLIC PROPERTIES
  112. //
  113. // used to start/stop collection of statistics data and do verify the current state
  114. //
  115. // devnote: start/stop should not performed using a property since it requires execution of code
  116. //
  117. // start statistics
  118. // set the internal flag (_statisticsEnabled) to true.
  119. // Create a new SqlStatistics object if not already there.
  120. // connect the parser to the object.
  121. // if there is no parser at this time we need to connect it after creation.
  122. //
  123. [
  124. DefaultValue(false),
  125. ResCategoryAttribute(Res.DataCategory_Data),
  126. ResDescriptionAttribute(Res.SqlConnection_StatisticsEnabled),
  127. ]
  128. public bool StatisticsEnabled {
  129. get {
  130. return (_collectstats);
  131. }
  132. set {
  133. if (IsContextConnection) {
  134. if (value) {
  135. throw SQL.NotAvailableOnContextConnection();
  136. }
  137. }
  138. else {
  139. if (value) {
  140. // start
  141. if (ConnectionState.Open == State) {
  142. if (null == _statistics) {
  143. _statistics = new SqlStatistics();
  144. ADP.TimerCurrent(out _statistics._openTimestamp);
  145. }
  146. // set statistics on the parser
  147. // update timestamp;
  148. Debug.Assert(Parser != null, "Where's the parser?");
  149. Parser.Statistics = _statistics;
  150. }
  151. }
  152. else {
  153. // stop
  154. if (null != _statistics) {
  155. if (ConnectionState.Open == State) {
  156. // remove statistics from parser
  157. // update timestamp;
  158. TdsParser parser = Parser;
  159. Debug.Assert(parser != null, "Where's the parser?");
  160. parser.Statistics = null;
  161. ADP.TimerCurrent(out _statistics._closeTimestamp);
  162. }
  163. }
  164. }
  165. this._collectstats = value;
  166. }
  167. }
  168. }
  169. internal bool AsyncCommandInProgress {
  170. get {
  171. return (_AsyncCommandInProgress);
  172. }
  173. [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
  174. set {
  175. _AsyncCommandInProgress = value;
  176. }
  177. }
  178. internal bool IsContextConnection {
  179. get {
  180. SqlConnectionString opt = (SqlConnectionString)ConnectionOptions;
  181. return UsesContextConnection(opt);
  182. }
  183. }
  184. // Is this connection is a Context Connection?
  185. private bool UsesContextConnection(SqlConnectionString opt)
  186. {
  187. return opt != null ? opt.ContextConnection : false;
  188. }
  189. // Does this connection uses Integrated Security?
  190. private bool UsesIntegratedSecurity(SqlConnectionString opt) {
  191. return opt != null ? opt.IntegratedSecurity : false;
  192. }
  193. // Does this connection uses old style of clear userID or Password in connection string?
  194. private bool UsesClearUserIdOrPassword(SqlConnectionString opt) {
  195. bool result = false;
  196. if (null != opt) {
  197. result = (!ADP.IsEmpty(opt.UserID) || !ADP.IsEmpty(opt.Password));
  198. }
  199. return result;
  200. }
  201. internal SqlConnectionString.TransactionBindingEnum TransactionBinding {
  202. get {
  203. return ((SqlConnectionString)ConnectionOptions).TransactionBinding;
  204. }
  205. }
  206. internal SqlConnectionString.TypeSystem TypeSystem {
  207. get {
  208. return ((SqlConnectionString)ConnectionOptions).TypeSystemVersion;
  209. }
  210. }
  211. internal Version TypeSystemAssemblyVersion {
  212. get {
  213. return ((SqlConnectionString)ConnectionOptions).TypeSystemAssemblyVersion;
  214. }
  215. }
  216. internal int ConnectRetryInterval {
  217. get {
  218. return ((SqlConnectionString)ConnectionOptions).ConnectRetryInterval;
  219. }
  220. }
  221. override protected DbProviderFactory DbProviderFactory {
  222. get {
  223. return SqlClientFactory.Instance;
  224. }
  225. }
  226. [
  227. DefaultValue(""),
  228. #pragma warning disable 618 // ignore obsolete warning about RecommendedAsConfigurable to use SettingsBindableAttribute
  229. RecommendedAsConfigurable(true),
  230. #pragma warning restore 618
  231. SettingsBindableAttribute(true),
  232. RefreshProperties(RefreshProperties.All),
  233. ResCategoryAttribute(Res.DataCategory_Data),
  234. Editor("Microsoft.VSDesigner.Data.SQL.Design.SqlConnectionStringEditor, " + AssemblyRef.MicrosoftVSDesigner, "System.Drawing.Design.UITypeEditor, " + AssemblyRef.SystemDrawing),
  235. ResDescriptionAttribute(Res.SqlConnection_ConnectionString),
  236. ]
  237. override public string ConnectionString {
  238. get {
  239. return ConnectionString_Get();
  240. }
  241. set {
  242. if (_credential != null)
  243. {
  244. SqlConnectionString connectionOptions = new SqlConnectionString(value);
  245. CheckAndThrowOnInvalidCombinationOfConnectionStringAndSqlCredential(connectionOptions);
  246. }
  247. ConnectionString_Set(new SqlConnectionPoolKey(value, _credential));
  248. _connectionString = value; // Change _connectionString value only after value is validated
  249. CacheConnectionStringProperties();
  250. }
  251. }
  252. [
  253. DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
  254. ResDescriptionAttribute(Res.SqlConnection_ConnectionTimeout),
  255. ]
  256. override public int ConnectionTimeout {
  257. get {
  258. SqlConnectionString constr = (SqlConnectionString)ConnectionOptions;
  259. return ((null != constr) ? constr.ConnectTimeout : SqlConnectionString.DEFAULT.Connect_Timeout);
  260. }
  261. }
  262. [
  263. DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
  264. ResDescriptionAttribute(Res.SqlConnection_Database),
  265. ]
  266. override public string Database {
  267. // if the connection is open, we need to ask the inner connection what it's
  268. // current catalog is because it may have gotten changed, otherwise we can
  269. // just return what the connection string had.
  270. get {
  271. SqlInternalConnection innerConnection = (InnerConnection as SqlInternalConnection);
  272. string result;
  273. if (null != innerConnection) {
  274. result = innerConnection.CurrentDatabase;
  275. }
  276. else {
  277. SqlConnectionString constr = (SqlConnectionString)ConnectionOptions;
  278. result = ((null != constr) ? constr.InitialCatalog : SqlConnectionString.DEFAULT.Initial_Catalog);
  279. }
  280. return result;
  281. }
  282. }
  283. [
  284. Browsable(true),
  285. DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
  286. ResDescriptionAttribute(Res.SqlConnection_DataSource),
  287. ]
  288. override public string DataSource {
  289. get {
  290. SqlInternalConnection innerConnection = (InnerConnection as SqlInternalConnection);
  291. string result;
  292. if (null != innerConnection) {
  293. result = innerConnection.CurrentDataSource;
  294. }
  295. else {
  296. SqlConnectionString constr = (SqlConnectionString)ConnectionOptions;
  297. result = ((null != constr) ? constr.DataSource : SqlConnectionString.DEFAULT.Data_Source);
  298. }
  299. return result;
  300. }
  301. }
  302. [
  303. DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
  304. ResCategoryAttribute(Res.DataCategory_Data),
  305. ResDescriptionAttribute(Res.SqlConnection_PacketSize),
  306. ]
  307. public int PacketSize {
  308. // if the connection is open, we need to ask the inner connection what it's
  309. // current packet size is because it may have gotten changed, otherwise we
  310. // can just return what the connection string had.
  311. get {
  312. if (IsContextConnection) {
  313. throw SQL.NotAvailableOnContextConnection();
  314. }
  315. SqlInternalConnectionTds innerConnection = (InnerConnection as SqlInternalConnectionTds);
  316. int result;
  317. if (null != innerConnection) {
  318. result = innerConnection.PacketSize;
  319. }
  320. else {
  321. SqlConnectionString constr = (SqlConnectionString)ConnectionOptions;
  322. result = ((null != constr) ? constr.PacketSize : SqlConnectionString.DEFAULT.Packet_Size);
  323. }
  324. return result;
  325. }
  326. }
  327. [
  328. DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
  329. ResCategoryAttribute(Res.DataCategory_Data),
  330. ResDescriptionAttribute(Res.SqlConnection_ClientConnectionId),
  331. ]
  332. public Guid ClientConnectionId {
  333. get {
  334. SqlInternalConnectionTds innerConnection = (InnerConnection as SqlInternalConnectionTds);
  335. if (null != innerConnection) {
  336. return innerConnection.ClientConnectionId;
  337. }
  338. else {
  339. Task reconnectTask = _currentReconnectionTask;
  340. if (reconnectTask != null && !reconnectTask.IsCompleted) {
  341. return _originalConnectionId;
  342. }
  343. return Guid.Empty;
  344. }
  345. }
  346. }
  347. [
  348. Browsable(false),
  349. DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
  350. ResDescriptionAttribute(Res.SqlConnection_ServerVersion),
  351. ]
  352. override public string ServerVersion {
  353. get {
  354. return GetOpenConnection().ServerVersion;
  355. }
  356. }
  357. [
  358. Browsable(false),
  359. DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
  360. ResDescriptionAttribute(Res.DbConnection_State),
  361. ]
  362. override public ConnectionState State {
  363. get {
  364. Task reconnectTask=_currentReconnectionTask;
  365. if (reconnectTask != null && !reconnectTask.IsCompleted) {
  366. return ConnectionState.Open;
  367. }
  368. return InnerConnection.State;
  369. }
  370. }
  371. internal SqlStatistics Statistics {
  372. get {
  373. return _statistics;
  374. }
  375. }
  376. [
  377. DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
  378. ResCategoryAttribute(Res.DataCategory_Data),
  379. ResDescriptionAttribute(Res.SqlConnection_WorkstationId),
  380. ]
  381. public string WorkstationId {
  382. get {
  383. if (IsContextConnection) {
  384. throw SQL.NotAvailableOnContextConnection();
  385. }
  386. // If not supplied by the user, the default value is the MachineName
  387. // Note: In Longhorn you'll be able to rename a machine without
  388. // rebooting. Therefore, don't cache this machine name.
  389. SqlConnectionString constr = (SqlConnectionString)ConnectionOptions;
  390. string result = ((null != constr) ? constr.WorkstationId : null);
  391. if (null == result) {
  392. // getting machine name requires Environment.Permission
  393. // user must have that permission in order to retrieve this
  394. result = Environment.MachineName;
  395. }
  396. return result;
  397. }
  398. }
  399. // SqlCredential: Pair User Id and password in SecureString which are to be used for SQL authentication
  400. [
  401. Browsable(false),
  402. DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
  403. ResDescriptionAttribute(Res.SqlConnection_Credential),
  404. ]
  405. public SqlCredential Credential
  406. {
  407. get
  408. {
  409. SqlCredential result = _credential;
  410. // When a connection is connecting or is ever opened, make credential available only if "Persist Security Info" is set to true
  411. // otherwise, return null
  412. SqlConnectionString connectionOptions = (SqlConnectionString) UserConnectionOptions;
  413. if (InnerConnection.ShouldHidePassword && connectionOptions != null && !connectionOptions.PersistSecurityInfo)
  414. {
  415. result = null;
  416. }
  417. return result;
  418. }
  419. set
  420. {
  421. // If a connection is connecting or is ever opened, user id/password cannot be set
  422. if (!InnerConnection.AllowSetConnectionString)
  423. {
  424. throw ADP.OpenConnectionPropertySet("Credential", InnerConnection.State);
  425. }
  426. // check if the usage of credential has any conflict with the keys used in connection string
  427. if (value != null)
  428. {
  429. CheckAndThrowOnInvalidCombinationOfConnectionStringAndSqlCredential((SqlConnectionString) ConnectionOptions);
  430. }
  431. _credential = value;
  432. // Need to call ConnectionString_Set to do proper pool group check
  433. ConnectionString_Set(new SqlConnectionPoolKey(_connectionString, _credential));
  434. }
  435. }
  436. // CheckAndThrowOnInvalidCombinationOfConnectionStringAndSqlCredential: check if the usage of credential has any conflict
  437. // with the keys used in connection string
  438. // If there is any conflict, it throws InvalidOperationException
  439. // This is to be used setter of ConnectionString and Credential properties
  440. private void CheckAndThrowOnInvalidCombinationOfConnectionStringAndSqlCredential(SqlConnectionString connectionOptions)
  441. {
  442. if (UsesClearUserIdOrPassword(connectionOptions))
  443. {
  444. throw ADP.InvalidMixedUsageOfSecureAndClearCredential();
  445. }
  446. if (UsesIntegratedSecurity(connectionOptions))
  447. {
  448. throw ADP.InvalidMixedUsageOfSecureCredentialAndIntegratedSecurity();
  449. }
  450. if (UsesContextConnection(connectionOptions))
  451. {
  452. throw ADP.InvalidMixedArgumentOfSecureCredentialAndContextConnection();
  453. }
  454. }
  455. //
  456. // PUBLIC EVENTS
  457. //
  458. [
  459. ResCategoryAttribute(Res.DataCategory_InfoMessage),
  460. ResDescriptionAttribute(Res.DbConnection_InfoMessage),
  461. ]
  462. public event SqlInfoMessageEventHandler InfoMessage {
  463. add {
  464. Events.AddHandler(EventInfoMessage, value);
  465. }
  466. remove {
  467. Events.RemoveHandler(EventInfoMessage, value);
  468. }
  469. }
  470. public bool FireInfoMessageEventOnUserErrors {
  471. get {
  472. return _fireInfoMessageEventOnUserErrors;
  473. }
  474. set {
  475. _fireInfoMessageEventOnUserErrors = value;
  476. }
  477. }
  478. // Approx. number of times that the internal connection has been reconnected
  479. internal int ReconnectCount {
  480. get {
  481. return _reconnectCount;
  482. }
  483. }
  484. //
  485. // PUBLIC METHODS
  486. //
  487. new public SqlTransaction BeginTransaction() {
  488. // this is just a delegate. The actual method tracks executiontime
  489. return BeginTransaction(IsolationLevel.Unspecified, null);
  490. }
  491. new public SqlTransaction BeginTransaction(IsolationLevel iso) {
  492. // this is just a delegate. The actual method tracks executiontime
  493. return BeginTransaction(iso, null);
  494. }
  495. public SqlTransaction BeginTransaction(string transactionName) {
  496. // Use transaction names only on the outermost pair of nested
  497. // BEGIN...COMMIT or BEGIN...ROLLBACK statements. Transaction names
  498. // are ignored for nested BEGIN's. The only way to rollback a nested
  499. // transaction is to have a save point from a SAVE TRANSACTION call.
  500. return BeginTransaction(IsolationLevel.Unspecified, transactionName);
  501. }
  502. // suppress this message - we cannot use SafeHandle here. Also, see notes in the code (VSTFDEVDIV# 560355)
  503. [SuppressMessage("Microsoft.Reliability", "CA2004:RemoveCallsToGCKeepAlive")]
  504. override protected DbTransaction BeginDbTransaction(IsolationLevel isolationLevel) {
  505. IntPtr hscp;
  506. Bid.ScopeEnter(out hscp, "<prov.SqlConnection.BeginDbTransaction|API> %d#, isolationLevel=%d{ds.IsolationLevel}", ObjectID, (int)isolationLevel);
  507. try {
  508. DbTransaction transaction = BeginTransaction(isolationLevel);
  509. // VSTFDEVDIV# 560355 - InnerConnection doesn't maintain a ref on the outer connection (this) and
  510. // subsequently leaves open the possibility that the outer connection could be GC'ed before the SqlTransaction
  511. // is fully hooked up (leaving a DbTransaction with a null connection property). Ensure that this is reachable
  512. // until the completion of BeginTransaction with KeepAlive
  513. GC.KeepAlive(this);
  514. return transaction;
  515. }
  516. finally {
  517. Bid.ScopeLeave(ref hscp);
  518. }
  519. }
  520. public SqlTransaction BeginTransaction(IsolationLevel iso, string transactionName) {
  521. WaitForPendingReconnection();
  522. SqlStatistics statistics = null;
  523. IntPtr hscp;
  524. string xactName = ADP.IsEmpty(transactionName)? "None" : transactionName;
  525. Bid.ScopeEnter(out hscp, "<sc.SqlConnection.BeginTransaction|API> %d#, iso=%d{ds.IsolationLevel}, transactionName='%ls'\n", ObjectID, (int)iso,
  526. xactName);
  527. try {
  528. statistics = SqlStatistics.StartTimer(Statistics);
  529. // NOTE: we used to throw an exception if the transaction name was empty
  530. // (see MDAC 50292) but that was incorrect because we have a BeginTransaction
  531. // method that doesn't have a transactionName argument.
  532. SqlTransaction transaction;
  533. bool isFirstAttempt = true;
  534. do {
  535. transaction = GetOpenConnection().BeginSqlTransaction(iso, transactionName, isFirstAttempt); // do not reconnect twice
  536. Debug.Assert(isFirstAttempt || !transaction.InternalTransaction.ConnectionHasBeenRestored, "Restored connection on non-first attempt");
  537. isFirstAttempt = false;
  538. } while (transaction.InternalTransaction.ConnectionHasBeenRestored);
  539. // SQLBU 503873 The GetOpenConnection line above doesn't keep a ref on the outer connection (this),
  540. // and it could be collected before the inner connection can hook it to the transaction, resulting in
  541. // a transaction with a null connection property. Use GC.KeepAlive to ensure this doesn't happen.
  542. GC.KeepAlive(this);
  543. return transaction;
  544. }
  545. finally {
  546. Bid.ScopeLeave(ref hscp);
  547. SqlStatistics.StopTimer(statistics);
  548. }
  549. }
  550. override public void ChangeDatabase(string database) {
  551. SqlStatistics statistics = null;
  552. RepairInnerConnection();
  553. Bid.CorrelationTrace("<sc.SqlConnection.ChangeDatabase|API|Correlation> ObjectID%d#, ActivityID %ls\n", ObjectID);
  554. TdsParser bestEffortCleanupTarget = null;
  555. RuntimeHelpers.PrepareConstrainedRegions();
  556. try {
  557. #if DEBUG
  558. TdsParser.ReliabilitySection tdsReliabilitySection = new TdsParser.ReliabilitySection();
  559. RuntimeHelpers.PrepareConstrainedRegions();
  560. try {
  561. tdsReliabilitySection.Start();
  562. #else
  563. {
  564. #endif //DEBUG
  565. bestEffortCleanupTarget = SqlInternalConnection.GetBestEffortCleanupTarget(this);
  566. statistics = SqlStatistics.StartTimer(Statistics);
  567. InnerConnection.ChangeDatabase(database);
  568. }
  569. #if DEBUG
  570. finally {
  571. tdsReliabilitySection.Stop();
  572. }
  573. #endif //DEBUG
  574. }
  575. catch (System.OutOfMemoryException e) {
  576. Abort(e);
  577. throw;
  578. }
  579. catch (System.StackOverflowException e) {
  580. Abort(e);
  581. throw;
  582. }
  583. catch (System.Threading.ThreadAbortException e) {
  584. Abort(e);
  585. SqlInternalConnection.BestEffortCleanup(bestEffortCleanupTarget);
  586. throw;
  587. }
  588. finally {
  589. SqlStatistics.StopTimer(statistics);
  590. }
  591. }
  592. static public void ClearAllPools() {
  593. (new SqlClientPermission(PermissionState.Unrestricted)).Demand();
  594. SqlConnectionFactory.SingletonInstance.ClearAllPools();
  595. }
  596. static public void ClearPool(SqlConnection connection) {
  597. ADP.CheckArgumentNull(connection, "connection");
  598. DbConnectionOptions connectionOptions = connection.UserConnectionOptions;
  599. if (null != connectionOptions) {
  600. connectionOptions.DemandPermission();
  601. if (connection.IsContextConnection) {
  602. throw SQL.NotAvailableOnContextConnection();
  603. }
  604. SqlConnectionFactory.SingletonInstance.ClearPool(connection);
  605. }
  606. }
  607. object ICloneable.Clone() {
  608. SqlConnection clone = new SqlConnection(this);
  609. Bid.Trace("<sc.SqlConnection.Clone|API> %d#, clone=%d#\n", ObjectID, clone.ObjectID);
  610. return clone;
  611. }
  612. void CloseInnerConnection() {
  613. // CloseConnection() now handles the lock
  614. // The SqlInternalConnectionTds is set to OpenBusy during close, once this happens the cast below will fail and
  615. // the command will no longer be cancelable. It might be desirable to be able to cancel the close opperation, but this is
  616. // outside of the scope of Whidbey RTM. See (SqlCommand::Cancel) for other lock.
  617. InnerConnection.CloseConnection(this, ConnectionFactory);
  618. }
  619. override public void Close() {
  620. IntPtr hscp;
  621. Bid.ScopeEnter(out hscp, "<sc.SqlConnection.Close|API> %d#" , ObjectID);
  622. Bid.CorrelationTrace("<sc.SqlConnection.Close|API|Correlation> ObjectID%d#, ActivityID %ls\n", ObjectID);
  623. try {
  624. SqlStatistics statistics = null;
  625. TdsParser bestEffortCleanupTarget = null;
  626. RuntimeHelpers.PrepareConstrainedRegions();
  627. try {
  628. #if DEBUG
  629. TdsParser.ReliabilitySection tdsReliabilitySection = new TdsParser.ReliabilitySection();
  630. RuntimeHelpers.PrepareConstrainedRegions();
  631. try {
  632. tdsReliabilitySection.Start();
  633. #else
  634. {
  635. #endif //DEBUG
  636. bestEffortCleanupTarget = SqlInternalConnection.GetBestEffortCleanupTarget(this);
  637. statistics = SqlStatistics.StartTimer(Statistics);
  638. Task reconnectTask = _currentReconnectionTask;
  639. if (reconnectTask != null && !reconnectTask.IsCompleted) {
  640. CancellationTokenSource cts = _reconnectionCancellationSource;
  641. if (cts != null) {
  642. cts.Cancel();
  643. }
  644. AsyncHelper.WaitForCompletion(reconnectTask, 0, null, rethrowExceptions: false); // we do not need to deal with possible exceptions in reconnection
  645. if (State != ConnectionState.Open) {// if we cancelled before the connection was opened
  646. OnStateChange(DbConnectionInternal.StateChangeClosed);
  647. }
  648. }
  649. CancelOpenAndWait();
  650. CloseInnerConnection();
  651. GC.SuppressFinalize(this);
  652. if (null != Statistics) {
  653. ADP.TimerCurrent(out _statistics._closeTimestamp);
  654. }
  655. }
  656. #if DEBUG
  657. finally {
  658. tdsReliabilitySection.Stop();
  659. }
  660. #endif //DEBUG
  661. }
  662. catch (System.OutOfMemoryException e) {
  663. Abort(e);
  664. throw;
  665. }
  666. catch (System.StackOverflowException e) {
  667. Abort(e);
  668. throw;
  669. }
  670. catch (System.Threading.ThreadAbortException e) {
  671. Abort(e);
  672. SqlInternalConnection.BestEffortCleanup(bestEffortCleanupTarget);
  673. throw;
  674. }
  675. finally {
  676. SqlStatistics.StopTimer(statistics);
  677. }
  678. }
  679. finally {
  680. SqlDebugContext sdc = _sdc;
  681. _sdc = null;
  682. Bid.ScopeLeave(ref hscp);
  683. if (sdc != null) {
  684. sdc.Dispose();
  685. }
  686. }
  687. }
  688. new public SqlCommand CreateCommand() {
  689. return new SqlCommand(null, this);
  690. }
  691. private void DisposeMe(bool disposing) { // MDAC 65459
  692. _credential = null; // clear credential here rather than in IDisposable.Dispose as this is only specific to SqlConnection only
  693. // IDisposable.Dispose is generated code from a template and used by other providers as well
  694. if (!disposing) {
  695. // DevDiv2 Bug 457934:SQLConnection leaks when not disposed
  696. // http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/457934
  697. // For non-pooled connections we need to make sure that if the SqlConnection was not closed, then we release the GCHandle on the stateObject to allow it to be GCed
  698. // For pooled connections, we will rely on the pool reclaiming the connection
  699. var innerConnection = (InnerConnection as SqlInternalConnectionTds);
  700. if ((innerConnection != null) && (!innerConnection.ConnectionOptions.Pooling)) {
  701. var parser = innerConnection.Parser;
  702. if ((parser != null) && (parser._physicalStateObj != null)) {
  703. parser._physicalStateObj.DecrementPendingCallbacks(release: false);
  704. }
  705. }
  706. }
  707. }
  708. #if !MOBILE
  709. public void EnlistDistributedTransaction(System.EnterpriseServices.ITransaction transaction) {
  710. if (IsContextConnection) {
  711. throw SQL.NotAvailableOnContextConnection();
  712. }
  713. EnlistDistributedTransactionHelper(transaction);
  714. }
  715. #endif
  716. override public void Open() {
  717. IntPtr hscp;
  718. Bid.ScopeEnter(out hscp, "<sc.SqlConnection.Open|API> %d#", ObjectID) ;
  719. Bid.CorrelationTrace("<sc.SqlConnection.Open|API|Correlation> ObjectID%d#, ActivityID %ls\n", ObjectID);
  720. try {
  721. if (StatisticsEnabled) {
  722. if (null == _statistics) {
  723. _statistics = new SqlStatistics();
  724. }
  725. else {
  726. _statistics.ContinueOnNewConnection();
  727. }
  728. }
  729. SqlStatistics statistics = null;
  730. RuntimeHelpers.PrepareConstrainedRegions();
  731. try {
  732. statistics = SqlStatistics.StartTimer(Statistics);
  733. if (!TryOpen(null)) {
  734. throw ADP.InternalError(ADP.InternalErrorCode.SynchronousConnectReturnedPending);
  735. }
  736. }
  737. finally {
  738. SqlStatistics.StopTimer(statistics);
  739. }
  740. }
  741. finally {
  742. Bid.ScopeLeave(ref hscp);
  743. }
  744. }
  745. internal void RegisterWaitingForReconnect(Task waitingTask) {
  746. if (((SqlConnectionString)ConnectionOptions).MARS) {
  747. return;
  748. }
  749. Interlocked.CompareExchange(ref _asyncWaitingForReconnection, waitingTask, null);
  750. if (_asyncWaitingForReconnection != waitingTask) { // somebody else managed to register
  751. throw SQL.MARSUnspportedOnConnection();
  752. }
  753. }
  754. private async Task ReconnectAsync(int timeout) {
  755. try {
  756. long commandTimeoutExpiration = 0;
  757. if (timeout > 0) {
  758. commandTimeoutExpiration = ADP.TimerCurrent() + ADP.TimerFromSeconds(timeout);
  759. }
  760. CancellationTokenSource cts = new CancellationTokenSource();
  761. _reconnectionCancellationSource = cts;
  762. CancellationToken ctoken = cts.Token;
  763. int retryCount = _connectRetryCount; // take a snapshot: could be changed by modifying the connection string
  764. for (int attempt = 0; attempt < retryCount; attempt++) {
  765. if (ctoken.IsCancellationRequested) {
  766. Bid.Trace("<sc.SqlConnection.ReconnectAsync|INFO> Orginal ClientConnectionID %ls - reconnection cancelled\n", _originalConnectionId.ToString());
  767. return;
  768. }
  769. try {
  770. _impersonateIdentity = _lastIdentity;
  771. try {
  772. ForceNewConnection = true;
  773. await OpenAsync(ctoken).ConfigureAwait(false);
  774. // On success, increment the reconnect count - we don't really care if it rolls over since it is approx.
  775. _reconnectCount = unchecked(_reconnectCount + 1);
  776. #if DEBUG
  777. Debug.Assert(_recoverySessionData._debugReconnectDataApplied, "Reconnect data was not applied !");
  778. #endif
  779. }
  780. finally {
  781. _impersonateIdentity = null;
  782. ForceNewConnection = false;
  783. }
  784. Bid.Trace("<sc.SqlConnection.ReconnectIfNeeded|INFO> Reconnection suceeded. ClientConnectionID %ls -> %ls \n", _originalConnectionId.ToString(), ClientConnectionId.ToString());
  785. return;
  786. }
  787. catch (SqlException e) {
  788. Bid.Trace("<sc.SqlConnection.ReconnectAsyncINFO> Orginal ClientConnectionID %ls - reconnection attempt failed error %ls\n", _originalConnectionId.ToString(), e.Message);
  789. if (attempt == retryCount - 1) {
  790. Bid.Trace("<sc.SqlConnection.ReconnectAsync|INFO> Orginal ClientConnectionID %ls - give up reconnection\n", _originalConnectionId.ToString());
  791. throw SQL.CR_AllAttemptsFailed(e, _originalConnectionId);
  792. }
  793. if (timeout > 0 && ADP.TimerRemaining(commandTimeoutExpiration) < ADP.TimerFromSeconds(ConnectRetryInterval)) {
  794. throw SQL.CR_NextAttemptWillExceedQueryTimeout(e, _originalConnectionId);
  795. }
  796. }
  797. await Task.Delay(1000 * ConnectRetryInterval, ctoken).ConfigureAwait(false);
  798. }
  799. }
  800. finally {
  801. _recoverySessionData = null;
  802. _supressStateChangeForReconnection = false;
  803. }
  804. Debug.Assert(false, "Should not reach this point");
  805. }
  806. internal Task ValidateAndReconnect(Action beforeDisconnect, int timeout) {
  807. Task runningReconnect = _currentReconnectionTask;
  808. // This loop in the end will return not completed reconnect task or null
  809. while (runningReconnect != null && runningReconnect.IsCompleted) {
  810. // clean current reconnect task (if it is the same one we checked
  811. Interlocked.CompareExchange<Task>(ref _currentReconnectionTask, null, runningReconnect);
  812. // make sure nobody started new task (if which case we did not clean it)
  813. runningReconnect = _currentReconnectionTask;
  814. }
  815. if (runningReconnect == null) {
  816. if (_connectRetryCount > 0) {
  817. SqlInternalConnectionTds tdsConn = GetOpenTdsConnection();
  818. if (tdsConn._sessionRecoveryAcknowledged) {
  819. TdsParserStateObject stateObj = tdsConn.Parser._physicalStateObj;
  820. if (!stateObj.ValidateSNIConnection()) {
  821. if (tdsConn.Parser._sessionPool != null) {
  822. if (tdsConn.Parser._sessionPool.ActiveSessionsCount > 0) {
  823. // >1 MARS session
  824. if (beforeDisconnect != null) {
  825. beforeDisconnect();
  826. }
  827. OnError(SQL.CR_UnrecoverableClient(ClientConnectionId), true, null);
  828. }
  829. }
  830. SessionData cData = tdsConn.CurrentSessionData;
  831. cData.AssertUnrecoverableStateCountIsCorrect();
  832. if (cData._unrecoverableStatesCount == 0) {
  833. bool callDisconnect = false;
  834. lock (_reconnectLock) {
  835. tdsConn.CheckEnlistedTransactionBinding();
  836. runningReconnect = _currentReconnectionTask; // double check after obtaining the lock
  837. if (runningReconnect == null) {
  838. if (cData._unrecoverableStatesCount == 0) { // could change since the first check, but now is stable since connection is know to be broken
  839. _originalConnectionId = ClientConnectionId;
  840. Bid.Trace("<sc.SqlConnection.ReconnectIfNeeded|INFO> Connection ClientConnectionID %ls is invalid, reconnecting\n", _originalConnectionId.ToString());
  841. _recoverySessionData = cData;
  842. if (beforeDisconnect != null) {
  843. beforeDisconnect();
  844. }
  845. try {
  846. _supressStateChangeForReconnection = true;
  847. tdsConn.DoomThisConnection();
  848. }
  849. catch (SqlException) {
  850. }
  851. runningReconnect = Task.Run(() => ReconnectAsync(timeout));
  852. // if current reconnect is not null, somebody already started reconnection task - some kind of race condition
  853. Debug.Assert(_currentReconnectionTask == null, "Duplicate reconnection tasks detected");
  854. _currentReconnectionTask = runningReconnect;
  855. }
  856. }
  857. else {
  858. callDisconnect = true;
  859. }
  860. }
  861. if (callDisconnect && beforeDisconnect != null) {
  862. beforeDisconnect();
  863. }
  864. }
  865. else {
  866. if (beforeDisconnect != null) {
  867. beforeDisconnect();
  868. }
  869. OnError(SQL.CR_UnrecoverableServer(ClientConnectionId), true, null);
  870. }
  871. } // ValidateSNIConnection
  872. } // sessionRecoverySupported
  873. } // connectRetryCount>0
  874. }
  875. else { // runningReconnect = null
  876. if (beforeDisconnect != null) {
  877. beforeDisconnect();
  878. }
  879. }
  880. return runningReconnect;
  881. }
  882. // this is straightforward, but expensive method to do connection resiliency - it take locks and all prepartions as for TDS request
  883. partial void RepairInnerConnection() {
  884. WaitForPendingReconnection();
  885. if (_connectRetryCount == 0) {
  886. return;
  887. }
  888. SqlInternalConnectionTds tdsConn = InnerConnection as SqlInternalConnectionTds;
  889. if (tdsConn != null) {
  890. tdsConn.ValidateConnectionForExecute(null);
  891. tdsConn.GetSessionAndReconnectIfNeeded((SqlConnection)this);
  892. }
  893. }
  894. private void WaitForPendingReconnection() {
  895. Task reconnectTask = _currentReconnectionTask;
  896. if (reconnectTask != null && !reconnectTask.IsCompleted) {
  897. AsyncHelper.WaitForCompletion(reconnectTask, 0, null, rethrowExceptions: false);
  898. }
  899. }
  900. void CancelOpenAndWait()
  901. {
  902. // copy from member to avoid changes by background thread
  903. var completion = _currentCompletion;
  904. if (completion != null)
  905. {
  906. completion.Item1.TrySetCanceled();
  907. ((IAsyncResult)completion.Item2).AsyncWaitHandle.WaitOne();
  908. }
  909. Debug.Assert(_currentCompletion == null, "After waiting for an async call to complete, there should be no completion source");
  910. }
  911. public override Task OpenAsync(CancellationToken cancellationToken) {
  912. IntPtr hscp;
  913. Bid.ScopeEnter(out hscp, "<sc.SqlConnection.OpenAsync|API> %d#", ObjectID) ;
  914. Bid.CorrelationTrace("<sc.SqlConnection.OpenAsync|API|Correlation> ObjectID%d#, ActivityID %ls\n", ObjectID);
  915. try {
  916. if (StatisticsEnabled) {
  917. if (null == _statistics) {
  918. _statistics = new SqlStatistics();
  919. }
  920. else {
  921. _statistics.ContinueOnNewConnection();
  922. }
  923. }
  924. SqlStatistics statistics = null;
  925. RuntimeHelpers.PrepareConstrainedRegions();
  926. try {
  927. statistics = SqlStatistics.StartTimer(Statistics);
  928. System.Transactions.Transaction transaction = ADP.GetCurrentTransaction();
  929. TaskCompletionSource<DbConnectionInternal> completion = new TaskCompletionSource<DbConnectionInternal>(transaction);
  930. TaskCompletionSource<object> result = new TaskCompletionSource<object>();
  931. if (cancellationToken.IsCancellationRequested) {
  932. result.SetCanceled();
  933. return result.Task;
  934. }
  935. if (IsContextConnection) {
  936. // Async not supported on Context Connections
  937. result.SetException(ADP.ExceptionWithStackTrace(SQL.NotAvailableOnContextConnection()));
  938. return result.Task;
  939. }
  940. bool completed;
  941. try {
  942. completed = TryOpen(completion);
  943. }
  944. catch (Exception e) {
  945. result.SetException(e);
  946. return result.Task;
  947. }
  948. if (completed) {
  949. result.SetResult(null);
  950. }
  951. else {
  952. CancellationTokenRegistration registration = new CancellationTokenRegistration();
  953. if (cancellationToken.CanBeCanceled) {
  954. registration = cancellationToken.Register(() => completion.TrySetCanceled());
  955. }
  956. OpenAsyncRetry retry = new OpenAsyncRetry(this, completion, result, registration);
  957. _currentCompletion = new Tuple<TaskCompletionSource<DbConnectionInternal>, Task>(completion, result.Task);
  958. completion.Task.ContinueWith(retry.Retry, TaskScheduler.Default);
  959. return result.Task;
  960. }
  961. return result.Task;
  962. }
  963. finally {
  964. SqlStatistics.StopTimer(statistics);
  965. }
  966. }
  967. finally {
  968. Bid.ScopeLeave(ref hscp);
  969. }
  970. }
  971. private class OpenAsyncRetry {
  972. SqlConnection _parent;
  973. TaskCompletionSource<DbConnectionInternal> _retry;
  974. TaskCompletionSource<object> _result;
  975. CancellationTokenRegistration _registration;
  976. public OpenAsyncRetry(SqlConnection parent, TaskCompletionSource<DbConnectionInternal> retry, TaskCompletionSource<object> result, CancellationTokenRegistration registration) {
  977. _parent = parent;
  978. _retry = retry;
  979. _result = result;
  980. _registration = registration;
  981. }
  982. internal void Retry(Task<DbConnectionInternal> retryTask) {
  983. Bid.Trace("<sc.SqlConnection.OpenAsyncRetry|Info> %d#\n", _parent.ObjectID);
  984. _registration.Dispose();
  985. try {
  986. SqlStatistics statistics = null;
  987. RuntimeHelpers.PrepareConstrainedRegions();
  988. try {
  989. statistics = SqlStatistics.StartTimer(_parent.Statistics);
  990. if (retryTask.IsFaulted) {
  991. Exception e = retryTask.Exception.InnerException;
  992. _parent.CloseInnerConnection();
  993. _parent._currentCompletion = null;
  994. _result.SetException(retryTask.Exception.InnerException);
  995. }
  996. else if (retryTask.IsCanceled) {
  997. _parent.CloseInnerConnection();
  998. _parent._currentCompletion = null;
  999. _result.SetCanceled();
  1000. }
  1001. else {
  1002. bool result;
  1003. // protect continuation from ----s with close and cancel
  1004. lock (_parent.InnerConnection) {
  1005. result = _parent.TryOpen(_retry);
  1006. }
  1007. if (result)
  1008. {
  1009. _parent._currentCompletion = null;
  1010. _result.SetResult(null);
  1011. }
  1012. else {
  1013. _parent.CloseInnerConnection();
  1014. _parent._currentCompletion = null;
  1015. _result.SetException(ADP.ExceptionWithStackTrace(ADP.InternalError(ADP.InternalErrorCode.CompletedConnectReturnedPending)));
  1016. }
  1017. }
  1018. }
  1019. finally {
  1020. SqlStatistics.StopTimer(statistics);
  1021. }
  1022. }
  1023. catch (Exception e) {
  1024. _parent.CloseInnerConnection();
  1025. _parent._currentCompletion = null;
  1026. _result.SetException(e);
  1027. }
  1028. }
  1029. }
  1030. private bool TryOpen(TaskCompletionSource<DbConnectionInternal> retry) {
  1031. if (_impersonateIdentity != null) {
  1032. if (_impersonateIdentity.User == DbConnectionPoolIdentity.GetCurrentWindowsIdentity().User) {
  1033. return TryOpenInner(retry);
  1034. }
  1035. else {
  1036. using (WindowsImpersonationContext context = _impersonateIdentity.Impersonate()) {
  1037. return TryOpenInner(retry);
  1038. }
  1039. }
  1040. }
  1041. else {
  1042. if (this.UsesIntegratedSecurity((SqlConnectionString)ConnectionOptions)) {
  1043. _lastIdentity = DbConnectionPoolIdentity.GetCurrentWindowsIdentity();
  1044. }
  1045. else {
  1046. _lastIdentity = null;
  1047. }
  1048. return TryOpenInner(retry);
  1049. }
  1050. }
  1051. private bool TryOpenInner(TaskCompletionSource<DbConnectionInternal> retry) {
  1052. TdsParser bestEffortCleanupTarget = null;
  1053. RuntimeHelpers.PrepareConstrainedRegions();
  1054. try {
  1055. #if DEBUG
  1056. TdsParser.ReliabilitySection tdsReliabilitySection = new TdsParser.ReliabilitySection();
  1057. RuntimeHelpers.PrepareConstrainedRegions();
  1058. try {
  1059. tdsReliabilitySection.Start();
  1060. #else
  1061. {
  1062. #endif //DEBUG
  1063. if (ForceNewConnection) {
  1064. if (!InnerConnection.TryReplaceConnection(this, ConnectionFactory, retry, UserConnectionOptions)) {
  1065. return false;
  1066. }
  1067. }
  1068. else {
  1069. if (!InnerConnection.TryOpenConnection(this, ConnectionFactory, retry, UserConnectionOptions)) {
  1070. return false;
  1071. }
  1072. }
  1073. // does not require GC.KeepAlive(this) because of OnStateChange
  1074. // GetBestEffortCleanup must happen AFTER OpenConnection to get the correct target.
  1075. bestEffortCleanupTarget = SqlInternalConnection.GetBestEffortCleanupTarget(this);
  1076. var tdsInnerConnection = (InnerConnection as SqlInternalConnectionTds);
  1077. if (tdsInnerConnection == null) {
  1078. SqlInternalConnectionSmi innerConnection = (InnerConnection as SqlInternalConnectionSmi);
  1079. innerConnection.AutomaticEnlistment();
  1080. }
  1081. else {
  1082. Debug.Assert(tdsInnerConnection.Parser != null, "Where's the parser?");
  1083. if (!tdsInnerConnection.ConnectionOptions.Pooling) {
  1084. // For non-pooled connections, we need to make sure that the finalizer does actually run to avoid leaking SNI handles
  1085. GC.ReRegisterForFinalize(this);
  1086. }
  1087. if (StatisticsEnabled) {
  1088. ADP.TimerCurrent(out _statistics._openTimestamp);
  1089. tdsInnerConnection.Parser.Statistics = _statistics;
  1090. }
  1091. else {
  1092. tdsInnerConnection.Parser.Statistics = null;
  1093. _statistics = null; // in case of previous Open/Close/reset_CollectStats sequence
  1094. }
  1095. CompleteOpen();
  1096. }
  1097. }
  1098. #if DEBUG
  1099. finally {
  1100. tdsReliabilitySection.Stop();
  1101. }
  1102. #endif //DEBUG
  1103. }
  1104. catch (System.OutOfMemoryException e) {
  1105. Abort(e);
  1106. throw;
  1107. }
  1108. catch (System.StackOverflowException e) {
  1109. Abort(e);
  1110. throw;
  1111. }
  1112. catch (System.Threading.ThreadAbortException e) {
  1113. Abort(e);
  1114. SqlInternalConnection.BestEffortCleanup(bestEffortCleanupTarget);
  1115. throw;
  1116. }
  1117. return true;
  1118. }
  1119. //
  1120. // INTERNAL PROPERTIES
  1121. //
  1122. internal bool HasLocalTransaction {
  1123. get {
  1124. return GetOpenConnection().HasLocalTransaction;
  1125. }
  1126. }
  1127. internal bool HasLocalTransactionFromAPI {
  1128. get {
  1129. Task reconnectTask = _currentReconnectionTask;
  1130. if (reconnectTask != null && !reconnectTask.IsCompleted) {
  1131. return false; //we will not go into reconnection if we are inside the transaction
  1132. }
  1133. return GetOpenConnection().HasLocalTransactionFromAPI;
  1134. }
  1135. }
  1136. internal bool IsShiloh {
  1137. get {
  1138. if (_currentReconnectionTask != null) { // holds true even if task is completed
  1139. return true; // if CR is enabled, connection, if established, will be Katmai+
  1140. }
  1141. return GetOpenConnection().IsShiloh;
  1142. }
  1143. }
  1144. internal bool IsYukonOrNewer {
  1145. get {
  1146. if (_currentReconnectionTask != null) { // holds true even if task is completed
  1147. return true; // if CR is enabled, connection, if established, will be Katmai+
  1148. }
  1149. return GetOpenConnection().IsYukonOrNewer;
  1150. }
  1151. }
  1152. internal bool IsKatmaiOrNewer {
  1153. get {
  1154. if (_currentReconnectionTask != null) { // holds true even if task is completed
  1155. return true; // if CR is enabled, connection, if established, will be Katmai+
  1156. }
  1157. return GetOpenConnection().IsKatmaiOrNewer;
  1158. }
  1159. }
  1160. internal TdsParser Parser {
  1161. get {
  1162. SqlInternalConnectionTds tdsConnection = (GetOpenConnection() as SqlInternalConnectionTds);
  1163. if (null == tdsConnection) {
  1164. throw SQL.NotAvailableOnContextConnection();
  1165. }
  1166. return tdsConnection.Parser;
  1167. }
  1168. }
  1169. internal bool Asynchronous {
  1170. get {
  1171. SqlConnectionString constr = (SqlConnectionString)ConnectionOptions;
  1172. return ((null != constr) ? constr.Asynchronous : SqlConnectionString.DEFAULT.Asynchronous);
  1173. }
  1174. }
  1175. //
  1176. // INTERNAL METHODS
  1177. //
  1178. internal void ValidateConnectionForExecute(string method, SqlCommand command) {
  1179. Task asyncWaitingForReconnection=_asyncWaitingForReconnection;
  1180. if (asyncWaitingForReconnection!=null) {
  1181. if (!asyncWaitingForReconnection.IsCompleted) {
  1182. throw SQL.MARSUnspportedOnConnection();
  1183. }
  1184. else {
  1185. Interlocked.CompareExchange(ref _asyncWaitingForReconnection, null, asyncWaitingForReconnection);
  1186. }
  1187. }
  1188. if (_currentReconnectionTask != null) {
  1189. Task currentReconnectionTask = _currentReconnectionTask;
  1190. if (currentReconnectionTask != null && !currentReconnectionTask.IsCompleted) {
  1191. return; // execution will wait for this task later
  1192. }
  1193. }
  1194. SqlInternalConnection innerConnection = GetOpenConnection(method);
  1195. innerConnection.ValidateConnectionForExecute(command);
  1196. }
  1197. // Surround name in brackets and then escape any end bracket to protect against SQL Injection.
  1198. // NOTE: if the user escapes it themselves it will not work, but this was the case in V1 as well
  1199. // as native OleDb and Odbc.
  1200. static internal string FixupDatabaseTransactionName(string name) {
  1201. if (!ADP.IsEmpty(name)) {
  1202. return SqlServerEscapeHelper.EscapeIdentifier(name);
  1203. }
  1204. else {
  1205. return name;
  1206. }
  1207. }
  1208. // If wrapCloseInAction is defined, then the action it defines will be run with the connection close action passed in as a parameter
  1209. // The close action also supports being run asynchronously
  1210. internal void OnError(SqlException exception, bool breakConnection, Action<Action> wrapCloseInAction) {
  1211. Debug.Assert(exception != null && exception.Errors.Count != 0, "SqlConnection: OnError called with null or empty exception!");
  1212. // Bug fix - MDAC 49022 - connection open after failure... Problem was parser was passing
  1213. // Open as a state - because the parser's connection to the netlib was open. We would
  1214. // then set the connection state to the parser's state - which is not correct. The only
  1215. // time the connection state should change to what is passed in to this function is if
  1216. // the parser is broken, then we should be closed. Changed to passing in
  1217. // TdsParserState, not ConnectionState.
  1218. // fixed by [....]
  1219. if (breakConnection && (ConnectionState.Open == State)) {
  1220. if (wrapCloseInAction != null) {
  1221. int capturedCloseCount = _closeCount;
  1222. Action closeAction = () => {
  1223. if (capturedCloseCount == _closeCount) {
  1224. Bid.Trace("<sc.SqlConnection.OnError|INFO> %d#, Connection broken.\n", ObjectID);
  1225. Close();
  1226. }
  1227. };
  1228. wrapCloseInAction(closeAction);
  1229. }
  1230. else {
  1231. Bid.Trace("<sc.SqlConnection.OnError|INFO> %d#, Connection broken.\n", ObjectID);
  1232. Close();
  1233. }
  1234. }
  1235. if (exception.Class >= TdsEnums.MIN_ERROR_CLASS) {
  1236. // It is an error, and should be thrown. Class of TdsEnums.MIN_ERROR_CLASS or above is an error,
  1237. // below TdsEnums.MIN_ERROR_CLASS denotes an info message.
  1238. throw exception;
  1239. }
  1240. else {
  1241. // If it is a class < TdsEnums.MIN_ERROR_CLASS, it is a warning collection - so pass to handler
  1242. this.OnInfoMessage(new SqlInfoMessageEventArgs(exception));
  1243. }
  1244. }
  1245. //
  1246. // PRIVATE METHODS
  1247. //
  1248. // SxS: using Debugger.IsAttached
  1249. //
  1250. [ResourceExposure(ResourceScope.None)]
  1251. [ResourceConsumption(ResourceScope.Process, ResourceScope.Process)]
  1252. private void CompleteOpen() {
  1253. Debug.Assert(ConnectionState.Open == State, "CompleteOpen not open");
  1254. // be sure to mark as open so SqlDebugCheck can issue Query
  1255. // check to see if we need to hook up sql-debugging if a debugger is attached
  1256. // We only need this check for Shiloh and earlier servers.
  1257. if (!GetOpenConnection().IsYukonOrNewer &&
  1258. System.Diagnostics.Debugger.IsAttached) {
  1259. bool debugCheck = false;
  1260. try {
  1261. new SecurityPermission(SecurityPermissionFlag.UnmanagedCode).Demand(); // MDAC 66682, 69017
  1262. debugCheck = true;
  1263. }
  1264. catch (SecurityException e) {
  1265. ADP.TraceExceptionWithoutRethrow(e);
  1266. }
  1267. if (debugCheck) {
  1268. // if we don't have Unmanaged code permission, don't check for debugging
  1269. // but let the connection be opened while under the debugger
  1270. CheckSQLDebugOnConnect();
  1271. }
  1272. }
  1273. }
  1274. internal SqlInternalConnection GetOpenConnection() {
  1275. SqlInternalConnection innerConnection = (InnerConnection as SqlInternalConnection);
  1276. if (null == innerConnection) {
  1277. throw ADP.ClosedConnectionError();
  1278. }
  1279. return innerConnection;
  1280. }
  1281. internal SqlInternalConnection GetOpenConnection(string method) {
  1282. DbConnectionInternal innerConnection = InnerConnection;
  1283. SqlInternalConnection innerSqlConnection = (innerConnection as SqlInternalConnection);
  1284. if (null == innerSqlConnection) {
  1285. throw ADP.OpenConnectionRequired(method, innerConnection.State);
  1286. }
  1287. return innerSqlConnection;
  1288. }
  1289. internal SqlInternalConnectionTds GetOpenTdsConnection() {
  1290. SqlInternalConnectionTds innerConnection = (InnerConnection as SqlInternalConnectionTds);
  1291. if (null == innerConnection) {
  1292. throw ADP.ClosedConnectionError();
  1293. }
  1294. return innerConnection;
  1295. }
  1296. internal SqlInternalConnectionTds GetOpenTdsConnection(string method) {
  1297. SqlInternalConnectionTds innerConnection = (InnerConnection as SqlInternalConnectionTds);
  1298. if (null == innerConnection) {
  1299. throw ADP.OpenConnectionRequired(method, InnerConnection.State);
  1300. }
  1301. return innerConnection;
  1302. }
  1303. internal void OnInfoMessage(SqlInfoMessageEventArgs imevent) {
  1304. bool notified;
  1305. OnInfoMessage(imevent, out notified);
  1306. }
  1307. internal void OnInfoMessage(SqlInfoMessageEventArgs imevent, out bool notified) {
  1308. if (Bid.TraceOn) {
  1309. Debug.Assert(null != imevent, "null SqlInfoMessageEventArgs");
  1310. Bid.Trace("<sc.SqlConnection.OnInfoMessage|API|INFO> %d#, Message='%ls'\n", ObjectID, ((null != imevent) ? imevent.Message : ""));
  1311. }
  1312. SqlInfoMessageEventHandler handler = (SqlInfoMessageEventHandler)Events[EventInfoMessage];
  1313. if (null != handler) {
  1314. notified = true;
  1315. try {
  1316. handler(this, imevent);
  1317. }
  1318. catch (Exception e) { // MDAC 53175
  1319. if (!ADP.IsCatchableOrSecurityExceptionType(e)) {
  1320. throw;
  1321. }
  1322. ADP.TraceExceptionWithoutRethrow(e);
  1323. }
  1324. } else {
  1325. notified = false;
  1326. }
  1327. }
  1328. //
  1329. // SQL DEBUGGING SUPPORT
  1330. //
  1331. // this only happens once per connection
  1332. // SxS: using named file mapping APIs
  1333. //
  1334. [ResourceExposure(ResourceScope.None)]
  1335. [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
  1336. private void CheckSQLDebugOnConnect() {
  1337. IntPtr hFileMap;
  1338. uint pid = (uint)SafeNativeMethods.GetCurrentProcessId();
  1339. string mapFileName;
  1340. // If Win2k or later, prepend "Global\\" to enable this to work through TerminalServices.
  1341. if (ADP.IsPlatformNT5) {
  1342. mapFileName = "Global\\" + TdsEnums.SDCI_MAPFILENAME;
  1343. }
  1344. else {
  1345. mapFileName = TdsEnums.SDCI_MAPFILENAME;
  1346. }
  1347. mapFileName = mapFileName + pid.ToString(CultureInfo.InvariantCulture);
  1348. hFileMap = NativeMethods.OpenFileMappingA(0x4/*FILE_MAP_READ*/, false, mapFileName);
  1349. if (ADP.PtrZero != hFileMap) {
  1350. IntPtr pMemMap = NativeMethods.MapViewOfFile(hFileMap, 0x4/*FILE_MAP_READ*/, 0, 0, IntPtr.Zero);
  1351. if (ADP.PtrZero != pMemMap) {
  1352. SqlDebugContext sdc = new SqlDebugContext();
  1353. sdc.hMemMap = hFileMap;
  1354. sdc.pMemMap = pMemMap;
  1355. sdc.pid = pid;
  1356. // optimization: if we only have to refresh memory-mapped data at connection open time
  1357. // optimization: then call here instead of in CheckSQLDebug() which gets called
  1358. // optimization: at command execution time
  1359. // RefreshMemoryMappedData(sdc);
  1360. // delaying setting out global state until after we issue this first SQLDebug command so that
  1361. // we don't reentrantly call into CheckSQLDebug
  1362. CheckSQLDebug(sdc);
  1363. // now set our global state
  1364. _sdc = sdc;
  1365. }
  1366. }
  1367. }
  1368. // This overload is called by the Command object when executing stored procedures. Note that
  1369. // if SQLDebug has never been called, it is a noop.
  1370. internal void CheckSQLDebug() {
  1371. if (null != _sdc)
  1372. CheckSQLDebug(_sdc);
  1373. }
  1374. // SxS: using GetCurrentThreadId
  1375. [ResourceExposure(ResourceScope.None)]
  1376. [ResourceConsumption(ResourceScope.Process, ResourceScope.Process)]
  1377. [SecurityPermissionAttribute(SecurityAction.Demand, Flags = SecurityPermissionFlag.UnmanagedCode)] // MDAC 66682, 69017
  1378. private void CheckSQLDebug(SqlDebugContext sdc) {
  1379. // check to see if debugging has been activated
  1380. Debug.Assert(null != sdc, "SQL Debug: invalid null debugging context!");
  1381. #pragma warning disable 618
  1382. uint tid = (uint)AppDomain.GetCurrentThreadId(); // Sql Debugging doesn't need fiber support;
  1383. #pragma warning restore 618
  1384. RefreshMemoryMappedData(sdc);
  1385. //
  1386. // If we get here, the debugger must be hooked up.
  1387. if (!sdc.active) {
  1388. if (sdc.fOption/*TdsEnums.SQLDEBUG_ON*/) {
  1389. // turn on
  1390. sdc.active = true;
  1391. sdc.tid = tid;
  1392. try {
  1393. IssueSQLDebug(TdsEnums.SQLDEBUG_ON, sdc.machineName, sdc.pid, sdc.dbgpid, sdc.sdiDllName, sdc.data);
  1394. sdc.tid = 0; // reset so that the first successful time through, we notify the server of the context switch
  1395. }
  1396. catch {
  1397. sdc.active = false;
  1398. throw;
  1399. }
  1400. }
  1401. }
  1402. // be sure to pick up thread context switch, especially the first time through
  1403. if (sdc.active) {
  1404. if (!sdc.fOption/*TdsEnums.SQLDEBUG_OFF*/) {
  1405. // turn off and free the memory
  1406. sdc.Dispose();
  1407. // okay if we throw out here, no state to clean up
  1408. IssueSQLDebug(TdsEnums.SQLDEBUG_OFF, null, 0, 0, null, null);
  1409. }
  1410. else {
  1411. // notify server of context change
  1412. if (sdc.tid != tid) {
  1413. sdc.tid = tid;
  1414. try {
  1415. IssueSQLDebug(TdsEnums.SQLDEBUG_CONTEXT, null, sdc.pid, sdc.tid, null, null);
  1416. }
  1417. catch {
  1418. sdc.tid = 0;
  1419. throw;
  1420. }
  1421. }
  1422. }
  1423. }
  1424. }
  1425. private void IssueSQLDebug(uint option, string machineName, uint pid, uint id, string sdiDllName, byte[] data) {
  1426. if (GetOpenConnection().IsYukonOrNewer) {
  1427. //
  1428. return;
  1429. }
  1430. //
  1431. SqlCommand c = new SqlCommand(TdsEnums.SP_SDIDEBUG, this);
  1432. c.CommandType = CommandType.StoredProcedure;
  1433. // context param
  1434. SqlParameter p = new SqlParameter(null, SqlDbType.VarChar, TdsEnums.SQLDEBUG_MODE_NAMES[option].Length);
  1435. p.Value = TdsEnums.SQLDEBUG_MODE_NAMES[option];
  1436. c.Parameters.Add(p);
  1437. if (option == TdsEnums.SQLDEBUG_ON) {
  1438. // debug dll name
  1439. p = new SqlParameter(null, SqlDbType.VarChar, sdiDllName.Length);
  1440. p.Value = sdiDllName;
  1441. c.Parameters.Add(p);
  1442. // debug machine name
  1443. p = new SqlParameter(null, SqlDbType.VarChar, machineName.Length);
  1444. p.Value = machineName;
  1445. c.Parameters.Add(p);
  1446. }
  1447. if (option != TdsEnums.SQLDEBUG_OFF) {
  1448. // client pid
  1449. p = new SqlParameter(null, SqlDbType.Int);
  1450. p.Value = pid;
  1451. c.Parameters.Add(p);
  1452. // dbgpid or tid
  1453. p = new SqlParameter(null, SqlDbType.Int);
  1454. p.Value = id;
  1455. c.Parameters.Add(p);
  1456. }
  1457. if (option == TdsEnums.SQLDEBUG_ON) {
  1458. // debug data
  1459. p = new SqlParameter(null, SqlDbType.VarBinary, (null != data) ? data.Length : 0);
  1460. p.Value = data;
  1461. c.Parameters.Add(p);
  1462. }
  1463. c.ExecuteNonQuery();
  1464. }
  1465. public static void ChangePassword(string connectionString, string newPassword) {
  1466. IntPtr hscp;
  1467. Bid.ScopeEnter(out hscp, "<sc.SqlConnection.ChangePassword|API>") ;
  1468. Bid.CorrelationTrace("<sc.SqlConnection.ChangePassword|API|Correlation> ActivityID %ls\n");
  1469. try {
  1470. if (ADP.IsEmpty(connectionString)) {
  1471. throw SQL.ChangePasswordArgumentMissing("connectionString");
  1472. }
  1473. if (ADP.IsEmpty(newPassword)) {
  1474. throw SQL.ChangePasswordArgumentMissing("newPassword");
  1475. }
  1476. if (TdsEnums.MAXLEN_NEWPASSWORD < newPassword.Length) {
  1477. throw ADP.InvalidArgumentLength("newPassword", TdsEnums.MAXLEN_NEWPASSWORD);
  1478. }
  1479. SqlConnectionPoolKey key = new SqlConnectionPoolKey(connectionString, null);
  1480. SqlConnectionString connectionOptions = SqlConnectionFactory.FindSqlConnectionOptions(key);
  1481. if (connectionOptions.IntegratedSecurity) {
  1482. throw SQL.ChangePasswordConflictsWithSSPI();
  1483. }
  1484. if (! ADP.IsEmpty(connectionOptions.AttachDBFilename)) {
  1485. throw SQL.ChangePasswordUseOfUnallowedKey(SqlConnectionString.KEY.AttachDBFilename);
  1486. }
  1487. if (connectionOptions.ContextConnection) {
  1488. throw SQL.ChangePasswordUseOfUnallowedKey(SqlConnectionString.KEY.Context_Connection);
  1489. }
  1490. System.Security.PermissionSet permissionSet = connectionOptions.CreatePermissionSet();
  1491. permissionSet.Demand();
  1492. ChangePassword(connectionString, connectionOptions, null, newPassword, null);
  1493. }
  1494. finally {
  1495. Bid.ScopeLeave(ref hscp) ;
  1496. }
  1497. }
  1498. public static void ChangePassword(string connectionString, SqlCredential credential, SecureString newSecurePassword) {
  1499. IntPtr hscp;
  1500. Bid.ScopeEnter(out hscp, "<sc.SqlConnection.ChangePassword|API>") ;
  1501. Bid.CorrelationTrace("<sc.SqlConnection.ChangePassword|API|Correlation> ActivityID %ls\n");
  1502. try {
  1503. if (ADP.IsEmpty(connectionString)) {
  1504. throw SQL.ChangePasswordArgumentMissing("connectionString");
  1505. }
  1506. // check credential; not necessary to check the length of password in credential as the check is done by SqlCredential class
  1507. if (credential == null) {
  1508. throw SQL.ChangePasswordArgumentMissing("credential");
  1509. }
  1510. if (newSecurePassword == null || newSecurePassword.Length == 0) {
  1511. throw SQL.ChangePasswordArgumentMissing("newSecurePassword");;
  1512. }
  1513. if (!newSecurePassword.IsReadOnly()) {
  1514. throw ADP.MustBeReadOnly("newSecurePassword");
  1515. }
  1516. if (TdsEnums.MAXLEN_NEWPASSWORD < newSecurePassword.Length) {
  1517. throw ADP.InvalidArgumentLength("newSecurePassword", TdsEnums.MAXLEN_NEWPASSWORD);
  1518. }
  1519. SqlConnectionPoolKey key = new SqlConnectionPoolKey(connectionString, credential);
  1520. SqlConnectionString connectionOptions = SqlConnectionFactory.FindSqlConnectionOptions(key);
  1521. // Check for incompatible connection string value with SqlCredential
  1522. if (!ADP.IsEmpty(connectionOptions.UserID) || !ADP.IsEmpty(connectionOptions.Password)) {
  1523. throw ADP.InvalidMixedArgumentOfSecureAndClearCredential();
  1524. }
  1525. if (connectionOptions.IntegratedSecurity) {
  1526. throw SQL.ChangePasswordConflictsWithSSPI();
  1527. }
  1528. if (! ADP.IsEmpty(connectionOptions.AttachDBFilename)) {
  1529. throw SQL.ChangePasswordUseOfUnallowedKey(SqlConnectionString.KEY.AttachDBFilename);
  1530. }
  1531. if (connectionOptions.ContextConnection) {
  1532. throw SQL.ChangePasswordUseOfUnallowedKey(SqlConnectionString.KEY.Context_Connection);
  1533. }
  1534. System.Security.PermissionSet permissionSet = connectionOptions.CreatePermissionSet();
  1535. permissionSet.Demand();
  1536. ChangePassword(connectionString, connectionOptions, credential, null, newSecurePassword);
  1537. }
  1538. finally {
  1539. Bid.ScopeLeave(ref hscp) ;
  1540. }
  1541. }
  1542. private static void ChangePassword(string connectionString, SqlConnectionString connectionOptions, SqlCredential credential, string newPassword, SecureString newSecurePassword ) {
  1543. // note: This is the only case where we directly construt the internal connection, passing in the new password.
  1544. // Normally we would simply create a regular connectoin and open it but there is no other way to pass the
  1545. // new password down to the constructor. Also it would have an unwanted impact on the connection pool
  1546. //
  1547. using (SqlInternalConnectionTds con = new SqlInternalConnectionTds(null, connectionOptions, credential, null, newPassword, newSecurePassword, false)) {
  1548. if (!con.IsYukonOrNewer) {
  1549. throw SQL.ChangePasswordRequiresYukon();
  1550. }
  1551. }
  1552. SqlConnectionPoolKey key = new SqlConnectionPoolKey(connectionString, credential);
  1553. SqlConnectionFactory.SingletonInstance.ClearPool(key);
  1554. }
  1555. internal void RegisterForConnectionCloseNotification<T>(ref Task<T> outterTask, object value, int tag) {
  1556. // Connection exists, schedule removal, will be added to ref collection after calling ValidateAndReconnect
  1557. outterTask = outterTask.ContinueWith(task => {
  1558. RemoveWeakReference(value);
  1559. return task;
  1560. }, TaskScheduler.Default).Unwrap();
  1561. }
  1562. // updates our context with any changes made to the memory-mapped data by an external process
  1563. static private void RefreshMemoryMappedData(SqlDebugContext sdc) {
  1564. Debug.Assert(ADP.PtrZero != sdc.pMemMap, "SQL Debug: invalid null value for pMemMap!");
  1565. // copy memory mapped file contents into managed types
  1566. MEMMAP memMap = (MEMMAP)Marshal.PtrToStructure(sdc.pMemMap, typeof(MEMMAP));
  1567. sdc.dbgpid = memMap.dbgpid;
  1568. sdc.fOption = (memMap.fOption == 1) ? true : false;
  1569. // xlate ansi byte[] -> managed strings
  1570. Encoding cp = System.Text.Encoding.GetEncoding(TdsEnums.DEFAULT_ENGLISH_CODE_PAGE_VALUE);
  1571. sdc.machineName = cp.GetString(memMap.rgbMachineName, 0, memMap.rgbMachineName.Length);
  1572. sdc.sdiDllName = cp.GetString(memMap.rgbDllName, 0, memMap.rgbDllName.Length);
  1573. // just get data reference
  1574. sdc.data = memMap.rgbData;
  1575. }
  1576. public void ResetStatistics() {
  1577. if (IsContextConnection) {
  1578. throw SQL.NotAvailableOnContextConnection();
  1579. }
  1580. if (null != Statistics) {
  1581. Statistics.Reset();
  1582. if (ConnectionState.Open == State) {
  1583. // update timestamp;
  1584. ADP.TimerCurrent(out _statistics._openTimestamp);
  1585. }
  1586. }
  1587. }
  1588. public IDictionary RetrieveStatistics() {
  1589. if (IsContextConnection) {
  1590. throw SQL.NotAvailableOnContextConnection();
  1591. }
  1592. if (null != Statistics) {
  1593. UpdateStatistics();
  1594. return Statistics.GetHashtable();
  1595. }
  1596. else {
  1597. return new SqlStatistics().GetHashtable();
  1598. }
  1599. }
  1600. private void UpdateStatistics() {
  1601. if (ConnectionState.Open == State) {
  1602. // update timestamp
  1603. ADP.TimerCurrent(out _statistics._closeTimestamp);
  1604. }
  1605. // delegate the rest of the work to the SqlStatistics class
  1606. Statistics.UpdateStatistics();
  1607. }
  1608. //
  1609. // UDT SUPPORT
  1610. //
  1611. private Assembly ResolveTypeAssembly(AssemblyName asmRef, bool throwOnError) {
  1612. Debug.Assert(TypeSystemAssemblyVersion != null, "TypeSystemAssembly should be set !");
  1613. if (string.Compare(asmRef.Name, "Microsoft.SqlServer.Types", StringComparison.OrdinalIgnoreCase) == 0) {
  1614. if (Bid.TraceOn) {
  1615. if (asmRef.Version!=TypeSystemAssemblyVersion) {
  1616. Bid.Trace("<sc.SqlConnection.ResolveTypeAssembly> SQL CLR type version change: Server sent %ls, client will instantiate %ls",
  1617. asmRef.Version.ToString(), TypeSystemAssemblyVersion.ToString());
  1618. }
  1619. }
  1620. asmRef.Version = TypeSystemAssemblyVersion;
  1621. }
  1622. try {
  1623. return Assembly.Load(asmRef);
  1624. }
  1625. catch (Exception e) {
  1626. if (throwOnError || !ADP.IsCatchableExceptionType(e)) {
  1627. throw;
  1628. }
  1629. else {
  1630. return null;
  1631. };
  1632. }
  1633. }
  1634. //
  1635. internal void CheckGetExtendedUDTInfo(SqlMetaDataPriv metaData, bool fThrow) {
  1636. if (metaData.udtType == null) { // If null, we have not obtained extended info.
  1637. Debug.Assert(!ADP.IsEmpty(metaData.udtAssemblyQualifiedName), "Unexpected state on GetUDTInfo");
  1638. // Parameter throwOnError determines whether exception from Assembly.Load is thrown.
  1639. metaData.udtType =
  1640. Type.GetType(typeName:metaData.udtAssemblyQualifiedName, assemblyResolver:asmRef => ResolveTypeAssembly(asmRef, fThrow), typeResolver:null, throwOnError: fThrow);
  1641. if (fThrow && metaData.udtType == null) {
  1642. //
  1643. throw SQL.UDTUnexpectedResult(metaData.udtAssemblyQualifiedName);
  1644. }
  1645. }
  1646. }
  1647. internal object GetUdtValue(object value, SqlMetaDataPriv metaData, bool returnDBNull) {
  1648. if (returnDBNull && ADP.IsNull(value)) {
  1649. return DBNull.Value;
  1650. }
  1651. object o = null;
  1652. // Since the serializer doesn't handle nulls...
  1653. if (ADP.IsNull(value)) {
  1654. Type t = metaData.udtType;
  1655. Debug.Assert(t != null, "Unexpected null of udtType on GetUdtValue!");
  1656. o = t.InvokeMember("Null", BindingFlags.Public | BindingFlags.GetProperty | BindingFlags.Static, null, null, new Object[]{}, CultureInfo.InvariantCulture);
  1657. Debug.Assert(o != null);
  1658. return o;
  1659. }
  1660. else {
  1661. MemoryStream stm = new MemoryStream((byte[]) value);
  1662. o = SerializationHelperSql9.Deserialize(stm, metaData.udtType);
  1663. Debug.Assert(o != null, "object could NOT be created");
  1664. return o;
  1665. }
  1666. }
  1667. internal byte[] GetBytes(object o) {
  1668. Microsoft.SqlServer.Server.Format format = Microsoft.SqlServer.Server.Format.Native;
  1669. int maxSize = 0;
  1670. return GetBytes(o, out format, out maxSize);
  1671. }
  1672. internal byte[] GetBytes(object o, out Microsoft.SqlServer.Server.Format format, out int maxSize) {
  1673. SqlUdtInfo attr = AssemblyCache.GetInfoFromType(o.GetType());
  1674. maxSize = attr.MaxByteSize;
  1675. format = attr.SerializationFormat;
  1676. if (maxSize < -1 || maxSize >= UInt16.MaxValue) { // Do we need this? Is this the right place?
  1677. throw new InvalidOperationException(o.GetType() + ": invalid Size");
  1678. }
  1679. byte[] retval;
  1680. using (MemoryStream stm = new MemoryStream(maxSize < 0 ? 0 : maxSize)) {
  1681. SerializationHelperSql9.Serialize(stm, o);
  1682. retval = stm.ToArray();
  1683. }
  1684. return retval;
  1685. }
  1686. } // SqlConnection
  1687. //
  1688. [
  1689. ComVisible(true),
  1690. ClassInterface(ClassInterfaceType.None),
  1691. Guid("afef65ad-4577-447a-a148-83acadd3d4b9"),
  1692. ]
  1693. [System.Security.Permissions.PermissionSetAttribute(System.Security.Permissions.SecurityAction.LinkDemand, Name = "FullTrust")]
  1694. public sealed class SQLDebugging: ISQLDebug {
  1695. // Security stuff
  1696. const int STANDARD_RIGHTS_REQUIRED = (0x000F0000);
  1697. const int DELETE = (0x00010000);
  1698. const int READ_CONTROL = (0x00020000);
  1699. const int WRITE_DAC = (0x00040000);
  1700. const int WRITE_OWNER = (0x00080000);
  1701. const int SYNCHRONIZE = (0x00100000);
  1702. const int FILE_ALL_ACCESS = (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0x000001FF);
  1703. const uint GENERIC_READ = (0x80000000);
  1704. const uint GENERIC_WRITE = (0x40000000);
  1705. const uint GENERIC_EXECUTE = (0x20000000);
  1706. const uint GENERIC_ALL = (0x10000000);
  1707. const int SECURITY_DESCRIPTOR_REVISION = (1);
  1708. const int ACL_REVISION = (2);
  1709. const int SECURITY_AUTHENTICATED_USER_RID = (0x0000000B);
  1710. const int SECURITY_LOCAL_SYSTEM_RID = (0x00000012);
  1711. const int SECURITY_BUILTIN_DOMAIN_RID = (0x00000020);
  1712. const int SECURITY_WORLD_RID = (0x00000000);
  1713. const byte SECURITY_NT_AUTHORITY = 5;
  1714. const int DOMAIN_GROUP_RID_ADMINS = (0x00000200);
  1715. const int DOMAIN_ALIAS_RID_ADMINS = (0x00000220);
  1716. const int sizeofSECURITY_ATTRIBUTES = 12; // sizeof(SECURITY_ATTRIBUTES);
  1717. const int sizeofSECURITY_DESCRIPTOR = 20; // sizeof(SECURITY_DESCRIPTOR);
  1718. const int sizeofACCESS_ALLOWED_ACE = 12; // sizeof(ACCESS_ALLOWED_ACE);
  1719. const int sizeofACCESS_DENIED_ACE = 12; // sizeof(ACCESS_DENIED_ACE);
  1720. const int sizeofSID_IDENTIFIER_AUTHORITY = 6; // sizeof(SID_IDENTIFIER_AUTHORITY)
  1721. const int sizeofACL = 8; // sizeof(ACL);
  1722. private IntPtr CreateSD(ref IntPtr pDacl) {
  1723. IntPtr pSecurityDescriptor = IntPtr.Zero;
  1724. IntPtr pUserSid = IntPtr.Zero;
  1725. IntPtr pAdminSid = IntPtr.Zero;
  1726. IntPtr pNtAuthority = IntPtr.Zero;
  1727. int cbAcl = 0;
  1728. bool status = false;
  1729. pNtAuthority = Marshal.AllocHGlobal(sizeofSID_IDENTIFIER_AUTHORITY);
  1730. if (pNtAuthority == IntPtr.Zero)
  1731. goto cleanup;
  1732. Marshal.WriteInt32(pNtAuthority, 0, 0);
  1733. Marshal.WriteByte(pNtAuthority, 4, 0);
  1734. Marshal.WriteByte(pNtAuthority, 5, SECURITY_NT_AUTHORITY);
  1735. status =
  1736. NativeMethods.AllocateAndInitializeSid(
  1737. pNtAuthority,
  1738. (byte)1,
  1739. SECURITY_AUTHENTICATED_USER_RID,
  1740. 0,
  1741. 0,
  1742. 0,
  1743. 0,
  1744. 0,
  1745. 0,
  1746. 0,
  1747. ref pUserSid);
  1748. if (!status || pUserSid == IntPtr.Zero) {
  1749. goto cleanup;
  1750. }
  1751. status =
  1752. NativeMethods.AllocateAndInitializeSid(
  1753. pNtAuthority,
  1754. (byte)2,
  1755. SECURITY_BUILTIN_DOMAIN_RID,
  1756. DOMAIN_ALIAS_RID_ADMINS,
  1757. 0,
  1758. 0,
  1759. 0,
  1760. 0,
  1761. 0,
  1762. 0,
  1763. ref pAdminSid);
  1764. if (!status || pAdminSid == IntPtr.Zero) {
  1765. goto cleanup;
  1766. }
  1767. status = false;
  1768. pSecurityDescriptor = Marshal.AllocHGlobal(sizeofSECURITY_DESCRIPTOR);
  1769. if (pSecurityDescriptor == IntPtr.Zero) {
  1770. goto cleanup;
  1771. }
  1772. for (int i = 0; i < sizeofSECURITY_DESCRIPTOR; i++)
  1773. Marshal.WriteByte(pSecurityDescriptor, i, (byte)0);
  1774. cbAcl = sizeofACL
  1775. + (2 * (sizeofACCESS_ALLOWED_ACE))
  1776. + sizeofACCESS_DENIED_ACE
  1777. + NativeMethods.GetLengthSid(pUserSid)
  1778. + NativeMethods.GetLengthSid(pAdminSid);
  1779. pDacl = Marshal.AllocHGlobal(cbAcl);
  1780. if (pDacl == IntPtr.Zero) {
  1781. goto cleanup;
  1782. }
  1783. // rights must be added in a certain order. Namely, deny access first, then add access
  1784. if (NativeMethods.InitializeAcl(pDacl, cbAcl, ACL_REVISION))
  1785. if (NativeMethods.AddAccessDeniedAce(pDacl, ACL_REVISION, WRITE_DAC, pUserSid))
  1786. if (NativeMethods.AddAccessAllowedAce(pDacl, ACL_REVISION, GENERIC_READ, pUserSid))
  1787. if (NativeMethods.AddAccessAllowedAce(pDacl, ACL_REVISION, GENERIC_ALL, pAdminSid))
  1788. if (NativeMethods.InitializeSecurityDescriptor(pSecurityDescriptor, SECURITY_DESCRIPTOR_REVISION))
  1789. if (NativeMethods.SetSecurityDescriptorDacl(pSecurityDescriptor, true, pDacl, false)) {
  1790. status = true;
  1791. }
  1792. cleanup :
  1793. if (pNtAuthority != IntPtr.Zero) {
  1794. Marshal.FreeHGlobal(pNtAuthority);
  1795. }
  1796. if (pAdminSid != IntPtr.Zero)
  1797. NativeMethods.FreeSid(pAdminSid);
  1798. if (pUserSid != IntPtr.Zero)
  1799. NativeMethods.FreeSid(pUserSid);
  1800. if (status)
  1801. return pSecurityDescriptor;
  1802. else {
  1803. if (pSecurityDescriptor != IntPtr.Zero) {
  1804. Marshal.FreeHGlobal(pSecurityDescriptor);
  1805. }
  1806. }
  1807. return IntPtr.Zero;
  1808. }
  1809. // SxS: using file mapping API (CreateFileMapping)
  1810. //
  1811. [ResourceExposure(ResourceScope.None)]
  1812. [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
  1813. bool ISQLDebug.SQLDebug(int dwpidDebugger, int dwpidDebuggee, [MarshalAs(UnmanagedType.LPStr)] string pszMachineName,
  1814. [MarshalAs(UnmanagedType.LPStr)] string pszSDIDLLName, int dwOption, int cbData, byte[] rgbData) {
  1815. bool result = false;
  1816. IntPtr hFileMap = IntPtr.Zero;
  1817. IntPtr pMemMap = IntPtr.Zero;
  1818. IntPtr pSecurityDescriptor = IntPtr.Zero;
  1819. IntPtr pSecurityAttributes = IntPtr.Zero;
  1820. IntPtr pDacl = IntPtr.Zero;
  1821. // validate the structure
  1822. if (null == pszMachineName || null == pszSDIDLLName)
  1823. return false;
  1824. if (pszMachineName.Length > TdsEnums.SDCI_MAX_MACHINENAME ||
  1825. pszSDIDLLName.Length > TdsEnums.SDCI_MAX_DLLNAME)
  1826. return false;
  1827. // note that these are ansi strings
  1828. Encoding cp = System.Text.Encoding.GetEncoding(TdsEnums.DEFAULT_ENGLISH_CODE_PAGE_VALUE);
  1829. byte[] rgbMachineName = cp.GetBytes(pszMachineName);
  1830. byte[] rgbSDIDLLName = cp.GetBytes(pszSDIDLLName);
  1831. if (null != rgbData && cbData > TdsEnums.SDCI_MAX_DATA)
  1832. return false;
  1833. string mapFileName;
  1834. // If Win2k or later, prepend "Global\\" to enable this to work through TerminalServices.
  1835. if (ADP.IsPlatformNT5) {
  1836. mapFileName = "Global\\" + TdsEnums.SDCI_MAPFILENAME;
  1837. }
  1838. else {
  1839. mapFileName = TdsEnums.SDCI_MAPFILENAME;
  1840. }
  1841. mapFileName = mapFileName + dwpidDebuggee.ToString(CultureInfo.InvariantCulture);
  1842. // Create Security Descriptor
  1843. pSecurityDescriptor = CreateSD(ref pDacl);
  1844. pSecurityAttributes = Marshal.AllocHGlobal(sizeofSECURITY_ATTRIBUTES);
  1845. if ((pSecurityDescriptor == IntPtr.Zero) || (pSecurityAttributes == IntPtr.Zero))
  1846. return false;
  1847. Marshal.WriteInt32(pSecurityAttributes, 0, sizeofSECURITY_ATTRIBUTES); // nLength = sizeof(SECURITY_ATTRIBUTES)
  1848. Marshal.WriteIntPtr(pSecurityAttributes, 4, pSecurityDescriptor); // lpSecurityDescriptor = pSecurityDescriptor
  1849. Marshal.WriteInt32(pSecurityAttributes, 8, 0); // bInheritHandle = FALSE
  1850. hFileMap = NativeMethods.CreateFileMappingA(
  1851. ADP.InvalidPtr/*INVALID_HANDLE_VALUE*/,
  1852. pSecurityAttributes,
  1853. 0x4/*PAGE_READWRITE*/,
  1854. 0,
  1855. Marshal.SizeOf(typeof(MEMMAP)),
  1856. mapFileName);
  1857. if (IntPtr.Zero == hFileMap) {
  1858. goto cleanup;
  1859. }
  1860. pMemMap = NativeMethods.MapViewOfFile(hFileMap, 0x6/*FILE_MAP_READ|FILE_MAP_WRITE*/, 0, 0, IntPtr.Zero);
  1861. if (IntPtr.Zero == pMemMap) {
  1862. goto cleanup;
  1863. }
  1864. // copy data to memory-mapped file
  1865. // layout of MEMMAP structure is:
  1866. // uint dbgpid
  1867. // uint fOption
  1868. // byte[32] machineName
  1869. // byte[16] sdiDllName
  1870. // uint dbData
  1871. // byte[255] vData
  1872. int offset = 0;
  1873. Marshal.WriteInt32(pMemMap, offset, (int)dwpidDebugger);
  1874. offset += 4;
  1875. Marshal.WriteInt32(pMemMap, offset, (int)dwOption);
  1876. offset += 4;
  1877. Marshal.Copy(rgbMachineName, 0, ADP.IntPtrOffset(pMemMap, offset), rgbMachineName.Length);
  1878. offset += TdsEnums.SDCI_MAX_MACHINENAME;
  1879. Marshal.Copy(rgbSDIDLLName, 0, ADP.IntPtrOffset(pMemMap, offset), rgbSDIDLLName.Length);
  1880. offset += TdsEnums.SDCI_MAX_DLLNAME;
  1881. Marshal.WriteInt32(pMemMap, offset, (int)cbData);
  1882. offset += 4;
  1883. if (null != rgbData) {
  1884. Marshal.Copy(rgbData, 0, ADP.IntPtrOffset(pMemMap, offset), (int)cbData);
  1885. }
  1886. NativeMethods.UnmapViewOfFile(pMemMap);
  1887. result = true;
  1888. cleanup :
  1889. if (result == false) {
  1890. if (hFileMap != IntPtr.Zero)
  1891. NativeMethods.CloseHandle(hFileMap);
  1892. }
  1893. if (pSecurityAttributes != IntPtr.Zero)
  1894. Marshal.FreeHGlobal(pSecurityAttributes);
  1895. if (pSecurityDescriptor != IntPtr.Zero)
  1896. Marshal.FreeHGlobal(pSecurityDescriptor);
  1897. if (pDacl != IntPtr.Zero)
  1898. Marshal.FreeHGlobal(pDacl);
  1899. return result;
  1900. }
  1901. }
  1902. // this is a private interface to com+ users
  1903. // do not change this guid
  1904. [
  1905. ComImport,
  1906. ComVisible(true),
  1907. Guid("6cb925bf-c3c0-45b3-9f44-5dd67c7b7fe8"),
  1908. InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
  1909. BestFitMapping(false, ThrowOnUnmappableChar = true),
  1910. ]
  1911. interface ISQLDebug {
  1912. [System.Security.Permissions.PermissionSetAttribute(System.Security.Permissions.SecurityAction.LinkDemand, Name = "FullTrust")]
  1913. bool SQLDebug(
  1914. int dwpidDebugger,
  1915. int dwpidDebuggee,
  1916. [MarshalAs(UnmanagedType.LPStr)] string pszMachineName,
  1917. [MarshalAs(UnmanagedType.LPStr)] string pszSDIDLLName,
  1918. int dwOption,
  1919. int cbData,
  1920. byte[] rgbData);
  1921. }
  1922. sealed class SqlDebugContext: IDisposable {
  1923. // context data
  1924. internal uint pid = 0;
  1925. internal uint tid = 0;
  1926. internal bool active = false;
  1927. // memory-mapped data
  1928. internal IntPtr pMemMap = ADP.PtrZero;
  1929. internal IntPtr hMemMap = ADP.PtrZero;
  1930. internal uint dbgpid = 0;
  1931. internal bool fOption = false;
  1932. internal string machineName = null;
  1933. internal string sdiDllName = null;
  1934. internal byte[] data = null;
  1935. public void Dispose() {
  1936. Dispose(true);
  1937. GC.SuppressFinalize(this);
  1938. }
  1939. // using CloseHandle and UnmapViewOfFile - no exposure
  1940. [ResourceExposure(ResourceScope.None)]
  1941. [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
  1942. private void Dispose(bool disposing) {
  1943. if (disposing) {
  1944. // Nothing to do here
  1945. ;
  1946. }
  1947. if (pMemMap != IntPtr.Zero) {
  1948. NativeMethods.UnmapViewOfFile(pMemMap);
  1949. pMemMap = IntPtr.Zero;
  1950. }
  1951. if (hMemMap != IntPtr.Zero) {
  1952. NativeMethods.CloseHandle(hMemMap);
  1953. hMemMap = IntPtr.Zero;
  1954. }
  1955. active = false;
  1956. }
  1957. ~SqlDebugContext() {
  1958. Dispose(false);
  1959. }
  1960. }
  1961. // native interop memory mapped structure for sdi debugging
  1962. [StructLayoutAttribute(LayoutKind.Sequential, Pack = 1)]
  1963. internal struct MEMMAP {
  1964. [MarshalAs(UnmanagedType.U4)]
  1965. internal uint dbgpid; // id of debugger
  1966. [MarshalAs(UnmanagedType.U4)]
  1967. internal uint fOption; // 1 - start debugging, 0 - stop debugging
  1968. [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)]
  1969. internal byte[] rgbMachineName;
  1970. [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
  1971. internal byte[] rgbDllName;
  1972. [MarshalAs(UnmanagedType.U4)]
  1973. internal uint cbData;
  1974. [MarshalAs(UnmanagedType.ByValArray, SizeConst = 255)]
  1975. internal byte[] rgbData;
  1976. }
  1977. } // System.Data.SqlClient namespace