SqlDataReader.cs 206 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672
  1. //------------------------------------------------------------------------------
  2. // <copyright file="SqlDataReader.cs" company="Microsoft">
  3. // Copyright (c) Microsoft Corporation. All rights reserved.
  4. // </copyright>
  5. // <owner current="true" primary="true">[....]</owner>
  6. // <owner current="true" primary="false">[....]</owner>
  7. //------------------------------------------------------------------------------
  8. namespace System.Data.SqlClient {
  9. using System;
  10. using System.Collections;
  11. using System.Collections.Specialized;
  12. using System.ComponentModel;
  13. using System.Data;
  14. using System.Data.Sql;
  15. using System.Data.SqlTypes;
  16. using System.Data.Common;
  17. using System.Data.ProviderBase;
  18. using System.Diagnostics;
  19. using System.Globalization;
  20. using System.IO;
  21. using System.Reflection;
  22. using System.Runtime.CompilerServices;
  23. using System.Threading;
  24. using System.Xml;
  25. using Microsoft.SqlServer.Server;
  26. using System.Threading.Tasks;
  27. public class SqlDataReader : DbDataReader, IDataReader {
  28. private enum ALTROWSTATUS {
  29. Null = 0, // default and after Done
  30. AltRow, // after calling NextResult and the first AltRow is available for read
  31. Done, // after consuming the value (GetValue -> GetValueInternal)
  32. }
  33. internal class SharedState { // parameters needed to execute cleanup from parser
  34. internal int _nextColumnHeaderToRead;
  35. internal int _nextColumnDataToRead;
  36. internal long _columnDataBytesRemaining;
  37. internal bool _dataReady; // ready to ProcessRow
  38. }
  39. internal SharedState _sharedState = new SharedState();
  40. private TdsParser _parser; // TODO: Probably don't need this, since it's on the stateObj
  41. private TdsParserStateObject _stateObj;
  42. private SqlCommand _command;
  43. private SqlConnection _connection;
  44. private int _defaultLCID;
  45. private bool _haltRead; // bool to denote whether we have read first row for single row behavior
  46. private bool _metaDataConsumed;
  47. private bool _browseModeInfoConsumed;
  48. private bool _isClosed;
  49. private bool _isInitialized; // Webdata 104560
  50. private bool _hasRows;
  51. private ALTROWSTATUS _altRowStatus;
  52. private int _recordsAffected = -1;
  53. private long _defaultTimeoutMilliseconds;
  54. private SqlConnectionString.TypeSystem _typeSystem;
  55. // SQLStatistics support
  56. private SqlStatistics _statistics;
  57. private SqlBuffer[] _data; // row buffer, filled in by ReadColumnData()
  58. private SqlStreamingXml _streamingXml; // Used by Getchars on an Xml column for sequential access
  59. // buffers and metadata
  60. private _SqlMetaDataSet _metaData; // current metaData for the stream, it is lazily loaded
  61. private _SqlMetaDataSetCollection _altMetaDataSetCollection;
  62. private FieldNameLookup _fieldNameLookup;
  63. private CommandBehavior _commandBehavior;
  64. private static int _objectTypeCount; // Bid counter
  65. internal readonly int ObjectID = System.Threading.Interlocked.Increment(ref _objectTypeCount);
  66. // context
  67. // undone: we may still want to do this...it's nice to pass in an lpvoid (essentially) and just have the reader keep the state
  68. // private object _context = null; // this is never looked at by the stream object. It is used by upper layers who wish
  69. // to remain stateless
  70. // metadata (no explicit table, use 'Table')
  71. private MultiPartTableName[] _tableNames = null;
  72. private string _resetOptionsString;
  73. private int _lastColumnWithDataChunkRead;
  74. private long _columnDataBytesRead; // last byte read by user
  75. private long _columnDataCharsRead; // last char read by user
  76. private char[] _columnDataChars;
  77. private int _columnDataCharsIndex; // Column index that is currently loaded in _columnDataChars
  78. private Task _currentTask;
  79. private Snapshot _snapshot;
  80. private CancellationTokenSource _cancelAsyncOnCloseTokenSource;
  81. private CancellationToken _cancelAsyncOnCloseToken;
  82. // Used for checking if the Type parameter provided to GetValue<T> is an INullable
  83. internal static readonly Type _typeofINullable = typeof(INullable);
  84. private static readonly Type _typeofSqlString = typeof(SqlString);
  85. private SqlSequentialStream _currentStream;
  86. private SqlSequentialTextReader _currentTextReader;
  87. internal SqlDataReader(SqlCommand command, CommandBehavior behavior)
  88. {
  89. SqlConnection.VerifyExecutePermission();
  90. _command = command;
  91. _commandBehavior = behavior;
  92. if (_command != null) {
  93. _defaultTimeoutMilliseconds = (long)command.CommandTimeout * 1000L;
  94. _connection = command.Connection;
  95. if (_connection != null) {
  96. _statistics = _connection.Statistics;
  97. _typeSystem = _connection.TypeSystem;
  98. }
  99. }
  100. _sharedState._dataReady = false;
  101. _metaDataConsumed = false;
  102. _hasRows = false;
  103. _browseModeInfoConsumed = false;
  104. _currentStream = null;
  105. _currentTextReader = null;
  106. _cancelAsyncOnCloseTokenSource = new CancellationTokenSource();
  107. _cancelAsyncOnCloseToken = _cancelAsyncOnCloseTokenSource.Token;
  108. _columnDataCharsIndex = -1;
  109. }
  110. internal bool BrowseModeInfoConsumed {
  111. set {
  112. _browseModeInfoConsumed = value;
  113. }
  114. }
  115. internal SqlCommand Command {
  116. get {
  117. return _command;
  118. }
  119. }
  120. protected SqlConnection Connection {
  121. get {
  122. return _connection;
  123. }
  124. }
  125. override public int Depth {
  126. get {
  127. if (this.IsClosed) {
  128. throw ADP.DataReaderClosed("Depth");
  129. }
  130. return 0;
  131. }
  132. }
  133. // fields/attributes collection
  134. override public int FieldCount {
  135. get {
  136. if (this.IsClosed) {
  137. throw ADP.DataReaderClosed("FieldCount");
  138. }
  139. if (_currentTask != null) {
  140. throw ADP.AsyncOperationPending();
  141. }
  142. if (MetaData == null) {
  143. return 0;
  144. }
  145. return _metaData.Length;
  146. }
  147. }
  148. override public bool HasRows {
  149. get {
  150. if (this.IsClosed) {
  151. throw ADP.DataReaderClosed("HasRows");
  152. }
  153. if (_currentTask != null) {
  154. throw ADP.AsyncOperationPending();
  155. }
  156. return _hasRows;
  157. }
  158. }
  159. override public bool IsClosed {
  160. get {
  161. return _isClosed;
  162. }
  163. }
  164. internal bool IsInitialized {
  165. get {
  166. return _isInitialized;
  167. }
  168. set {
  169. Debug.Assert(value, "attempting to uninitialize a data reader?");
  170. _isInitialized = value;
  171. }
  172. }
  173. // NOTE: For PLP values this indicates the amount of data left in the current chunk (or 0 if there are no more chunks left)
  174. internal long ColumnDataBytesRemaining() {
  175. // If there are an unknown (-1) number of bytes left for a PLP, read its size
  176. if (-1 == _sharedState._columnDataBytesRemaining) {
  177. _sharedState._columnDataBytesRemaining = (long)_parser.PlpBytesLeft(_stateObj);
  178. }
  179. return _sharedState._columnDataBytesRemaining;
  180. }
  181. internal _SqlMetaDataSet MetaData {
  182. get {
  183. if (IsClosed) {
  184. throw ADP.DataReaderClosed("MetaData");
  185. }
  186. // metaData comes in pieces: colmetadata, tabname, colinfo, etc
  187. // if we have any metaData, return it. If we have none,
  188. // then fetch it
  189. if (_metaData == null && !_metaDataConsumed) {
  190. if (_currentTask != null) {
  191. throw SQL.PendingBeginXXXExists();
  192. }
  193. RuntimeHelpers.PrepareConstrainedRegions();
  194. try {
  195. #if DEBUG
  196. TdsParser.ReliabilitySection tdsReliabilitySection = new TdsParser.ReliabilitySection();
  197. RuntimeHelpers.PrepareConstrainedRegions();
  198. try {
  199. tdsReliabilitySection.Start();
  200. #else
  201. {
  202. #endif //DEBUG
  203. Debug.Assert(_stateObj == null || _stateObj._syncOverAsync, "Should not attempt pends in a synchronous call");
  204. if (!TryConsumeMetaData())
  205. {
  206. throw SQL.SynchronousCallMayNotPend();
  207. }
  208. }
  209. #if DEBUG
  210. finally {
  211. tdsReliabilitySection.Stop();
  212. }
  213. #endif //DEBUG
  214. }
  215. catch (System.OutOfMemoryException e) {
  216. _isClosed = true;
  217. if (null != _connection) {
  218. _connection.Abort(e);
  219. }
  220. throw;
  221. }
  222. catch (System.StackOverflowException e) {
  223. _isClosed = true;
  224. if (null != _connection) {
  225. _connection.Abort(e);
  226. }
  227. throw;
  228. }
  229. catch (System.Threading.ThreadAbortException e) {
  230. _isClosed = true;
  231. if (null != _connection) {
  232. _connection.Abort(e);
  233. }
  234. throw;
  235. }
  236. }
  237. return _metaData;
  238. }
  239. }
  240. internal virtual SmiExtendedMetaData[] GetInternalSmiMetaData() {
  241. SmiExtendedMetaData[] metaDataReturn = null;
  242. _SqlMetaDataSet metaData = this.MetaData;
  243. if ( null != metaData && 0 < metaData.Length ) {
  244. metaDataReturn = new SmiExtendedMetaData[metaData.visibleColumns];
  245. for( int index=0; index < metaData.Length; index++ ) {
  246. _SqlMetaData colMetaData = metaData[index];
  247. if ( !colMetaData.isHidden ) {
  248. SqlCollation collation = colMetaData.collation;
  249. string typeSpecificNamePart1 = null;
  250. string typeSpecificNamePart2 = null;
  251. string typeSpecificNamePart3 = null;
  252. if (SqlDbType.Xml == colMetaData.type) {
  253. typeSpecificNamePart1 = colMetaData.xmlSchemaCollectionDatabase;
  254. typeSpecificNamePart2 = colMetaData.xmlSchemaCollectionOwningSchema;
  255. typeSpecificNamePart3 = colMetaData.xmlSchemaCollectionName;
  256. }
  257. else if (SqlDbType.Udt == colMetaData.type) {
  258. Connection.CheckGetExtendedUDTInfo(colMetaData, true); // SQLBUDT #370593 ensure that colMetaData.udtType is set
  259. typeSpecificNamePart1 = colMetaData.udtDatabaseName;
  260. typeSpecificNamePart2 = colMetaData.udtSchemaName;
  261. typeSpecificNamePart3 = colMetaData.udtTypeName;
  262. }
  263. int length = colMetaData.length;
  264. if ( length > TdsEnums.MAXSIZE ) {
  265. length = (int) SmiMetaData.UnlimitedMaxLengthIndicator;
  266. }
  267. else if (SqlDbType.NChar == colMetaData.type
  268. ||SqlDbType.NVarChar == colMetaData.type) {
  269. length /= ADP.CharSize;
  270. }
  271. metaDataReturn[index] = new SmiQueryMetaData(
  272. colMetaData.type,
  273. length,
  274. colMetaData.precision,
  275. colMetaData.scale,
  276. (null != collation) ? collation.LCID : _defaultLCID,
  277. (null != collation) ? collation.SqlCompareOptions : SqlCompareOptions.None,
  278. colMetaData.udtType,
  279. false, // isMultiValued
  280. null, // fieldmetadata
  281. null, // extended properties
  282. colMetaData.column,
  283. typeSpecificNamePart1,
  284. typeSpecificNamePart2,
  285. typeSpecificNamePart3,
  286. colMetaData.isNullable,
  287. colMetaData.serverName,
  288. colMetaData.catalogName,
  289. colMetaData.schemaName,
  290. colMetaData.tableName,
  291. colMetaData.baseColumn,
  292. colMetaData.isKey,
  293. colMetaData.isIdentity,
  294. 0==colMetaData.updatability,
  295. colMetaData.isExpression,
  296. colMetaData.isDifferentName,
  297. colMetaData.isHidden
  298. );
  299. }
  300. }
  301. }
  302. return metaDataReturn;
  303. }
  304. override public int RecordsAffected {
  305. get {
  306. if (null != _command)
  307. return _command.InternalRecordsAffected;
  308. // cached locally for after Close() when command is nulled out
  309. return _recordsAffected;
  310. }
  311. }
  312. internal string ResetOptionsString {
  313. set {
  314. _resetOptionsString = value;
  315. }
  316. }
  317. private SqlStatistics Statistics {
  318. get {
  319. return _statistics;
  320. }
  321. }
  322. internal MultiPartTableName[] TableNames {
  323. get {
  324. return _tableNames;
  325. }
  326. set {
  327. _tableNames = value;
  328. }
  329. }
  330. override public int VisibleFieldCount {
  331. get {
  332. if (this.IsClosed) {
  333. throw ADP.DataReaderClosed("VisibleFieldCount");
  334. }
  335. _SqlMetaDataSet md = this.MetaData;
  336. if (md == null) {
  337. return 0;
  338. }
  339. return (md.visibleColumns);
  340. }
  341. }
  342. // this operator
  343. override public object this[int i] {
  344. get {
  345. return GetValue(i);
  346. }
  347. }
  348. override public object this[string name] {
  349. get {
  350. return GetValue(GetOrdinal(name));
  351. }
  352. }
  353. internal void Bind(TdsParserStateObject stateObj) {
  354. Debug.Assert(null != stateObj, "null stateobject");
  355. Debug.Assert(null == _snapshot, "Should not change during execution of asynchronous command");
  356. stateObj.Owner = this;
  357. _stateObj = stateObj;
  358. _parser = stateObj.Parser;
  359. _defaultLCID = _parser.DefaultLCID;
  360. }
  361. // Fills in a schema table with meta data information. This function should only really be called by
  362. //
  363. internal DataTable BuildSchemaTable() {
  364. _SqlMetaDataSet md = this.MetaData;
  365. Debug.Assert(null != md, "BuildSchemaTable - unexpected null metadata information");
  366. DataTable schemaTable = new DataTable("SchemaTable");
  367. schemaTable.Locale = CultureInfo.InvariantCulture;
  368. schemaTable.MinimumCapacity = md.Length;
  369. DataColumn ColumnName = new DataColumn(SchemaTableColumn.ColumnName, typeof(System.String));
  370. DataColumn Ordinal = new DataColumn(SchemaTableColumn.ColumnOrdinal, typeof(System.Int32));
  371. DataColumn Size = new DataColumn(SchemaTableColumn.ColumnSize, typeof(System.Int32));
  372. DataColumn Precision = new DataColumn(SchemaTableColumn.NumericPrecision, typeof(System.Int16));
  373. DataColumn Scale = new DataColumn(SchemaTableColumn.NumericScale, typeof(System.Int16));
  374. DataColumn DataType = new DataColumn(SchemaTableColumn.DataType, typeof(System.Type));
  375. DataColumn ProviderSpecificDataType = new DataColumn(SchemaTableOptionalColumn.ProviderSpecificDataType, typeof(System.Type));
  376. DataColumn NonVersionedProviderType = new DataColumn(SchemaTableColumn.NonVersionedProviderType, typeof(System.Int32));
  377. DataColumn ProviderType = new DataColumn(SchemaTableColumn.ProviderType, typeof(System.Int32));
  378. DataColumn IsLong = new DataColumn(SchemaTableColumn.IsLong, typeof(System.Boolean));
  379. DataColumn AllowDBNull = new DataColumn(SchemaTableColumn.AllowDBNull, typeof(System.Boolean));
  380. DataColumn IsReadOnly = new DataColumn(SchemaTableOptionalColumn.IsReadOnly, typeof(System.Boolean));
  381. DataColumn IsRowVersion = new DataColumn(SchemaTableOptionalColumn.IsRowVersion, typeof(System.Boolean));
  382. DataColumn IsUnique = new DataColumn(SchemaTableColumn.IsUnique, typeof(System.Boolean));
  383. DataColumn IsKey = new DataColumn(SchemaTableColumn.IsKey, typeof(System.Boolean));
  384. DataColumn IsAutoIncrement = new DataColumn(SchemaTableOptionalColumn.IsAutoIncrement, typeof(System.Boolean));
  385. DataColumn IsHidden = new DataColumn(SchemaTableOptionalColumn.IsHidden, typeof(System.Boolean));
  386. DataColumn BaseCatalogName = new DataColumn(SchemaTableOptionalColumn.BaseCatalogName, typeof(System.String));
  387. DataColumn BaseSchemaName = new DataColumn(SchemaTableColumn.BaseSchemaName, typeof(System.String));
  388. DataColumn BaseTableName = new DataColumn(SchemaTableColumn.BaseTableName, typeof(System.String));
  389. DataColumn BaseColumnName = new DataColumn(SchemaTableColumn.BaseColumnName, typeof(System.String));
  390. // unique to SqlClient
  391. DataColumn BaseServerName = new DataColumn(SchemaTableOptionalColumn.BaseServerName, typeof(System.String));
  392. DataColumn IsAliased = new DataColumn(SchemaTableColumn.IsAliased, typeof(System.Boolean));
  393. DataColumn IsExpression = new DataColumn(SchemaTableColumn.IsExpression, typeof(System.Boolean));
  394. DataColumn IsIdentity = new DataColumn("IsIdentity", typeof(System.Boolean));
  395. DataColumn DataTypeName = new DataColumn("DataTypeName", typeof(System.String));
  396. DataColumn UdtAssemblyQualifiedName = new DataColumn("UdtAssemblyQualifiedName", typeof(System.String));
  397. // Xml metadata specific
  398. DataColumn XmlSchemaCollectionDatabase = new DataColumn("XmlSchemaCollectionDatabase", typeof(System.String));
  399. DataColumn XmlSchemaCollectionOwningSchema = new DataColumn("XmlSchemaCollectionOwningSchema", typeof(System.String));
  400. DataColumn XmlSchemaCollectionName = new DataColumn("XmlSchemaCollectionName", typeof(System.String));
  401. // SparseColumnSet
  402. DataColumn IsColumnSet = new DataColumn("IsColumnSet", typeof(System.Boolean));
  403. Ordinal.DefaultValue = 0;
  404. IsLong.DefaultValue = false;
  405. DataColumnCollection columns = schemaTable.Columns;
  406. // must maintain order for backward compatibility
  407. columns.Add(ColumnName);
  408. columns.Add(Ordinal);
  409. columns.Add(Size);
  410. columns.Add(Precision);
  411. columns.Add(Scale);
  412. columns.Add(IsUnique);
  413. columns.Add(IsKey);
  414. columns.Add(BaseServerName);
  415. columns.Add(BaseCatalogName);
  416. columns.Add(BaseColumnName);
  417. columns.Add(BaseSchemaName);
  418. columns.Add(BaseTableName);
  419. columns.Add(DataType);
  420. columns.Add(AllowDBNull);
  421. columns.Add(ProviderType);
  422. columns.Add(IsAliased);
  423. columns.Add(IsExpression);
  424. columns.Add(IsIdentity);
  425. columns.Add(IsAutoIncrement);
  426. columns.Add(IsRowVersion);
  427. columns.Add(IsHidden);
  428. columns.Add(IsLong);
  429. columns.Add(IsReadOnly);
  430. columns.Add(ProviderSpecificDataType);
  431. columns.Add(DataTypeName);
  432. columns.Add(XmlSchemaCollectionDatabase);
  433. columns.Add(XmlSchemaCollectionOwningSchema);
  434. columns.Add(XmlSchemaCollectionName);
  435. columns.Add(UdtAssemblyQualifiedName);
  436. columns.Add(NonVersionedProviderType);
  437. columns.Add(IsColumnSet);
  438. for (int i = 0; i < md.Length; i++) {
  439. _SqlMetaData col = md[i];
  440. DataRow schemaRow = schemaTable.NewRow();
  441. schemaRow[ColumnName] = col.column;
  442. schemaRow[Ordinal] = col.ordinal;
  443. //
  444. // be sure to return character count for string types, byte count otherwise
  445. // col.length is always byte count so for unicode types, half the length
  446. //
  447. // For MAX and XML datatypes, we get 0x7fffffff from the server. Do not divide this.
  448. schemaRow[Size] = (col.metaType.IsSizeInCharacters && (col.length != 0x7fffffff)) ? (col.length / 2) : col.length;
  449. schemaRow[DataType] = GetFieldTypeInternal(col);
  450. schemaRow[ProviderSpecificDataType] = GetProviderSpecificFieldTypeInternal(col);
  451. schemaRow[NonVersionedProviderType] = (int) col.type; // SqlDbType enum value - does not change with TypeSystem.
  452. schemaRow[DataTypeName] = GetDataTypeNameInternal(col);
  453. if (_typeSystem <= SqlConnectionString.TypeSystem.SQLServer2005 && col.IsNewKatmaiDateTimeType) {
  454. schemaRow[ProviderType] = SqlDbType.NVarChar;
  455. switch (col.type) {
  456. case SqlDbType.Date:
  457. schemaRow[Size] = TdsEnums.WHIDBEY_DATE_LENGTH;
  458. break;
  459. case SqlDbType.Time:
  460. Debug.Assert(TdsEnums.UNKNOWN_PRECISION_SCALE == col.scale || (0 <= col.scale && col.scale <= 7), "Invalid scale for Time column: " + col.scale);
  461. schemaRow[Size] = TdsEnums.WHIDBEY_TIME_LENGTH[TdsEnums.UNKNOWN_PRECISION_SCALE != col.scale ? col.scale : col.metaType.Scale];
  462. break;
  463. case SqlDbType.DateTime2:
  464. Debug.Assert(TdsEnums.UNKNOWN_PRECISION_SCALE == col.scale || (0 <= col.scale && col.scale <= 7), "Invalid scale for DateTime2 column: " + col.scale);
  465. schemaRow[Size] = TdsEnums.WHIDBEY_DATETIME2_LENGTH[TdsEnums.UNKNOWN_PRECISION_SCALE != col.scale ? col.scale : col.metaType.Scale];
  466. break;
  467. case SqlDbType.DateTimeOffset:
  468. Debug.Assert(TdsEnums.UNKNOWN_PRECISION_SCALE == col.scale || (0 <= col.scale && col.scale <= 7), "Invalid scale for DateTimeOffset column: " + col.scale);
  469. schemaRow[Size] = TdsEnums.WHIDBEY_DATETIMEOFFSET_LENGTH[TdsEnums.UNKNOWN_PRECISION_SCALE != col.scale ? col.scale : col.metaType.Scale];
  470. break;
  471. }
  472. }
  473. else if (_typeSystem <= SqlConnectionString.TypeSystem.SQLServer2005 && col.IsLargeUdt) {
  474. if (_typeSystem == SqlConnectionString.TypeSystem.SQLServer2005) {
  475. schemaRow[ProviderType] = SqlDbType.VarBinary;
  476. }
  477. else {
  478. // TypeSystem.SQLServer2000
  479. schemaRow[ProviderType] = SqlDbType.Image;
  480. }
  481. }
  482. else if (_typeSystem != SqlConnectionString.TypeSystem.SQLServer2000) {
  483. // TypeSystem.SQLServer2005 and above
  484. // SqlDbType enum value - always the actual type for SQLServer2005.
  485. schemaRow[ProviderType] = (int) col.type;
  486. if (col.type == SqlDbType.Udt) { // Additional metadata for UDTs.
  487. Debug.Assert(Connection.IsYukonOrNewer, "Invalid Column type received from the server");
  488. schemaRow[UdtAssemblyQualifiedName] = col.udtAssemblyQualifiedName;
  489. }
  490. else if (col.type == SqlDbType.Xml) { // Additional metadata for Xml.
  491. Debug.Assert(Connection.IsYukonOrNewer, "Invalid DataType (Xml) for the column");
  492. schemaRow[XmlSchemaCollectionDatabase] = col.xmlSchemaCollectionDatabase;
  493. schemaRow[XmlSchemaCollectionOwningSchema] = col.xmlSchemaCollectionOwningSchema;
  494. schemaRow[XmlSchemaCollectionName] = col.xmlSchemaCollectionName;
  495. }
  496. }
  497. else {
  498. // TypeSystem.SQLServer2000
  499. // SqlDbType enum value - variable for certain types when SQLServer2000.
  500. schemaRow[ProviderType] = GetVersionedMetaType(col.metaType).SqlDbType;
  501. }
  502. if (TdsEnums.UNKNOWN_PRECISION_SCALE != col.precision) {
  503. schemaRow[Precision] = col.precision;
  504. }
  505. else {
  506. schemaRow[Precision] = col.metaType.Precision;
  507. }
  508. if (_typeSystem <= SqlConnectionString.TypeSystem.SQLServer2005 && col.IsNewKatmaiDateTimeType) {
  509. schemaRow[Scale] = MetaType.MetaNVarChar.Scale;
  510. }
  511. else if (TdsEnums.UNKNOWN_PRECISION_SCALE != col.scale) {
  512. schemaRow[Scale] = col.scale;
  513. }
  514. else {
  515. schemaRow[Scale] = col.metaType.Scale;
  516. }
  517. schemaRow[AllowDBNull] = col.isNullable;
  518. // If no ColInfo token received, do not set value, leave as null.
  519. if (_browseModeInfoConsumed) {
  520. schemaRow[IsAliased] = col.isDifferentName;
  521. schemaRow[IsKey] = col.isKey;
  522. schemaRow[IsHidden] = col.isHidden;
  523. schemaRow[IsExpression] = col.isExpression;
  524. }
  525. schemaRow[IsIdentity] = col.isIdentity;
  526. schemaRow[IsAutoIncrement] = col.isIdentity;
  527. schemaRow[IsLong] = col.metaType.IsLong;
  528. // mark unique for timestamp columns
  529. if (SqlDbType.Timestamp == col.type) {
  530. schemaRow[IsUnique] = true;
  531. schemaRow[IsRowVersion] = true;
  532. }
  533. else {
  534. schemaRow[IsUnique] = false;
  535. schemaRow[IsRowVersion] = false;
  536. }
  537. schemaRow[IsReadOnly] = (0 == col.updatability);
  538. schemaRow[IsColumnSet] = col.isColumnSet;
  539. if (!ADP.IsEmpty(col.serverName)) {
  540. schemaRow[BaseServerName] = col.serverName;
  541. }
  542. if (!ADP.IsEmpty(col.catalogName)) {
  543. schemaRow[BaseCatalogName] = col.catalogName;
  544. }
  545. if (!ADP.IsEmpty(col.schemaName)) {
  546. schemaRow[BaseSchemaName] = col.schemaName;
  547. }
  548. if (!ADP.IsEmpty(col.tableName)) {
  549. schemaRow[BaseTableName] = col.tableName;
  550. }
  551. if (!ADP.IsEmpty(col.baseColumn)) {
  552. schemaRow[BaseColumnName] = col.baseColumn;
  553. }
  554. else if (!ADP.IsEmpty(col.column)) {
  555. schemaRow[BaseColumnName] = col.column;
  556. }
  557. schemaTable.Rows.Add(schemaRow);
  558. schemaRow.AcceptChanges();
  559. }
  560. // mark all columns as readonly
  561. foreach(DataColumn column in columns) {
  562. column.ReadOnly = true; // MDAC 70943
  563. }
  564. return schemaTable;
  565. }
  566. internal void Cancel(int objectID) {
  567. TdsParserStateObject stateObj = _stateObj;
  568. if (null != stateObj) {
  569. stateObj.Cancel(objectID);
  570. }
  571. }
  572. // wipe any data off the wire from a partial read
  573. // and reset all pointers for sequential access
  574. private bool TryCleanPartialRead() {
  575. AssertReaderState(requireData: true, permitAsync: true);
  576. // VSTS DEVDIV2 380446: It is possible that read attempt we are cleaning after ended with partially
  577. // processed header (if it falls between network packets). In this case the first thing to do is to
  578. // finish reading the header, otherwise code will start treating unread header as TDS payload.
  579. if (_stateObj._partialHeaderBytesRead > 0) {
  580. if (!_stateObj.TryProcessHeader()) {
  581. return false;
  582. }
  583. }
  584. // following cases for sequential read
  585. // i. user called read but didn't fetch anything
  586. // iia. user called read and fetched a subset of the columns
  587. // iib. user called read and fetched a subset of the column data
  588. // Wipe out any Streams or TextReaders
  589. if (-1 != _lastColumnWithDataChunkRead) {
  590. CloseActiveSequentialStreamAndTextReader();
  591. }
  592. // i. user called read but didn't fetch anything
  593. if (0 == _sharedState._nextColumnHeaderToRead) {
  594. if (!_stateObj.Parser.TrySkipRow(_metaData, _stateObj)) {
  595. return false;
  596. }
  597. }
  598. else {
  599. // iia. if we still have bytes left from a partially read column, skip
  600. if (!TryResetBlobState()) {
  601. return false;
  602. }
  603. // iib.
  604. // now read the remaining values off the wire for this row
  605. if (!_stateObj.Parser.TrySkipRow(_metaData, _sharedState._nextColumnHeaderToRead, _stateObj)) {
  606. return false;
  607. }
  608. }
  609. #if DEBUG
  610. if (_stateObj._pendingData) {
  611. byte token;
  612. if (!_stateObj.TryPeekByte(out token)) {
  613. return false;
  614. }
  615. Debug.Assert(TdsParser.IsValidTdsToken(token), string.Format("Invalid token after performing CleanPartialRead: {0,-2:X2}", token));
  616. }
  617. #endif
  618. _sharedState._dataReady = false;
  619. return true;
  620. }
  621. private void CleanPartialReadReliable() {
  622. AssertReaderState(requireData: true, permitAsync: false);
  623. RuntimeHelpers.PrepareConstrainedRegions();
  624. try {
  625. #if DEBUG
  626. TdsParser.ReliabilitySection tdsReliabilitySection = new TdsParser.ReliabilitySection();
  627. RuntimeHelpers.PrepareConstrainedRegions();
  628. try {
  629. tdsReliabilitySection.Start();
  630. #else
  631. {
  632. #endif //DEBUG
  633. bool result = TryCleanPartialRead();
  634. Debug.Assert(result, "Should not pend on sync call");
  635. Debug.Assert(!_sharedState._dataReady, "_dataReady should be cleared");
  636. }
  637. #if DEBUG
  638. finally {
  639. tdsReliabilitySection.Stop();
  640. }
  641. #endif //DEBUG
  642. }
  643. catch (System.OutOfMemoryException e) {
  644. _isClosed = true;
  645. if (_connection != null) {
  646. _connection.Abort(e);
  647. }
  648. throw;
  649. }
  650. catch (System.StackOverflowException e) {
  651. _isClosed = true;
  652. if (_connection != null) {
  653. _connection.Abort(e);
  654. }
  655. throw;
  656. }
  657. catch (System.Threading.ThreadAbortException e) {
  658. _isClosed = true;
  659. if (_connection != null) {
  660. _connection.Abort(e);
  661. }
  662. throw;
  663. }
  664. }
  665. override public void Close() {
  666. SqlStatistics statistics = null;
  667. IntPtr hscp;
  668. Bid.ScopeEnter(out hscp, "<sc.SqlDataReader.Close|API> %d#", ObjectID);
  669. try {
  670. statistics = SqlStatistics.StartTimer(Statistics);
  671. TdsParserStateObject stateObj = _stateObj;
  672. // Request that the current task is stopped
  673. _cancelAsyncOnCloseTokenSource.Cancel();
  674. var currentTask = _currentTask;
  675. if ((currentTask != null) && (!currentTask.IsCompleted)) {
  676. try {
  677. // Wait for the task to complete
  678. ((IAsyncResult)currentTask).AsyncWaitHandle.WaitOne();
  679. // Ensure that we've finished reading any pending data
  680. var networkPacketTaskSource = stateObj._networkPacketTaskSource;
  681. if (networkPacketTaskSource != null) {
  682. ((IAsyncResult)networkPacketTaskSource.Task).AsyncWaitHandle.WaitOne();
  683. }
  684. }
  685. catch (Exception) {
  686. // If we receive any exceptions while waiting, something has gone horribly wrong and we need to doom the connection and fast-fail the reader
  687. _connection.InnerConnection.DoomThisConnection();
  688. _isClosed = true;
  689. if (stateObj != null) {
  690. lock (stateObj) {
  691. _stateObj = null;
  692. _command = null;
  693. _connection = null;
  694. }
  695. }
  696. throw;
  697. }
  698. }
  699. // Close down any active Streams and TextReaders (this will also wait for them to finish their async tasks)
  700. // NOTE: This must be done outside of the lock on the stateObj otherwise it will deadlock with CleanupAfterAsyncInvocation
  701. CloseActiveSequentialStreamAndTextReader();
  702. if (stateObj != null) {
  703. // protect against concurrent close and cancel
  704. lock (stateObj) {
  705. if (_stateObj != null ) { // reader not closed while we waited for the lock
  706. // TryCloseInternal will clear out the snapshot when it is done
  707. if (_snapshot != null) {
  708. #if DEBUG
  709. // The stack trace for replays will differ since they weren't captured during close
  710. stateObj._permitReplayStackTraceToDiffer = true;
  711. #endif
  712. PrepareForAsyncContinuation();
  713. }
  714. SetTimeout(_defaultTimeoutMilliseconds);
  715. // Close can be called from async methods in error cases,
  716. // in which case we need to switch to syncOverAsync
  717. stateObj._syncOverAsync = true;
  718. if (!TryCloseInternal(true /*closeReader*/)) {
  719. throw SQL.SynchronousCallMayNotPend();
  720. }
  721. // DO NOT USE stateObj after this point - it has been returned to the TdsParser's session pool and potentially handed out to another thread
  722. }
  723. }
  724. }
  725. }
  726. finally {
  727. SqlStatistics.StopTimer(statistics);
  728. Bid.ScopeLeave(ref hscp);
  729. }
  730. }
  731. private bool TryCloseInternal(bool closeReader) {
  732. TdsParser parser = _parser;
  733. TdsParserStateObject stateObj = _stateObj;
  734. bool closeConnection = (IsCommandBehavior(CommandBehavior.CloseConnection));
  735. bool aborting = false;
  736. bool cleanDataFailed = false;
  737. RuntimeHelpers.PrepareConstrainedRegions();
  738. try {
  739. #if DEBUG
  740. TdsParser.ReliabilitySection tdsReliabilitySection = new TdsParser.ReliabilitySection();
  741. RuntimeHelpers.PrepareConstrainedRegions();
  742. try {
  743. tdsReliabilitySection.Start();
  744. #else
  745. {
  746. #endif //DEBUG
  747. if ((!_isClosed) && (parser != null) && (stateObj != null) && (stateObj._pendingData)) {
  748. // It is possible for this to be called during connection close on a
  749. // broken connection, so check state first.
  750. if (parser.State == TdsParserState.OpenLoggedIn) {
  751. // if user called read but didn't fetch any values, skip the row
  752. // same applies after NextResult on ALTROW because NextResult starts rowconsumption in that case ...
  753. Debug.Assert(SniContext.Snix_Read==stateObj.SniContext, String.Format((IFormatProvider)null, "The SniContext should be Snix_Read but it actually is {0}", stateObj.SniContext));
  754. if (_altRowStatus == ALTROWSTATUS.AltRow) {
  755. _sharedState._dataReady = true; // set _sharedState._dataReady to not confuse CleanPartialRead
  756. }
  757. _stateObj._internalTimeout = false;
  758. if (_sharedState._dataReady) {
  759. cleanDataFailed = true;
  760. if (TryCleanPartialRead()) {
  761. cleanDataFailed = false;
  762. }
  763. else {
  764. return false;
  765. }
  766. }
  767. #if DEBUG
  768. else {
  769. byte token;
  770. if (!_stateObj.TryPeekByte(out token)) {
  771. return false;
  772. }
  773. Debug.Assert(TdsParser.IsValidTdsToken(token), string.Format("DataReady is false, but next token is invalid: {0,-2:X2}", token));
  774. }
  775. #endif
  776. bool ignored;
  777. if (!parser.TryRun(RunBehavior.Clean, _command, this, null, stateObj, out ignored)) {
  778. return false;
  779. }
  780. }
  781. }
  782. RestoreServerSettings(parser, stateObj);
  783. return true;
  784. }
  785. #if DEBUG
  786. finally {
  787. tdsReliabilitySection.Stop();
  788. }
  789. #endif //DEBUG
  790. }
  791. catch (System.OutOfMemoryException e) {
  792. _isClosed = true;
  793. aborting = true;
  794. if (null != _connection) {
  795. _connection.Abort(e);
  796. }
  797. throw;
  798. }
  799. catch (System.StackOverflowException e) {
  800. _isClosed = true;
  801. aborting = true;
  802. if (null != _connection) {
  803. _connection.Abort(e);
  804. }
  805. throw;
  806. }
  807. catch (System.Threading.ThreadAbortException e) {
  808. _isClosed = true;
  809. aborting = true;
  810. if (null != _connection) {
  811. _connection.Abort(e);
  812. }
  813. throw;
  814. }
  815. finally {
  816. if (aborting) {
  817. _isClosed = true;
  818. _command = null; // we are done at this point, don't allow navigation to the connection
  819. _connection = null;
  820. _statistics = null;
  821. _stateObj = null;
  822. _parser = null;
  823. }
  824. else if (closeReader) {
  825. bool wasClosed = _isClosed;
  826. _isClosed = true;
  827. _parser = null;
  828. _stateObj = null;
  829. _data = null;
  830. if (_snapshot != null) {
  831. CleanupAfterAsyncInvocationInternal(stateObj);
  832. }
  833. // SQLBUDT #284712 - Note the order here is extremely important:
  834. //
  835. // (1) First, we remove the reader from the reference collection
  836. // to prevent it from being forced closed by the parser if
  837. // any future work occurs.
  838. //
  839. // (2) Next, we ensure that cancellation can no longer happen by
  840. // calling CloseSession.
  841. if (Connection != null) {
  842. Connection.RemoveWeakReference(this); // This doesn't catch everything -- the connection may be closed, but it prevents dead readers from clogging the collection
  843. }
  844. RuntimeHelpers.PrepareConstrainedRegions();
  845. try {
  846. #if DEBUG
  847. TdsParser.ReliabilitySection tdsReliabilitySection = new TdsParser.ReliabilitySection();
  848. RuntimeHelpers.PrepareConstrainedRegions();
  849. try {
  850. tdsReliabilitySection.Start();
  851. #else
  852. {
  853. #endif //DEBUG
  854. // IsClosed may be true if CloseReaderFromConnection was called - in which case, the session has already been closed
  855. if ((!wasClosed) && (null != stateObj)) {
  856. if (!cleanDataFailed) {
  857. stateObj.CloseSession();
  858. }
  859. else {
  860. if (parser != null) {
  861. parser.State = TdsParserState.Broken; // We failed while draining data, so TDS pointer can be between tokens - cannot recover
  862. parser.PutSession(stateObj);
  863. parser.Connection.BreakConnection();
  864. }
  865. }
  866. }
  867. // DO NOT USE stateObj after this point - it has been returned to the TdsParser's session pool and potentially handed out to another thread
  868. }
  869. #if DEBUG
  870. finally {
  871. tdsReliabilitySection.Stop();
  872. }
  873. #endif //DEBUG
  874. }
  875. catch (System.OutOfMemoryException e) {
  876. if (null != _connection) {
  877. _connection.Abort(e);
  878. }
  879. throw;
  880. }
  881. catch (System.StackOverflowException e) {
  882. if (null != _connection) {
  883. _connection.Abort(e);
  884. }
  885. throw;
  886. }
  887. catch (System.Threading.ThreadAbortException e) {
  888. if (null != _connection) {
  889. _connection.Abort(e);
  890. }
  891. throw;
  892. }
  893. // do not retry here
  894. bool result = TrySetMetaData(null, false);
  895. Debug.Assert(result, "Should not pend a synchronous request");
  896. _fieldNameLookup = null;
  897. // if the user calls ExecuteReader(CommandBehavior.CloseConnection)
  898. // then we close down the connection when we are done reading results
  899. if (closeConnection) {
  900. if (Connection != null) {
  901. Connection.Close();
  902. }
  903. }
  904. if (_command != null) {
  905. // cache recordsaffected to be returnable after DataReader.Close();
  906. _recordsAffected = _command.InternalRecordsAffected;
  907. }
  908. _command = null; // we are done at this point, don't allow navigation to the connection
  909. _connection = null;
  910. _statistics = null;
  911. }
  912. }
  913. }
  914. virtual internal void CloseReaderFromConnection() {
  915. var parser = _parser;
  916. Debug.Assert(parser == null || parser.State != TdsParserState.OpenNotLoggedIn, "Reader on a connection that is not logged in");
  917. if ((parser != null) && (parser.State == TdsParserState.OpenLoggedIn)) {
  918. // Connection is ok - proper cleanup
  919. // NOTE: This is NOT thread-safe
  920. Close();
  921. }
  922. else {
  923. // Connection is broken - quick cleanup
  924. // NOTE: This MUST be thread-safe as a broken connection can happen at any time
  925. var stateObj = _stateObj;
  926. _isClosed = true;
  927. // Request that the current task is stopped
  928. _cancelAsyncOnCloseTokenSource.Cancel();
  929. if (stateObj != null) {
  930. var networkPacketTaskSource = stateObj._networkPacketTaskSource;
  931. if (networkPacketTaskSource != null) {
  932. // If the connection is closed or broken, this will never complete
  933. networkPacketTaskSource.TrySetException(ADP.ClosedConnectionError());
  934. }
  935. if (_snapshot != null) {
  936. // CleanWire will do cleanup - so we don't really care about the snapshot
  937. CleanupAfterAsyncInvocationInternal(stateObj, resetNetworkPacketTaskSource: false);
  938. }
  939. // Switch to [....] to prepare for cleanwire
  940. stateObj._syncOverAsync = true;
  941. // Remove owner (this will allow the stateObj to be disposed after the connection is closed)
  942. stateObj.RemoveOwner();
  943. }
  944. }
  945. }
  946. private bool TryConsumeMetaData() {
  947. // warning: Don't check the MetaData property within this function
  948. // warning: as it will be a reentrant call
  949. while (_parser != null && _stateObj != null && _stateObj._pendingData && !_metaDataConsumed) {
  950. if (_parser.State == TdsParserState.Broken || _parser.State == TdsParserState.Closed) {
  951. // Happened for DEVDIV2:180509 (SqlDataReader.ConsumeMetaData Hangs In 100% CPU Loop Forever When TdsParser._state == TdsParserState.Broken)
  952. // during request for DTC address.
  953. // NOTE: We doom connection for TdsParserState.Closed since it indicates that it is in some abnormal and unstable state, probably as a result of
  954. // closing from another thread. In general, TdsParserState.Closed does not necessitate dooming the connection.
  955. if (_parser.Connection != null)
  956. _parser.Connection.DoomThisConnection();
  957. throw SQL.ConnectionDoomed();
  958. }
  959. bool ignored;
  960. if (!_parser.TryRun(RunBehavior.ReturnImmediately, _command, this, null, _stateObj, out ignored)) {
  961. return false;
  962. }
  963. Debug.Assert(!ignored, "Parser read a row token while trying to read metadata");
  964. }
  965. // we hide hidden columns from the user so build an internal map
  966. // that compacts all hidden columns from the array
  967. if (null != _metaData) {
  968. if (_snapshot != null && object.ReferenceEquals(_snapshot._metadata, _metaData)) {
  969. _metaData = (_SqlMetaDataSet)_metaData.Clone();
  970. }
  971. _metaData.visibleColumns = 0;
  972. Debug.Assert(null == _metaData.indexMap, "non-null metaData indexmap");
  973. int[] indexMap = new int[_metaData.Length];
  974. for (int i = 0; i < indexMap.Length; ++i) {
  975. indexMap[i] = _metaData.visibleColumns;
  976. if (!(_metaData[i].isHidden)) {
  977. _metaData.visibleColumns++;
  978. }
  979. }
  980. _metaData.indexMap = indexMap;
  981. }
  982. return true;
  983. }
  984. override public string GetDataTypeName(int i) {
  985. SqlStatistics statistics = null;
  986. try {
  987. statistics = SqlStatistics.StartTimer(Statistics);
  988. CheckMetaDataIsReady(columnIndex: i);
  989. return GetDataTypeNameInternal(_metaData[i]);
  990. }
  991. finally {
  992. SqlStatistics.StopTimer(statistics);
  993. }
  994. }
  995. private string GetDataTypeNameInternal(_SqlMetaData metaData) {
  996. string dataTypeName = null;
  997. if (_typeSystem <= SqlConnectionString.TypeSystem.SQLServer2005 && metaData.IsNewKatmaiDateTimeType) {
  998. dataTypeName = MetaType.MetaNVarChar.TypeName;
  999. }
  1000. else if (_typeSystem <= SqlConnectionString.TypeSystem.SQLServer2005 && metaData.IsLargeUdt) {
  1001. if (_typeSystem == SqlConnectionString.TypeSystem.SQLServer2005) {
  1002. dataTypeName = MetaType.MetaMaxVarBinary.TypeName;
  1003. }
  1004. else {
  1005. // TypeSystem.SQLServer2000
  1006. dataTypeName = MetaType.MetaImage.TypeName;
  1007. }
  1008. }
  1009. else if (_typeSystem != SqlConnectionString.TypeSystem.SQLServer2000) {
  1010. // TypeSystem.SQLServer2005 and above
  1011. if (metaData.type == SqlDbType.Udt) {
  1012. Debug.Assert(Connection.IsYukonOrNewer, "Invalid Column type received from the server");
  1013. dataTypeName = metaData.udtDatabaseName + "." + metaData.udtSchemaName + "." + metaData.udtTypeName;
  1014. }
  1015. else { // For all other types, including Xml - use data in MetaType.
  1016. dataTypeName = metaData.metaType.TypeName;
  1017. }
  1018. }
  1019. else {
  1020. // TypeSystem.SQLServer2000
  1021. dataTypeName = GetVersionedMetaType(metaData.metaType).TypeName;
  1022. }
  1023. return dataTypeName;
  1024. }
  1025. virtual internal SqlBuffer.StorageType GetVariantInternalStorageType(int i) {
  1026. Debug.Assert(null != _data, "Attempting to get variant internal storage type");
  1027. Debug.Assert(i < _data.Length, "Reading beyond data length?");
  1028. return _data[i].VariantInternalStorageType;
  1029. }
  1030. override public IEnumerator GetEnumerator() {
  1031. return new DbEnumerator((IDataReader)this, IsCommandBehavior(CommandBehavior.CloseConnection));
  1032. }
  1033. override public Type GetFieldType(int i) {
  1034. SqlStatistics statistics = null;
  1035. try {
  1036. statistics = SqlStatistics.StartTimer(Statistics);
  1037. CheckMetaDataIsReady(columnIndex: i);
  1038. return GetFieldTypeInternal(_metaData[i]);
  1039. }
  1040. finally {
  1041. SqlStatistics.StopTimer(statistics);
  1042. }
  1043. }
  1044. private Type GetFieldTypeInternal(_SqlMetaData metaData) {
  1045. Type fieldType = null;
  1046. if (_typeSystem <= SqlConnectionString.TypeSystem.SQLServer2005 && metaData.IsNewKatmaiDateTimeType) {
  1047. // Return katmai types as string
  1048. fieldType = MetaType.MetaNVarChar.ClassType;
  1049. }
  1050. else if (_typeSystem <= SqlConnectionString.TypeSystem.SQLServer2005 && metaData.IsLargeUdt) {
  1051. if (_typeSystem == SqlConnectionString.TypeSystem.SQLServer2005) {
  1052. fieldType = MetaType.MetaMaxVarBinary.ClassType;
  1053. }
  1054. else {
  1055. // TypeSystem.SQLServer2000
  1056. fieldType = MetaType.MetaImage.ClassType;
  1057. }
  1058. }
  1059. else if (_typeSystem != SqlConnectionString.TypeSystem.SQLServer2000) {
  1060. // TypeSystem.SQLServer2005 and above
  1061. if (metaData.type == SqlDbType.Udt) {
  1062. Debug.Assert(Connection.IsYukonOrNewer, "Invalid Column type received from the server");
  1063. Connection.CheckGetExtendedUDTInfo(metaData, false);
  1064. fieldType = metaData.udtType;
  1065. }
  1066. else { // For all other types, including Xml - use data in MetaType.
  1067. fieldType = metaData.metaType.ClassType; // Com+ type.
  1068. }
  1069. }
  1070. else {
  1071. // TypeSystem.SQLServer2000
  1072. fieldType = GetVersionedMetaType(metaData.metaType).ClassType; // Com+ type.
  1073. }
  1074. return fieldType;
  1075. }
  1076. virtual internal int GetLocaleId(int i) {
  1077. _SqlMetaData sqlMetaData = MetaData[i];
  1078. int lcid;
  1079. if (sqlMetaData.collation != null) {
  1080. lcid = sqlMetaData.collation.LCID;
  1081. }
  1082. else {
  1083. lcid = 0;
  1084. }
  1085. return lcid;
  1086. }
  1087. override public string GetName(int i) {
  1088. CheckMetaDataIsReady(columnIndex: i);
  1089. Debug.Assert(null != _metaData[i].column, "MDAC 66681");
  1090. return _metaData[i].column;
  1091. }
  1092. override public Type GetProviderSpecificFieldType(int i) {
  1093. SqlStatistics statistics = null;
  1094. try {
  1095. statistics = SqlStatistics.StartTimer(Statistics);
  1096. CheckMetaDataIsReady(columnIndex: i);
  1097. return GetProviderSpecificFieldTypeInternal(_metaData[i]);
  1098. }
  1099. finally {
  1100. SqlStatistics.StopTimer(statistics);
  1101. }
  1102. }
  1103. private Type GetProviderSpecificFieldTypeInternal(_SqlMetaData metaData) {
  1104. Type providerSpecificFieldType = null;
  1105. if (_typeSystem <= SqlConnectionString.TypeSystem.SQLServer2005 && metaData.IsNewKatmaiDateTimeType) {
  1106. providerSpecificFieldType = MetaType.MetaNVarChar.SqlType;
  1107. }
  1108. else if (_typeSystem <= SqlConnectionString.TypeSystem.SQLServer2005 && metaData.IsLargeUdt) {
  1109. if (_typeSystem == SqlConnectionString.TypeSystem.SQLServer2005) {
  1110. providerSpecificFieldType = MetaType.MetaMaxVarBinary.SqlType;
  1111. }
  1112. else {
  1113. // TypeSystem.SQLServer2000
  1114. providerSpecificFieldType = MetaType.MetaImage.SqlType;
  1115. }
  1116. }
  1117. else if (_typeSystem != SqlConnectionString.TypeSystem.SQLServer2000) {
  1118. // TypeSystem.SQLServer2005 and above
  1119. if (metaData.type == SqlDbType.Udt) {
  1120. Debug.Assert(Connection.IsYukonOrNewer, "Invalid Column type received from the server");
  1121. Connection.CheckGetExtendedUDTInfo(metaData, false);
  1122. providerSpecificFieldType = metaData.udtType;
  1123. }
  1124. else { // For all other types, including Xml - use data in MetaType.
  1125. providerSpecificFieldType = metaData.metaType.SqlType; // SqlType type.
  1126. }
  1127. }
  1128. else {
  1129. // TypeSystem.SQLServer2000
  1130. providerSpecificFieldType = GetVersionedMetaType(metaData.metaType).SqlType; // SqlType type.
  1131. }
  1132. return providerSpecificFieldType;
  1133. }
  1134. // named field access
  1135. override public int GetOrdinal(string name) {
  1136. SqlStatistics statistics = null;
  1137. try {
  1138. statistics = SqlStatistics.StartTimer(Statistics);
  1139. if (null == _fieldNameLookup) {
  1140. CheckMetaDataIsReady();
  1141. _fieldNameLookup = new FieldNameLookup(this, _defaultLCID);
  1142. }
  1143. return _fieldNameLookup.GetOrdinal(name); // MDAC 71470
  1144. }
  1145. finally {
  1146. SqlStatistics.StopTimer(statistics);
  1147. }
  1148. }
  1149. override public object GetProviderSpecificValue(int i) {
  1150. return GetSqlValue(i);
  1151. }
  1152. override public int GetProviderSpecificValues(object[] values) {
  1153. return GetSqlValues(values);
  1154. }
  1155. override public DataTable GetSchemaTable() {
  1156. SqlStatistics statistics = null;
  1157. IntPtr hscp;
  1158. Bid.ScopeEnter(out hscp, "<sc.SqlDataReader.GetSchemaTable|API> %d#", ObjectID);
  1159. try {
  1160. statistics = SqlStatistics.StartTimer(Statistics);
  1161. if (null == _metaData || null == _metaData.schemaTable) {
  1162. if (null != this.MetaData) {
  1163. _metaData.schemaTable = BuildSchemaTable();
  1164. Debug.Assert(null != _metaData.schemaTable, "No schema information yet!");
  1165. // filter table?
  1166. }
  1167. }
  1168. if (null != _metaData) {
  1169. return _metaData.schemaTable;
  1170. }
  1171. return null;
  1172. }
  1173. finally {
  1174. SqlStatistics.StopTimer(statistics);
  1175. Bid.ScopeLeave(ref hscp);
  1176. }
  1177. }
  1178. override public bool GetBoolean(int i) {
  1179. ReadColumn(i);
  1180. return _data[i].Boolean;
  1181. }
  1182. virtual public XmlReader GetXmlReader(int i) {
  1183. // NOTE: sql_variant can not contain a XML data type: http://msdn.microsoft.com/en-us/library/ms173829.aspx
  1184. // If this ever changes, the following code should be changed to be like GetStream\GetTextReader
  1185. CheckDataIsReady(columnIndex: i, methodName: "GetXmlReader");
  1186. MetaType mt = _metaData[i].metaType;
  1187. // XmlReader only allowed on XML types
  1188. if (mt.SqlDbType != SqlDbType.Xml) {
  1189. throw SQL.XmlReaderNotSupportOnColumnType(_metaData[i].column);
  1190. }
  1191. if (IsCommandBehavior(CommandBehavior.SequentialAccess)) {
  1192. // Wrap the sequential stream in an XmlReader
  1193. _currentStream = new SqlSequentialStream(this, i);
  1194. _lastColumnWithDataChunkRead = i;
  1195. return SqlXml.CreateSqlXmlReader(_currentStream, closeInput: true);
  1196. }
  1197. else {
  1198. // Need to call ReadColumn, since we want to access the internal data structures (i.e. SqlBinary) rather than calling anther Get*() method
  1199. ReadColumn(i);
  1200. if (_data[i].IsNull) {
  1201. // A 'null' stream
  1202. return SqlXml.CreateSqlXmlReader(new MemoryStream(new byte[0], writable: false), closeInput: true);
  1203. }
  1204. else {
  1205. // Grab already read data
  1206. return _data[i].SqlXml.CreateReader();
  1207. }
  1208. }
  1209. }
  1210. override public Stream GetStream(int i) {
  1211. CheckDataIsReady(columnIndex: i, methodName: "GetStream");
  1212. // Stream is only for Binary, Image, VarBinary, Udt and Xml types
  1213. // NOTE: IsBinType also includes Timestamp for some reason...
  1214. MetaType mt = _metaData[i].metaType;
  1215. if (((!mt.IsBinType) || (mt.SqlDbType == SqlDbType.Timestamp)) && (mt.SqlDbType != SqlDbType.Variant)) {
  1216. throw SQL.StreamNotSupportOnColumnType(_metaData[i].column);
  1217. }
  1218. // For non-variant types with sequential access, we support proper streaming
  1219. if ((mt.SqlDbType != SqlDbType.Variant) && (IsCommandBehavior(CommandBehavior.SequentialAccess))) {
  1220. _currentStream = new SqlSequentialStream(this, i);
  1221. _lastColumnWithDataChunkRead = i;
  1222. return _currentStream;
  1223. }
  1224. else {
  1225. // Need to call ReadColumn, since we want to access the internal data structures (i.e. SqlBinary) rather than calling anther Get*() method
  1226. ReadColumn(i);
  1227. byte[] data;
  1228. if (_data[i].IsNull) {
  1229. // A 'null' stream
  1230. data = new byte[0];
  1231. }
  1232. else {
  1233. // Grab already read data
  1234. data = _data[i].SqlBinary.Value;
  1235. }
  1236. // If non-sequential then we just have a read-only MemoryStream
  1237. return new MemoryStream(data, writable: false);
  1238. }
  1239. }
  1240. override public byte GetByte(int i) {
  1241. ReadColumn(i);
  1242. return _data[i].Byte;
  1243. }
  1244. override public long GetBytes(int i, long dataIndex, byte[] buffer, int bufferIndex, int length) {
  1245. SqlStatistics statistics = null;
  1246. long cbBytes = 0;
  1247. CheckDataIsReady(columnIndex: i, allowPartiallyReadColumn: true, methodName: "GetBytes");
  1248. // don't allow get bytes on non-long or non-binary columns
  1249. MetaType mt = _metaData[i].metaType;
  1250. if (!(mt.IsLong || mt.IsBinType) || (SqlDbType.Xml == mt.SqlDbType)) {
  1251. throw SQL.NonBlobColumn(_metaData[i].column);
  1252. }
  1253. try {
  1254. statistics = SqlStatistics.StartTimer(Statistics);
  1255. SetTimeout(_defaultTimeoutMilliseconds);
  1256. cbBytes = GetBytesInternal(i, dataIndex, buffer, bufferIndex, length);
  1257. _lastColumnWithDataChunkRead = i;
  1258. }
  1259. finally {
  1260. SqlStatistics.StopTimer(statistics);
  1261. }
  1262. return cbBytes;
  1263. }
  1264. // Used (indirectly) by SqlCommand.CompleteXmlReader
  1265. virtual internal long GetBytesInternal(int i, long dataIndex, byte[] buffer, int bufferIndex, int length) {
  1266. if (_currentTask != null) {
  1267. throw ADP.AsyncOperationPending();
  1268. }
  1269. long value;
  1270. Debug.Assert(_stateObj == null || _stateObj._syncOverAsync, "Should not attempt pends in a synchronous call");
  1271. bool result = TryGetBytesInternal(i, dataIndex, buffer, bufferIndex, length, out value);
  1272. if (!result) { throw SQL.SynchronousCallMayNotPend(); }
  1273. return value;
  1274. }
  1275. private bool TryGetBytesInternal(int i, long dataIndex, byte[] buffer, int bufferIndex, int length, out long remaining) {
  1276. remaining = 0;
  1277. RuntimeHelpers.PrepareConstrainedRegions();
  1278. try {
  1279. #if DEBUG
  1280. TdsParser.ReliabilitySection tdsReliabilitySection = new TdsParser.ReliabilitySection();
  1281. RuntimeHelpers.PrepareConstrainedRegions();
  1282. try {
  1283. tdsReliabilitySection.Start();
  1284. #else
  1285. {
  1286. #endif //DEBUG
  1287. int cbytes = 0;
  1288. AssertReaderState(requireData: true, permitAsync: true, columnIndex: i, enforceSequentialAccess: true);
  1289. // sequential reading
  1290. if (IsCommandBehavior(CommandBehavior.SequentialAccess)) {
  1291. Debug.Assert(!HasActiveStreamOrTextReaderOnColumn(i), "Column has an active Stream or TextReader");
  1292. if (_sharedState._nextColumnHeaderToRead <= i) {
  1293. if (!TryReadColumnHeader(i)) {
  1294. return false;
  1295. }
  1296. }
  1297. // If data is null, ReadColumnHeader sets the data.IsNull bit.
  1298. if (_data[i] != null && _data[i].IsNull) {
  1299. throw new SqlNullValueException();
  1300. }
  1301. // If there are an unknown (-1) number of bytes left for a PLP, read its size
  1302. if ((-1 == _sharedState._columnDataBytesRemaining) && (_metaData[i].metaType.IsPlp)) {
  1303. ulong left;
  1304. if (!_parser.TryPlpBytesLeft(_stateObj, out left)) {
  1305. return false;
  1306. }
  1307. _sharedState._columnDataBytesRemaining = (long)left;
  1308. }
  1309. if (0 == _sharedState._columnDataBytesRemaining) {
  1310. return true; // We've read this column to the end
  1311. }
  1312. // if no buffer is passed in, return the number total of bytes, or -1
  1313. if (null == buffer) {
  1314. if (_metaData[i].metaType.IsPlp) {
  1315. remaining = (long) _parser.PlpBytesTotalLength(_stateObj);
  1316. return true;
  1317. }
  1318. remaining = _sharedState._columnDataBytesRemaining;
  1319. return true;
  1320. }
  1321. if (dataIndex < 0)
  1322. throw ADP.NegativeParameter("dataIndex");
  1323. if (dataIndex < _columnDataBytesRead) {
  1324. throw ADP.NonSeqByteAccess(dataIndex, _columnDataBytesRead, ADP.GetBytes);
  1325. }
  1326. // if the dataIndex is not equal to bytes read, then we have to skip bytes
  1327. long cb = dataIndex - _columnDataBytesRead;
  1328. // if dataIndex is outside of the data range, return 0
  1329. if ((cb > _sharedState._columnDataBytesRemaining) && !_metaData[i].metaType.IsPlp) {
  1330. return true;
  1331. }
  1332. // if bad buffer index, throw
  1333. if (bufferIndex < 0 || bufferIndex >= buffer.Length)
  1334. throw ADP.InvalidDestinationBufferIndex(buffer.Length, bufferIndex, "bufferIndex");
  1335. // if there is not enough room in the buffer for data
  1336. if (length + bufferIndex > buffer.Length)
  1337. throw ADP.InvalidBufferSizeOrIndex(length, bufferIndex);
  1338. if (length < 0)
  1339. throw ADP.InvalidDataLength(length);
  1340. // Skip if needed
  1341. if (cb > 0) {
  1342. if (_metaData[i].metaType.IsPlp) {
  1343. ulong skipped;
  1344. if (!_parser.TrySkipPlpValue((ulong) cb, _stateObj, out skipped)) {
  1345. return false;
  1346. }
  1347. _columnDataBytesRead += (long) skipped;
  1348. }
  1349. else {
  1350. if (!_stateObj.TrySkipLongBytes(cb)) {
  1351. return false;
  1352. }
  1353. _columnDataBytesRead += cb;
  1354. _sharedState._columnDataBytesRemaining -= cb;
  1355. }
  1356. }
  1357. int bytesRead;
  1358. bool result = TryGetBytesInternalSequential(i, buffer, bufferIndex, length, out bytesRead);
  1359. remaining = (int)bytesRead;
  1360. return result;
  1361. }
  1362. // random access now!
  1363. // note that since we are caching in an array, and arrays aren't 64 bit ready yet,
  1364. // we need can cast to int if the dataIndex is in range
  1365. if (dataIndex < 0)
  1366. throw ADP.NegativeParameter("dataIndex");
  1367. if (dataIndex > Int32.MaxValue) {
  1368. throw ADP.InvalidSourceBufferIndex(cbytes, dataIndex, "dataIndex");
  1369. }
  1370. int ndataIndex = (int)dataIndex;
  1371. byte[] data;
  1372. // WebData 99342 - in the non-sequential case, we need to support
  1373. // the use of GetBytes on string data columns, but
  1374. // GetSqlBinary isn't supposed to. What we end up
  1375. // doing isn't exactly pretty, but it does work.
  1376. if (_metaData[i].metaType.IsBinType) {
  1377. data = GetSqlBinary(i).Value;
  1378. }
  1379. else {
  1380. Debug.Assert(_metaData[i].metaType.IsLong, "non long type?");
  1381. Debug.Assert(_metaData[i].metaType.IsCharType, "non-char type?");
  1382. SqlString temp = GetSqlString(i);
  1383. if (_metaData[i].metaType.IsNCharType) {
  1384. data = temp.GetUnicodeBytes();
  1385. }
  1386. else {
  1387. data = temp.GetNonUnicodeBytes();
  1388. }
  1389. }
  1390. cbytes = data.Length;
  1391. // if no buffer is passed in, return the number of characters we have
  1392. if (null == buffer) {
  1393. remaining = cbytes;
  1394. return true;
  1395. }
  1396. // if dataIndex is outside of data range, return 0
  1397. if (ndataIndex < 0 || ndataIndex >= cbytes) {
  1398. return true;
  1399. }
  1400. try {
  1401. if (ndataIndex < cbytes) {
  1402. // help the user out in the case where there's less data than requested
  1403. if ((ndataIndex + length) > cbytes)
  1404. cbytes = cbytes - ndataIndex;
  1405. else
  1406. cbytes = length;
  1407. }
  1408. Array.Copy(data, ndataIndex, buffer, bufferIndex, cbytes);
  1409. }
  1410. catch (Exception e) {
  1411. //
  1412. if (!ADP.IsCatchableExceptionType(e)) {
  1413. throw;
  1414. }
  1415. cbytes = data.Length;
  1416. if (length < 0)
  1417. throw ADP.InvalidDataLength(length);
  1418. // if bad buffer index, throw
  1419. if (bufferIndex < 0 || bufferIndex >= buffer.Length)
  1420. throw ADP.InvalidDestinationBufferIndex(buffer.Length, bufferIndex, "bufferIndex");
  1421. // if there is not enough room in the buffer for data
  1422. if (cbytes + bufferIndex > buffer.Length)
  1423. throw ADP.InvalidBufferSizeOrIndex(cbytes, bufferIndex);
  1424. throw;
  1425. }
  1426. remaining = cbytes;
  1427. return true;
  1428. }
  1429. #if DEBUG
  1430. finally {
  1431. tdsReliabilitySection.Stop();
  1432. }
  1433. #endif //DEBUG
  1434. }
  1435. catch (System.OutOfMemoryException e) {
  1436. _isClosed = true;
  1437. if (null != _connection) {
  1438. _connection.Abort(e);
  1439. }
  1440. throw;
  1441. }
  1442. catch (System.StackOverflowException e) {
  1443. _isClosed = true;
  1444. if (null != _connection) {
  1445. _connection.Abort(e);
  1446. }
  1447. throw;
  1448. }
  1449. catch (System.Threading.ThreadAbortException e) {
  1450. _isClosed = true;
  1451. if (null != _connection) {
  1452. _connection.Abort(e);
  1453. }
  1454. throw;
  1455. }
  1456. }
  1457. internal int GetBytesInternalSequential(int i, byte[] buffer, int index, int length, long? timeoutMilliseconds = null) {
  1458. if (_currentTask != null) {
  1459. throw ADP.AsyncOperationPending();
  1460. }
  1461. int value;
  1462. SqlStatistics statistics = null;
  1463. Debug.Assert(_stateObj._syncOverAsync, "Should not attempt pends in a synchronous call");
  1464. try {
  1465. statistics = SqlStatistics.StartTimer(Statistics);
  1466. SetTimeout(timeoutMilliseconds ?? _defaultTimeoutMilliseconds);
  1467. bool result = TryReadColumnHeader(i);
  1468. if (!result) { throw SQL.SynchronousCallMayNotPend(); }
  1469. result = TryGetBytesInternalSequential(i, buffer, index, length, out value);
  1470. if (!result) { throw SQL.SynchronousCallMayNotPend(); }
  1471. }
  1472. finally {
  1473. SqlStatistics.StopTimer(statistics);
  1474. }
  1475. return value;
  1476. }
  1477. // This is meant to be called from other internal methods once we are at the column to read
  1478. // NOTE: This method must be retriable WITHOUT replaying a snapshot
  1479. // Every time you call this method increment the index and decrease length by the value of bytesRead
  1480. internal bool TryGetBytesInternalSequential(int i, byte[] buffer, int index, int length, out int bytesRead) {
  1481. AssertReaderState(requireData: true, permitAsync: true, columnIndex: i, enforceSequentialAccess: true);
  1482. Debug.Assert(_sharedState._nextColumnHeaderToRead == i + 1 && _sharedState._nextColumnDataToRead == i, "Non sequential access");
  1483. Debug.Assert(buffer != null, "Null buffer");
  1484. Debug.Assert(index >= 0, "Invalid index");
  1485. Debug.Assert(length >= 0, "Invalid length");
  1486. Debug.Assert(index + length <= buffer.Length, "Buffer too small");
  1487. bytesRead = 0;
  1488. RuntimeHelpers.PrepareConstrainedRegions();
  1489. try
  1490. {
  1491. #if DEBUG
  1492. TdsParser.ReliabilitySection tdsReliabilitySection = new TdsParser.ReliabilitySection();
  1493. RuntimeHelpers.PrepareConstrainedRegions();
  1494. try {
  1495. tdsReliabilitySection.Start();
  1496. #endif //DEBUG
  1497. if ((_sharedState._columnDataBytesRemaining == 0) || (length == 0)) {
  1498. // No data left or nothing requested, return 0
  1499. bytesRead = 0;
  1500. return true;
  1501. }
  1502. else {
  1503. // if plp columns, do partial reads. Don't read the entire value in one shot.
  1504. if (_metaData[i].metaType.IsPlp) {
  1505. // Read in data
  1506. bool result = _stateObj.TryReadPlpBytes(ref buffer, index, length, out bytesRead);
  1507. _columnDataBytesRead += bytesRead;
  1508. if (!result) {
  1509. return false;
  1510. }
  1511. // Query for number of bytes left
  1512. ulong left;
  1513. if (!_parser.TryPlpBytesLeft(_stateObj, out left)) {
  1514. _sharedState._columnDataBytesRemaining = -1;
  1515. return false;
  1516. }
  1517. _sharedState._columnDataBytesRemaining = (long)left;
  1518. return true;
  1519. }
  1520. else {
  1521. // Read data (not exceeding the total amount of data available)
  1522. int bytesToRead = (int)Math.Min((long)length, _sharedState._columnDataBytesRemaining);
  1523. bool result = _stateObj.TryReadByteArray(buffer, index, bytesToRead, out bytesRead);
  1524. _columnDataBytesRead += bytesRead;
  1525. _sharedState._columnDataBytesRemaining -= bytesRead;
  1526. return result;
  1527. }
  1528. }
  1529. #if DEBUG
  1530. }
  1531. finally {
  1532. tdsReliabilitySection.Stop();
  1533. }
  1534. #endif //DEBUG
  1535. }
  1536. catch (System.OutOfMemoryException e) {
  1537. _isClosed = true;
  1538. if (null != _connection) {
  1539. _connection.Abort(e);
  1540. }
  1541. throw;
  1542. }
  1543. catch (System.StackOverflowException e) {
  1544. _isClosed = true;
  1545. if (null != _connection) {
  1546. _connection.Abort(e);
  1547. }
  1548. throw;
  1549. }
  1550. catch (System.Threading.ThreadAbortException e) {
  1551. _isClosed = true;
  1552. if (null != _connection) {
  1553. _connection.Abort(e);
  1554. }
  1555. throw;
  1556. }
  1557. }
  1558. override public TextReader GetTextReader(int i) {
  1559. CheckDataIsReady(columnIndex: i, methodName: "GetTextReader");
  1560. // Xml type is not supported
  1561. MetaType mt = _metaData[i].metaType;
  1562. if (((!mt.IsCharType) && (mt.SqlDbType != SqlDbType.Variant)) || (mt.SqlDbType == SqlDbType.Xml)) {
  1563. throw SQL.TextReaderNotSupportOnColumnType(_metaData[i].column);
  1564. }
  1565. // For non-variant types with sequential access, we support proper streaming
  1566. if ((mt.SqlDbType != SqlDbType.Variant) && (IsCommandBehavior(CommandBehavior.SequentialAccess))) {
  1567. System.Text.Encoding encoding;
  1568. if (mt.IsNCharType)
  1569. {
  1570. // NChar types always use unicode
  1571. encoding = SqlUnicodeEncoding.SqlUnicodeEncodingInstance;
  1572. }
  1573. else
  1574. {
  1575. encoding = _metaData[i].encoding;
  1576. }
  1577. _currentTextReader = new SqlSequentialTextReader(this, i, encoding);
  1578. _lastColumnWithDataChunkRead = i;
  1579. return _currentTextReader;
  1580. }
  1581. else {
  1582. // Need to call ReadColumn, since we want to access the internal data structures (i.e. SqlString) rather than calling anther Get*() method
  1583. ReadColumn(i);
  1584. string data;
  1585. if (_data[i].IsNull) {
  1586. // A 'null' stream
  1587. data = string.Empty;
  1588. }
  1589. else {
  1590. // Grab already read data
  1591. data = _data[i].SqlString.Value;
  1592. }
  1593. // We've already read the data, so just wrap it in a StringReader
  1594. return new StringReader(data);
  1595. }
  1596. }
  1597. [ EditorBrowsableAttribute(EditorBrowsableState.Never) ] // MDAC 69508
  1598. override public char GetChar(int i) {
  1599. throw ADP.NotSupported();
  1600. }
  1601. override public long GetChars(int i, long dataIndex, char[] buffer, int bufferIndex, int length) {
  1602. SqlStatistics statistics = null;
  1603. CheckMetaDataIsReady(columnIndex: i);
  1604. if (_currentTask != null) {
  1605. throw ADP.AsyncOperationPending();
  1606. }
  1607. try {
  1608. statistics = SqlStatistics.StartTimer(Statistics);
  1609. SetTimeout(_defaultTimeoutMilliseconds);
  1610. if ((_metaData[i].metaType.IsPlp) &&
  1611. (IsCommandBehavior(CommandBehavior.SequentialAccess)) ) {
  1612. if (length < 0) {
  1613. throw ADP.InvalidDataLength(length);
  1614. }
  1615. // if bad buffer index, throw
  1616. if ((bufferIndex < 0) || (buffer != null && bufferIndex >= buffer.Length)) {
  1617. throw ADP.InvalidDestinationBufferIndex(buffer.Length, bufferIndex, "bufferIndex");
  1618. }
  1619. // if there is not enough room in the buffer for data
  1620. if (buffer != null && (length + bufferIndex > buffer.Length)) {
  1621. throw ADP.InvalidBufferSizeOrIndex(length, bufferIndex);
  1622. }
  1623. long charsRead = 0;
  1624. if ( _metaData[i].type == SqlDbType.Xml ) {
  1625. try {
  1626. CheckDataIsReady(columnIndex: i, allowPartiallyReadColumn: true, methodName: "GetChars");
  1627. }
  1628. catch (Exception ex) {
  1629. // Dev11 Bug #315513: Exception type breaking change from 4.0 RTM when calling GetChars on null xml
  1630. // We need to wrap all exceptions inside a TargetInvocationException to simulate calling CreateSqlReader via MethodInfo.Invoke
  1631. if (ADP.IsCatchableExceptionType(ex)) {
  1632. throw new TargetInvocationException(ex);
  1633. }
  1634. else {
  1635. throw;
  1636. }
  1637. }
  1638. charsRead = GetStreamingXmlChars(i, dataIndex, buffer, bufferIndex, length);
  1639. }
  1640. else {
  1641. CheckDataIsReady(columnIndex: i, allowPartiallyReadColumn: true, methodName: "GetChars");
  1642. charsRead = GetCharsFromPlpData(i, dataIndex, buffer, bufferIndex, length);
  1643. }
  1644. _lastColumnWithDataChunkRead = i;
  1645. return charsRead;
  1646. }
  1647. // Did we start reading this value yet?
  1648. if ((_sharedState._nextColumnDataToRead == (i+1)) && (_sharedState._nextColumnHeaderToRead == (i+1)) && (_columnDataChars != null) && (IsCommandBehavior(CommandBehavior.SequentialAccess)) && (dataIndex < _columnDataCharsRead)) {
  1649. // Don't allow re-read of same chars in sequential access mode
  1650. throw ADP.NonSeqByteAccess(dataIndex, _columnDataCharsRead, ADP.GetChars);
  1651. }
  1652. if (_columnDataCharsIndex != i) {
  1653. // if the object doesn't contain a char[] then the user will get an exception
  1654. string s = GetSqlString(i).Value;
  1655. _columnDataChars = s.ToCharArray();
  1656. _columnDataCharsRead = 0;
  1657. _columnDataCharsIndex = i;
  1658. }
  1659. int cchars = _columnDataChars.Length;
  1660. // note that since we are caching in an array, and arrays aren't 64 bit ready yet,
  1661. // we need can cast to int if the dataIndex is in range
  1662. if (dataIndex > Int32.MaxValue) {
  1663. throw ADP.InvalidSourceBufferIndex(cchars, dataIndex, "dataIndex");
  1664. }
  1665. int ndataIndex = (int)dataIndex;
  1666. // if no buffer is passed in, return the number of characters we have
  1667. if (null == buffer)
  1668. return cchars;
  1669. // if dataIndex outside of data range, return 0
  1670. if (ndataIndex < 0 || ndataIndex >= cchars)
  1671. return 0;
  1672. try {
  1673. if (ndataIndex < cchars) {
  1674. // help the user out in the case where there's less data than requested
  1675. if ((ndataIndex + length) > cchars)
  1676. cchars = cchars - ndataIndex;
  1677. else
  1678. cchars = length;
  1679. }
  1680. Array.Copy(_columnDataChars, ndataIndex, buffer, bufferIndex, cchars);
  1681. _columnDataCharsRead += cchars;
  1682. }
  1683. catch (Exception e) {
  1684. //
  1685. if (!ADP.IsCatchableExceptionType(e)) {
  1686. throw;
  1687. }
  1688. cchars = _columnDataChars.Length;
  1689. if (length < 0)
  1690. throw ADP.InvalidDataLength(length);
  1691. // if bad buffer index, throw
  1692. if (bufferIndex < 0 || bufferIndex >= buffer.Length)
  1693. throw ADP.InvalidDestinationBufferIndex(buffer.Length, bufferIndex, "bufferIndex");
  1694. // if there is not enough room in the buffer for data
  1695. if (cchars + bufferIndex > buffer.Length)
  1696. throw ADP.InvalidBufferSizeOrIndex(cchars, bufferIndex);
  1697. throw;
  1698. }
  1699. return cchars;
  1700. }
  1701. finally {
  1702. SqlStatistics.StopTimer(statistics);
  1703. }
  1704. }
  1705. private long GetCharsFromPlpData(int i, long dataIndex, char[] buffer, int bufferIndex, int length) {
  1706. RuntimeHelpers.PrepareConstrainedRegions();
  1707. try {
  1708. #if DEBUG
  1709. TdsParser.ReliabilitySection tdsReliabilitySection = new TdsParser.ReliabilitySection();
  1710. RuntimeHelpers.PrepareConstrainedRegions();
  1711. try {
  1712. tdsReliabilitySection.Start();
  1713. #else
  1714. {
  1715. #endif //DEBUG
  1716. long cch;
  1717. AssertReaderState(requireData: true, permitAsync: false, columnIndex: i, enforceSequentialAccess: true);
  1718. Debug.Assert(!HasActiveStreamOrTextReaderOnColumn(i), "Column has active Stream or TextReader");
  1719. // don't allow get bytes on non-long or non-binary columns
  1720. Debug.Assert(_metaData[i].metaType.IsPlp, "GetCharsFromPlpData called on a non-plp column!");
  1721. // Must be sequential reading
  1722. Debug.Assert (IsCommandBehavior(CommandBehavior.SequentialAccess), "GetCharsFromPlpData called for non-Sequential access");
  1723. if (!_metaData[i].metaType.IsCharType) {
  1724. throw SQL.NonCharColumn(_metaData[i].column);
  1725. }
  1726. if (_sharedState._nextColumnHeaderToRead <= i) {
  1727. ReadColumnHeader(i);
  1728. }
  1729. // If data is null, ReadColumnHeader sets the data.IsNull bit.
  1730. if (_data[i] != null && _data[i].IsNull) {
  1731. throw new SqlNullValueException();
  1732. }
  1733. if (dataIndex < _columnDataCharsRead) {
  1734. // Don't allow re-read of same chars in sequential access mode
  1735. throw ADP.NonSeqByteAccess(dataIndex, _columnDataCharsRead, ADP.GetChars);
  1736. }
  1737. // If we start reading the new column, either dataIndex is 0 or
  1738. // _columnDataCharsRead is 0 and dataIndex > _columnDataCharsRead is true below.
  1739. // In both cases we will clean decoder
  1740. if (dataIndex == 0)
  1741. _stateObj._plpdecoder = null;
  1742. bool isUnicode = _metaData[i].metaType.IsNCharType;
  1743. // If there are an unknown (-1) number of bytes left for a PLP, read its size
  1744. if (-1 == _sharedState._columnDataBytesRemaining) {
  1745. _sharedState._columnDataBytesRemaining = (long)_parser.PlpBytesLeft(_stateObj);
  1746. }
  1747. if (0 == _sharedState._columnDataBytesRemaining) {
  1748. _stateObj._plpdecoder = null;
  1749. return 0; // We've read this column to the end
  1750. }
  1751. // if no buffer is passed in, return the total number of characters or -1
  1752. //
  1753. if (null == buffer) {
  1754. cch = (long) _parser.PlpBytesTotalLength(_stateObj);
  1755. return (isUnicode && (cch > 0)) ? cch >> 1 : cch;
  1756. }
  1757. if (dataIndex > _columnDataCharsRead) {
  1758. // Skip chars
  1759. // Clean decoder state: we do not reset it, but destroy to ensure
  1760. // that we do not start decoding the column with decoder from the old one
  1761. _stateObj._plpdecoder = null;
  1762. //
  1763. cch = dataIndex - _columnDataCharsRead;
  1764. cch = isUnicode ? (cch << 1 ) : cch;
  1765. cch = (long) _parser.SkipPlpValue((ulong)(cch), _stateObj);
  1766. _columnDataBytesRead += cch;
  1767. _columnDataCharsRead += (isUnicode && (cch > 0)) ? cch >> 1 : cch;
  1768. }
  1769. cch = length;
  1770. if (isUnicode) {
  1771. cch = (long) _parser.ReadPlpUnicodeChars(ref buffer, bufferIndex, length, _stateObj);
  1772. _columnDataBytesRead += (cch << 1);
  1773. }
  1774. else {
  1775. cch = (long) _parser.ReadPlpAnsiChars(ref buffer, bufferIndex, length, _metaData[i], _stateObj);
  1776. _columnDataBytesRead += cch << 1;
  1777. }
  1778. _columnDataCharsRead += cch;
  1779. _sharedState._columnDataBytesRemaining = (long)_parser.PlpBytesLeft(_stateObj);
  1780. return cch;
  1781. }
  1782. #if DEBUG
  1783. finally {
  1784. tdsReliabilitySection.Stop();
  1785. }
  1786. #endif //DEBUG
  1787. }
  1788. catch (System.OutOfMemoryException e) {
  1789. _isClosed = true;
  1790. if (null != _connection) {
  1791. _connection.Abort(e);
  1792. }
  1793. throw;
  1794. }
  1795. catch (System.StackOverflowException e) {
  1796. _isClosed = true;
  1797. if (null != _connection) {
  1798. _connection.Abort(e);
  1799. }
  1800. throw;
  1801. }
  1802. catch (System.Threading.ThreadAbortException e) {
  1803. _isClosed = true;
  1804. if (null != _connection) {
  1805. _connection.Abort(e);
  1806. }
  1807. throw;
  1808. }
  1809. }
  1810. internal long GetStreamingXmlChars(int i, long dataIndex, char[] buffer, int bufferIndex, int length) {
  1811. SqlStreamingXml localSXml = null;
  1812. if ((_streamingXml != null) && ( _streamingXml.ColumnOrdinal != i)) {
  1813. _streamingXml.Close();
  1814. _streamingXml = null;
  1815. }
  1816. if (_streamingXml == null) {
  1817. localSXml = new SqlStreamingXml(i, this);
  1818. }
  1819. else {
  1820. localSXml = _streamingXml;
  1821. }
  1822. long cnt = localSXml.GetChars(dataIndex, buffer, bufferIndex, length);
  1823. if (_streamingXml == null) {
  1824. // Data is read through GetBytesInternal which may dispose _streamingXml if it has to advance the column ordinal.
  1825. // Therefore save the new SqlStreamingXml class after the read succeeds.
  1826. _streamingXml = localSXml;
  1827. }
  1828. return cnt;
  1829. }
  1830. [ EditorBrowsableAttribute(EditorBrowsableState.Never) ] // MDAC 69508
  1831. IDataReader IDataRecord.GetData(int i) {
  1832. throw ADP.NotSupported();
  1833. }
  1834. override public DateTime GetDateTime(int i) {
  1835. ReadColumn(i);
  1836. DateTime dt = _data[i].DateTime;
  1837. // This accessor can be called for regular DateTime column. In this case we should not throw
  1838. if (_typeSystem <= SqlConnectionString.TypeSystem.SQLServer2005 && _metaData[i].IsNewKatmaiDateTimeType) {
  1839. // TypeSystem.SQLServer2005 or less
  1840. // If the above succeeds, then we received a valid DateTime instance, now we need to force
  1841. // an InvalidCastException since DateTime is not exposed with the version knob in this setting.
  1842. // To do so, we simply force the exception by casting the string representation of the value
  1843. // To DateTime.
  1844. object temp = (object) _data[i].String;
  1845. dt = (DateTime) temp;
  1846. }
  1847. return dt;
  1848. }
  1849. override public Decimal GetDecimal(int i) {
  1850. ReadColumn(i);
  1851. return _data[i].Decimal;
  1852. }
  1853. override public double GetDouble(int i) {
  1854. ReadColumn(i);
  1855. return _data[i].Double;
  1856. }
  1857. override public float GetFloat(int i) {
  1858. ReadColumn(i);
  1859. return _data[i].Single;
  1860. }
  1861. override public Guid GetGuid(int i) {
  1862. ReadColumn(i);
  1863. return _data[i].SqlGuid.Value;
  1864. }
  1865. override public Int16 GetInt16(int i) {
  1866. ReadColumn(i);
  1867. return _data[i].Int16;
  1868. }
  1869. override public Int32 GetInt32(int i) {
  1870. ReadColumn(i);
  1871. return _data[i].Int32;
  1872. }
  1873. override public Int64 GetInt64(int i) {
  1874. ReadColumn(i);
  1875. return _data[i].Int64;
  1876. }
  1877. virtual public SqlBoolean GetSqlBoolean(int i) {
  1878. ReadColumn(i);
  1879. return _data[i].SqlBoolean;
  1880. }
  1881. virtual public SqlBinary GetSqlBinary(int i) {
  1882. ReadColumn(i, setTimeout: true, allowPartiallyReadColumn: true);
  1883. return _data[i].SqlBinary;
  1884. }
  1885. virtual public SqlByte GetSqlByte(int i) {
  1886. ReadColumn(i);
  1887. return _data[i].SqlByte;
  1888. }
  1889. virtual public SqlBytes GetSqlBytes(int i) {
  1890. ReadColumn(i);
  1891. SqlBinary data = _data[i].SqlBinary;
  1892. return new SqlBytes(data);
  1893. }
  1894. virtual public SqlChars GetSqlChars(int i) {
  1895. ReadColumn(i);
  1896. SqlString data;
  1897. // Convert Katmai types to string
  1898. if (_typeSystem <= SqlConnectionString.TypeSystem.SQLServer2005 && _metaData[i].IsNewKatmaiDateTimeType)
  1899. {
  1900. data = _data[i].KatmaiDateTimeSqlString;
  1901. } else {
  1902. data = _data[i].SqlString;
  1903. }
  1904. return new SqlChars(data);
  1905. }
  1906. virtual public SqlDateTime GetSqlDateTime(int i) {
  1907. ReadColumn(i);
  1908. return _data[i].SqlDateTime;
  1909. }
  1910. virtual public SqlDecimal GetSqlDecimal(int i) {
  1911. ReadColumn(i);
  1912. return _data[i].SqlDecimal;
  1913. }
  1914. virtual public SqlGuid GetSqlGuid(int i) {
  1915. ReadColumn(i);
  1916. return _data[i].SqlGuid;
  1917. }
  1918. virtual public SqlDouble GetSqlDouble(int i) {
  1919. ReadColumn(i);
  1920. return _data[i].SqlDouble;
  1921. }
  1922. virtual public SqlInt16 GetSqlInt16(int i) {
  1923. ReadColumn(i);
  1924. return _data[i].SqlInt16;
  1925. }
  1926. virtual public SqlInt32 GetSqlInt32(int i) {
  1927. ReadColumn(i);
  1928. return _data[i].SqlInt32;
  1929. }
  1930. virtual public SqlInt64 GetSqlInt64(int i) {
  1931. ReadColumn(i);
  1932. return _data[i].SqlInt64;
  1933. }
  1934. virtual public SqlMoney GetSqlMoney(int i) {
  1935. ReadColumn(i);
  1936. return _data[i].SqlMoney;
  1937. }
  1938. virtual public SqlSingle GetSqlSingle(int i) {
  1939. ReadColumn(i);
  1940. return _data[i].SqlSingle;
  1941. }
  1942. //
  1943. virtual public SqlString GetSqlString(int i) {
  1944. ReadColumn(i);
  1945. if (_typeSystem <= SqlConnectionString.TypeSystem.SQLServer2005 && _metaData[i].IsNewKatmaiDateTimeType) {
  1946. return _data[i].KatmaiDateTimeSqlString;
  1947. }
  1948. return _data[i].SqlString;
  1949. }
  1950. virtual public SqlXml GetSqlXml(int i){
  1951. ReadColumn(i);
  1952. SqlXml sx = null;
  1953. if (_typeSystem != SqlConnectionString.TypeSystem.SQLServer2000) {
  1954. // TypeSystem.SQLServer2005
  1955. sx = _data[i].IsNull ? SqlXml.Null : _data[i].SqlCachedBuffer.ToSqlXml();
  1956. }
  1957. else {
  1958. // TypeSystem.SQLServer2000
  1959. // First, attempt to obtain SqlXml value. If not SqlXml, we will throw the appropriate
  1960. // cast exception.
  1961. sx = _data[i].IsNull ? SqlXml.Null : _data[i].SqlCachedBuffer.ToSqlXml();
  1962. // If the above succeeds, then we received a valid SqlXml instance, now we need to force
  1963. // an InvalidCastException since SqlXml is not exposed with the version knob in this setting.
  1964. // To do so, we simply force the exception by casting the string representation of the value
  1965. // To SqlXml.
  1966. object temp = (object) _data[i].String;
  1967. sx = (SqlXml) temp;
  1968. }
  1969. return sx;
  1970. }
  1971. virtual public object GetSqlValue(int i) {
  1972. SqlStatistics statistics = null;
  1973. try {
  1974. statistics = SqlStatistics.StartTimer(Statistics);
  1975. SetTimeout(_defaultTimeoutMilliseconds);
  1976. return GetSqlValueInternal(i);
  1977. }
  1978. finally {
  1979. SqlStatistics.StopTimer(statistics);
  1980. }
  1981. }
  1982. private object GetSqlValueInternal(int i) {
  1983. if (_currentTask != null) {
  1984. throw ADP.AsyncOperationPending();
  1985. }
  1986. Debug.Assert(_stateObj == null || _stateObj._syncOverAsync, "Should not attempt pends in a synchronous call");
  1987. bool result = TryReadColumn(i, setTimeout: false);
  1988. if (!result) { throw SQL.SynchronousCallMayNotPend(); }
  1989. return GetSqlValueFromSqlBufferInternal(_data[i], _metaData[i]);
  1990. }
  1991. // NOTE: This method is called by the fast-paths in Async methods and, therefore, should be resilient to the DataReader being closed
  1992. // Always make sure to take reference copies of anything set to null in TryCloseInternal()
  1993. private object GetSqlValueFromSqlBufferInternal(SqlBuffer data, _SqlMetaData metaData) {
  1994. // Dev11 Bug #336820, Dev10 Bug #479607 (SqlClient: IsDBNull always returns false for timestamp datatype)
  1995. // Due to a bug in TdsParser.GetNullSqlValue, Timestamps' IsNull is not correctly set - so we need to bypass the following check
  1996. Debug.Assert(!data.IsEmpty || data.IsNull || metaData.type == SqlDbType.Timestamp, "Data has been read, but the buffer is empty");
  1997. // Convert Katmai types to string
  1998. if (_typeSystem <= SqlConnectionString.TypeSystem.SQLServer2005 && metaData.IsNewKatmaiDateTimeType) {
  1999. return data.KatmaiDateTimeSqlString;
  2000. }
  2001. else if (_typeSystem <= SqlConnectionString.TypeSystem.SQLServer2005 && metaData.IsLargeUdt) {
  2002. return data.SqlValue;
  2003. }
  2004. else if (_typeSystem != SqlConnectionString.TypeSystem.SQLServer2000) {
  2005. // TypeSystem.SQLServer2005
  2006. if (metaData.type == SqlDbType.Udt) {
  2007. var connection = _connection;
  2008. if (connection != null) {
  2009. connection.CheckGetExtendedUDTInfo(metaData, true);
  2010. return connection.GetUdtValue(data.Value, metaData, false);
  2011. }
  2012. else {
  2013. throw ADP.DataReaderClosed("GetSqlValueFromSqlBufferInternal");
  2014. }
  2015. }
  2016. else {
  2017. return data.SqlValue;
  2018. }
  2019. }
  2020. else {
  2021. // TypeSystem.SQLServer2000
  2022. if (metaData.type == SqlDbType.Xml) {
  2023. return data.SqlString;
  2024. }
  2025. else {
  2026. return data.SqlValue;
  2027. }
  2028. }
  2029. }
  2030. virtual public int GetSqlValues(object[] values){
  2031. SqlStatistics statistics = null;
  2032. try {
  2033. statistics = SqlStatistics.StartTimer(Statistics);
  2034. CheckDataIsReady();
  2035. if (null == values) {
  2036. throw ADP.ArgumentNull("values");
  2037. }
  2038. SetTimeout(_defaultTimeoutMilliseconds);
  2039. int copyLen = (values.Length < _metaData.visibleColumns) ? values.Length : _metaData.visibleColumns;
  2040. for (int i = 0; i < copyLen; i++) {
  2041. values[_metaData.indexMap[i]] = GetSqlValueInternal(i);
  2042. }
  2043. return copyLen;
  2044. }
  2045. finally {
  2046. SqlStatistics.StopTimer(statistics);
  2047. }
  2048. }
  2049. override public string GetString(int i) {
  2050. ReadColumn(i);
  2051. // Convert katmai value to string if type system knob is 2005 or earlier
  2052. if (_typeSystem <= SqlConnectionString.TypeSystem.SQLServer2005 && _metaData[i].IsNewKatmaiDateTimeType) {
  2053. return _data[i].KatmaiDateTimeString;
  2054. }
  2055. return _data[i].String;
  2056. }
  2057. override public T GetFieldValue<T>(int i) {
  2058. SqlStatistics statistics = null;
  2059. try {
  2060. statistics = SqlStatistics.StartTimer(Statistics);
  2061. SetTimeout(_defaultTimeoutMilliseconds);
  2062. return GetFieldValueInternal<T>(i);
  2063. }
  2064. finally {
  2065. SqlStatistics.StopTimer(statistics);
  2066. }
  2067. }
  2068. override public object GetValue(int i) {
  2069. SqlStatistics statistics = null;
  2070. try {
  2071. statistics = SqlStatistics.StartTimer(Statistics);
  2072. SetTimeout(_defaultTimeoutMilliseconds);
  2073. return GetValueInternal(i);
  2074. }
  2075. finally {
  2076. SqlStatistics.StopTimer(statistics);
  2077. }
  2078. }
  2079. virtual public TimeSpan GetTimeSpan(int i) {
  2080. ReadColumn(i);
  2081. TimeSpan t = _data[i].Time;
  2082. if (_typeSystem <= SqlConnectionString.TypeSystem.SQLServer2005) {
  2083. // TypeSystem.SQLServer2005 or less
  2084. // If the above succeeds, then we received a valid TimeSpan instance, now we need to force
  2085. // an InvalidCastException since TimeSpan is not exposed with the version knob in this setting.
  2086. // To do so, we simply force the exception by casting the string representation of the value
  2087. // To TimeSpan.
  2088. object temp = (object) _data[i].String;
  2089. t = (TimeSpan) temp;
  2090. }
  2091. return t;
  2092. }
  2093. virtual public DateTimeOffset GetDateTimeOffset(int i) {
  2094. ReadColumn(i);
  2095. DateTimeOffset dto = _data[i].DateTimeOffset;
  2096. if (_typeSystem <= SqlConnectionString.TypeSystem.SQLServer2005) {
  2097. // TypeSystem.SQLServer2005 or less
  2098. // If the above succeeds, then we received a valid DateTimeOffset instance, now we need to force
  2099. // an InvalidCastException since DateTime is not exposed with the version knob in this setting.
  2100. // To do so, we simply force the exception by casting the string representation of the value
  2101. // To DateTimeOffset.
  2102. object temp = (object) _data[i].String;
  2103. dto = (DateTimeOffset) temp;
  2104. }
  2105. return dto;
  2106. }
  2107. private object GetValueInternal(int i) {
  2108. if (_currentTask != null) {
  2109. throw ADP.AsyncOperationPending();
  2110. }
  2111. Debug.Assert(_stateObj == null || _stateObj._syncOverAsync, "Should not attempt pends in a synchronous call");
  2112. bool result = TryReadColumn(i, setTimeout: false);
  2113. if (!result) { throw SQL.SynchronousCallMayNotPend(); }
  2114. return GetValueFromSqlBufferInternal(_data[i], _metaData[i]);
  2115. }
  2116. // NOTE: This method is called by the fast-paths in Async methods and, therefore, should be resilient to the DataReader being closed
  2117. // Always make sure to take reference copies of anything set to null in TryCloseInternal()
  2118. private object GetValueFromSqlBufferInternal(SqlBuffer data, _SqlMetaData metaData) {
  2119. // Dev11 Bug #336820, Dev10 Bug #479607 (SqlClient: IsDBNull always returns false for timestamp datatype)
  2120. // Due to a bug in TdsParser.GetNullSqlValue, Timestamps' IsNull is not correctly set - so we need to bypass the following check
  2121. Debug.Assert(!data.IsEmpty || data.IsNull || metaData.type == SqlDbType.Timestamp, "Data has been read, but the buffer is empty");
  2122. if (_typeSystem <= SqlConnectionString.TypeSystem.SQLServer2005 && metaData.IsNewKatmaiDateTimeType) {
  2123. if (data.IsNull) {
  2124. return DBNull.Value;
  2125. }
  2126. else {
  2127. return data.KatmaiDateTimeString;
  2128. }
  2129. }
  2130. else if (_typeSystem <= SqlConnectionString.TypeSystem.SQLServer2005 && metaData.IsLargeUdt) {
  2131. return data.Value;
  2132. }
  2133. else if (_typeSystem != SqlConnectionString.TypeSystem.SQLServer2000) {
  2134. // TypeSystem.SQLServer2005
  2135. if (metaData.type != SqlDbType.Udt) {
  2136. return data.Value;
  2137. }
  2138. else {
  2139. var connection = _connection;
  2140. if (connection != null) {
  2141. connection.CheckGetExtendedUDTInfo(metaData, true);
  2142. return connection.GetUdtValue(data.Value, metaData, true);
  2143. }
  2144. else {
  2145. throw ADP.DataReaderClosed("GetValueFromSqlBufferInternal");
  2146. }
  2147. }
  2148. }
  2149. else {
  2150. // TypeSystem.SQLServer2000
  2151. return data.Value;
  2152. }
  2153. }
  2154. private T GetFieldValueInternal<T>(int i) {
  2155. if (_currentTask != null) {
  2156. throw ADP.AsyncOperationPending();
  2157. }
  2158. Debug.Assert(_stateObj == null || _stateObj._syncOverAsync, "Should not attempt pends in a synchronous call");
  2159. bool result = TryReadColumn(i, setTimeout: false);
  2160. if (!result) { throw SQL.SynchronousCallMayNotPend(); }
  2161. return GetFieldValueFromSqlBufferInternal<T>(_data[i], _metaData[i]);
  2162. }
  2163. private T GetFieldValueFromSqlBufferInternal<T>(SqlBuffer data, _SqlMetaData metaData) {
  2164. Type typeofT = typeof(T);
  2165. if (_typeofINullable.IsAssignableFrom(typeofT)) {
  2166. // If its a SQL Type or Nullable UDT
  2167. object rawValue = GetSqlValueFromSqlBufferInternal(data, metaData);
  2168. // Special case: User wants SqlString, but we have a SqlXml
  2169. // SqlXml can not be typecast into a SqlString, but we need to support SqlString on XML Types - so do a manual conversion
  2170. if (typeofT == _typeofSqlString) {
  2171. SqlXml xmlValue = rawValue as SqlXml;
  2172. if (xmlValue != null) {
  2173. if (xmlValue.IsNull) {
  2174. rawValue = SqlString.Null;
  2175. }
  2176. else {
  2177. rawValue = new SqlString(xmlValue.Value);
  2178. }
  2179. }
  2180. }
  2181. return (T)rawValue;
  2182. }
  2183. else {
  2184. // Otherwise Its a CLR or non-Nullable UDT
  2185. try {
  2186. return (T)GetValueFromSqlBufferInternal(data, metaData);
  2187. }
  2188. catch (InvalidCastException) {
  2189. if (data.IsNull) {
  2190. // If the value was actually null, then we should throw a SqlNullValue instead
  2191. throw SQL.SqlNullValue();
  2192. }
  2193. else {
  2194. // Legitmate InvalidCast, rethrow
  2195. throw;
  2196. }
  2197. }
  2198. }
  2199. }
  2200. override public int GetValues(object[] values) {
  2201. SqlStatistics statistics = null;
  2202. bool sequentialAccess = IsCommandBehavior(CommandBehavior.SequentialAccess);
  2203. try {
  2204. statistics = SqlStatistics.StartTimer(Statistics);
  2205. if (null == values) {
  2206. throw ADP.ArgumentNull("values");
  2207. }
  2208. CheckMetaDataIsReady();
  2209. int copyLen = (values.Length < _metaData.visibleColumns) ? values.Length : _metaData.visibleColumns;
  2210. int maximumColumn = copyLen - 1;
  2211. SetTimeout(_defaultTimeoutMilliseconds);
  2212. // Temporarily disable sequential access
  2213. _commandBehavior &= ~CommandBehavior.SequentialAccess;
  2214. // Read in all of the columns in one TryReadColumn call
  2215. bool result = TryReadColumn(maximumColumn, setTimeout: false);
  2216. if (!result) { throw SQL.SynchronousCallMayNotPend(); }
  2217. for (int i = 0; i < copyLen; i++) {
  2218. // Get the usable, TypeSystem-compatible value from the iternal buffer
  2219. values[_metaData.indexMap[i]] = GetValueFromSqlBufferInternal(_data[i], _metaData[i]);
  2220. // If this is sequential access, then we need to wipe the internal buffer
  2221. if ((sequentialAccess) && (i < maximumColumn)) {
  2222. _data[i].Clear();
  2223. }
  2224. }
  2225. return copyLen;
  2226. }
  2227. finally {
  2228. // Restore sequential access
  2229. if (sequentialAccess) {
  2230. _commandBehavior |= CommandBehavior.SequentialAccess;
  2231. }
  2232. SqlStatistics.StopTimer(statistics);
  2233. }
  2234. }
  2235. private MetaType GetVersionedMetaType(MetaType actualMetaType) {
  2236. Debug.Assert(_typeSystem == SqlConnectionString.TypeSystem.SQLServer2000, "Should not be in this function under anything else but SQLServer2000");
  2237. MetaType metaType = null;
  2238. if (actualMetaType == MetaType.MetaUdt) {
  2239. metaType = MetaType.MetaVarBinary;
  2240. }
  2241. else if (actualMetaType == MetaType.MetaXml) {
  2242. metaType = MetaType.MetaNText;
  2243. }
  2244. else if (actualMetaType == MetaType.MetaMaxVarBinary) {
  2245. metaType = MetaType.MetaImage;
  2246. }
  2247. else if (actualMetaType == MetaType.MetaMaxVarChar) {
  2248. metaType = MetaType.MetaText;
  2249. }
  2250. else if (actualMetaType == MetaType.MetaMaxNVarChar) {
  2251. metaType = MetaType.MetaNText;
  2252. }
  2253. else {
  2254. metaType = actualMetaType;
  2255. }
  2256. return metaType;
  2257. }
  2258. private bool TryHasMoreResults(out bool moreResults) {
  2259. if(null != _parser) {
  2260. bool moreRows;
  2261. if (!TryHasMoreRows(out moreRows)) {
  2262. moreResults = false;
  2263. return false;
  2264. }
  2265. if(moreRows) {
  2266. // When does this happen? This is only called from NextResult(), which loops until Read() false.
  2267. moreResults = false;
  2268. return true;
  2269. }
  2270. Debug.Assert(null != _command, "unexpected null command from the data reader!");
  2271. while(_stateObj._pendingData) {
  2272. byte token;
  2273. if (!_stateObj.TryPeekByte(out token)) {
  2274. moreResults = false;
  2275. return false;
  2276. }
  2277. switch(token) {
  2278. case TdsEnums.SQLALTROW:
  2279. if(_altRowStatus == ALTROWSTATUS.Null) {
  2280. // cache the regular metadata
  2281. _altMetaDataSetCollection.metaDataSet = _metaData;
  2282. _metaData = null;
  2283. }
  2284. else {
  2285. Debug.Assert(_altRowStatus == ALTROWSTATUS.Done, "invalid AltRowStatus");
  2286. }
  2287. _altRowStatus = ALTROWSTATUS.AltRow;
  2288. _hasRows = true;
  2289. moreResults = true;
  2290. return true;
  2291. case TdsEnums.SQLROW:
  2292. case TdsEnums.SQLNBCROW:
  2293. // always happens if there is a row following an altrow
  2294. moreResults = true;
  2295. return true;
  2296. // VSTFDEVDIV 926281: DONEINPROC case is missing here; we have decided to reject this bug as it would result in breaking change
  2297. // from Orcas RTM/SP1 and Dev10 RTM. See the bug for more details.
  2298. // case TdsEnums.DONEINPROC:
  2299. case TdsEnums.SQLDONE:
  2300. Debug.Assert(_altRowStatus == ALTROWSTATUS.Done || _altRowStatus == ALTROWSTATUS.Null, "invalid AltRowStatus");
  2301. _altRowStatus = ALTROWSTATUS.Null;
  2302. _metaData = null;
  2303. _altMetaDataSetCollection = null;
  2304. moreResults = true;
  2305. return true;
  2306. case TdsEnums.SQLCOLMETADATA:
  2307. moreResults = true;
  2308. return true;
  2309. }
  2310. // Dev11 Bug 316483:Hang on SqlDataReader::TryHasMoreResults using MARS
  2311. // http://vstfdevdiv:8080/web/wi.aspx?pcguid=22f9acc9-569a-41ff-b6ac-fac1b6370209&id=316483
  2312. // TryRun() will immediately return if the TdsParser is closed\broken, causing us to enter an infinite loop
  2313. // Instead, we will throw a closed connection exception
  2314. if (_parser.State == TdsParserState.Broken || _parser.State == TdsParserState.Closed) {
  2315. throw ADP.ClosedConnectionError();
  2316. }
  2317. bool ignored;
  2318. if (!_parser.TryRun(RunBehavior.ReturnImmediately, _command, this, null, _stateObj, out ignored)) {
  2319. moreResults = false;
  2320. return false;
  2321. }
  2322. }
  2323. }
  2324. moreResults = false;
  2325. return true;
  2326. }
  2327. private bool TryHasMoreRows(out bool moreRows) {
  2328. if (null != _parser) {
  2329. if (_sharedState._dataReady) {
  2330. moreRows = true;
  2331. return true;
  2332. }
  2333. // NextResult: previous call to NextResult started to process the altrowpackage, can't peek anymore
  2334. // Read: Read prepared for final processing of altrow package, No more Rows until NextResult ...
  2335. // Done: Done processing the altrow, no more rows until NextResult ...
  2336. switch (_altRowStatus) {
  2337. case ALTROWSTATUS.AltRow:
  2338. moreRows = true;
  2339. return true;
  2340. case ALTROWSTATUS.Done:
  2341. moreRows = false;
  2342. return true;
  2343. }
  2344. if (_stateObj._pendingData) {
  2345. // Consume error's, info's, done's on HasMoreRows, so user obtains error on Read.
  2346. // Previous bug where Read() would return false with error on the wire in the case
  2347. // of metadata and error immediately following. See MDAC 78285 and 75225.
  2348. //
  2349. // process any done, doneproc and doneinproc token streams and
  2350. // any order, error or info token preceeding the first done, doneproc or doneinproc token stream
  2351. byte b;
  2352. if (!_stateObj.TryPeekByte(out b)) {
  2353. moreRows = false;
  2354. return false;
  2355. }
  2356. bool ParsedDoneToken = false;
  2357. while ( b == TdsEnums.SQLDONE ||
  2358. b == TdsEnums.SQLDONEPROC ||
  2359. b == TdsEnums.SQLDONEINPROC ||
  2360. !ParsedDoneToken && (
  2361. b == TdsEnums.SQLSESSIONSTATE ||
  2362. b == TdsEnums.SQLENVCHANGE ||
  2363. b == TdsEnums.SQLORDER ||
  2364. b == TdsEnums.SQLERROR ||
  2365. b == TdsEnums.SQLINFO ) ) {
  2366. if (b == TdsEnums.SQLDONE ||
  2367. b == TdsEnums.SQLDONEPROC ||
  2368. b == TdsEnums.SQLDONEINPROC) {
  2369. ParsedDoneToken = true;
  2370. }
  2371. // Dev11 Bug 316483:Hang on SqlDataReader::TryHasMoreResults using MARS
  2372. // http://vstfdevdiv:8080/web/wi.aspx?pcguid=22f9acc9-569a-41ff-b6ac-fac1b6370209&id=316483
  2373. // TryRun() will immediately return if the TdsParser is closed\broken, causing us to enter an infinite loop
  2374. // Instead, we will throw a closed connection exception
  2375. if (_parser.State == TdsParserState.Broken || _parser.State == TdsParserState.Closed) {
  2376. throw ADP.ClosedConnectionError();
  2377. }
  2378. bool ignored;
  2379. if (!_parser.TryRun(RunBehavior.ReturnImmediately, _command, this, null, _stateObj, out ignored)) {
  2380. moreRows = false;
  2381. return false;
  2382. }
  2383. if ( _stateObj._pendingData) {
  2384. if (!_stateObj.TryPeekByte(out b)) {
  2385. moreRows = false;
  2386. return false;
  2387. }
  2388. }
  2389. else {
  2390. break;
  2391. }
  2392. }
  2393. // Only return true when we are positioned on a row token.
  2394. if (IsRowToken(b)) {
  2395. moreRows = true;
  2396. return true;
  2397. }
  2398. }
  2399. }
  2400. moreRows = false;
  2401. return true;
  2402. }
  2403. private bool IsRowToken(byte token) {
  2404. return TdsEnums.SQLROW == token || TdsEnums.SQLNBCROW == token;
  2405. }
  2406. override public bool IsDBNull(int i) {
  2407. if ((IsCommandBehavior(CommandBehavior.SequentialAccess)) && ((_sharedState._nextColumnHeaderToRead > i + 1) || (_lastColumnWithDataChunkRead > i))) {
  2408. // Bug 447026 : A breaking change in System.Data .NET 4.5 for calling IsDBNull on commands in SequentialAccess mode
  2409. // http://vstfdevdiv:8080/web/wi.aspx?pcguid=22f9acc9-569a-41ff-b6ac-fac1b6370209&id=447026
  2410. // In .Net 4.0 and previous, it was possible to read a previous column using IsDBNull when in sequential mode
  2411. // However, since it had already gone past the column, the current IsNull value is simply returned
  2412. // To replicate this behavior we will skip CheckHeaderIsReady\ReadColumnHeader and instead just check that the reader is ready and the column is valid
  2413. CheckMetaDataIsReady(columnIndex: i);
  2414. }
  2415. else {
  2416. CheckHeaderIsReady(columnIndex: i, methodName: "IsDBNull");
  2417. SetTimeout(_defaultTimeoutMilliseconds);
  2418. ReadColumnHeader(i); // header data only
  2419. }
  2420. return _data[i].IsNull;
  2421. }
  2422. protected internal bool IsCommandBehavior(CommandBehavior condition) {
  2423. return (condition == (condition & _commandBehavior));
  2424. }
  2425. override public bool NextResult() {
  2426. if (_currentTask != null) {
  2427. throw SQL.PendingBeginXXXExists();
  2428. }
  2429. bool more;
  2430. bool result;
  2431. Debug.Assert(_stateObj == null || _stateObj._syncOverAsync, "Should not attempt pends in a synchronous call");
  2432. result = TryNextResult(out more);
  2433. if (!result) { throw SQL.SynchronousCallMayNotPend(); }
  2434. return more;
  2435. }
  2436. // recordset is automatically positioned on the first result set
  2437. private bool TryNextResult(out bool more) {
  2438. SqlStatistics statistics = null;
  2439. IntPtr hscp;
  2440. Bid.ScopeEnter(out hscp, "<sc.SqlDataReader.NextResult|API> %d#", ObjectID);
  2441. RuntimeHelpers.PrepareConstrainedRegions();
  2442. try {
  2443. #if DEBUG
  2444. TdsParser.ReliabilitySection tdsReliabilitySection = new TdsParser.ReliabilitySection();
  2445. RuntimeHelpers.PrepareConstrainedRegions();
  2446. try {
  2447. tdsReliabilitySection.Start();
  2448. #else
  2449. {
  2450. #endif //DEBUG
  2451. statistics = SqlStatistics.StartTimer(Statistics);
  2452. SetTimeout(_defaultTimeoutMilliseconds);
  2453. if (IsClosed) {
  2454. throw ADP.DataReaderClosed("NextResult");
  2455. }
  2456. _fieldNameLookup = null;
  2457. bool success = false; // WebData 100390
  2458. _hasRows = false; // reset HasRows
  2459. // if we are specifically only processing a single result, then read all the results off the wire and detach
  2460. if (IsCommandBehavior(CommandBehavior.SingleResult)) {
  2461. if (!TryCloseInternal(false /*closeReader*/)) {
  2462. more = false;
  2463. return false;
  2464. }
  2465. // In the case of not closing the reader, null out the metadata AFTER
  2466. // CloseInternal finishes - since CloseInternal may go to the wire
  2467. // and use the metadata.
  2468. ClearMetaData();
  2469. more = success;
  2470. return true;
  2471. }
  2472. if (null != _parser) {
  2473. // if there are more rows, then skip them, the user wants the next result
  2474. bool moreRows = true;
  2475. while (moreRows) {
  2476. if (!TryReadInternal(false, out moreRows)) { // don't reset set the timeout value
  2477. more = false;
  2478. return false;
  2479. }
  2480. }
  2481. }
  2482. // we may be done, so continue only if we have not detached ourselves from the parser
  2483. if (null != _parser) {
  2484. bool moreResults;
  2485. if (!TryHasMoreResults(out moreResults)) {
  2486. more = false;
  2487. return false;
  2488. }
  2489. if (moreResults) {
  2490. _metaDataConsumed = false;
  2491. _browseModeInfoConsumed = false;
  2492. switch (_altRowStatus) {
  2493. case ALTROWSTATUS.AltRow:
  2494. int altRowId;
  2495. if (!_parser.TryGetAltRowId(_stateObj, out altRowId)) {
  2496. more = false;
  2497. return false;
  2498. }
  2499. _SqlMetaDataSet altMetaDataSet = _altMetaDataSetCollection.GetAltMetaData(altRowId);
  2500. if (altMetaDataSet != null) {
  2501. _metaData = altMetaDataSet;
  2502. }
  2503. Debug.Assert ((_metaData != null), "Can't match up altrowmetadata");
  2504. break;
  2505. case ALTROWSTATUS.Done:
  2506. // restore the row-metaData
  2507. _metaData = _altMetaDataSetCollection.metaDataSet;
  2508. Debug.Assert (_altRowStatus == ALTROWSTATUS.Done, "invalid AltRowStatus");
  2509. _altRowStatus = ALTROWSTATUS.Null;
  2510. break;
  2511. default:
  2512. if (!TryConsumeMetaData()) {
  2513. more = false;
  2514. return false;
  2515. }
  2516. if (_metaData == null) {
  2517. more = false;
  2518. return true;
  2519. }
  2520. break;
  2521. }
  2522. success = true;
  2523. }
  2524. else {
  2525. // detach the parser from this reader now
  2526. if (!TryCloseInternal(false /*closeReader*/)) {
  2527. more = false;
  2528. return false;
  2529. }
  2530. // In the case of not closing the reader, null out the metadata AFTER
  2531. // CloseInternal finishes - since CloseInternal may go to the wire
  2532. // and use the metadata.
  2533. if (!TrySetMetaData(null, false)) {
  2534. more = false;
  2535. return false;
  2536. }
  2537. }
  2538. }
  2539. else {
  2540. // Clear state in case of Read calling CloseInternal() then user calls NextResult()
  2541. // MDAC 81986. Or, also the case where the Read() above will do essentially the same
  2542. // thing.
  2543. ClearMetaData();
  2544. }
  2545. more = success;
  2546. return true;
  2547. }
  2548. #if DEBUG
  2549. finally {
  2550. tdsReliabilitySection.Stop();
  2551. }
  2552. #endif //DEBUG
  2553. }
  2554. catch (System.OutOfMemoryException e) {
  2555. _isClosed = true;
  2556. if (null != _connection) {
  2557. _connection.Abort(e);
  2558. }
  2559. throw;
  2560. }
  2561. catch (System.StackOverflowException e) {
  2562. _isClosed = true;
  2563. if (null != _connection) {
  2564. _connection.Abort(e);
  2565. }
  2566. throw;
  2567. }
  2568. catch (System.Threading.ThreadAbortException e) {
  2569. _isClosed = true;
  2570. if (null != _connection) {
  2571. _connection.Abort(e);
  2572. }
  2573. throw;
  2574. }
  2575. finally {
  2576. SqlStatistics.StopTimer(statistics);
  2577. Bid.ScopeLeave(ref hscp);
  2578. }
  2579. }
  2580. // user must call Read() to position on the first row
  2581. override public bool Read() {
  2582. if (_currentTask != null) {
  2583. throw SQL.PendingBeginXXXExists();
  2584. }
  2585. bool more;
  2586. bool result;
  2587. Debug.Assert(_stateObj == null || _stateObj._syncOverAsync, "Should not attempt pends in a synchronous call");
  2588. result = TryReadInternal(true, out more);
  2589. if (!result) { throw SQL.SynchronousCallMayNotPend(); }
  2590. return more;
  2591. }
  2592. // user must call Read() to position on the first row
  2593. private bool TryReadInternal(bool setTimeout, out bool more) {
  2594. SqlStatistics statistics = null;
  2595. IntPtr hscp;
  2596. Bid.ScopeEnter(out hscp, "<sc.SqlDataReader.Read|API> %d#", ObjectID);
  2597. RuntimeHelpers.PrepareConstrainedRegions();
  2598. try {
  2599. #if DEBUG
  2600. TdsParser.ReliabilitySection tdsReliabilitySection = new TdsParser.ReliabilitySection();
  2601. RuntimeHelpers.PrepareConstrainedRegions();
  2602. try {
  2603. tdsReliabilitySection.Start();
  2604. #else
  2605. {
  2606. #endif //DEBUG
  2607. statistics = SqlStatistics.StartTimer(Statistics);
  2608. if (null != _parser) {
  2609. if (setTimeout) {
  2610. SetTimeout(_defaultTimeoutMilliseconds);
  2611. }
  2612. if (_sharedState._dataReady) {
  2613. if (!TryCleanPartialRead()) {
  2614. more = false;
  2615. return false;
  2616. }
  2617. }
  2618. // clear out our buffers
  2619. SqlBuffer.Clear(_data);
  2620. _sharedState._nextColumnHeaderToRead = 0;
  2621. _sharedState._nextColumnDataToRead = 0;
  2622. _sharedState._columnDataBytesRemaining = -1; // unknown
  2623. _lastColumnWithDataChunkRead = -1;
  2624. if (!_haltRead) {
  2625. bool moreRows;
  2626. if (!TryHasMoreRows(out moreRows)) {
  2627. more = false;
  2628. return false;
  2629. }
  2630. if (moreRows) {
  2631. // read the row from the backend (unless it's an altrow were the marker is already inside the altrow ...)
  2632. while (_stateObj._pendingData) {
  2633. if (_altRowStatus != ALTROWSTATUS.AltRow) {
  2634. // if this is an ordinary row we let the run method consume the ROW token
  2635. if (!_parser.TryRun(RunBehavior.ReturnImmediately, _command, this, null, _stateObj, out _sharedState._dataReady)) {
  2636. more = false;
  2637. return false;
  2638. }
  2639. if (_sharedState._dataReady) {
  2640. break;
  2641. }
  2642. }
  2643. else {
  2644. // ALTROW token and AltrowId are already consumed ...
  2645. Debug.Assert (_altRowStatus == ALTROWSTATUS.AltRow, "invalid AltRowStatus");
  2646. _altRowStatus = ALTROWSTATUS.Done;
  2647. _sharedState._dataReady = true;
  2648. break;
  2649. }
  2650. }
  2651. if (_sharedState._dataReady) {
  2652. _haltRead = IsCommandBehavior(CommandBehavior.SingleRow);
  2653. more = true;
  2654. return true;
  2655. }
  2656. }
  2657. if (!_stateObj._pendingData) {
  2658. if (!TryCloseInternal(false /*closeReader*/)) {
  2659. more = false;
  2660. return false;
  2661. }
  2662. }
  2663. }
  2664. else {
  2665. // if we did not get a row and halt is true, clean off rows of result
  2666. // success must be false - or else we could have just read off row and set
  2667. // halt to true
  2668. bool moreRows;
  2669. if (!TryHasMoreRows(out moreRows)) {
  2670. more = false;
  2671. return false;
  2672. }
  2673. while (moreRows) {
  2674. // if we are in SingleRow mode, and we've read the first row,
  2675. // read the rest of the rows, if any
  2676. while (_stateObj._pendingData && !_sharedState._dataReady) {
  2677. if (!_parser.TryRun(RunBehavior.ReturnImmediately, _command, this, null, _stateObj, out _sharedState._dataReady)) {
  2678. more = false;
  2679. return false;
  2680. }
  2681. }
  2682. if (_sharedState._dataReady) {
  2683. if (!TryCleanPartialRead()) {
  2684. more = false;
  2685. return false;
  2686. }
  2687. }
  2688. // clear out our buffers
  2689. SqlBuffer.Clear(_data);
  2690. _sharedState._nextColumnHeaderToRead = 0;
  2691. if (!TryHasMoreRows(out moreRows)) {
  2692. more = false;
  2693. return false;
  2694. }
  2695. }
  2696. // reset haltRead
  2697. _haltRead = false;
  2698. }
  2699. }
  2700. else if (IsClosed) {
  2701. throw ADP.DataReaderClosed("Read");
  2702. }
  2703. more = false;
  2704. #if DEBUG
  2705. if ((!_sharedState._dataReady) && (_stateObj._pendingData)) {
  2706. byte token;
  2707. if (!_stateObj.TryPeekByte(out token)) {
  2708. return false;
  2709. }
  2710. Debug.Assert(TdsParser.IsValidTdsToken(token), string.Format("DataReady is false, but next token is invalid: {0,-2:X2}", token));
  2711. }
  2712. #endif
  2713. return true;
  2714. }
  2715. #if DEBUG
  2716. finally {
  2717. tdsReliabilitySection.Stop();
  2718. }
  2719. #endif //DEBUG
  2720. }
  2721. catch (System.OutOfMemoryException e) {
  2722. _isClosed = true;
  2723. SqlConnection con = _connection;
  2724. if (con != null) {
  2725. con.Abort(e);
  2726. }
  2727. throw;
  2728. }
  2729. catch (System.StackOverflowException e) {
  2730. _isClosed = true;
  2731. SqlConnection con = _connection;
  2732. if (con != null) {
  2733. con.Abort(e);
  2734. }
  2735. throw;
  2736. }
  2737. catch (System.Threading.ThreadAbortException e) {
  2738. _isClosed = true;
  2739. SqlConnection con = _connection;
  2740. if (con != null) {
  2741. con.Abort(e);
  2742. }
  2743. throw;
  2744. }
  2745. finally {
  2746. SqlStatistics.StopTimer(statistics);
  2747. Bid.ScopeLeave(ref hscp);
  2748. }
  2749. }
  2750. private void ReadColumn(int i, bool setTimeout = true, bool allowPartiallyReadColumn = false) {
  2751. if (_currentTask != null) {
  2752. throw ADP.AsyncOperationPending();
  2753. }
  2754. Debug.Assert(_stateObj == null || _stateObj._syncOverAsync, "Should not attempt pends in a synchronous call");
  2755. bool result = TryReadColumn(i, setTimeout, allowPartiallyReadColumn);
  2756. if (!result) { throw SQL.SynchronousCallMayNotPend(); }
  2757. }
  2758. private bool TryReadColumn(int i, bool setTimeout, bool allowPartiallyReadColumn = false) {
  2759. CheckDataIsReady(columnIndex: i, permitAsync: true, allowPartiallyReadColumn: allowPartiallyReadColumn);
  2760. RuntimeHelpers.PrepareConstrainedRegions();
  2761. try {
  2762. #if DEBUG
  2763. TdsParser.ReliabilitySection tdsReliabilitySection = new TdsParser.ReliabilitySection();
  2764. RuntimeHelpers.PrepareConstrainedRegions();
  2765. try {
  2766. tdsReliabilitySection.Start();
  2767. #else
  2768. {
  2769. #endif //DEBUG
  2770. Debug.Assert(_sharedState._nextColumnHeaderToRead <= _metaData.Length, "_sharedState._nextColumnHeaderToRead too large");
  2771. Debug.Assert(_sharedState._nextColumnDataToRead <= _metaData.Length, "_sharedState._nextColumnDataToRead too large");
  2772. if (setTimeout) {
  2773. SetTimeout(_defaultTimeoutMilliseconds);
  2774. }
  2775. if (!TryReadColumnInternal(i, readHeaderOnly: false)) {
  2776. return false;
  2777. }
  2778. Debug.Assert(null != _data[i], " data buffer is null?");
  2779. }
  2780. #if DEBUG
  2781. finally {
  2782. tdsReliabilitySection.Stop();
  2783. }
  2784. #endif //DEBUG
  2785. }
  2786. catch (System.OutOfMemoryException e) {
  2787. _isClosed = true;
  2788. if (null != _connection) {
  2789. _connection.Abort(e);
  2790. }
  2791. throw;
  2792. }
  2793. catch (System.StackOverflowException e) {
  2794. _isClosed = true;
  2795. if (null != _connection) {
  2796. _connection.Abort(e);
  2797. }
  2798. throw;
  2799. }
  2800. catch (System.Threading.ThreadAbortException e) {
  2801. _isClosed = true;
  2802. if (null != _connection) {
  2803. _connection.Abort(e);
  2804. }
  2805. throw;
  2806. }
  2807. return true;
  2808. }
  2809. private bool TryReadColumnData() {
  2810. // If we've already read the value (because it was NULL) we don't
  2811. // bother to read here.
  2812. if (!_data[_sharedState._nextColumnDataToRead].IsNull) {
  2813. _SqlMetaData columnMetaData = _metaData[_sharedState._nextColumnDataToRead];
  2814. if (!_parser.TryReadSqlValue(_data[_sharedState._nextColumnDataToRead], columnMetaData, (int)_sharedState._columnDataBytesRemaining, _stateObj)) { // will read UDTs as VARBINARY.
  2815. return false;
  2816. }
  2817. _sharedState._columnDataBytesRemaining = 0;
  2818. }
  2819. _sharedState._nextColumnDataToRead++;
  2820. return true;
  2821. }
  2822. private void ReadColumnHeader(int i) {
  2823. Debug.Assert(_stateObj == null || _stateObj._syncOverAsync, "Should not attempt pends in a synchronous call");
  2824. bool result = TryReadColumnHeader(i);
  2825. if (!result) { throw SQL.SynchronousCallMayNotPend(); }
  2826. }
  2827. private bool TryReadColumnHeader(int i) {
  2828. if (!_sharedState._dataReady) {
  2829. throw SQL.InvalidRead();
  2830. }
  2831. RuntimeHelpers.PrepareConstrainedRegions();
  2832. try {
  2833. #if DEBUG
  2834. TdsParser.ReliabilitySection tdsReliabilitySection = new TdsParser.ReliabilitySection();
  2835. RuntimeHelpers.PrepareConstrainedRegions();
  2836. try {
  2837. tdsReliabilitySection.Start();
  2838. #endif //DEBUG
  2839. return TryReadColumnInternal(i, readHeaderOnly: true);
  2840. #if DEBUG
  2841. }
  2842. finally {
  2843. tdsReliabilitySection.Stop();
  2844. }
  2845. #endif //DEBUG
  2846. }
  2847. catch (System.OutOfMemoryException e) {
  2848. _isClosed = true;
  2849. if (null != _connection) {
  2850. _connection.Abort(e);
  2851. }
  2852. throw;
  2853. }
  2854. catch (System.StackOverflowException e) {
  2855. _isClosed = true;
  2856. if (null != _connection) {
  2857. _connection.Abort(e);
  2858. }
  2859. throw;
  2860. }
  2861. catch (System.Threading.ThreadAbortException e) {
  2862. _isClosed = true;
  2863. if (null != _connection) {
  2864. _connection.Abort(e);
  2865. }
  2866. throw;
  2867. }
  2868. }
  2869. private bool TryReadColumnInternal(int i, bool readHeaderOnly = false) {
  2870. AssertReaderState(requireData: true, permitAsync: true, columnIndex: i);
  2871. // Check if we've already read the header already
  2872. if (i < _sharedState._nextColumnHeaderToRead) {
  2873. // Read the header, but we need to read the data
  2874. if ((i == _sharedState._nextColumnDataToRead) && (!readHeaderOnly)) {
  2875. return TryReadColumnData();
  2876. }
  2877. // Else we've already read the data, or we're reading the header only
  2878. else {
  2879. // Ensure that, if we've read past the column, then we did store its data
  2880. Debug.Assert(i == _sharedState._nextColumnDataToRead || // Either we haven't read the column yet
  2881. ((i + 1 < _sharedState._nextColumnDataToRead) && (IsCommandBehavior(CommandBehavior.SequentialAccess))) || // Or we're in sequential mode and we've read way past the column (i.e. it was not the last column we read)
  2882. (!_data[i].IsEmpty || _data[i].IsNull) || // Or we should have data stored for the column (unless the column was null)
  2883. (_metaData[i].type == SqlDbType.Timestamp), // Or Dev11 Bug #336820, Dev10 Bug #479607 (SqlClient: IsDBNull always returns false for timestamp datatype)
  2884. // Due to a bug in TdsParser.GetNullSqlValue, Timestamps' IsNull is not correctly set - so we need to bypass the check
  2885. "Gone past column, be we have no data stored for it");
  2886. return true;
  2887. }
  2888. }
  2889. Debug.Assert(_data[i].IsEmpty || _data[i].IsNull, "re-reading column value?");
  2890. // If we're in sequential access mode, we can safely clear out any
  2891. // data from the previous column.
  2892. bool isSequentialAccess = IsCommandBehavior(CommandBehavior.SequentialAccess);
  2893. if (isSequentialAccess) {
  2894. if (0 < _sharedState._nextColumnDataToRead) {
  2895. _data[_sharedState._nextColumnDataToRead - 1].Clear();
  2896. }
  2897. // Only wipe out the blob objects if they aren't for a 'future' column (i.e. we haven't read up to them yet)
  2898. if ((_lastColumnWithDataChunkRead > -1) && (i > _lastColumnWithDataChunkRead)) {
  2899. CloseActiveSequentialStreamAndTextReader();
  2900. }
  2901. }
  2902. else if (_sharedState._nextColumnDataToRead < _sharedState._nextColumnHeaderToRead) {
  2903. // We read the header but not the column for the previous column
  2904. if (!TryReadColumnData()) {
  2905. return false;
  2906. }
  2907. Debug.Assert(_sharedState._nextColumnDataToRead == _sharedState._nextColumnHeaderToRead);
  2908. }
  2909. // if we still have bytes left from the previous blob read, clear the wire and reset
  2910. if (!TryResetBlobState()) {
  2911. return false;
  2912. }
  2913. do {
  2914. _SqlMetaData columnMetaData = _metaData[_sharedState._nextColumnHeaderToRead];
  2915. if ((isSequentialAccess) && (_sharedState._nextColumnHeaderToRead < i)) {
  2916. // SkipValue is no-op if the column appears in NBC bitmask
  2917. // if not, it skips regular and PLP types
  2918. if (!_parser.TrySkipValue(columnMetaData, _sharedState._nextColumnHeaderToRead, _stateObj)) {
  2919. return false;
  2920. }
  2921. _sharedState._nextColumnDataToRead = _sharedState._nextColumnHeaderToRead;
  2922. _sharedState._nextColumnHeaderToRead++;
  2923. }
  2924. else {
  2925. bool isNull;
  2926. ulong dataLength;
  2927. if (!_parser.TryProcessColumnHeader(columnMetaData, _stateObj, _sharedState._nextColumnHeaderToRead, out isNull, out dataLength)) {
  2928. return false;
  2929. }
  2930. _sharedState._nextColumnDataToRead = _sharedState._nextColumnHeaderToRead;
  2931. _sharedState._nextColumnHeaderToRead++; // We read this one
  2932. if (isNull && columnMetaData.type != SqlDbType.Timestamp /* Maintain behavior for known bug (Dev10 479607) rejected as breaking change - See comments in GetNullSqlValue for timestamp */)
  2933. {
  2934. _parser.GetNullSqlValue(_data[_sharedState._nextColumnDataToRead], columnMetaData);
  2935. if (!readHeaderOnly) {
  2936. _sharedState._nextColumnDataToRead++;
  2937. }
  2938. }
  2939. else {
  2940. if ((i > _sharedState._nextColumnDataToRead) || (!readHeaderOnly)) {
  2941. // If we're not in sequential access mode, we have to
  2942. // save the data we skip over so that the consumer
  2943. // can read it out of order
  2944. if (!_parser.TryReadSqlValue(_data[_sharedState._nextColumnDataToRead], columnMetaData, (int)dataLength, _stateObj)) { // will read UDTs as VARBINARY.
  2945. return false;
  2946. }
  2947. _sharedState._nextColumnDataToRead++;
  2948. }
  2949. else {
  2950. _sharedState._columnDataBytesRemaining = (long)dataLength;
  2951. }
  2952. }
  2953. }
  2954. if (_snapshot != null) {
  2955. // reset snapshot to save memory use. We can safely do that here because all SqlDataReader values are stable.
  2956. // The retry logic can use the current values to get back to the right state.
  2957. _snapshot = null;
  2958. PrepareAsyncInvocation(useSnapshot: true);
  2959. }
  2960. } while (_sharedState._nextColumnHeaderToRead <= i);
  2961. return true;
  2962. }
  2963. // Estimates if there is enough data available to read the number of columns requested
  2964. private bool WillHaveEnoughData(int targetColumn, bool headerOnly = false) {
  2965. AssertReaderState(requireData: true, permitAsync: true, columnIndex: targetColumn);
  2966. if ((_lastColumnWithDataChunkRead == _sharedState._nextColumnDataToRead) && (_metaData[_lastColumnWithDataChunkRead].metaType.IsPlp)) {
  2967. // In the middle of reading a Plp - no idea how much is left
  2968. return false;
  2969. }
  2970. int bytesRemaining = Math.Min(checked(_stateObj._inBytesRead - _stateObj._inBytesUsed), _stateObj._inBytesPacket);
  2971. // There are some parts of our code that peeks at the next token after doing its read
  2972. // So we will make sure that there is always a spare byte for it to look at
  2973. bytesRemaining--;
  2974. if ((targetColumn >= _sharedState._nextColumnDataToRead) && (_sharedState._nextColumnDataToRead < _sharedState._nextColumnHeaderToRead)) {
  2975. if (_sharedState._columnDataBytesRemaining > bytesRemaining) {
  2976. // The current column needs more data than we currently have
  2977. // NOTE: Since the Long data types (TEXT, IMAGE, NTEXT) can have a size of Int32.MaxValue we cannot simply subtract
  2978. // _columnDataBytesRemaining from bytesRemaining and then compare it to zero as this may lead to an overflow
  2979. return false;
  2980. }
  2981. else {
  2982. // Already read the header, so subtract actual data size
  2983. bytesRemaining = checked(bytesRemaining - (int)_sharedState._columnDataBytesRemaining);
  2984. }
  2985. }
  2986. // For each column that we need to read, subtract the size of its header and the size of its data
  2987. int currentColumn = _sharedState._nextColumnHeaderToRead;
  2988. while ((bytesRemaining >= 0) && (currentColumn <= targetColumn)) {
  2989. // Check NBC first
  2990. if (!_stateObj.IsNullCompressionBitSet(currentColumn)) {
  2991. // NOTE: This is mostly duplicated from TryProcessColumnHeaderNoNBC and TryGetTokenLength
  2992. var metaType = _metaData[currentColumn].metaType;
  2993. if ((metaType.IsLong) || (metaType.IsPlp) || (metaType.SqlDbType == SqlDbType.Udt) || (metaType.SqlDbType == SqlDbType.Structured)) {
  2994. // Plp, Udt and TVP types have an unknownable size - so return that the estimate failed
  2995. return false;
  2996. }
  2997. int maxHeaderSize;
  2998. byte typeAndMask = (byte)(_metaData[currentColumn].tdsType & TdsEnums.SQLLenMask);
  2999. if ((typeAndMask == TdsEnums.SQLVarLen) || (typeAndMask == TdsEnums.SQLVarCnt)) {
  3000. if (0 != (_metaData[currentColumn].tdsType & 0x80)) {
  3001. // UInt16 represents size
  3002. maxHeaderSize = 2;
  3003. }
  3004. else if (0 == (_metaData[currentColumn].tdsType & 0x0c)) {
  3005. // UInt32 represents size
  3006. maxHeaderSize = 4;
  3007. }
  3008. else {
  3009. // Byte represents size
  3010. maxHeaderSize = 1;
  3011. }
  3012. }
  3013. else
  3014. {
  3015. maxHeaderSize = 0;
  3016. }
  3017. bytesRemaining = checked(bytesRemaining - maxHeaderSize);
  3018. if ((currentColumn < targetColumn) || (!headerOnly)) {
  3019. bytesRemaining = checked(bytesRemaining - _metaData[currentColumn].length);
  3020. }
  3021. }
  3022. currentColumn++;
  3023. }
  3024. return (bytesRemaining >= 0);
  3025. }
  3026. // clean remainder bytes for the column off the wire
  3027. private bool TryResetBlobState() {
  3028. Debug.Assert(null != _stateObj, "null state object"); // _parser may be null at this point
  3029. AssertReaderState(requireData: true, permitAsync: true);
  3030. Debug.Assert(_sharedState._nextColumnHeaderToRead <= _metaData.Length, "_sharedState._nextColumnHeaderToRead too large");
  3031. // If we haven't already entirely read the column
  3032. if (_sharedState._nextColumnDataToRead < _sharedState._nextColumnHeaderToRead) {
  3033. if ((_sharedState._nextColumnHeaderToRead > 0) && (_metaData[_sharedState._nextColumnHeaderToRead - 1].metaType.IsPlp)) {
  3034. if (_stateObj._longlen != 0) {
  3035. ulong ignored;
  3036. if (!_stateObj.Parser.TrySkipPlpValue(UInt64.MaxValue, _stateObj, out ignored)) {
  3037. return false;
  3038. }
  3039. }
  3040. if (_streamingXml != null) {
  3041. SqlStreamingXml localSXml = _streamingXml;
  3042. _streamingXml = null;
  3043. localSXml.Close();
  3044. }
  3045. }
  3046. else if (0 < _sharedState._columnDataBytesRemaining) {
  3047. if (!_stateObj.TrySkipLongBytes(_sharedState._columnDataBytesRemaining)) {
  3048. return false;
  3049. }
  3050. }
  3051. }
  3052. #if DEBUG
  3053. else {
  3054. Debug.Assert((_sharedState._columnDataBytesRemaining == 0 || _sharedState._columnDataBytesRemaining == -1) && _stateObj._longlen == 0, "Haven't read header yet, but column is partially read?");
  3055. }
  3056. #endif
  3057. _sharedState._columnDataBytesRemaining = 0;
  3058. _columnDataBytesRead = 0;
  3059. _columnDataCharsRead = 0;
  3060. _columnDataChars = null;
  3061. _columnDataCharsIndex = -1;
  3062. _stateObj._plpdecoder = null;
  3063. return true;
  3064. }
  3065. private void CloseActiveSequentialStreamAndTextReader() {
  3066. if (_currentStream != null) {
  3067. _currentStream.SetClosed();
  3068. _currentStream = null;
  3069. }
  3070. if (_currentTextReader != null) {
  3071. _currentTextReader.SetClosed();
  3072. _currentStream = null;
  3073. }
  3074. }
  3075. private void RestoreServerSettings(TdsParser parser, TdsParserStateObject stateObj) {
  3076. // turn off any set options
  3077. if (null != parser && null != _resetOptionsString) {
  3078. // It is possible for this to be called during connection close on a
  3079. // broken connection, so check state first.
  3080. if (parser.State == TdsParserState.OpenLoggedIn) {
  3081. Bid.CorrelationTrace("<sc.SqlDataReader.RestoreServerSettings|Info|Correlation> ObjectID%d#, ActivityID %ls\n", ObjectID);
  3082. Task executeTask = parser.TdsExecuteSQLBatch(_resetOptionsString, (_command != null) ? _command.CommandTimeout : 0, null, stateObj, sync: true);
  3083. Debug.Assert(executeTask == null, "Shouldn't get a task when doing sync writes");
  3084. // must execute this one synchronously as we can't retry
  3085. parser.Run(RunBehavior.UntilDone, _command, this, null, stateObj);
  3086. }
  3087. _resetOptionsString = null;
  3088. }
  3089. }
  3090. internal bool TrySetAltMetaDataSet(_SqlMetaDataSet metaDataSet, bool metaDataConsumed) {
  3091. if (_altMetaDataSetCollection == null) {
  3092. _altMetaDataSetCollection = new _SqlMetaDataSetCollection();
  3093. }
  3094. else if (_snapshot != null && object.ReferenceEquals(_snapshot._altMetaDataSetCollection, _altMetaDataSetCollection)) {
  3095. _altMetaDataSetCollection = (_SqlMetaDataSetCollection)_altMetaDataSetCollection.Clone();
  3096. }
  3097. _altMetaDataSetCollection.SetAltMetaData(metaDataSet);
  3098. _metaDataConsumed = metaDataConsumed;
  3099. if (_metaDataConsumed && null != _parser) {
  3100. byte b;
  3101. if (!_stateObj.TryPeekByte(out b)) {
  3102. return false;
  3103. }
  3104. if (TdsEnums.SQLORDER == b) {
  3105. bool ignored;
  3106. if (!_parser.TryRun(RunBehavior.ReturnImmediately, _command, this, null, _stateObj, out ignored)) {
  3107. return false;
  3108. }
  3109. if (!_stateObj.TryPeekByte(out b)) {
  3110. return false;
  3111. }
  3112. }
  3113. if (b == TdsEnums.SQLINFO) {
  3114. try {
  3115. _stateObj._accumulateInfoEvents = true;
  3116. bool ignored;
  3117. if (!_parser.TryRun(RunBehavior.ReturnImmediately, _command, null, null, _stateObj, out ignored)) {
  3118. return false;
  3119. }
  3120. }
  3121. finally {
  3122. _stateObj._accumulateInfoEvents = false;
  3123. }
  3124. if (!_stateObj.TryPeekByte(out b)) {
  3125. return false;
  3126. }
  3127. }
  3128. _hasRows = IsRowToken(b);
  3129. }
  3130. if (metaDataSet != null) {
  3131. if (_data == null || _data.Length<metaDataSet.Length) {
  3132. _data = SqlBuffer.CreateBufferArray(metaDataSet.Length);
  3133. }
  3134. }
  3135. return true;
  3136. }
  3137. private void ClearMetaData() {
  3138. _metaData = null;
  3139. _tableNames = null;
  3140. _fieldNameLookup = null;
  3141. _metaDataConsumed = false;
  3142. _browseModeInfoConsumed = false;
  3143. }
  3144. internal bool TrySetMetaData(_SqlMetaDataSet metaData, bool moreInfo) {
  3145. _metaData = metaData;
  3146. // get rid of cached metadata info as well
  3147. _tableNames = null;
  3148. if (_metaData != null) {
  3149. _metaData.schemaTable = null;
  3150. _data = SqlBuffer.CreateBufferArray(metaData.Length);
  3151. }
  3152. _fieldNameLookup = null;
  3153. if (null != metaData) {
  3154. // we are done consuming metadata only if there is no moreInfo
  3155. if (!moreInfo) {
  3156. _metaDataConsumed = true;
  3157. if (_parser != null) { // There is a valid case where parser is null
  3158. // Peek, and if row token present, set _hasRows true since there is a
  3159. // row in the result
  3160. byte b;
  3161. if (!_stateObj.TryPeekByte(out b)) {
  3162. return false;
  3163. }
  3164. //
  3165. // simply rip the order token off the wire
  3166. if (b == TdsEnums.SQLORDER) { // same logic as SetAltMetaDataSet
  3167. // Devnote: That's not the right place to process TDS
  3168. // Can this result in Reentrance to Run?
  3169. //
  3170. bool ignored;
  3171. if (!_parser.TryRun(RunBehavior.ReturnImmediately, null, null, null, _stateObj, out ignored)) {
  3172. return false;
  3173. }
  3174. if (!_stateObj.TryPeekByte(out b)) {
  3175. return false;
  3176. }
  3177. }
  3178. if (b == TdsEnums.SQLINFO)
  3179. {
  3180. // VSTFDEVDIV713926
  3181. // We are accumulating informational events and fire them at next
  3182. // TdsParser.Run purely to avoid breaking change
  3183. try {
  3184. _stateObj._accumulateInfoEvents = true;
  3185. bool ignored;
  3186. if (!_parser.TryRun(RunBehavior.ReturnImmediately, null, null, null, _stateObj, out ignored)) {
  3187. return false;
  3188. }
  3189. }
  3190. finally {
  3191. _stateObj._accumulateInfoEvents = false;
  3192. }
  3193. if (!_stateObj.TryPeekByte(out b)) {
  3194. return false;
  3195. }
  3196. }
  3197. _hasRows = IsRowToken(b);
  3198. if (TdsEnums.SQLALTMETADATA == b)
  3199. {
  3200. _metaDataConsumed = false;
  3201. }
  3202. }
  3203. }
  3204. }
  3205. else {
  3206. _metaDataConsumed = false;
  3207. }
  3208. _browseModeInfoConsumed = false;
  3209. return true;
  3210. }
  3211. private void SetTimeout(long timeoutMilliseconds) {
  3212. // WebData 111653,112003 -- we now set timeouts per operation, not
  3213. // per command (it's not supposed to be a cumulative per command).
  3214. TdsParserStateObject stateObj = _stateObj;
  3215. if (null != stateObj) {
  3216. stateObj.SetTimeoutMilliseconds(timeoutMilliseconds);
  3217. }
  3218. }
  3219. private bool HasActiveStreamOrTextReaderOnColumn(int columnIndex) {
  3220. bool active = false;
  3221. active |= ((_currentStream != null) && (_currentStream.ColumnIndex == columnIndex));
  3222. active |= ((_currentTextReader != null) && (_currentTextReader.ColumnIndex == columnIndex));
  3223. return active;
  3224. }
  3225. private void CheckMetaDataIsReady() {
  3226. if (_currentTask != null) {
  3227. throw ADP.AsyncOperationPending();
  3228. }
  3229. if (MetaData == null) {
  3230. throw SQL.InvalidRead();
  3231. }
  3232. }
  3233. private void CheckMetaDataIsReady(int columnIndex, bool permitAsync = false) {
  3234. if ((!permitAsync) && (_currentTask != null)) {
  3235. throw ADP.AsyncOperationPending();
  3236. }
  3237. if (MetaData == null) {
  3238. throw SQL.InvalidRead();
  3239. }
  3240. if ((columnIndex < 0) || (columnIndex >= _metaData.Length)) {
  3241. throw ADP.IndexOutOfRange();
  3242. }
  3243. }
  3244. private void CheckDataIsReady() {
  3245. if (_currentTask != null) {
  3246. throw ADP.AsyncOperationPending();
  3247. }
  3248. Debug.Assert(!_sharedState._dataReady || _metaData != null, "Data is ready, but there is no metadata?");
  3249. if ((!_sharedState._dataReady) || (_metaData == null)) {
  3250. throw SQL.InvalidRead();
  3251. }
  3252. }
  3253. private void CheckHeaderIsReady(int columnIndex, bool permitAsync = false, string methodName = null) {
  3254. if (_isClosed) {
  3255. throw ADP.DataReaderClosed(methodName ?? "CheckHeaderIsReady");
  3256. }
  3257. if ((!permitAsync) && (_currentTask != null)) {
  3258. throw ADP.AsyncOperationPending();
  3259. }
  3260. Debug.Assert(!_sharedState._dataReady || _metaData != null, "Data is ready, but there is no metadata?");
  3261. if ((!_sharedState._dataReady) || (_metaData == null)) {
  3262. throw SQL.InvalidRead();
  3263. }
  3264. if ((columnIndex < 0) || (columnIndex >= _metaData.Length)) {
  3265. throw ADP.IndexOutOfRange();
  3266. }
  3267. if ((IsCommandBehavior(CommandBehavior.SequentialAccess)) && // Only for sequential access
  3268. ((_sharedState._nextColumnHeaderToRead > columnIndex + 1) || (_lastColumnWithDataChunkRead > columnIndex))) { // Read past column
  3269. throw ADP.NonSequentialColumnAccess(columnIndex, Math.Max(_sharedState._nextColumnHeaderToRead - 1, _lastColumnWithDataChunkRead));
  3270. }
  3271. }
  3272. private void CheckDataIsReady(int columnIndex, bool allowPartiallyReadColumn = false, bool permitAsync = false, string methodName = null) {
  3273. if (_isClosed) {
  3274. throw ADP.DataReaderClosed(methodName ?? "CheckDataIsReady");
  3275. }
  3276. if ((!permitAsync) && (_currentTask != null)) {
  3277. throw ADP.AsyncOperationPending();
  3278. }
  3279. Debug.Assert(!_sharedState._dataReady || _metaData != null, "Data is ready, but there is no metadata?");
  3280. if ((!_sharedState._dataReady) || (_metaData == null)) {
  3281. throw SQL.InvalidRead();
  3282. }
  3283. if ((columnIndex < 0) || (columnIndex >= _metaData.Length)) {
  3284. throw ADP.IndexOutOfRange();
  3285. }
  3286. if ((IsCommandBehavior(CommandBehavior.SequentialAccess)) && // Only for sequential access
  3287. ((_sharedState._nextColumnDataToRead > columnIndex) || (_lastColumnWithDataChunkRead > columnIndex) || // Read past column
  3288. ((!allowPartiallyReadColumn) && (_lastColumnWithDataChunkRead == columnIndex)) || // Partially read column
  3289. ((allowPartiallyReadColumn) && (HasActiveStreamOrTextReaderOnColumn(columnIndex))))) { // Has a Stream or TextReader on a partially-read column
  3290. throw ADP.NonSequentialColumnAccess(columnIndex, Math.Max(_sharedState._nextColumnDataToRead, _lastColumnWithDataChunkRead + 1));
  3291. }
  3292. }
  3293. [Conditional("DEBUG")]
  3294. private void AssertReaderState(bool requireData, bool permitAsync, int? columnIndex = null, bool enforceSequentialAccess = false) {
  3295. Debug.Assert(!_sharedState._dataReady || _metaData != null, "Data is ready, but there is no metadata?");
  3296. Debug.Assert(permitAsync || _currentTask == null, "Call while async operation is pending");
  3297. Debug.Assert(_metaData != null, "_metaData is null, check MetaData before calling this method");
  3298. Debug.Assert(!requireData || _sharedState._dataReady, "No data is ready to be read");
  3299. if (columnIndex.HasValue) {
  3300. Debug.Assert(columnIndex.Value >= 0 && columnIndex.Value < _metaData.Length, "Invalid column index");
  3301. Debug.Assert((!enforceSequentialAccess) || (!IsCommandBehavior(CommandBehavior.SequentialAccess)) || ((_sharedState._nextColumnDataToRead <= columnIndex) && (_lastColumnWithDataChunkRead <= columnIndex)), "Already read past column");
  3302. }
  3303. }
  3304. public override Task<bool> NextResultAsync(CancellationToken cancellationToken) {
  3305. IntPtr hscp;
  3306. Bid.ScopeEnter(out hscp, "<sc.SqlDataReader.NextResultAsync|API> %d#", ObjectID);
  3307. try {
  3308. TaskCompletionSource<bool> source = new TaskCompletionSource<bool>();
  3309. if (IsClosed) {
  3310. source.SetException(ADP.ExceptionWithStackTrace(ADP.DataReaderClosed("NextResultAsync")));
  3311. return source.Task;
  3312. }
  3313. IDisposable registration = null;
  3314. if (cancellationToken.CanBeCanceled) {
  3315. if (cancellationToken.IsCancellationRequested) {
  3316. source.SetCanceled();
  3317. return source.Task;
  3318. }
  3319. registration = cancellationToken.Register(_command.CancelIgnoreFailure);
  3320. }
  3321. Task original = Interlocked.CompareExchange(ref _currentTask, source.Task, null);
  3322. if (original != null) {
  3323. source.SetException(ADP.ExceptionWithStackTrace(SQL.PendingBeginXXXExists()));
  3324. return source.Task;
  3325. }
  3326. // Check if cancellation due to close is requested (this needs to be done after setting _currentTask)
  3327. if (_cancelAsyncOnCloseToken.IsCancellationRequested) {
  3328. source.SetCanceled();
  3329. _currentTask = null;
  3330. return source.Task;
  3331. }
  3332. PrepareAsyncInvocation(useSnapshot: true);
  3333. Func<Task, Task<bool>> moreFunc = null;
  3334. moreFunc = (t) => {
  3335. if (t != null) {
  3336. Bid.Trace("<sc.SqlDataReader.NextResultAsync> attempt retry %d#\n", ObjectID);
  3337. PrepareForAsyncContinuation();
  3338. }
  3339. bool more;
  3340. if (TryNextResult(out more)) {
  3341. // completed
  3342. return more ? ADP.TrueTask : ADP.FalseTask;
  3343. }
  3344. return ContinueRetryable(moreFunc);
  3345. };
  3346. return InvokeRetryable(moreFunc, source, registration);
  3347. }
  3348. finally {
  3349. Bid.ScopeLeave(ref hscp);
  3350. }
  3351. }
  3352. // NOTE: This will return null if it completed sequentially
  3353. // If this returns null, then you can use bytesRead to see how many bytes were read - otherwise bytesRead should be ignored
  3354. internal Task<int> GetBytesAsync(int i, byte[] buffer, int index, int length, int timeout, CancellationToken cancellationToken, out int bytesRead) {
  3355. AssertReaderState(requireData: true, permitAsync: true, columnIndex: i, enforceSequentialAccess: true);
  3356. Debug.Assert(IsCommandBehavior(CommandBehavior.SequentialAccess));
  3357. bytesRead = 0;
  3358. if (IsClosed) {
  3359. TaskCompletionSource<int> source = new TaskCompletionSource<int>();
  3360. source.SetException(ADP.ExceptionWithStackTrace(ADP.DataReaderClosed("GetBytesAsync")));
  3361. return source.Task;
  3362. }
  3363. if (_currentTask != null) {
  3364. TaskCompletionSource<int> source = new TaskCompletionSource<int>();
  3365. source.SetException(ADP.ExceptionWithStackTrace(ADP.AsyncOperationPending()));
  3366. return source.Task;
  3367. }
  3368. if (cancellationToken.CanBeCanceled) {
  3369. if (cancellationToken.IsCancellationRequested) {
  3370. return null;
  3371. }
  3372. }
  3373. // Check if we need to skip columns
  3374. Debug.Assert(_sharedState._nextColumnDataToRead <= _lastColumnWithDataChunkRead, "Non sequential access");
  3375. if ((_sharedState._nextColumnHeaderToRead <= _lastColumnWithDataChunkRead) || (_sharedState._nextColumnDataToRead < _lastColumnWithDataChunkRead)) {
  3376. TaskCompletionSource<int> source = new TaskCompletionSource<int>();
  3377. Task original = Interlocked.CompareExchange(ref _currentTask, source.Task, null);
  3378. if (original != null) {
  3379. source.SetException(ADP.ExceptionWithStackTrace(ADP.AsyncOperationPending()));
  3380. return source.Task;
  3381. }
  3382. PrepareAsyncInvocation(useSnapshot: true);
  3383. Func<Task, Task<int>> moreFunc = null;
  3384. // Timeout
  3385. CancellationToken timeoutToken = CancellationToken.None;
  3386. CancellationTokenSource timeoutCancellationSource = null;
  3387. if (timeout > 0) {
  3388. timeoutCancellationSource = new CancellationTokenSource();
  3389. timeoutCancellationSource.CancelAfter(timeout);
  3390. timeoutToken = timeoutCancellationSource.Token;
  3391. }
  3392. moreFunc = (t) => {
  3393. if (t != null) {
  3394. Bid.Trace("<sc.SqlDataReader.GetBytesAsync> attempt retry %d#\n", ObjectID);
  3395. PrepareForAsyncContinuation();
  3396. }
  3397. // Prepare for stateObj timeout
  3398. SetTimeout(_defaultTimeoutMilliseconds);
  3399. if (TryReadColumnHeader(i)) {
  3400. // Only once we have read upto where we need to be can we check the cancellation tokens (otherwise we will be in an unknown state)
  3401. if (cancellationToken.IsCancellationRequested) {
  3402. // User requested cancellation
  3403. return ADP.CreatedTaskWithCancellation<int>();
  3404. }
  3405. else if (timeoutToken.IsCancellationRequested) {
  3406. // Timeout
  3407. return ADP.CreatedTaskWithException<int>(ADP.ExceptionWithStackTrace(ADP.IO(SQLMessage.Timeout())));
  3408. }
  3409. else {
  3410. // Upto the correct column - continue to read
  3411. SwitchToAsyncWithoutSnapshot();
  3412. int totalBytesRead;
  3413. var readTask = GetBytesAsyncReadDataStage(i, buffer, index, length, timeout, true, cancellationToken, timeoutToken, out totalBytesRead);
  3414. if (readTask == null) {
  3415. // Completed synchronously
  3416. return Task.FromResult<int>(totalBytesRead);
  3417. }
  3418. else {
  3419. return readTask;
  3420. }
  3421. }
  3422. }
  3423. else {
  3424. return ContinueRetryable(moreFunc);
  3425. }
  3426. };
  3427. return InvokeRetryable(moreFunc, source, timeoutCancellationSource);
  3428. }
  3429. else {
  3430. // We're already at the correct column, just read the data
  3431. // Switch to async
  3432. PrepareAsyncInvocation(useSnapshot: false);
  3433. try {
  3434. return GetBytesAsyncReadDataStage(i, buffer, index, length, timeout, false, cancellationToken, CancellationToken.None, out bytesRead);
  3435. }
  3436. catch {
  3437. CleanupAfterAsyncInvocation();
  3438. throw;
  3439. }
  3440. }
  3441. }
  3442. private Task<int> GetBytesAsyncReadDataStage(int i, byte[] buffer, int index, int length, int timeout, bool isContinuation, CancellationToken cancellationToken, CancellationToken timeoutToken, out int bytesRead) {
  3443. _lastColumnWithDataChunkRead = i;
  3444. TaskCompletionSource<int> source = null;
  3445. CancellationTokenSource timeoutCancellationSource = null;
  3446. // Prepare for stateObj timeout
  3447. SetTimeout(_defaultTimeoutMilliseconds);
  3448. // Try to read without any continuations (all the data may already be in the stateObj's buffer)
  3449. if (!TryGetBytesInternalSequential(i, buffer, index, length, out bytesRead)) {
  3450. // This will be the 'state' for the callback
  3451. int totalBytesRead = bytesRead;
  3452. if (!isContinuation) {
  3453. // This is the first async operation which is happening - setup the _currentTask and timeout
  3454. source = new TaskCompletionSource<int>();
  3455. Task original = Interlocked.CompareExchange(ref _currentTask, source.Task, null);
  3456. if (original != null) {
  3457. source.SetException(ADP.ExceptionWithStackTrace(ADP.AsyncOperationPending()));
  3458. return source.Task;
  3459. }
  3460. // Check if cancellation due to close is requested (this needs to be done after setting _currentTask)
  3461. if (_cancelAsyncOnCloseToken.IsCancellationRequested) {
  3462. source.SetCanceled();
  3463. _currentTask = null;
  3464. return source.Task;
  3465. }
  3466. // Timeout
  3467. Debug.Assert(timeoutToken == CancellationToken.None, "TimeoutToken is set when GetBytesAsyncReadDataStage is not a continuation");
  3468. if (timeout > 0) {
  3469. timeoutCancellationSource = new CancellationTokenSource();
  3470. timeoutCancellationSource.CancelAfter(timeout);
  3471. timeoutToken = timeoutCancellationSource.Token;
  3472. }
  3473. }
  3474. Func<Task, Task<int>> moreFunc = null;
  3475. moreFunc = (_ => {
  3476. PrepareForAsyncContinuation();
  3477. if (cancellationToken.IsCancellationRequested) {
  3478. // User requested cancellation
  3479. return ADP.CreatedTaskWithCancellation<int>();
  3480. }
  3481. else if (timeoutToken.IsCancellationRequested) {
  3482. // Timeout
  3483. return ADP.CreatedTaskWithException<int>(ADP.ExceptionWithStackTrace(ADP.IO(SQLMessage.Timeout())));
  3484. }
  3485. else {
  3486. // Prepare for stateObj timeout
  3487. SetTimeout(_defaultTimeoutMilliseconds);
  3488. int bytesReadThisIteration;
  3489. bool result = TryGetBytesInternalSequential(i, buffer, index + totalBytesRead, length - totalBytesRead, out bytesReadThisIteration);
  3490. totalBytesRead += bytesReadThisIteration;
  3491. Debug.Assert(totalBytesRead <= length, "Read more bytes than required");
  3492. if (result) {
  3493. return Task.FromResult<int>(totalBytesRead);
  3494. }
  3495. else {
  3496. return ContinueRetryable(moreFunc);
  3497. }
  3498. }
  3499. });
  3500. Task<int> retryTask = ContinueRetryable(moreFunc);
  3501. if (isContinuation) {
  3502. // Let the caller handle cleanup\completing
  3503. return retryTask;
  3504. }
  3505. else {
  3506. // setup for cleanup\completing
  3507. retryTask.ContinueWith((t) => CompleteRetryable(t, source, timeoutCancellationSource), TaskScheduler.Default);
  3508. return source.Task;
  3509. }
  3510. }
  3511. if (!isContinuation) {
  3512. // If this is the first async op, we need to cleanup
  3513. CleanupAfterAsyncInvocation();
  3514. }
  3515. // Completed synchronously, return null
  3516. return null;
  3517. }
  3518. public override Task<bool> ReadAsync(CancellationToken cancellationToken) {
  3519. IntPtr hscp;
  3520. Bid.ScopeEnter(out hscp, "<sc.SqlDataReader.ReadAsync|API> %d#", ObjectID);
  3521. try {
  3522. if (IsClosed) {
  3523. return ADP.CreatedTaskWithException<bool>(ADP.ExceptionWithStackTrace(ADP.DataReaderClosed("ReadAsync")));
  3524. }
  3525. // If user's token is canceled, return a canceled task
  3526. if (cancellationToken.IsCancellationRequested) {
  3527. return ADP.CreatedTaskWithCancellation<bool>();
  3528. }
  3529. // Check for existing async
  3530. if (_currentTask != null) {
  3531. return ADP.CreatedTaskWithException<bool>(ADP.ExceptionWithStackTrace(SQL.PendingBeginXXXExists()));
  3532. }
  3533. // These variables will be captured in moreFunc so that we can skip searching for a row token once one has been read
  3534. bool rowTokenRead = false;
  3535. bool more = false;
  3536. // Shortcut, do we have enough data to immediately do the ReadAsync?
  3537. try {
  3538. // First, check if we can finish reading the current row
  3539. // NOTE: If we are in SingleRow mode and we've read that single row (i.e. _haltRead == true), then skip the shortcut
  3540. if ((!_haltRead) && ((!_sharedState._dataReady) || (WillHaveEnoughData(_metaData.Length - 1)))) {
  3541. #if DEBUG
  3542. try {
  3543. _stateObj._shouldHaveEnoughData = true;
  3544. #endif
  3545. if (_sharedState._dataReady) {
  3546. // Clean off current row
  3547. CleanPartialReadReliable();
  3548. }
  3549. // If there a ROW token ready (as well as any metadata for the row)
  3550. if (_stateObj.IsRowTokenReady()) {
  3551. // Read the ROW token
  3552. bool result = TryReadInternal(true, out more);
  3553. Debug.Assert(result, "Should not have run out of data");
  3554. rowTokenRead = true;
  3555. if (more) {
  3556. // Sequential mode, nothing left to do
  3557. if (IsCommandBehavior(CommandBehavior.SequentialAccess)) {
  3558. return ADP.TrueTask;
  3559. }
  3560. // For non-sequential, check if we can read the row data now
  3561. else if (WillHaveEnoughData(_metaData.Length - 1)) {
  3562. // Read row data
  3563. result = TryReadColumn(_metaData.Length - 1, setTimeout: true);
  3564. Debug.Assert(result, "Should not have run out of data");
  3565. return ADP.TrueTask;
  3566. }
  3567. }
  3568. else {
  3569. // No data left, return
  3570. return ADP.FalseTask;
  3571. }
  3572. }
  3573. #if DEBUG
  3574. }
  3575. finally {
  3576. _stateObj._shouldHaveEnoughData = false;
  3577. }
  3578. #endif
  3579. }
  3580. }
  3581. catch (Exception ex) {
  3582. if (!ADP.IsCatchableExceptionType(ex)) {
  3583. throw;
  3584. }
  3585. return ADP.CreatedTaskWithException<bool>(ex);
  3586. }
  3587. TaskCompletionSource<bool> source = new TaskCompletionSource<bool>();
  3588. Task original = Interlocked.CompareExchange(ref _currentTask, source.Task, null);
  3589. if (original != null) {
  3590. source.SetException(ADP.ExceptionWithStackTrace(SQL.PendingBeginXXXExists()));
  3591. return source.Task;
  3592. }
  3593. // Check if cancellation due to close is requested (this needs to be done after setting _currentTask)
  3594. if (_cancelAsyncOnCloseToken.IsCancellationRequested) {
  3595. source.SetCanceled();
  3596. _currentTask = null;
  3597. return source.Task;
  3598. }
  3599. IDisposable registration = null;
  3600. if (cancellationToken.CanBeCanceled) {
  3601. registration = cancellationToken.Register(_command.CancelIgnoreFailure);
  3602. }
  3603. PrepareAsyncInvocation(useSnapshot: true);
  3604. Func<Task, Task<bool>> moreFunc = null;
  3605. moreFunc = (t) => {
  3606. if (t != null) {
  3607. Bid.Trace("<sc.SqlDataReader.ReadAsync> attempt retry %d#\n", ObjectID);
  3608. PrepareForAsyncContinuation();
  3609. }
  3610. if (rowTokenRead || TryReadInternal(true, out more)) {
  3611. // If there are no more rows, or this is Sequential Access, then we are done
  3612. if (!more || (_commandBehavior & CommandBehavior.SequentialAccess) == CommandBehavior.SequentialAccess) {
  3613. // completed
  3614. return more ? ADP.TrueTask : ADP.FalseTask;
  3615. }
  3616. else {
  3617. // First time reading the row token - update the snapshot
  3618. if (!rowTokenRead) {
  3619. rowTokenRead = true;
  3620. _snapshot = null;
  3621. PrepareAsyncInvocation(useSnapshot: true);
  3622. }
  3623. // if non-sequentialaccess then read entire row before returning
  3624. if (TryReadColumn(_metaData.Length - 1, true)) {
  3625. // completed
  3626. return ADP.TrueTask;
  3627. }
  3628. }
  3629. }
  3630. return ContinueRetryable(moreFunc);
  3631. };
  3632. return InvokeRetryable(moreFunc, source, registration);
  3633. }
  3634. finally {
  3635. Bid.ScopeLeave(ref hscp);
  3636. }
  3637. }
  3638. override public Task<bool> IsDBNullAsync(int i, CancellationToken cancellationToken) {
  3639. try {
  3640. CheckHeaderIsReady(columnIndex: i, methodName: "IsDBNullAsync");
  3641. }
  3642. catch (Exception ex) {
  3643. if (!ADP.IsCatchableExceptionType(ex)) {
  3644. throw;
  3645. }
  3646. return ADP.CreatedTaskWithException<bool>(ex);
  3647. }
  3648. // Shortcut - if there are no issues and the data is already read, then just return the value
  3649. if ((_sharedState._nextColumnHeaderToRead > i) && (!cancellationToken.IsCancellationRequested) && (_currentTask == null)) {
  3650. var data = _data;
  3651. if (data != null) {
  3652. return data[i].IsNull ? ADP.TrueTask : ADP.FalseTask;
  3653. }
  3654. else {
  3655. // Reader was closed between the CheckHeaderIsReady and accessing _data - throw closed exception
  3656. return ADP.CreatedTaskWithException<bool>(ADP.ExceptionWithStackTrace(ADP.DataReaderClosed("IsDBNullAsync")));
  3657. }
  3658. }
  3659. else {
  3660. // Throw if there is any current task
  3661. if (_currentTask != null) {
  3662. return ADP.CreatedTaskWithException<bool>(ADP.ExceptionWithStackTrace(ADP.AsyncOperationPending()));
  3663. }
  3664. // If user's token is canceled, return a canceled task
  3665. if (cancellationToken.IsCancellationRequested) {
  3666. return ADP.CreatedTaskWithCancellation<bool>();
  3667. }
  3668. // Shortcut - if we have enough data, then run [....]
  3669. try {
  3670. if (WillHaveEnoughData(i, headerOnly: true)) {
  3671. #if DEBUG
  3672. try {
  3673. _stateObj._shouldHaveEnoughData = true;
  3674. #endif
  3675. ReadColumnHeader(i);
  3676. return _data[i].IsNull ? ADP.TrueTask : ADP.FalseTask;
  3677. #if DEBUG
  3678. }
  3679. finally {
  3680. _stateObj._shouldHaveEnoughData = false;
  3681. }
  3682. #endif
  3683. }
  3684. }
  3685. catch (Exception ex) {
  3686. if (!ADP.IsCatchableExceptionType(ex)) {
  3687. throw;
  3688. }
  3689. return ADP.CreatedTaskWithException<bool>(ex);
  3690. }
  3691. // Setup and check for pending task
  3692. TaskCompletionSource<bool> source = new TaskCompletionSource<bool>();
  3693. Task original = Interlocked.CompareExchange(ref _currentTask, source.Task, null);
  3694. if (original != null) {
  3695. source.SetException(ADP.ExceptionWithStackTrace(ADP.AsyncOperationPending()));
  3696. return source.Task;
  3697. }
  3698. // Check if cancellation due to close is requested (this needs to be done after setting _currentTask)
  3699. if (_cancelAsyncOnCloseToken.IsCancellationRequested) {
  3700. source.SetCanceled();
  3701. _currentTask = null;
  3702. return source.Task;
  3703. }
  3704. // Setup cancellations
  3705. IDisposable registration = null;
  3706. if (cancellationToken.CanBeCanceled) {
  3707. registration = cancellationToken.Register(_command.CancelIgnoreFailure);
  3708. }
  3709. // Setup async
  3710. PrepareAsyncInvocation(useSnapshot: true);
  3711. // Setup the retryable function
  3712. Func<Task, Task<bool>> moreFunc = null;
  3713. moreFunc = (t) => {
  3714. if (t != null) {
  3715. PrepareForAsyncContinuation();
  3716. }
  3717. if (TryReadColumnHeader(i)) {
  3718. return _data[i].IsNull ? ADP.TrueTask : ADP.FalseTask;
  3719. }
  3720. else {
  3721. return ContinueRetryable(moreFunc);
  3722. }
  3723. };
  3724. // Go!
  3725. return InvokeRetryable(moreFunc, source, registration);
  3726. }
  3727. }
  3728. override public Task<T> GetFieldValueAsync<T>(int i, CancellationToken cancellationToken) {
  3729. try {
  3730. CheckDataIsReady(columnIndex: i, methodName: "GetFieldValueAsync");
  3731. // Shortcut - if there are no issues and the data is already read, then just return the value
  3732. if ((!IsCommandBehavior(CommandBehavior.SequentialAccess)) && (_sharedState._nextColumnDataToRead > i) && (!cancellationToken.IsCancellationRequested) && (_currentTask == null)) {
  3733. var data = _data;
  3734. var metaData =_metaData;
  3735. if ((data != null) && (metaData != null)) {
  3736. return Task.FromResult<T>(GetFieldValueFromSqlBufferInternal<T>(data[i], metaData[i]));
  3737. }
  3738. else {
  3739. // Reader was closed between the CheckDataIsReady and accessing _data\_metaData - throw closed exception
  3740. return ADP.CreatedTaskWithException<T>(ADP.ExceptionWithStackTrace(ADP.DataReaderClosed("GetFieldValueAsync")));
  3741. }
  3742. }
  3743. } catch (Exception ex) {
  3744. if (!ADP.IsCatchableExceptionType(ex)) {
  3745. throw;
  3746. }
  3747. return ADP.CreatedTaskWithException<T>(ex);
  3748. }
  3749. // Throw if there is any current task
  3750. if (_currentTask != null) {
  3751. return ADP.CreatedTaskWithException<T>(ADP.ExceptionWithStackTrace(ADP.AsyncOperationPending()));
  3752. }
  3753. // If user's token is canceled, return a canceled task
  3754. if (cancellationToken.IsCancellationRequested) {
  3755. return ADP.CreatedTaskWithCancellation<T>();
  3756. }
  3757. // Shortcut - if we have enough data, then run [....]
  3758. try {
  3759. if (WillHaveEnoughData(i)) {
  3760. #if DEBUG
  3761. try {
  3762. _stateObj._shouldHaveEnoughData = true;
  3763. #endif
  3764. return Task.FromResult(GetFieldValueInternal<T>(i));
  3765. #if DEBUG
  3766. }
  3767. finally {
  3768. _stateObj._shouldHaveEnoughData = false;
  3769. }
  3770. #endif
  3771. }
  3772. }
  3773. catch (Exception ex) {
  3774. if (!ADP.IsCatchableExceptionType(ex)) {
  3775. throw;
  3776. }
  3777. return ADP.CreatedTaskWithException<T>(ex);
  3778. }
  3779. // Setup and check for pending task
  3780. TaskCompletionSource<T> source = new TaskCompletionSource<T>();
  3781. Task original = Interlocked.CompareExchange(ref _currentTask, source.Task, null);
  3782. if (original != null) {
  3783. source.SetException(ADP.ExceptionWithStackTrace(ADP.AsyncOperationPending()));
  3784. return source.Task;
  3785. }
  3786. // Check if cancellation due to close is requested (this needs to be done after setting _currentTask)
  3787. if (_cancelAsyncOnCloseToken.IsCancellationRequested) {
  3788. source.SetCanceled();
  3789. _currentTask = null;
  3790. return source.Task;
  3791. }
  3792. // Setup cancellations
  3793. IDisposable registration = null;
  3794. if (cancellationToken.CanBeCanceled) {
  3795. registration = cancellationToken.Register(_command.CancelIgnoreFailure);
  3796. }
  3797. // Setup async
  3798. PrepareAsyncInvocation(useSnapshot: true);
  3799. // Setup the retryable function
  3800. Func<Task, Task<T>> moreFunc = null;
  3801. moreFunc = (t) => {
  3802. if (t != null) {
  3803. PrepareForAsyncContinuation();
  3804. }
  3805. if (TryReadColumn(i, setTimeout: false)) {
  3806. return Task.FromResult<T>(GetFieldValueFromSqlBufferInternal<T>(_data[i], _metaData[i]));
  3807. }
  3808. else {
  3809. return ContinueRetryable(moreFunc);
  3810. }
  3811. };
  3812. // Go!
  3813. return InvokeRetryable(moreFunc, source, registration);
  3814. }
  3815. #if DEBUG
  3816. internal void CompletePendingReadWithSuccess(bool resetForcePendingReadsToWait) {
  3817. var stateObj = _stateObj;
  3818. if (stateObj != null) {
  3819. stateObj.CompletePendingReadWithSuccess(resetForcePendingReadsToWait);
  3820. }
  3821. }
  3822. internal void CompletePendingReadWithFailure(int errorCode, bool resetForcePendingReadsToWait) {
  3823. var stateObj = _stateObj;
  3824. if (stateObj != null) {
  3825. stateObj.CompletePendingReadWithFailure(errorCode, resetForcePendingReadsToWait);
  3826. }
  3827. }
  3828. #endif
  3829. class Snapshot {
  3830. public bool _dataReady;
  3831. public bool _haltRead;
  3832. public bool _metaDataConsumed;
  3833. public bool _browseModeInfoConsumed;
  3834. public bool _hasRows;
  3835. public ALTROWSTATUS _altRowStatus;
  3836. public int _nextColumnDataToRead;
  3837. public int _nextColumnHeaderToRead;
  3838. public long _columnDataBytesRead;
  3839. public long _columnDataBytesRemaining;
  3840. public _SqlMetaDataSet _metadata;
  3841. public _SqlMetaDataSetCollection _altMetaDataSetCollection;
  3842. public MultiPartTableName[] _tableNames;
  3843. public SqlSequentialStream _currentStream;
  3844. public SqlSequentialTextReader _currentTextReader;
  3845. }
  3846. private Task<T> ContinueRetryable<T>(Func<Task, Task<T>> moreFunc) {
  3847. // _networkPacketTaskSource could be null if the connection was closed
  3848. // while an async invocation was outstanding.
  3849. TaskCompletionSource<object> completionSource = _stateObj._networkPacketTaskSource;
  3850. if (_cancelAsyncOnCloseToken.IsCancellationRequested || completionSource == null) {
  3851. // Cancellation requested due to datareader being closed
  3852. TaskCompletionSource<T> source = new TaskCompletionSource<T>();
  3853. source.TrySetException(ADP.ExceptionWithStackTrace(ADP.ClosedConnectionError()));
  3854. return source.Task;
  3855. }
  3856. else {
  3857. return completionSource.Task.ContinueWith((retryTask) => {
  3858. if (retryTask.IsFaulted) {
  3859. // Somehow the network task faulted - return the exception
  3860. TaskCompletionSource<T> exceptionSource = new TaskCompletionSource<T>();
  3861. exceptionSource.TrySetException(retryTask.Exception.InnerException);
  3862. return exceptionSource.Task;
  3863. }
  3864. else if (!_cancelAsyncOnCloseToken.IsCancellationRequested) {
  3865. TdsParserStateObject stateObj = _stateObj;
  3866. if (stateObj != null) {
  3867. // protect continuations against concurrent
  3868. // close and cancel
  3869. lock (stateObj) {
  3870. if (_stateObj != null) { // reader not closed while we waited for the lock
  3871. if (retryTask.IsCanceled) {
  3872. if (_parser != null) {
  3873. _parser.State = TdsParserState.Broken; // We failed to respond to attention, we have to quit!
  3874. _parser.Connection.BreakConnection();
  3875. _parser.ThrowExceptionAndWarning(_stateObj);
  3876. }
  3877. }
  3878. else {
  3879. if (!IsClosed) {
  3880. try {
  3881. return moreFunc(retryTask);
  3882. }
  3883. catch (Exception) {
  3884. CleanupAfterAsyncInvocation();
  3885. throw;
  3886. }
  3887. }
  3888. }
  3889. }
  3890. }
  3891. }
  3892. }
  3893. // if stateObj is null, or we closed the connection or the connection was already closed,
  3894. // then mark this operation as cancelled.
  3895. TaskCompletionSource<T> source = new TaskCompletionSource<T>();
  3896. source.SetException(ADP.ExceptionWithStackTrace(ADP.ClosedConnectionError()));
  3897. return source.Task;
  3898. }, TaskScheduler.Default).Unwrap();
  3899. }
  3900. }
  3901. private Task<T> InvokeRetryable<T>(Func<Task, Task<T>> moreFunc, TaskCompletionSource<T> source, IDisposable objectToDispose = null) {
  3902. try {
  3903. Task<T> task;
  3904. try {
  3905. task = moreFunc(null);
  3906. }
  3907. catch (Exception ex) {
  3908. task = ADP.CreatedTaskWithException<T>(ex);
  3909. }
  3910. if (task.IsCompleted) {
  3911. // If we've completed [....], then don't bother handling the TaskCompletionSource - we'll just return the completed task
  3912. CompleteRetryable(task, source, objectToDispose);
  3913. return task;
  3914. }
  3915. else {
  3916. task.ContinueWith((t) => CompleteRetryable(t, source, objectToDispose), TaskScheduler.Default);
  3917. }
  3918. }
  3919. catch (AggregateException e) {
  3920. source.TrySetException(e.InnerException);
  3921. }
  3922. catch (Exception e) {
  3923. source.TrySetException(e);
  3924. }
  3925. // Fall through for exceptions\completing async
  3926. return source.Task;
  3927. }
  3928. private void CompleteRetryable<T>(Task<T> task, TaskCompletionSource<T> source, IDisposable objectToDispose) {
  3929. if (objectToDispose != null) {
  3930. objectToDispose.Dispose();
  3931. }
  3932. // If something has forced us to switch to SyncOverAsync mode while in an async task then we need to guarantee that we do the cleanup
  3933. // This avoids us replaying non-replayable data (such as DONE or ENV_CHANGE tokens)
  3934. var stateObj = _stateObj;
  3935. bool ignoreCloseToken = ((stateObj != null) && (stateObj._syncOverAsync));
  3936. CleanupAfterAsyncInvocation(ignoreCloseToken);
  3937. Task current = Interlocked.CompareExchange(ref _currentTask, null, source.Task);
  3938. Debug.Assert(current == source.Task, "Should not be able to change the _currentTask while an asynchronous operation is pending");
  3939. if (task.IsFaulted) {
  3940. Exception e = task.Exception.InnerException;
  3941. source.TrySetException(e);
  3942. }
  3943. else if (task.IsCanceled) {
  3944. source.TrySetCanceled();
  3945. }
  3946. else {
  3947. source.TrySetResult(task.Result);
  3948. }
  3949. }
  3950. private void PrepareAsyncInvocation(bool useSnapshot) {
  3951. // if there is already a snapshot, then the previous async command
  3952. // completed with exception or cancellation. We need to continue
  3953. // with the old snapshot.
  3954. if (useSnapshot) {
  3955. Debug.Assert(!_stateObj._asyncReadWithoutSnapshot, "Can't prepare async invocation with snapshot if doing async without snapshots");
  3956. if (_snapshot == null) {
  3957. _snapshot = new Snapshot {
  3958. _dataReady = _sharedState._dataReady,
  3959. _haltRead = _haltRead,
  3960. _metaDataConsumed = _metaDataConsumed,
  3961. _browseModeInfoConsumed = _browseModeInfoConsumed,
  3962. _hasRows = _hasRows,
  3963. _altRowStatus = _altRowStatus,
  3964. _nextColumnDataToRead = _sharedState._nextColumnDataToRead,
  3965. _nextColumnHeaderToRead = _sharedState._nextColumnHeaderToRead,
  3966. _columnDataBytesRead = _columnDataBytesRead,
  3967. _columnDataBytesRemaining = _sharedState._columnDataBytesRemaining,
  3968. // _metadata and _altaMetaDataSetCollection must be Cloned
  3969. // before they are updated
  3970. _metadata = _metaData,
  3971. _altMetaDataSetCollection = _altMetaDataSetCollection,
  3972. _tableNames = _tableNames,
  3973. _currentStream = _currentStream,
  3974. _currentTextReader = _currentTextReader,
  3975. };
  3976. _stateObj.SetSnapshot();
  3977. }
  3978. }
  3979. else {
  3980. Debug.Assert(_snapshot == null, "Can prepare async invocation without snapshot if there is currently a snapshot");
  3981. _stateObj._asyncReadWithoutSnapshot = true;
  3982. }
  3983. _stateObj._syncOverAsync = false;
  3984. _stateObj._executionContext = ExecutionContext.Capture();
  3985. }
  3986. private void CleanupAfterAsyncInvocation(bool ignoreCloseToken = false) {
  3987. var stateObj = _stateObj;
  3988. if (stateObj != null) {
  3989. // If close requested cancellation and we have a snapshot, then it will deal with cleaning up
  3990. // NOTE: There are some cases where we wish to ignore the close token, such as when we've read some data that is not replayable (e.g. DONE or ENV_CHANGE token)
  3991. if ((ignoreCloseToken) || (!_cancelAsyncOnCloseToken.IsCancellationRequested) || (stateObj._asyncReadWithoutSnapshot)) {
  3992. // Prevent race condition between the DataReader being closed (e.g. when another MARS thread has an error)
  3993. lock(stateObj) {
  3994. if (_stateObj != null) { // reader not closed while we waited for the lock
  3995. CleanupAfterAsyncInvocationInternal(_stateObj);
  3996. Debug.Assert(_snapshot == null && !_stateObj._asyncReadWithoutSnapshot, "Snapshot not null or async without snapshot still enabled after cleaning async state");
  3997. }
  3998. }
  3999. }
  4000. }
  4001. }
  4002. // This function is called directly if calling function already closed the reader, so _stateObj is null,
  4003. // in other cases parameterless version should be called
  4004. private void CleanupAfterAsyncInvocationInternal(TdsParserStateObject stateObj, bool resetNetworkPacketTaskSource = true)
  4005. {
  4006. if (resetNetworkPacketTaskSource) {
  4007. stateObj._networkPacketTaskSource = null;
  4008. }
  4009. stateObj.ResetSnapshot();
  4010. stateObj._syncOverAsync = true;
  4011. stateObj._executionContext = null;
  4012. stateObj._asyncReadWithoutSnapshot = false;
  4013. #if DEBUG
  4014. stateObj._permitReplayStackTraceToDiffer = false;
  4015. #endif
  4016. // We are setting this to null inside the if-statement because stateObj==null means that the reader hasn't been initialized or has been closed (either way _snapshot should already be null)
  4017. _snapshot = null;
  4018. }
  4019. private void PrepareForAsyncContinuation() {
  4020. Debug.Assert(((_snapshot != null) || (_stateObj._asyncReadWithoutSnapshot)), "Can not prepare for an async continuation if no async if setup");
  4021. if (_snapshot != null) {
  4022. _sharedState._dataReady = _snapshot._dataReady;
  4023. _haltRead = _snapshot._haltRead;
  4024. _metaDataConsumed = _snapshot._metaDataConsumed;
  4025. _browseModeInfoConsumed = _snapshot._browseModeInfoConsumed;
  4026. _hasRows = _snapshot._hasRows;
  4027. _altRowStatus = _snapshot._altRowStatus;
  4028. _sharedState._nextColumnDataToRead = _snapshot._nextColumnDataToRead;
  4029. _sharedState._nextColumnHeaderToRead = _snapshot._nextColumnHeaderToRead;
  4030. _columnDataBytesRead = _snapshot._columnDataBytesRead;
  4031. _sharedState._columnDataBytesRemaining = _snapshot._columnDataBytesRemaining;
  4032. _metaData = _snapshot._metadata;
  4033. _altMetaDataSetCollection = _snapshot._altMetaDataSetCollection;
  4034. _tableNames = _snapshot._tableNames;
  4035. _currentStream = _snapshot._currentStream;
  4036. _currentTextReader = _snapshot._currentTextReader;
  4037. _stateObj.PrepareReplaySnapshot();
  4038. }
  4039. _stateObj._executionContext = ExecutionContext.Capture();
  4040. }
  4041. private void SwitchToAsyncWithoutSnapshot() {
  4042. Debug.Assert(_snapshot != null, "Should currently have a snapshot");
  4043. Debug.Assert(_stateObj != null && !_stateObj._asyncReadWithoutSnapshot, "Already in async without snapshot");
  4044. _snapshot = null;
  4045. _stateObj.ResetSnapshot();
  4046. _stateObj._asyncReadWithoutSnapshot = true;
  4047. }
  4048. }// SqlDataReader
  4049. }// namespace