dbrfx.cpp 89 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459
  1. // This is a part of the Microsoft Foundation Classes C++ library.
  2. // Copyright (C) 1992-1998 Microsoft Corporation
  3. // All rights reserved.
  4. //
  5. // This source code is only intended as a supplement to the
  6. // Microsoft Foundation Classes Reference and related
  7. // electronic documentation provided with the library.
  8. // See these sources for detailed information regarding the
  9. // Microsoft Foundation Classes product.
  10. #include "stdafx.h"
  11. #ifdef AFX_DB_SEG
  12. #pragma code_seg(AFX_DB_SEG)
  13. #endif
  14. #ifdef _DEBUG
  15. #undef THIS_FILE
  16. static char THIS_FILE[] = __FILE__;
  17. #endif
  18. #define new DEBUG_NEW
  19. /////////////////////////////////////////////////////////////////////////////
  20. // CDBByteArray db specific class for holding byte array data
  21. class CDBByteArray : public CByteArray
  22. {
  23. DECLARE_DYNAMIC(CDBByteArray)
  24. // Operations
  25. void SetLength(int nNewSize);
  26. };
  27. inline void CDBByteArray::SetLength(int nNewSize)
  28. {
  29. // Can't grow buffer since ODBC has been SQLBindCol'd on it.
  30. ASSERT(nNewSize <= m_nMaxSize);
  31. m_nSize = nNewSize;
  32. }
  33. //////////////////////////////////////////////////////////////////////////////
  34. // CFieldExchange
  35. CFieldExchange::CFieldExchange(UINT nOperation, CRecordset* prs, void* pvField)
  36. {
  37. #ifdef _DEBUG
  38. ASSERT(nOperation >= BindParam && nOperation <= DumpField);
  39. #endif
  40. ASSERT_VALID(prs);
  41. ASSERT(prs->m_hstmt != SQL_NULL_HSTMT);
  42. m_nFieldType = (UINT) noFieldType;
  43. m_nOperation = nOperation;
  44. m_prs = prs;
  45. m_pvField = pvField;
  46. m_nFields = 0;
  47. m_nParams = 0;
  48. m_nParamFields = 0;
  49. m_bField = FALSE;
  50. m_pstr = NULL;
  51. m_hstmt = SQL_NULL_HSTMT;
  52. m_lDefaultLBFetchSize = 0x00010000;
  53. m_lDefaultLBReallocSize = 0x00010000;
  54. }
  55. BOOL CFieldExchange::IsFieldType(UINT* pnField)
  56. {
  57. if (m_nFieldType == outputColumn)
  58. {
  59. *pnField = ++m_nFields;
  60. // Recordset's m_nFields must match number of Fields!
  61. ASSERT(m_nFields <= m_prs->m_nFields);
  62. }
  63. else
  64. {
  65. // Make sure SetFieldType was called
  66. ASSERT(m_nFieldType == inputParam ||
  67. m_nFieldType == outputParam ||
  68. m_nFieldType == inoutParam);
  69. *pnField = ++m_nParams;
  70. // Recordset's m_nParams must match number of Params!
  71. ASSERT(m_nParams <= m_prs->m_nParams);
  72. }
  73. if (m_nOperation == BindParam || m_nOperation == RebindParam)
  74. {
  75. // only valid on a param field type
  76. return m_nFieldType != outputColumn;
  77. }
  78. else
  79. {
  80. // valid only on an outputColumn field type
  81. return m_nFieldType == outputColumn;
  82. }
  83. }
  84. // Default implementation for RFX functions
  85. void CFieldExchange::Default(LPCTSTR szName,
  86. void* pv, LONG* plLength, int nCType, UINT cbValue, UINT cbPrecision)
  87. {
  88. RETCODE nRetCode;
  89. UINT nField = (m_nFieldType == outputColumn)? m_nFields: m_nParams;
  90. switch (m_nOperation)
  91. {
  92. case BindParam:
  93. if (m_prs->IsParamStatusNull(nField - 1))
  94. *plLength = SQL_NULL_DATA;
  95. else
  96. *plLength = cbValue;
  97. // For params, CType is same as SQL type
  98. AFX_SQL_SYNC(::SQLBindParameter(m_hstmt, (UWORD)nField,
  99. (SWORD)m_nFieldType, (SWORD)nCType, (SWORD)nCType, cbPrecision, 0,
  100. pv, 0, plLength));
  101. if (nRetCode != SQL_SUCCESS)
  102. m_prs->ThrowDBException(nRetCode, m_hstmt);
  103. // Add the member address to the param map
  104. m_prs->m_mapParamIndex.SetAt(pv, (void*)nField);
  105. return;
  106. case RebindParam:
  107. // Only need to reset param length
  108. *plLength = m_prs->IsParamStatusNull(nField - 1) ? SQL_NULL_DATA : cbValue;
  109. return;
  110. case BindFieldForUpdate:
  111. if (!m_prs->IsFieldStatusDirty(nField - 1))
  112. {
  113. // If not dirty, set length to SQL_IGNORE for SQLSetPos updates
  114. *plLength = SQL_IGNORE;
  115. }
  116. else if (!m_prs->IsFieldStatusNull(nField - 1))
  117. {
  118. // Reset the length as it may have changed for var length fields
  119. *plLength = cbValue;
  120. }
  121. return;
  122. case UnbindFieldForUpdate:
  123. // Reset bound length to actual length to clear SQL_IGNOREs
  124. if (!m_prs->IsFieldStatusDirty(nField - 1))
  125. *plLength = cbValue;
  126. return;
  127. case BindFieldToColumn:
  128. AFX_SQL_SYNC(::SQLBindCol(m_prs->m_hstmt, (UWORD)nField, (SWORD)nCType,
  129. pv, cbValue, plLength));
  130. if (!m_prs->Check(nRetCode))
  131. m_prs->ThrowDBException(nRetCode);
  132. // Add the member address to the field map
  133. m_prs->m_mapFieldIndex.SetAt(pv, (void*)nField);
  134. return;
  135. case Name:
  136. if (m_prs->IsFieldStatusDirty(nField - 1))
  137. {
  138. // We require a name
  139. ASSERT(lstrlen(szName) != 0);
  140. *m_pstr += szName;
  141. *m_pstr += m_lpszSeparator;
  142. }
  143. return;
  144. case NameValue:
  145. if (m_prs->IsFieldStatusDirty(nField - 1))
  146. {
  147. *m_pstr += szName;
  148. *m_pstr += '=';
  149. }
  150. // Fall through
  151. case Value:
  152. if (m_prs->IsFieldStatusDirty(nField - 1))
  153. {
  154. // If user marked column NULL, reflect this in length
  155. if (m_prs->IsFieldStatusNull(nField - 1))
  156. *plLength = SQL_NULL_DATA;
  157. else
  158. *plLength = cbValue;
  159. // If optimizing for bulk add, only need lengths set correctly
  160. if(!(m_prs->m_dwOptions & CRecordset::optimizeBulkAdd))
  161. {
  162. *m_pstr += '?';
  163. *m_pstr += m_lpszSeparator;
  164. m_nParamFields++;
  165. // Assumes all bound fields BEFORE unbound fields
  166. CODBCFieldInfo* pODBCInfo =
  167. &m_prs->m_rgODBCFieldInfos[nField - 1];
  168. AFX_SQL_SYNC(::SQLBindParameter(m_hstmt,
  169. (UWORD)m_nParamFields, SQL_PARAM_INPUT,
  170. (SWORD)nCType, pODBCInfo->m_nSQLType,
  171. pODBCInfo->m_nPrecision, pODBCInfo->m_nScale,
  172. pv, 0, plLength));
  173. if (nRetCode != SQL_SUCCESS)
  174. m_prs->ThrowDBException(nRetCode, m_hstmt);
  175. }
  176. }
  177. return;
  178. case MarkForUpdate:
  179. {
  180. // Get the field data
  181. CFieldInfo* pInfo = &m_prs->m_rgFieldInfos[nField - 1];
  182. // If user changed field value from previous value, mark field dirty
  183. if ((pInfo->m_bStatus & AFX_SQL_FIELD_FLAG_NULL))
  184. {
  185. if (!m_prs->IsFieldStatusNull(nField - 1))
  186. m_prs->SetDirtyFieldStatus(nField - 1);
  187. }
  188. else
  189. {
  190. // Saved field is not NULL. current field null, so field dirty
  191. BOOL bDirty = m_prs->IsFieldStatusNull(nField - 1);
  192. // If values differ, then field dirty
  193. void* pvDataCache;
  194. if (pInfo->m_nDataType == AFX_RFX_BOOL ||
  195. pInfo->m_nDataType == AFX_RFX_BYTE ||
  196. pInfo->m_nDataType == AFX_RFX_INT ||
  197. pInfo->m_nDataType == AFX_RFX_LONG ||
  198. pInfo->m_nDataType == AFX_RFX_SINGLE)
  199. {
  200. // If caching data by value, pass a ref
  201. pvDataCache = &pInfo->m_pvDataCache;
  202. }
  203. else
  204. pvDataCache = pInfo->m_pvDataCache;
  205. if (bDirty || !AfxCompareValueByRef(pv, pvDataCache, pInfo->m_nDataType))
  206. m_prs->SetDirtyFieldStatus(nField - 1);
  207. }
  208. #ifdef _DEBUG
  209. // Field address must not change - ODBC's SQLBindCol depends upon this
  210. void* pvBind;
  211. switch (pInfo->m_nDataType)
  212. {
  213. default:
  214. pvBind = pv;
  215. break;
  216. case AFX_RFX_LPTSTR:
  217. #ifdef _UNICODE
  218. pvBind = m_prs->m_pvFieldProxy[nField-1];
  219. #else // !_UNICODE
  220. pvBind = pv;
  221. #endif
  222. break;
  223. case AFX_RFX_TEXT:
  224. #ifdef _UNICODE
  225. pvBind = m_prs->m_pvFieldProxy[nField-1];
  226. #else // !_UNICODE
  227. {
  228. pvBind = ((CString*)pv)->GetBuffer(0);
  229. ((CString*)pv)->ReleaseBuffer();
  230. }
  231. #endif
  232. break;
  233. case AFX_RFX_OLEDATE:
  234. case AFX_RFX_DATE:
  235. pvBind = m_prs->m_pvFieldProxy[nField-1];
  236. break;
  237. case AFX_RFX_BINARY:
  238. pvBind = ((CByteArray*)pv)->GetData();
  239. break;
  240. }
  241. if (pInfo->m_pvBindAddress != pvBind)
  242. {
  243. TRACE1("Error: field address (column %u) has changed!\n",
  244. nField);
  245. ASSERT(FALSE);
  246. }
  247. #endif // _DEBUG
  248. if ((m_pvField == NULL || m_pvField == pv) &&
  249. m_prs->IsFieldStatusDirty(nField - 1))
  250. {
  251. m_bField = TRUE;
  252. }
  253. }
  254. return;
  255. case StoreField:
  256. AfxStoreField(*m_prs, nField, pv);
  257. return;
  258. case LoadField:
  259. AfxLoadField(*m_prs, nField, pv, plLength);
  260. return;
  261. default:
  262. ASSERT(FALSE);
  263. }
  264. }
  265. void AFXAPI RFX_Text(CFieldExchange* pFX, LPCTSTR szName,
  266. LPTSTR value, int nMaxLength, int nColumnType, short nScale)
  267. {
  268. ASSERT(AfxIsValidAddress(pFX, sizeof(CFieldExchange)));
  269. ASSERT(AfxIsValidString(szName));
  270. ASSERT(AfxIsValidAddress(value, nMaxLength));
  271. RETCODE nRetCode;
  272. UINT nField;
  273. if (!pFX->IsFieldType(&nField))
  274. return;
  275. LONG* plLength = pFX->m_prs->GetFieldLengthBuffer(
  276. nField - 1, pFX->m_nFieldType);
  277. switch (pFX->m_nOperation)
  278. {
  279. default:
  280. pFX->Default(szName, value, plLength,
  281. SQL_C_CHAR, lstrlen(value), nMaxLength);
  282. return;
  283. case CFieldExchange::BindParam:
  284. {
  285. void* pvParam = value; // will be overwritten if UNICODE
  286. #ifdef _UNICODE
  287. // Must use proxy to translate unicode data into non-unicode param
  288. pFX->m_prs->m_bRebindParams = TRUE;
  289. // Allocate proxy array if necessary
  290. if (pFX->m_prs->m_pvParamProxy == NULL)
  291. {
  292. pFX->m_prs->m_pvParamProxy = new void*[pFX->m_prs->m_nParams];
  293. memset(pFX->m_prs->m_pvParamProxy, 0,
  294. pFX->m_prs->m_nParams*sizeof(void*));
  295. pFX->m_prs->m_nProxyParams = pFX->m_prs->m_nParams;
  296. }
  297. // Allocate non-unicode string to nMaxLength if necessary for SQLBindParameter
  298. if (pFX->m_prs->m_pvParamProxy[nField-1] == NULL)
  299. {
  300. pvParam = new CHAR[nMaxLength+1];
  301. pFX->m_prs->m_pvParamProxy[nField-1] = pvParam;
  302. }
  303. else
  304. pvParam = pFX->m_prs->m_pvParamProxy[nField-1];
  305. // Now fill in the data value
  306. USES_CONVERSION;
  307. lstrcpyA((char*)pvParam, T2A((LPCTSTR)value));
  308. #endif // _UNICODE
  309. *plLength = pFX->m_prs->IsParamStatusNull(nField - 1) ?
  310. SQL_NULL_DATA : SQL_NTS;
  311. AFX_SQL_SYNC(::SQLBindParameter(pFX->m_hstmt, (UWORD)nField,
  312. (SWORD)pFX->m_nFieldType, SQL_C_CHAR, (SWORD)nColumnType,
  313. nMaxLength, nScale, pvParam, nMaxLength, plLength));
  314. if (nRetCode != SQL_SUCCESS)
  315. pFX->m_prs->ThrowDBException(nRetCode, pFX->m_hstmt);
  316. // Add the member address to the param map
  317. pFX->m_prs->m_mapParamIndex.SetAt(value, (void*)nField);
  318. }
  319. return;
  320. #ifdef _UNICODE
  321. case CFieldExchange::RebindParam:
  322. *plLength = pFX->m_prs->IsParamStatusNull(nField - 1) ?
  323. SQL_NULL_DATA : SQL_NTS;
  324. if (pFX->m_prs->m_nProxyParams != 0)
  325. {
  326. // Fill buffer (expected by SQLBindParameter) with new param data
  327. USES_CONVERSION;
  328. LPSTR lpszParam = (LPSTR)pFX->m_prs->m_pvParamProxy[nField-1];
  329. lstrcpyA(lpszParam, T2A((LPCTSTR)value));
  330. }
  331. return;
  332. #endif // _UNICODE
  333. case CFieldExchange::BindFieldToColumn:
  334. {
  335. // Assumes all bound fields BEFORE unbound fields
  336. CODBCFieldInfo* pODBCInfo =
  337. &pFX->m_prs->m_rgODBCFieldInfos[nField - 1];
  338. UINT cbColumn = pODBCInfo->m_nPrecision;
  339. switch (pODBCInfo->m_nSQLType)
  340. {
  341. default:
  342. #ifdef _DEBUG
  343. // Warn of possible field schema mismatch
  344. if (afxTraceFlags & traceDatabase)
  345. TRACE1("Warning: string converted from SQL type %ld.\n",
  346. pODBCInfo->m_nSQLType);
  347. #endif // _DEBUG
  348. // Add room for extra information like sign, decimal point, etc.
  349. cbColumn += 10;
  350. break;
  351. case SQL_LONGVARCHAR:
  352. case SQL_CHAR:
  353. case SQL_VARCHAR:
  354. break;
  355. case SQL_FLOAT:
  356. case SQL_REAL:
  357. case SQL_DOUBLE:
  358. // Add room for sign, decimal point and " E +XXX"
  359. cbColumn += 10;
  360. break;
  361. case SQL_DECIMAL:
  362. case SQL_NUMERIC:
  363. // Add room for sign and decimal point
  364. cbColumn += 2;
  365. break;
  366. case SQL_TIMESTAMP:
  367. case SQL_DATE:
  368. case SQL_TIME:
  369. // May need extra space, i.e. "{TS mm/dd/yyyy hh:mm:ss}"
  370. cbColumn += 10;
  371. break;
  372. case SQL_TINYINT:
  373. case SQL_SMALLINT:
  374. case SQL_INTEGER:
  375. case SQL_BIGINT:
  376. // Add room for sign
  377. cbColumn += 1;
  378. break;
  379. }
  380. // Constrain to user specified max length, subject to 256 byte min
  381. if (cbColumn > (UINT)nMaxLength || cbColumn < 256)
  382. cbColumn = nMaxLength;
  383. // Set up binding addres
  384. void* pvData = value; // overwritten if _UNICODE
  385. value[cbColumn] = '\0';
  386. #ifdef _UNICODE
  387. // Allocate proxy array if necessary
  388. if (pFX->m_prs->m_pvFieldProxy == NULL)
  389. {
  390. pFX->m_prs->m_pvFieldProxy = new void*[pFX->m_prs->m_nFields];
  391. memset(pFX->m_prs->m_pvFieldProxy, 0,
  392. pFX->m_prs->m_nFields*sizeof(void*));
  393. pFX->m_prs->m_nProxyFields = pFX->m_prs->m_nFields;
  394. }
  395. // Allocate non-unicode string for SQLBindCol (not necessary on Requery)
  396. if (pFX->m_prs->m_pvFieldProxy[nField-1] == NULL)
  397. pFX->m_prs->m_pvFieldProxy[nField-1] = new CHAR[cbColumn+2];
  398. pvData = pFX->m_prs->m_pvFieldProxy[nField-1];
  399. #endif // _UNICODE
  400. AFX_SQL_SYNC(::SQLBindCol(pFX->m_prs->m_hstmt, (UWORD)nField,
  401. SQL_C_CHAR, pvData, cbColumn+1, plLength));
  402. if (!pFX->m_prs->Check(nRetCode))
  403. pFX->m_prs->ThrowDBException(nRetCode);
  404. // Add the member address to the field map
  405. pFX->m_prs->m_mapFieldIndex.SetAt(value, (void*)nField);
  406. }
  407. return;
  408. #ifdef _UNICODE
  409. case CFieldExchange::BindFieldForUpdate:
  410. if (pFX->m_prs->m_nProxyFields != 0)
  411. {
  412. // Fill buffer (expected by SQLSetPos) with new field data
  413. USES_CONVERSION;
  414. LPSTR lpszData = (LPSTR)pFX->m_prs->m_pvFieldProxy[nField-1];
  415. lstrcpyA(lpszData, T2A((LPCTSTR)value));
  416. pFX->Default(szName, (void *)lpszData, plLength, SQL_C_CHAR,
  417. lstrlenA(lpszData), nMaxLength);
  418. }
  419. return;
  420. #endif // _UNICODE
  421. case CFieldExchange::Fixup:
  422. if (*plLength == SQL_NULL_DATA)
  423. {
  424. pFX->m_prs->SetNullFieldStatus(nField - 1);
  425. value[0] = '\0';
  426. }
  427. else
  428. {
  429. #ifdef _UNICODE
  430. // Copy value out of the proxy
  431. value = (LPTSTR)pFX->m_prs->m_pvFieldProxy[nField-1];
  432. #endif
  433. LPTSTR lpsz = value;
  434. if (pFX->m_prs->m_pDatabase->m_bStripTrailingSpaces)
  435. {
  436. // find first trailing space
  437. LPTSTR lpszFirstTrailing = NULL;
  438. while (*lpsz != '\0')
  439. {
  440. if (*lpsz != ' ')
  441. lpszFirstTrailing = NULL;
  442. else
  443. {
  444. if (lpszFirstTrailing == NULL)
  445. lpszFirstTrailing = lpsz;
  446. }
  447. lpsz = _tcsinc(lpsz);
  448. }
  449. // truncate
  450. if (lpszFirstTrailing != NULL)
  451. *lpszFirstTrailing = '\0';
  452. }
  453. *plLength = lstrlen(value);
  454. }
  455. return;
  456. case CFieldExchange::SetFieldNull:
  457. if ((pFX->m_pvField == NULL &&
  458. pFX->m_nFieldType == CFieldExchange::outputColumn) ||
  459. pFX->m_pvField == value)
  460. {
  461. if (pFX->m_bField)
  462. {
  463. // Mark fields null
  464. pFX->m_prs->SetNullFieldStatus(nField - 1);
  465. // Set string 0 length
  466. *plLength = SQL_NULL_DATA;
  467. }
  468. else
  469. {
  470. pFX->m_prs->ClearNullFieldStatus(nField - 1);
  471. *plLength = SQL_NTS;
  472. }
  473. #ifdef _DEBUG
  474. pFX->m_nFieldFound = nField;
  475. #endif
  476. }
  477. return;
  478. #ifdef _UNICODE
  479. case CFieldExchange::NameValue:
  480. if (pFX->m_prs->IsFieldStatusDirty(nField - 1))
  481. {
  482. *pFX->m_pstr += szName;
  483. *pFX->m_pstr += '=';
  484. }
  485. // Fall through
  486. case CFieldExchange::Value:
  487. if (pFX->m_prs->IsFieldStatusDirty(nField - 1))
  488. {
  489. // Get the field data
  490. CODBCFieldInfo* pODBCInfo =
  491. &pFX->m_prs->m_rgODBCFieldInfos[nField - 1];
  492. LPSTR lpszData = (LPSTR)pFX->m_prs->m_pvFieldProxy[nField-1];
  493. if (pFX->m_prs->IsFieldStatusNull(nField - 1))
  494. {
  495. *plLength = SQL_NULL_DATA;
  496. }
  497. else
  498. {
  499. USES_CONVERSION;
  500. lstrcpyA(lpszData, T2A((LPCTSTR)value));
  501. *plLength = lstrlen(value);
  502. }
  503. // If optimizing for bulk add, only need lengths & proxy set correctly
  504. if(!(pFX->m_prs->m_dwOptions & CRecordset::optimizeBulkAdd))
  505. {
  506. *pFX->m_pstr += '?';
  507. *pFX->m_pstr += pFX->m_lpszSeparator;
  508. pFX->m_nParamFields++;
  509. AFX_SQL_SYNC(::SQLBindParameter(pFX->m_hstmt,
  510. (UWORD)pFX->m_nParamFields, SQL_PARAM_INPUT,
  511. SQL_C_CHAR, pODBCInfo->m_nSQLType, nMaxLength,
  512. pODBCInfo->m_nScale, lpszData, 0, plLength));
  513. }
  514. }
  515. return;
  516. #endif // _UNICODE
  517. case CFieldExchange::MarkForAddNew:
  518. // can force writing of psuedo-null value (as a non-null) by setting field dirty
  519. if (*value != '\0')
  520. {
  521. pFX->m_prs->SetDirtyFieldStatus(nField - 1);
  522. pFX->m_prs->ClearNullFieldStatus(nField - 1);
  523. }
  524. return;
  525. case CFieldExchange::MarkForUpdate:
  526. if (*value == '\0')
  527. pFX->m_prs->SetNullFieldStatus(nField - 1);
  528. else
  529. pFX->m_prs->ClearNullFieldStatus(nField - 1);
  530. pFX->Default(szName, value, plLength,
  531. SQL_C_CHAR, lstrlen(value), nMaxLength);
  532. return;
  533. case CFieldExchange::LoadField:
  534. {
  535. // Get the field data
  536. CFieldInfo* pInfo = &pFX->m_prs->m_rgFieldInfos[nField - 1];
  537. // Restore the status
  538. pFX->m_prs->SetFieldStatus(nField - 1, pInfo->m_bStatus);
  539. // If not NULL, restore the value and length
  540. if (!pFX->m_prs->IsFieldStatusNull(nField - 1))
  541. {
  542. value = LPTSTR(pInfo->m_pvDataCache);
  543. *plLength = lstrlen(value);
  544. #ifdef _UNICODE
  545. // Must restore proxy for correct WHERE CURRENT OF operation
  546. USES_CONVERSION;
  547. LPSTR lpszData = (LPSTR)pFX->m_prs->m_pvFieldProxy[nField-1];
  548. lstrcpyA(lpszData, T2A((LPCTSTR)value));
  549. #endif // _UNICODE
  550. }
  551. else
  552. {
  553. *plLength = SQL_NULL_DATA;
  554. }
  555. #ifdef _DEBUG
  556. // Buffer address must not change - ODBC's SQLBindCol depends upon this
  557. void* pvBind;
  558. #ifdef _UNICODE
  559. pvBind = pFX->m_prs->m_pvFieldProxy[nField-1];
  560. #else // !_UNICODE
  561. pvBind = value;
  562. #endif
  563. if (pvBind != pInfo->m_pvBindAddress)
  564. {
  565. TRACE1("Error: buffer (column %u) address has changed!\n",
  566. nField);
  567. ASSERT(FALSE);
  568. }
  569. #endif // _DEBUG
  570. }
  571. return;
  572. case CFieldExchange::StoreField:
  573. AfxStoreField(*pFX->m_prs, nField, value);
  574. return;
  575. case CFieldExchange::AllocCache:
  576. {
  577. CFieldInfo* pInfo = &pFX->m_prs->m_rgFieldInfos[nField - 1];
  578. pInfo->m_pvDataCache = new TCHAR[nMaxLength];
  579. pInfo->m_nDataType = AFX_RFX_LPTSTR;
  580. }
  581. return;
  582. #ifdef _DEBUG
  583. case CFieldExchange::DumpField:
  584. *pFX->m_pdcDump << "\n" << szName << " = " << value;
  585. return;
  586. #endif // _DEBUG
  587. }
  588. }
  589. // Note: CString.m_pchData must not be changed. This address is registered
  590. // with ODBC and must remain valid until the recordset is released.
  591. void AFXAPI RFX_Text(CFieldExchange* pFX, LPCTSTR szName,
  592. CString& value, int nMaxLength, int nColumnType, short nScale)
  593. {
  594. ASSERT(AfxIsValidAddress(pFX, sizeof(CFieldExchange)));
  595. ASSERT(AfxIsValidString(szName));
  596. ASSERT(AfxIsValidAddress(&value, sizeof(CString)));
  597. RETCODE nRetCode;
  598. UINT nField;
  599. if (!pFX->IsFieldType(&nField))
  600. return;
  601. LONG* plLength = pFX->m_prs->GetFieldLengthBuffer(
  602. nField - 1, pFX->m_nFieldType);
  603. switch (pFX->m_nOperation)
  604. {
  605. default:
  606. pFX->Default(szName, value.GetBuffer(0), plLength,
  607. SQL_C_CHAR, value.GetLength(), nMaxLength);
  608. value.ReleaseBuffer();
  609. return;
  610. case CFieldExchange::BindParam:
  611. {
  612. // Preallocate to nMaxLength and setup binding address
  613. value.GetBufferSetLength(nMaxLength);
  614. void* pvParam = value.LockBuffer(); // will be overwritten if UNICODE
  615. #ifdef _UNICODE
  616. // Must use proxy to translate unicode data into non-unicode param
  617. pFX->m_prs->m_bRebindParams = TRUE;
  618. // Allocate proxy array if necessary
  619. if (pFX->m_prs->m_pvParamProxy == NULL)
  620. {
  621. pFX->m_prs->m_pvParamProxy = new void*[pFX->m_prs->m_nParams];
  622. memset(pFX->m_prs->m_pvParamProxy, 0,
  623. pFX->m_prs->m_nParams*sizeof(void*));
  624. pFX->m_prs->m_nProxyParams = pFX->m_prs->m_nParams;
  625. }
  626. // Allocate non-unicode string to nMaxLength if necessary for SQLBindParameter
  627. if (pFX->m_prs->m_pvParamProxy[nField-1] == NULL)
  628. {
  629. pvParam = new CHAR[nMaxLength+1];
  630. pFX->m_prs->m_pvParamProxy[nField-1] = pvParam;
  631. }
  632. else
  633. pvParam = pFX->m_prs->m_pvParamProxy[nField-1];
  634. // Now fill in the data value
  635. USES_CONVERSION;
  636. lstrcpyA((char*)pvParam, T2A((LPCTSTR)value));
  637. #endif // _UNICODE
  638. *plLength = pFX->m_prs->IsParamStatusNull(nField - 1) ?
  639. SQL_NULL_DATA : SQL_NTS;
  640. AFX_SQL_SYNC(::SQLBindParameter(pFX->m_hstmt, (UWORD)nField,
  641. (SWORD)pFX->m_nFieldType, SQL_C_CHAR, (SWORD)nColumnType,
  642. nMaxLength, nScale, pvParam, nMaxLength, plLength));
  643. value.ReleaseBuffer();
  644. if (nRetCode != SQL_SUCCESS)
  645. pFX->m_prs->ThrowDBException(nRetCode, pFX->m_hstmt);
  646. // Add the member address to the param map
  647. pFX->m_prs->m_mapParamIndex.SetAt(&value, (void*)nField);
  648. }
  649. return;
  650. #ifdef _UNICODE
  651. case CFieldExchange::RebindParam:
  652. *plLength = pFX->m_prs->IsParamStatusNull(nField - 1) ?
  653. SQL_NULL_DATA : SQL_NTS;
  654. if (pFX->m_prs->m_nProxyParams != 0)
  655. {
  656. // Fill buffer (expected by SQLBindParameter) with new param data
  657. USES_CONVERSION;
  658. LPSTR lpszParam = (LPSTR)pFX->m_prs->m_pvParamProxy[nField-1];
  659. lstrcpyA(lpszParam, T2A((LPCTSTR)value));
  660. }
  661. return;
  662. #endif // _UNICODE
  663. case CFieldExchange::BindFieldToColumn:
  664. {
  665. // Assumes all bound fields BEFORE unbound fields
  666. CODBCFieldInfo* pODBCInfo =
  667. &pFX->m_prs->m_rgODBCFieldInfos[nField - 1];
  668. UINT cbColumn = pODBCInfo->m_nPrecision;
  669. switch (pODBCInfo->m_nSQLType)
  670. {
  671. default:
  672. #ifdef _DEBUG
  673. // Warn of possible field schema mismatch
  674. if (afxTraceFlags & traceDatabase)
  675. TRACE1("Warning: CString converted from SQL type %ld.\n",
  676. pODBCInfo->m_nSQLType);
  677. #endif // _DEBUG
  678. // Add room for extra information like sign, decimal point, etc.
  679. cbColumn += 10;
  680. break;
  681. case SQL_LONGVARCHAR:
  682. case SQL_CHAR:
  683. case SQL_VARCHAR:
  684. break;
  685. case SQL_FLOAT:
  686. case SQL_REAL:
  687. case SQL_DOUBLE:
  688. // Add room for sign, decimal point and " E +XXX"
  689. cbColumn += 10;
  690. break;
  691. case SQL_DECIMAL:
  692. case SQL_NUMERIC:
  693. // Add room for sign and decimal point
  694. cbColumn += 2;
  695. break;
  696. case SQL_TIMESTAMP:
  697. case SQL_DATE:
  698. case SQL_TIME:
  699. // May need extra space, i.e. "{TS mm/dd/yyyy hh:mm:ss}"
  700. cbColumn += 10;
  701. break;
  702. case SQL_TINYINT:
  703. case SQL_SMALLINT:
  704. case SQL_INTEGER:
  705. case SQL_BIGINT:
  706. // Add room for sign
  707. cbColumn += 1;
  708. break;
  709. }
  710. // Constrain to user specified max length, subject to 256 byte min
  711. if (cbColumn > (UINT)nMaxLength || cbColumn < 256)
  712. cbColumn = nMaxLength;
  713. // Set up binding addres
  714. void* pvData;
  715. value.GetBufferSetLength(cbColumn+1);
  716. pvData = value.LockBuffer(); // will be overwritten if UNICODE
  717. #ifdef _UNICODE
  718. // Allocate proxy array if necessary
  719. if (pFX->m_prs->m_pvFieldProxy == NULL)
  720. {
  721. pFX->m_prs->m_pvFieldProxy = new void*[pFX->m_prs->m_nFields];
  722. memset(pFX->m_prs->m_pvFieldProxy, 0,
  723. pFX->m_prs->m_nFields*sizeof(void*));
  724. pFX->m_prs->m_nProxyFields = pFX->m_prs->m_nFields;
  725. }
  726. // Allocate non-unicode string for SQLBindCol (not necessary on Requery)
  727. if (pFX->m_prs->m_pvFieldProxy[nField-1] == NULL)
  728. pFX->m_prs->m_pvFieldProxy[nField-1] = new CHAR[cbColumn+2];
  729. pvData = pFX->m_prs->m_pvFieldProxy[nField-1];
  730. #endif // _UNICODE
  731. AFX_SQL_SYNC(::SQLBindCol(pFX->m_prs->m_hstmt, (UWORD)nField,
  732. SQL_C_CHAR, pvData, cbColumn+1, plLength));
  733. value.ReleaseBuffer();
  734. if (!pFX->m_prs->Check(nRetCode))
  735. pFX->m_prs->ThrowDBException(nRetCode);
  736. // Add the member address to the field map
  737. pFX->m_prs->m_mapFieldIndex.SetAt(&value, (void*)nField);
  738. }
  739. return;
  740. #ifdef _UNICODE
  741. case CFieldExchange::BindFieldForUpdate:
  742. if (pFX->m_prs->m_nProxyFields != 0)
  743. {
  744. // Fill buffer (expected by SQLSetPos) with new field data
  745. USES_CONVERSION;
  746. LPSTR lpszData = (LPSTR)pFX->m_prs->m_pvFieldProxy[nField-1];
  747. lstrcpyA(lpszData, T2A((LPCTSTR)value));
  748. pFX->Default(szName, (void *)lpszData, plLength, SQL_C_CHAR,
  749. value.GetLength(), nMaxLength);
  750. }
  751. return;
  752. #endif // _UNICODE
  753. case CFieldExchange::Fixup:
  754. if (*plLength == SQL_NULL_DATA)
  755. {
  756. pFX->m_prs->SetNullFieldStatus(nField - 1);
  757. value.GetBufferSetLength(0);
  758. value.ReleaseBuffer();
  759. }
  760. else
  761. {
  762. #ifdef _UNICODE
  763. // Copy value out of the proxy
  764. value = (LPSTR)pFX->m_prs->m_pvFieldProxy[nField-1];
  765. #endif
  766. LPTSTR lpsz = value.GetBuffer(0);
  767. if (pFX->m_prs->m_pDatabase->m_bStripTrailingSpaces)
  768. {
  769. // find first trailing space
  770. LPTSTR lpszFirstTrailing = NULL;
  771. while (*lpsz != '\0')
  772. {
  773. if (*lpsz != ' ')
  774. lpszFirstTrailing = NULL;
  775. else
  776. {
  777. if (lpszFirstTrailing == NULL)
  778. lpszFirstTrailing = lpsz;
  779. }
  780. lpsz = _tcsinc(lpsz);
  781. }
  782. // truncate
  783. if (lpszFirstTrailing != NULL)
  784. *lpszFirstTrailing = '\0';
  785. }
  786. value.ReleaseBuffer();
  787. *plLength = value.GetLength();
  788. }
  789. return;
  790. case CFieldExchange::SetFieldNull:
  791. if ((pFX->m_pvField == NULL &&
  792. pFX->m_nFieldType == CFieldExchange::outputColumn) ||
  793. pFX->m_pvField == &value)
  794. {
  795. if (pFX->m_bField)
  796. {
  797. // Mark fields null
  798. pFX->m_prs->SetNullFieldStatus(nField - 1);
  799. // Set string 0 length
  800. value.GetBufferSetLength(0);
  801. value.ReleaseBuffer();
  802. *plLength = SQL_NULL_DATA;
  803. }
  804. else
  805. {
  806. pFX->m_prs->ClearNullFieldStatus(nField - 1);
  807. *plLength = SQL_NTS;
  808. }
  809. #ifdef _DEBUG
  810. pFX->m_nFieldFound = nField;
  811. #endif
  812. }
  813. return;
  814. #ifdef _UNICODE
  815. case CFieldExchange::NameValue:
  816. if (pFX->m_prs->IsFieldStatusDirty(nField - 1))
  817. {
  818. *pFX->m_pstr += szName;
  819. *pFX->m_pstr += '=';
  820. }
  821. // Fall through
  822. case CFieldExchange::Value:
  823. if (pFX->m_prs->IsFieldStatusDirty(nField - 1))
  824. {
  825. // Get the field data
  826. CODBCFieldInfo* pODBCInfo =
  827. &pFX->m_prs->m_rgODBCFieldInfos[nField - 1];
  828. LPSTR lpszData = (LPSTR)pFX->m_prs->m_pvFieldProxy[nField-1];
  829. if (pFX->m_prs->IsFieldStatusNull(nField - 1))
  830. {
  831. *plLength = SQL_NULL_DATA;
  832. }
  833. else
  834. {
  835. USES_CONVERSION;
  836. lstrcpyA(lpszData, T2A((LPCTSTR)value));
  837. *plLength = value.GetLength();
  838. }
  839. // If optimizing for bulk add, only need lengths & proxy set correctly
  840. if(!(pFX->m_prs->m_dwOptions & CRecordset::optimizeBulkAdd))
  841. {
  842. *pFX->m_pstr += '?';
  843. *pFX->m_pstr += pFX->m_lpszSeparator;
  844. pFX->m_nParamFields++;
  845. AFX_SQL_SYNC(::SQLBindParameter(pFX->m_hstmt,
  846. (UWORD)pFX->m_nParamFields, SQL_PARAM_INPUT,
  847. SQL_C_CHAR, pODBCInfo->m_nSQLType, nMaxLength,
  848. pODBCInfo->m_nScale, lpszData, 0, plLength));
  849. }
  850. }
  851. return;
  852. #endif // _UNICODE
  853. case CFieldExchange::MarkForAddNew:
  854. // can force writing of psuedo-null value (as a non-null) by setting field dirty
  855. if (!value.IsEmpty())
  856. {
  857. pFX->m_prs->SetDirtyFieldStatus(nField - 1);
  858. pFX->m_prs->ClearNullFieldStatus(nField - 1);
  859. }
  860. return;
  861. case CFieldExchange::MarkForUpdate:
  862. if (value.IsEmpty())
  863. pFX->m_prs->SetNullFieldStatus(nField - 1);
  864. else
  865. pFX->m_prs->ClearNullFieldStatus(nField - 1);
  866. pFX->Default(szName, &value, plLength,
  867. SQL_C_CHAR, value.GetLength(), nMaxLength);
  868. return;
  869. case CFieldExchange::LoadField:
  870. {
  871. // Get the field data
  872. CFieldInfo* pInfo = &pFX->m_prs->m_rgFieldInfos[nField - 1];
  873. CString* pStrCachedValue = (CString*)pInfo->m_pvDataCache;
  874. // Restore the status
  875. pFX->m_prs->SetFieldStatus(nField - 1, pInfo->m_bStatus);
  876. // If not NULL, restore the value and length
  877. if (!pFX->m_prs->IsFieldStatusNull(nField - 1))
  878. {
  879. value = *pStrCachedValue;
  880. *plLength = value.GetLength();
  881. #ifdef _UNICODE
  882. // Must restore proxy for correct WHERE CURRENT OF operation
  883. USES_CONVERSION;
  884. LPSTR lpszData = (LPSTR)pFX->m_prs->m_pvFieldProxy[nField-1];
  885. lstrcpyA(lpszData, T2A((LPCTSTR)value));
  886. #endif // _UNICODE
  887. }
  888. else
  889. {
  890. *plLength = SQL_NULL_DATA;
  891. }
  892. #ifdef _DEBUG
  893. // Buffer address must not change - ODBC's SQLBindCol depends upon this
  894. void* pvBind;
  895. #ifdef _UNICODE
  896. pvBind = pFX->m_prs->m_pvFieldProxy[nField-1];
  897. #else // !_UNICODE
  898. pvBind = value.GetBuffer(0);
  899. value.ReleaseBuffer();
  900. #endif
  901. if (pvBind != pInfo->m_pvBindAddress)
  902. {
  903. TRACE1("Error: CString buffer (column %u) address has changed!\n",
  904. nField);
  905. ASSERT(FALSE);
  906. }
  907. #endif // _DEBUG
  908. }
  909. return;
  910. case CFieldExchange::StoreField:
  911. AfxStoreField(*pFX->m_prs, nField, &value);
  912. return;
  913. case CFieldExchange::AllocCache:
  914. {
  915. CFieldInfo* pInfo = &pFX->m_prs->m_rgFieldInfos[nField - 1];
  916. pInfo->m_pvDataCache = new CString;
  917. pInfo->m_nDataType = AFX_RFX_TEXT;
  918. }
  919. return;
  920. #ifdef _DEBUG
  921. case CFieldExchange::DumpField:
  922. *pFX->m_pdcDump << "\n" << szName << " = " << value;
  923. return;
  924. #endif // _DEBUG
  925. }
  926. }
  927. void AFXAPI RFX_Int(CFieldExchange* pFX, LPCTSTR szName, int& value)
  928. {
  929. ASSERT(AfxIsValidAddress(pFX, sizeof(CFieldExchange)));
  930. ASSERT(AfxIsValidString(szName));
  931. UINT nField;
  932. if (!pFX->IsFieldType(&nField))
  933. return;
  934. LONG* plLength = pFX->m_prs->GetFieldLengthBuffer(
  935. nField - 1, pFX->m_nFieldType);
  936. switch (pFX->m_nOperation)
  937. {
  938. case CFieldExchange::BindFieldToColumn:
  939. {
  940. #ifdef _DEBUG
  941. // Assumes all bound fields BEFORE unbound fields
  942. CODBCFieldInfo* pODBCInfo =
  943. &pFX->m_prs->m_rgODBCFieldInfos[nField - 1];
  944. if (pODBCInfo->m_nSQLType != SQL_C_SHORT)
  945. {
  946. // Warn of possible field schema mismatch
  947. if (afxTraceFlags & traceDatabase)
  948. TRACE1("Warning: int converted from SQL type %ld.\n",
  949. pODBCInfo->m_nSQLType);
  950. }
  951. #endif // _DEBUG
  952. }
  953. // fall through
  954. default:
  955. LDefault:
  956. pFX->Default(szName, &value, plLength, SQL_C_LONG,
  957. sizeof(value), 5);
  958. return;
  959. case CFieldExchange::Fixup:
  960. if (*plLength == SQL_NULL_DATA)
  961. {
  962. pFX->m_prs->SetNullFieldStatus(nField - 1);
  963. value = AFX_RFX_INT_PSEUDO_NULL;
  964. }
  965. return;
  966. case CFieldExchange::SetFieldNull:
  967. if ((pFX->m_pvField == NULL &&
  968. pFX->m_nFieldType == CFieldExchange::outputColumn) ||
  969. pFX->m_pvField == &value)
  970. {
  971. if (pFX->m_bField)
  972. {
  973. // Mark fields null
  974. pFX->m_prs->SetNullFieldStatus(nField - 1);
  975. value = AFX_RFX_INT_PSEUDO_NULL;
  976. *plLength = SQL_NULL_DATA;
  977. }
  978. else
  979. {
  980. pFX->m_prs->ClearNullFieldStatus(nField - 1);
  981. *plLength = sizeof(value);
  982. }
  983. #ifdef _DEBUG
  984. pFX->m_nFieldFound = nField;
  985. #endif
  986. }
  987. return;
  988. case CFieldExchange::MarkForAddNew:
  989. // can force writing of psuedo-null value (as a non-null) by setting field dirty
  990. if (value != AFX_RFX_INT_PSEUDO_NULL)
  991. {
  992. pFX->m_prs->SetDirtyFieldStatus(nField - 1);
  993. pFX->m_prs->ClearNullFieldStatus(nField - 1);
  994. }
  995. return;
  996. case CFieldExchange::MarkForUpdate:
  997. if (value != AFX_RFX_INT_PSEUDO_NULL)
  998. pFX->m_prs->ClearNullFieldStatus(nField - 1);
  999. goto LDefault;
  1000. case CFieldExchange::AllocCache:
  1001. {
  1002. CFieldInfo* pInfo = &pFX->m_prs->m_rgFieldInfos[nField - 1];
  1003. // Data cached by value, no allocation necessary
  1004. pInfo->m_nDataType = AFX_RFX_INT;
  1005. }
  1006. return;
  1007. #ifdef _DEBUG
  1008. case CFieldExchange::DumpField:
  1009. *pFX->m_pdcDump << "\n" << szName << " = " << value;
  1010. return;
  1011. #endif // _DEBUG
  1012. }
  1013. }
  1014. void AFXAPI RFX_Long(CFieldExchange* pFX, LPCTSTR szName, long& value)
  1015. {
  1016. ASSERT(AfxIsValidAddress(pFX, sizeof(CFieldExchange)));
  1017. ASSERT(AfxIsValidString(szName));
  1018. UINT nField;
  1019. if (!pFX->IsFieldType(&nField))
  1020. return;
  1021. LONG* plLength = pFX->m_prs->GetFieldLengthBuffer(
  1022. nField - 1, pFX->m_nFieldType);
  1023. switch (pFX->m_nOperation)
  1024. {
  1025. case CFieldExchange::BindFieldToColumn:
  1026. {
  1027. #ifdef _DEBUG
  1028. // Assumes all bound fields BEFORE unbound fields
  1029. CODBCFieldInfo* pODBCInfo =
  1030. &pFX->m_prs->m_rgODBCFieldInfos[nField - 1];
  1031. if (pODBCInfo->m_nSQLType != SQL_C_LONG)
  1032. {
  1033. // Warn of possible field schema mismatch
  1034. if (afxTraceFlags & traceDatabase)
  1035. TRACE1("Warning: long converted from SQL type %ld.\n",
  1036. pODBCInfo->m_nSQLType);
  1037. }
  1038. #endif // _DEBUG
  1039. }
  1040. // fall through
  1041. default:
  1042. LDefault:
  1043. pFX->Default(szName, &value, plLength, SQL_C_LONG,
  1044. sizeof(value), 10);
  1045. return;
  1046. case CFieldExchange::Fixup:
  1047. if (*plLength == SQL_NULL_DATA)
  1048. {
  1049. pFX->m_prs->SetNullFieldStatus(nField - 1);
  1050. value = AFX_RFX_LONG_PSEUDO_NULL;
  1051. }
  1052. return;
  1053. case CFieldExchange::SetFieldNull:
  1054. if ((pFX->m_pvField == NULL &&
  1055. pFX->m_nFieldType == CFieldExchange::outputColumn) ||
  1056. pFX->m_pvField == &value)
  1057. {
  1058. if (pFX->m_bField)
  1059. {
  1060. // Mark fields null
  1061. pFX->m_prs->SetNullFieldStatus(nField - 1);
  1062. value = AFX_RFX_LONG_PSEUDO_NULL;
  1063. *plLength = SQL_NULL_DATA;
  1064. }
  1065. else
  1066. {
  1067. pFX->m_prs->ClearNullFieldStatus(nField - 1);
  1068. *plLength = sizeof(value);
  1069. }
  1070. #ifdef _DEBUG
  1071. pFX->m_nFieldFound = nField;
  1072. #endif
  1073. }
  1074. return;
  1075. case CFieldExchange::MarkForAddNew:
  1076. // can force writing of psuedo-null value (as a non-null) by setting field dirty
  1077. if (value != AFX_RFX_LONG_PSEUDO_NULL)
  1078. {
  1079. pFX->m_prs->SetDirtyFieldStatus(nField - 1);
  1080. pFX->m_prs->ClearNullFieldStatus(nField - 1);
  1081. }
  1082. return;
  1083. case CFieldExchange::MarkForUpdate:
  1084. if (value != AFX_RFX_LONG_PSEUDO_NULL)
  1085. pFX->m_prs->ClearNullFieldStatus(nField - 1);
  1086. goto LDefault;
  1087. case CFieldExchange::AllocCache:
  1088. {
  1089. CFieldInfo* pInfo = &pFX->m_prs->m_rgFieldInfos[nField - 1];
  1090. // Data cached by value, no allocation necessary
  1091. pInfo->m_nDataType = AFX_RFX_LONG;
  1092. }
  1093. return;
  1094. #ifdef _DEBUG
  1095. case CFieldExchange::DumpField:
  1096. *pFX->m_pdcDump << "\n" << szName << " = " << value;
  1097. return;
  1098. #endif // _DEBUG
  1099. }
  1100. }
  1101. void AFXAPI RFX_Byte(CFieldExchange* pFX, LPCTSTR szName, BYTE& value)
  1102. {
  1103. ASSERT(AfxIsValidAddress(pFX, sizeof(CFieldExchange)));
  1104. ASSERT(AfxIsValidString(szName));
  1105. UINT nField;
  1106. if (!pFX->IsFieldType(&nField))
  1107. return;
  1108. LONG* plLength = pFX->m_prs->GetFieldLengthBuffer(
  1109. nField - 1, pFX->m_nFieldType);
  1110. switch (pFX->m_nOperation)
  1111. {
  1112. case CFieldExchange::BindFieldToColumn:
  1113. {
  1114. #ifdef _DEBUG
  1115. // Assumes all bound fields BEFORE unbound fields
  1116. CODBCFieldInfo* pODBCInfo =
  1117. &pFX->m_prs->m_rgODBCFieldInfos[nField - 1];
  1118. if (pODBCInfo->m_nSQLType != SQL_TINYINT)
  1119. {
  1120. // Warn of possible field schema mismatch
  1121. if (afxTraceFlags & traceDatabase)
  1122. TRACE1("Warning: BYTE converted from SQL type %ld.\n",
  1123. pODBCInfo->m_nSQLType);
  1124. }
  1125. #endif // _DEBUG
  1126. }
  1127. // fall through
  1128. default:
  1129. LDefault:
  1130. pFX->Default(szName, &value, plLength, SQL_TINYINT,
  1131. sizeof(value), 3);
  1132. break;
  1133. case CFieldExchange::Fixup:
  1134. if (*plLength == SQL_NULL_DATA)
  1135. {
  1136. pFX->m_prs->SetNullFieldStatus(nField - 1);
  1137. value = AFX_RFX_BYTE_PSEUDO_NULL;
  1138. }
  1139. return;
  1140. case CFieldExchange::SetFieldNull:
  1141. if ((pFX->m_pvField == NULL &&
  1142. pFX->m_nFieldType == CFieldExchange::outputColumn) ||
  1143. pFX->m_pvField == &value)
  1144. {
  1145. if (pFX->m_bField)
  1146. {
  1147. // Mark fields null
  1148. pFX->m_prs->SetNullFieldStatus(nField - 1);
  1149. value = AFX_RFX_BYTE_PSEUDO_NULL;
  1150. *plLength = SQL_NULL_DATA;
  1151. }
  1152. else
  1153. {
  1154. pFX->m_prs->ClearNullFieldStatus(nField - 1);
  1155. *plLength = sizeof(value);
  1156. }
  1157. #ifdef _DEBUG
  1158. pFX->m_nFieldFound = nField;
  1159. #endif
  1160. }
  1161. return;
  1162. case CFieldExchange::MarkForAddNew:
  1163. // can force writing of psuedo-null value (as a non-null) by setting field dirty
  1164. if (value != AFX_RFX_BYTE_PSEUDO_NULL)
  1165. {
  1166. pFX->m_prs->SetDirtyFieldStatus(nField - 1);
  1167. pFX->m_prs->ClearNullFieldStatus(nField - 1);
  1168. }
  1169. return;
  1170. case CFieldExchange::MarkForUpdate:
  1171. if (value != AFX_RFX_BYTE_PSEUDO_NULL)
  1172. pFX->m_prs->ClearNullFieldStatus(nField - 1);
  1173. goto LDefault;
  1174. case CFieldExchange::AllocCache:
  1175. {
  1176. CFieldInfo* pInfo = &pFX->m_prs->m_rgFieldInfos[nField - 1];
  1177. // Data cached by value, no allocation necessary
  1178. pInfo->m_nDataType = AFX_RFX_BYTE;
  1179. }
  1180. return;
  1181. #ifdef _DEBUG
  1182. case CFieldExchange::DumpField:
  1183. *pFX->m_pdcDump << "\n" << szName << " = " << value;
  1184. return;
  1185. #endif // _DEBUG
  1186. }
  1187. }
  1188. void AFXAPI RFX_Bool(CFieldExchange* pFX, LPCTSTR szName, BOOL& value)
  1189. {
  1190. ASSERT(AfxIsValidAddress(pFX, sizeof(CFieldExchange)));
  1191. ASSERT(AfxIsValidString(szName));
  1192. UINT nField;
  1193. if (!pFX->IsFieldType(&nField))
  1194. return;
  1195. LONG* plLength = pFX->m_prs->GetFieldLengthBuffer(
  1196. nField - 1, pFX->m_nFieldType);
  1197. switch (pFX->m_nOperation)
  1198. {
  1199. case CFieldExchange::BindFieldToColumn:
  1200. {
  1201. #ifdef _DEBUG
  1202. // Assumes all bound fields BEFORE unbound fields
  1203. CODBCFieldInfo* pODBCInfo =
  1204. &pFX->m_prs->m_rgODBCFieldInfos[nField - 1];
  1205. if (pODBCInfo->m_nSQLType != SQL_BIT)
  1206. {
  1207. // Warn of possible field schema mismatch
  1208. if (afxTraceFlags & traceDatabase)
  1209. TRACE1("Warning: BOOL converted from SQL type %ld.\n",
  1210. pODBCInfo->m_nSQLType);
  1211. }
  1212. #endif // _DEBUG
  1213. }
  1214. // Fall through
  1215. default:
  1216. LDefault:
  1217. pFX->Default(szName, &value, plLength, SQL_BIT,
  1218. sizeof(value), 1);
  1219. return;
  1220. case CFieldExchange::Fixup:
  1221. if (*plLength == SQL_NULL_DATA)
  1222. {
  1223. pFX->m_prs->SetNullFieldStatus(nField - 1);
  1224. value = AFX_RFX_BOOL_PSEUDO_NULL;
  1225. }
  1226. else
  1227. // Cast BYTE into BOOL (int)
  1228. value = *(BYTE *)&value;
  1229. return;
  1230. case CFieldExchange::SetFieldNull:
  1231. if ((pFX->m_pvField == NULL &&
  1232. pFX->m_nFieldType == CFieldExchange::outputColumn) ||
  1233. pFX->m_pvField == &value)
  1234. {
  1235. if (pFX->m_bField)
  1236. {
  1237. // Mark fields null
  1238. pFX->m_prs->SetNullFieldStatus(nField - 1);
  1239. value = AFX_RFX_BOOL_PSEUDO_NULL;
  1240. *plLength = SQL_NULL_DATA;
  1241. }
  1242. else
  1243. {
  1244. pFX->m_prs->ClearNullFieldStatus(nField - 1);
  1245. *plLength = sizeof(value);
  1246. }
  1247. #ifdef _DEBUG
  1248. pFX->m_nFieldFound = nField;
  1249. #endif
  1250. }
  1251. return;
  1252. case CFieldExchange::MarkForAddNew:
  1253. // can force writing of psuedo-null value (as a non-null) by setting field dirty
  1254. if (value != AFX_RFX_BOOL_PSEUDO_NULL)
  1255. {
  1256. pFX->m_prs->SetDirtyFieldStatus(nField - 1);
  1257. pFX->m_prs->ClearNullFieldStatus(nField - 1);
  1258. }
  1259. return;
  1260. case CFieldExchange::MarkForUpdate:
  1261. if (value != AFX_RFX_BOOL_PSEUDO_NULL)
  1262. pFX->m_prs->ClearNullFieldStatus(nField - 1);
  1263. goto LDefault;
  1264. case CFieldExchange::AllocCache:
  1265. {
  1266. CFieldInfo* pInfo = &pFX->m_prs->m_rgFieldInfos[nField - 1];
  1267. // Data cached by value, no allocation necessary
  1268. pInfo->m_nDataType = AFX_RFX_BOOL;
  1269. }
  1270. return;
  1271. #ifdef _DEBUG
  1272. case CFieldExchange::DumpField:
  1273. *pFX->m_pdcDump << "\n" << szName << " = " << value;
  1274. return;
  1275. #endif // _DEBUG
  1276. }
  1277. }
  1278. // Note: CByteArray.m_pData must not be changed. This address is registered
  1279. // with ODBC and must remain valid until the recordset is released.
  1280. void AFXAPI RFX_Binary(CFieldExchange* pFX, LPCTSTR szName,
  1281. CByteArray& value, int nMaxLength)
  1282. {
  1283. ASSERT(AfxIsValidAddress(pFX, sizeof(CFieldExchange)));
  1284. ASSERT(AfxIsValidString(szName));
  1285. RETCODE nRetCode;
  1286. UINT nField;
  1287. if (!pFX->IsFieldType(&nField))
  1288. return;
  1289. LONG* plLength = pFX->m_prs->GetFieldLengthBuffer(
  1290. nField - 1, pFX->m_nFieldType);
  1291. BOOL bByRef = FALSE;
  1292. switch (pFX->m_nOperation)
  1293. {
  1294. default:
  1295. LDefault:
  1296. {
  1297. void* pvData = NULL;
  1298. if (value.GetSize() > 0)
  1299. {
  1300. if (bByRef)
  1301. pvData = &value;
  1302. else
  1303. pvData = &value[0];
  1304. }
  1305. pFX->Default(szName, pvData, plLength, SQL_C_BINARY,
  1306. (int)value.GetSize(), (UINT)value.GetSize());
  1307. }
  1308. return;
  1309. case CFieldExchange::BindFieldToColumn:
  1310. {
  1311. // Assumes all bound fields BEFORE unbound fields
  1312. CODBCFieldInfo* pODBCInfo =
  1313. &pFX->m_prs->m_rgODBCFieldInfos[nField - 1];
  1314. UDWORD cbColumn = pODBCInfo->m_nPrecision;
  1315. #ifdef _DEBUG
  1316. if (pODBCInfo->m_nSQLType != SQL_BINARY &&
  1317. pODBCInfo->m_nSQLType != SQL_VARBINARY &&
  1318. pODBCInfo->m_nSQLType != SQL_LONGVARBINARY)
  1319. {
  1320. // Warn of possible field schema mismatch
  1321. if (afxTraceFlags & traceDatabase)
  1322. TRACE1("Warning: CByteArray converted from SQL type %ld.\n",
  1323. pODBCInfo->m_nSQLType);
  1324. }
  1325. #endif // _DEBUG
  1326. // Constrain to user specified max length
  1327. if (cbColumn > (UINT)nMaxLength)
  1328. cbColumn = nMaxLength;
  1329. value.SetSize(cbColumn);
  1330. AFX_SQL_SYNC(::SQLBindCol(pFX->m_prs->m_hstmt, (UWORD)nField,
  1331. SQL_C_BINARY, &value[0], (LONG)cbColumn, plLength));
  1332. if (!pFX->m_prs->Check(nRetCode))
  1333. pFX->m_prs->ThrowDBException(nRetCode);
  1334. // Add the member address to the field map
  1335. pFX->m_prs->m_mapFieldIndex.SetAt(&value, (void*)nField);
  1336. }
  1337. return;
  1338. case CFieldExchange::Fixup:
  1339. if (*plLength == SQL_NULL_DATA)
  1340. {
  1341. pFX->m_prs->SetNullFieldStatus(nField - 1);
  1342. value.SetSize(1);
  1343. value[0] = AFX_RFX_BYTE_PSEUDO_NULL;
  1344. }
  1345. else
  1346. {
  1347. ASSERT(*plLength <= (LONG)nMaxLength);
  1348. ((CDBByteArray&)value).SetLength((UINT)*plLength);
  1349. }
  1350. return;
  1351. case CFieldExchange::SetFieldNull:
  1352. if ((pFX->m_pvField == NULL &&
  1353. pFX->m_nFieldType == CFieldExchange::outputColumn) ||
  1354. pFX->m_pvField == &value)
  1355. {
  1356. if (pFX->m_bField)
  1357. {
  1358. // Mark fields null
  1359. pFX->m_prs->SetNullFieldStatus(nField - 1);
  1360. value.SetSize(1);
  1361. value[0] = AFX_RFX_BYTE_PSEUDO_NULL;
  1362. *plLength = SQL_NULL_DATA;
  1363. }
  1364. else
  1365. {
  1366. pFX->m_prs->ClearNullFieldStatus(nField - 1);
  1367. *plLength = value.GetSize();
  1368. }
  1369. #ifdef _DEBUG
  1370. pFX->m_nFieldFound = nField;
  1371. #endif
  1372. }
  1373. return;
  1374. case CFieldExchange::MarkForAddNew:
  1375. // can force writing of psuedo-null value (as a non-null) by setting field dirty
  1376. if (value.GetSize() != 1 || value[0] != AFX_RFX_BYTE_PSEUDO_NULL)
  1377. {
  1378. pFX->m_prs->SetDirtyFieldStatus(nField - 1);
  1379. pFX->m_prs->ClearNullFieldStatus(nField - 1);
  1380. }
  1381. return;
  1382. case CFieldExchange::MarkForUpdate:
  1383. if (value.GetSize() != 1 || value[0] != AFX_RFX_BYTE_PSEUDO_NULL)
  1384. pFX->m_prs->ClearNullFieldStatus(nField - 1);
  1385. bByRef = TRUE;
  1386. goto LDefault;
  1387. case CFieldExchange::StoreField:
  1388. AfxStoreField(*pFX->m_prs, nField, &value);
  1389. return;
  1390. case CFieldExchange::LoadField:
  1391. AfxLoadField(*pFX->m_prs, nField, &value, plLength);
  1392. return;
  1393. case CFieldExchange::AllocCache:
  1394. {
  1395. CFieldInfo* pInfo = &pFX->m_prs->m_rgFieldInfos[nField - 1];
  1396. pInfo->m_pvDataCache = new CByteArray;
  1397. pInfo->m_nDataType = AFX_RFX_BINARY;
  1398. }
  1399. return;
  1400. #ifdef _DEBUG
  1401. case CFieldExchange::DumpField:
  1402. *pFX->m_pdcDump << "\n" << szName << ":";
  1403. value.Dump(*pFX->m_pdcDump);
  1404. return;
  1405. #endif // _DEBUG
  1406. }
  1407. }
  1408. void AFXAPI RFX_Date(CFieldExchange* pFX, LPCTSTR szName, CTime& value)
  1409. {
  1410. ASSERT(AfxIsValidAddress(pFX, sizeof(CFieldExchange)));
  1411. ASSERT(AfxIsValidString(szName));
  1412. RETCODE nRetCode;
  1413. UINT nField;
  1414. if (!pFX->IsFieldType(&nField))
  1415. return;
  1416. LONG* plLength = pFX->m_prs->GetFieldLengthBuffer(
  1417. nField - 1, pFX->m_nFieldType);
  1418. switch (pFX->m_nOperation)
  1419. {
  1420. default:
  1421. LDefault:
  1422. pFX->Default(szName, &value, plLength, SQL_C_TIMESTAMP,
  1423. sizeof(value), TIMESTAMP_PRECISION);
  1424. return;
  1425. case CFieldExchange::BindParam:
  1426. {
  1427. TIMESTAMP_STRUCT* pts;
  1428. pFX->m_prs->m_bRebindParams = TRUE;
  1429. if (pFX->m_prs->IsParamStatusNull(nField - 1))
  1430. {
  1431. pts = NULL;
  1432. *plLength = SQL_NULL_DATA;
  1433. }
  1434. else
  1435. {
  1436. // Allocate proxy array if necessary
  1437. if (pFX->m_prs->m_pvParamProxy == NULL)
  1438. {
  1439. pFX->m_prs->m_pvParamProxy = new void*[pFX->m_prs->m_nParams];
  1440. memset(pFX->m_prs->m_pvParamProxy, 0,
  1441. pFX->m_prs->m_nParams*sizeof(void*));
  1442. pFX->m_prs->m_nProxyParams = pFX->m_prs->m_nParams;
  1443. }
  1444. // Allocate TIMESTAMP_STRUCT if necessary for SQLBindParameter
  1445. if (pFX->m_prs->m_pvParamProxy[nField-1] == NULL)
  1446. {
  1447. pts = new TIMESTAMP_STRUCT;
  1448. pFX->m_prs->m_pvParamProxy[nField-1] = pts;
  1449. }
  1450. else
  1451. pts = (TIMESTAMP_STRUCT *)pFX->m_prs->m_pvParamProxy[nField-1];
  1452. pts->year = (SWORD)value.GetYear();
  1453. pts->month = (UWORD)value.GetMonth();
  1454. pts->day = (UWORD)value.GetDay();
  1455. pts->hour = (UWORD)value.GetHour();
  1456. pts->minute = (UWORD)value.GetMinute();
  1457. pts->second = (UWORD)value.GetSecond();
  1458. pts->fraction = 0;
  1459. *plLength = sizeof(TIMESTAMP_STRUCT);
  1460. }
  1461. AFX_SQL_SYNC(::SQLBindParameter(pFX->m_hstmt, (UWORD)nField,
  1462. (SWORD)pFX->m_nFieldType, SQL_C_TIMESTAMP, SQL_C_TIMESTAMP,
  1463. TIMESTAMP_PRECISION, 0, pts, 0, plLength));
  1464. if (nRetCode != SQL_SUCCESS)
  1465. pFX->m_prs->ThrowDBException(nRetCode, pFX->m_hstmt);
  1466. // Add the member address to the param map
  1467. pFX->m_prs->m_mapParamIndex.SetAt(&value, (void*)nField);
  1468. }
  1469. return;
  1470. case CFieldExchange::RebindParam:
  1471. {
  1472. *plLength = pFX->m_prs->IsParamStatusNull(nField - 1) ?
  1473. SQL_NULL_DATA : sizeof(TIMESTAMP_STRUCT);
  1474. if (pFX->m_prs->m_nProxyParams != 0)
  1475. {
  1476. // Fill buffer (expected by SQLBindParameter) with new param data
  1477. TIMESTAMP_STRUCT* pts;
  1478. pts = (TIMESTAMP_STRUCT *)pFX->m_prs->m_pvParamProxy[nField-1];
  1479. pts->year = (SWORD)value.GetYear();
  1480. pts->month = (UWORD)value.GetMonth();
  1481. pts->day = (UWORD)value.GetDay();
  1482. pts->hour = (UWORD)value.GetHour();
  1483. pts->minute = (UWORD)value.GetMinute();
  1484. pts->second = (UWORD)value.GetSecond();
  1485. pts->fraction = 0;
  1486. }
  1487. }
  1488. return;
  1489. case CFieldExchange::BindFieldToColumn:
  1490. {
  1491. #ifdef _DEBUG
  1492. // Assumes all bound fields BEFORE unbound fields
  1493. CODBCFieldInfo* pODBCInfo =
  1494. &pFX->m_prs->m_rgODBCFieldInfos[nField - 1];
  1495. if (pODBCInfo->m_nSQLType != SQL_DATE &&
  1496. pODBCInfo->m_nSQLType != SQL_TIME &&
  1497. pODBCInfo->m_nSQLType != SQL_TIMESTAMP)
  1498. {
  1499. // Warn of possible field schema mismatch
  1500. if (afxTraceFlags & traceDatabase)
  1501. TRACE1("Warning: CTime converted from SQL type %ld.\n",
  1502. pODBCInfo->m_nSQLType);
  1503. }
  1504. #endif // _DEBUG
  1505. // Allocate proxy array if necessary
  1506. if (pFX->m_prs->m_pvFieldProxy == NULL)
  1507. {
  1508. pFX->m_prs->m_pvFieldProxy = new void*[pFX->m_prs->m_nFields];
  1509. memset(pFX->m_prs->m_pvFieldProxy, 0,
  1510. pFX->m_prs->m_nFields*sizeof(void*));
  1511. pFX->m_prs->m_nProxyFields = pFX->m_prs->m_nFields;
  1512. }
  1513. // Allocate TIMESTAMP_STRUCT for SQLBindCol (not necessary on Requery)
  1514. if (pFX->m_prs->m_pvFieldProxy[nField-1] == NULL)
  1515. pFX->m_prs->m_pvFieldProxy[nField-1] = new TIMESTAMP_STRUCT;
  1516. AFX_SQL_SYNC(::SQLBindCol(pFX->m_prs->m_hstmt, (UWORD)nField,
  1517. SQL_C_TIMESTAMP, pFX->m_prs->m_pvFieldProxy[nField-1],
  1518. sizeof(TIMESTAMP_STRUCT), plLength));
  1519. if (!pFX->m_prs->Check(nRetCode))
  1520. pFX->m_prs->ThrowDBException(nRetCode);
  1521. // Add the member address to the field map
  1522. pFX->m_prs->m_mapFieldIndex.SetAt(&value, (void*)nField);
  1523. }
  1524. return;
  1525. case CFieldExchange::BindFieldForUpdate:
  1526. if (pFX->m_prs->m_nProxyFields != 0)
  1527. {
  1528. // Fill buffer (expected by SQLSetPos) with new field data
  1529. TIMESTAMP_STRUCT* pts;
  1530. pts = (TIMESTAMP_STRUCT *)pFX->m_prs->m_pvFieldProxy[nField-1];
  1531. pts->year = (SWORD)value.GetYear();
  1532. pts->month = (UWORD)value.GetMonth();
  1533. pts->day = (UWORD)value.GetDay();
  1534. pts->hour = (UWORD)value.GetHour();
  1535. pts->minute = (UWORD)value.GetMinute();
  1536. pts->second = (UWORD)value.GetSecond();
  1537. pts->fraction = 0;
  1538. pFX->Default(szName, (void *)pts, plLength, SQL_C_TIMESTAMP,
  1539. sizeof(TIMESTAMP_STRUCT), TIMESTAMP_PRECISION);
  1540. }
  1541. return;
  1542. case CFieldExchange::Fixup:
  1543. if (*plLength == SQL_NULL_DATA)
  1544. {
  1545. pFX->m_prs->SetNullFieldStatus(nField - 1);
  1546. value = AFX_RFX_DATE_PSEUDO_NULL;
  1547. }
  1548. else
  1549. {
  1550. TIMESTAMP_STRUCT* pts =
  1551. (TIMESTAMP_STRUCT*)pFX->m_prs->m_pvFieldProxy[nField-1];
  1552. if (pts->year < 1970 || pts->year > 2038)
  1553. {
  1554. // Time value out of range, return NULL
  1555. #ifdef _DEBUG
  1556. if (afxTraceFlags & traceDatabase)
  1557. TRACE0("Warning: date value out of range, returning NULL value.\n");
  1558. #endif
  1559. pFX->m_prs->SetNullFieldStatus(nField - 1);
  1560. value = AFX_RFX_DATE_PSEUDO_NULL;
  1561. }
  1562. else
  1563. {
  1564. #ifdef _DEBUG
  1565. if ((afxTraceFlags & traceDatabase) && pts->fraction != 0)
  1566. TRACE0("Warning: ignoring milliseconds.\n");
  1567. #endif
  1568. value = CTime(pts->year, pts->month, pts->day,
  1569. pts->hour, pts->minute, pts->second);
  1570. }
  1571. }
  1572. return;
  1573. case CFieldExchange::NameValue:
  1574. if (pFX->m_prs->IsFieldStatusDirty(nField - 1))
  1575. {
  1576. *pFX->m_pstr += szName;
  1577. *pFX->m_pstr += '=';
  1578. }
  1579. // Fall through
  1580. case CFieldExchange::Value:
  1581. if (pFX->m_prs->IsFieldStatusDirty(nField - 1))
  1582. {
  1583. TIMESTAMP_STRUCT* pts =
  1584. (TIMESTAMP_STRUCT*)pFX->m_prs->m_pvFieldProxy[nField-1];
  1585. if (pFX->m_prs->IsFieldStatusNull(nField - 1))
  1586. {
  1587. *plLength = SQL_NULL_DATA;
  1588. }
  1589. else
  1590. {
  1591. pts->year = (SWORD)value.GetYear();
  1592. pts->month = (UWORD)value.GetMonth();
  1593. pts->day = (UWORD)value.GetDay();
  1594. pts->hour = (UWORD)value.GetHour();
  1595. pts->minute = (UWORD)value.GetMinute();
  1596. pts->second = (UWORD)value.GetSecond();
  1597. pts->fraction = 0;
  1598. *plLength = sizeof(TIMESTAMP_STRUCT);
  1599. }
  1600. // If optimizing for bulk add, only need lengths & proxy set correctly
  1601. if(!(pFX->m_prs->m_dwOptions & CRecordset::optimizeBulkAdd))
  1602. {
  1603. *pFX->m_pstr += '?';
  1604. *pFX->m_pstr += pFX->m_lpszSeparator;
  1605. pFX->m_nParamFields++;
  1606. // Assumes all bound fields BEFORE unbound fields
  1607. CODBCFieldInfo* pODBCInfo =
  1608. &pFX->m_prs->m_rgODBCFieldInfos[nField - 1];
  1609. AFX_SQL_SYNC(::SQLBindParameter(pFX->m_hstmt,
  1610. (UWORD)pFX->m_nParamFields, SQL_PARAM_INPUT,
  1611. SQL_C_TIMESTAMP, pODBCInfo->m_nSQLType,
  1612. TIMESTAMP_PRECISION, 0, pts, 0, plLength));
  1613. }
  1614. }
  1615. return;
  1616. case CFieldExchange::SetFieldNull:
  1617. if ((pFX->m_pvField == NULL &&
  1618. pFX->m_nFieldType == CFieldExchange::outputColumn) ||
  1619. pFX->m_pvField == &value)
  1620. {
  1621. if (pFX->m_bField)
  1622. {
  1623. // Mark fields null
  1624. pFX->m_prs->SetNullFieldStatus(nField - 1);
  1625. value = AFX_RFX_DATE_PSEUDO_NULL;
  1626. *plLength = SQL_NULL_DATA;
  1627. }
  1628. else
  1629. {
  1630. pFX->m_prs->ClearNullFieldStatus(nField - 1);
  1631. *plLength = sizeof(TIMESTAMP_STRUCT);
  1632. }
  1633. #ifdef _DEBUG
  1634. pFX->m_nFieldFound = nField;
  1635. #endif
  1636. }
  1637. return;
  1638. case CFieldExchange::MarkForAddNew:
  1639. {
  1640. // can force writing of psuedo-null value (as a non-null) by setting field dirty
  1641. CTime timeNull = AFX_RFX_DATE_PSEUDO_NULL;
  1642. if (value != timeNull)
  1643. {
  1644. pFX->m_prs->SetDirtyFieldStatus(nField - 1);
  1645. pFX->m_prs->ClearNullFieldStatus(nField - 1);
  1646. }
  1647. }
  1648. return;
  1649. case CFieldExchange::MarkForUpdate:
  1650. {
  1651. CTime timeNull = AFX_RFX_DATE_PSEUDO_NULL;
  1652. if (value != timeNull)
  1653. pFX->m_prs->ClearNullFieldStatus(nField - 1);
  1654. }
  1655. goto LDefault;
  1656. case CFieldExchange::LoadField:
  1657. {
  1658. // Get the field data
  1659. CFieldInfo* pInfo = &pFX->m_prs->m_rgFieldInfos[nField - 1];
  1660. // Restore the status
  1661. pFX->m_prs->SetFieldStatus(nField - 1, pInfo->m_bStatus);
  1662. // If not NULL, restore the value, length and proxy
  1663. if (!pFX->m_prs->IsFieldStatusNull(nField - 1))
  1664. {
  1665. AfxCopyValueByRef(pInfo->m_pvDataCache, &value,
  1666. plLength, pInfo->m_nDataType);
  1667. // Restore proxy for correct WHERE CURRENT OF operations
  1668. TIMESTAMP_STRUCT* pts =
  1669. (TIMESTAMP_STRUCT*)pFX->m_prs->m_pvFieldProxy[nField-1];
  1670. pts->year = (SWORD)value.GetYear();
  1671. pts->month = (UWORD)value.GetMonth();
  1672. pts->day = (UWORD)value.GetDay();
  1673. pts->hour = (UWORD)value.GetHour();
  1674. pts->minute = (UWORD)value.GetMinute();
  1675. pts->second = (UWORD)value.GetSecond();
  1676. pts->fraction = 0;
  1677. }
  1678. else
  1679. *plLength = SQL_NULL_DATA;
  1680. #ifdef _DEBUG
  1681. // Buffer address must not change - ODBC's SQLBindCol depends upon this
  1682. if (pInfo->m_pvBindAddress != pFX->m_prs->m_pvFieldProxy[nField-1])
  1683. {
  1684. TRACE1("Error: CString buffer (column %u) address has changed!\n",
  1685. nField);
  1686. ASSERT(FALSE);
  1687. }
  1688. #endif // _DEBUG
  1689. }
  1690. return;
  1691. case CFieldExchange::AllocCache:
  1692. {
  1693. CFieldInfo* pInfo = &pFX->m_prs->m_rgFieldInfos[nField - 1];
  1694. pInfo->m_pvDataCache = new CTime;
  1695. pInfo->m_nDataType = AFX_RFX_DATE;
  1696. }
  1697. return;
  1698. #ifdef _DEBUG
  1699. case CFieldExchange::DumpField:
  1700. *pFX->m_pdcDump << "\n" << szName << " = " << value;
  1701. return;
  1702. #endif // _DEBUG
  1703. }
  1704. }
  1705. void AFXAPI RFX_Date(CFieldExchange* pFX, LPCTSTR szName,
  1706. TIMESTAMP_STRUCT& value)
  1707. {
  1708. ASSERT(AfxIsValidAddress(pFX, sizeof(CFieldExchange)));
  1709. ASSERT(AfxIsValidString(szName));
  1710. UINT nField;
  1711. if (!pFX->IsFieldType(&nField))
  1712. return;
  1713. LONG* plLength = pFX->m_prs->GetFieldLengthBuffer(
  1714. nField - 1, pFX->m_nFieldType);
  1715. switch (pFX->m_nOperation)
  1716. {
  1717. case CFieldExchange::BindFieldToColumn:
  1718. {
  1719. #ifdef _DEBUG
  1720. // Assumes all bound fields BEFORE unbound fields
  1721. CODBCFieldInfo* pODBCInfo =
  1722. &pFX->m_prs->m_rgODBCFieldInfos[nField - 1];
  1723. if (pODBCInfo->m_nSQLType != SQL_DATE &&
  1724. pODBCInfo->m_nSQLType != SQL_TIME &&
  1725. pODBCInfo->m_nSQLType != SQL_TIMESTAMP)
  1726. {
  1727. // Warn of possible field schema mismatch
  1728. if (afxTraceFlags & traceDatabase)
  1729. TRACE1("Warning: TIMESTAMP_STRUCT converted from SQL type %ld.\n",
  1730. pODBCInfo->m_nSQLType);
  1731. }
  1732. #endif // _DEBUG
  1733. // fall through
  1734. }
  1735. default:
  1736. LDefault:
  1737. pFX->Default(szName, &value, plLength, SQL_C_TIMESTAMP,
  1738. sizeof(value), TIMESTAMP_PRECISION);
  1739. return;
  1740. case CFieldExchange::Fixup:
  1741. if (*plLength == SQL_NULL_DATA)
  1742. {
  1743. pFX->m_prs->SetNullFieldStatus(nField - 1);
  1744. value.year = AFX_RFX_TIMESTAMP_PSEUDO_NULL;
  1745. value.month = AFX_RFX_TIMESTAMP_PSEUDO_NULL;
  1746. value.day = AFX_RFX_TIMESTAMP_PSEUDO_NULL;
  1747. value.hour = AFX_RFX_TIMESTAMP_PSEUDO_NULL;
  1748. value.minute = AFX_RFX_TIMESTAMP_PSEUDO_NULL;
  1749. value.second = AFX_RFX_TIMESTAMP_PSEUDO_NULL;
  1750. value.fraction = AFX_RFX_TIMESTAMP_PSEUDO_NULL;
  1751. }
  1752. return;
  1753. case CFieldExchange::SetFieldNull:
  1754. if ((pFX->m_pvField == NULL &&
  1755. pFX->m_nFieldType == CFieldExchange::outputColumn) ||
  1756. pFX->m_pvField == &value)
  1757. {
  1758. if (pFX->m_bField)
  1759. {
  1760. // Mark fields null
  1761. pFX->m_prs->SetNullFieldStatus(nField - 1);
  1762. value.year = AFX_RFX_TIMESTAMP_PSEUDO_NULL;
  1763. value.month = AFX_RFX_TIMESTAMP_PSEUDO_NULL;
  1764. value.day = AFX_RFX_TIMESTAMP_PSEUDO_NULL;
  1765. value.hour = AFX_RFX_TIMESTAMP_PSEUDO_NULL;
  1766. value.minute = AFX_RFX_TIMESTAMP_PSEUDO_NULL;
  1767. value.second = AFX_RFX_TIMESTAMP_PSEUDO_NULL;
  1768. value.fraction = AFX_RFX_TIMESTAMP_PSEUDO_NULL;
  1769. *plLength = SQL_NULL_DATA;
  1770. }
  1771. else
  1772. {
  1773. pFX->m_prs->ClearNullFieldStatus(nField - 1);
  1774. *plLength = sizeof(TIMESTAMP_STRUCT);
  1775. }
  1776. #ifdef _DEBUG
  1777. pFX->m_nFieldFound = nField;
  1778. #endif
  1779. }
  1780. return;
  1781. case CFieldExchange::MarkForAddNew:
  1782. // can force writing of psuedo-null value (as a non-null) by setting field dirty
  1783. if (!(value.year == AFX_RFX_TIMESTAMP_PSEUDO_NULL &&
  1784. value.month == AFX_RFX_TIMESTAMP_PSEUDO_NULL &&
  1785. value.day == AFX_RFX_TIMESTAMP_PSEUDO_NULL &&
  1786. value.hour == AFX_RFX_TIMESTAMP_PSEUDO_NULL &&
  1787. value.minute == AFX_RFX_TIMESTAMP_PSEUDO_NULL &&
  1788. value.second == AFX_RFX_TIMESTAMP_PSEUDO_NULL &&
  1789. value.fraction == AFX_RFX_TIMESTAMP_PSEUDO_NULL ))
  1790. {
  1791. pFX->m_prs->SetDirtyFieldStatus(nField - 1);
  1792. pFX->m_prs->ClearNullFieldStatus(nField - 1);
  1793. }
  1794. return;
  1795. case CFieldExchange::MarkForUpdate:
  1796. if (!(value.year == AFX_RFX_TIMESTAMP_PSEUDO_NULL &&
  1797. value.month == AFX_RFX_TIMESTAMP_PSEUDO_NULL &&
  1798. value.day == AFX_RFX_TIMESTAMP_PSEUDO_NULL &&
  1799. value.hour == AFX_RFX_TIMESTAMP_PSEUDO_NULL &&
  1800. value.minute == AFX_RFX_TIMESTAMP_PSEUDO_NULL &&
  1801. value.second == AFX_RFX_TIMESTAMP_PSEUDO_NULL &&
  1802. value.fraction == AFX_RFX_TIMESTAMP_PSEUDO_NULL ))
  1803. {
  1804. pFX->m_prs->ClearNullFieldStatus(nField - 1);
  1805. }
  1806. goto LDefault;
  1807. case CFieldExchange::AllocCache:
  1808. {
  1809. CFieldInfo* pInfo = &pFX->m_prs->m_rgFieldInfos[nField - 1];
  1810. pInfo->m_pvDataCache = new TIMESTAMP_STRUCT;
  1811. pInfo->m_nDataType = AFX_RFX_TIMESTAMP;
  1812. }
  1813. return;
  1814. #ifdef _DEBUG
  1815. case CFieldExchange::DumpField:
  1816. *pFX->m_pdcDump << "\n" << szName << ".year = " << (int)value.year;
  1817. *pFX->m_pdcDump << "\n" << szName << ".month = " << value.month;
  1818. *pFX->m_pdcDump << "\n" << szName << ".day = " << value.day;
  1819. *pFX->m_pdcDump << "\n" << szName << ".hour = " << value.hour;
  1820. *pFX->m_pdcDump << "\n" << szName << ".minute = " << value.minute;
  1821. *pFX->m_pdcDump << "\n" << szName << ".second = " << value.second;
  1822. *pFX->m_pdcDump << "\n" << szName << ".fraction = " << value.fraction;
  1823. return;
  1824. #endif // _DEBUG
  1825. }
  1826. }
  1827. void AFXAPI RFX_Date(CFieldExchange* pFX, LPCTSTR szName,
  1828. COleDateTime& value)
  1829. {
  1830. ASSERT(AfxIsValidAddress(pFX, sizeof(CFieldExchange)));
  1831. ASSERT(AfxIsValidString(szName));
  1832. UINT nField;
  1833. if (!pFX->IsFieldType(&nField))
  1834. return;
  1835. RETCODE nRetCode;
  1836. LONG* plLength = pFX->m_prs->GetFieldLengthBuffer(
  1837. nField - 1, pFX->m_nFieldType);
  1838. switch (pFX->m_nOperation)
  1839. {
  1840. case CFieldExchange::BindParam:
  1841. {
  1842. TIMESTAMP_STRUCT* pts;
  1843. pFX->m_prs->m_bRebindParams = TRUE;
  1844. if (pFX->m_prs->IsParamStatusNull(nField - 1))
  1845. {
  1846. pts = NULL;
  1847. *plLength = SQL_NULL_DATA;
  1848. }
  1849. else
  1850. {
  1851. // Allocate proxy array if necessary
  1852. if (pFX->m_prs->m_pvParamProxy == NULL)
  1853. {
  1854. pFX->m_prs->m_pvParamProxy = new void*[pFX->m_prs->m_nParams];
  1855. memset(pFX->m_prs->m_pvParamProxy, 0,
  1856. pFX->m_prs->m_nParams*sizeof(void*));
  1857. pFX->m_prs->m_nProxyParams = pFX->m_prs->m_nParams;
  1858. }
  1859. // Allocate TIMESTAMP_STRUCT if necessary for SQLBindParameter
  1860. if (pFX->m_prs->m_pvParamProxy[nField-1] == NULL)
  1861. {
  1862. pts = new TIMESTAMP_STRUCT;
  1863. pFX->m_prs->m_pvParamProxy[nField-1] = pts;
  1864. }
  1865. else
  1866. pts = (TIMESTAMP_STRUCT *)pFX->m_prs->m_pvParamProxy[nField-1];
  1867. pts->year = (SWORD)value.GetYear();
  1868. pts->month = (UWORD)value.GetMonth();
  1869. pts->day = (UWORD)value.GetDay();
  1870. pts->hour = (UWORD)value.GetHour();
  1871. pts->minute = (UWORD)value.GetMinute();
  1872. pts->second = (UWORD)value.GetSecond();
  1873. pts->fraction = 0;
  1874. *plLength = sizeof(TIMESTAMP_STRUCT);
  1875. }
  1876. AFX_SQL_SYNC(::SQLBindParameter(pFX->m_hstmt, (UWORD)nField,
  1877. (SWORD)pFX->m_nFieldType, SQL_C_TIMESTAMP, SQL_C_TIMESTAMP,
  1878. TIMESTAMP_PRECISION, 0, pts, 0, plLength));
  1879. if (nRetCode != SQL_SUCCESS)
  1880. pFX->m_prs->ThrowDBException(nRetCode, pFX->m_hstmt);
  1881. // Add the member address to the param map
  1882. pFX->m_prs->m_mapParamIndex.SetAt(&value, (void*)nField);
  1883. }
  1884. return;
  1885. case CFieldExchange::NameValue:
  1886. if (pFX->m_prs->IsFieldStatusDirty(nField - 1))
  1887. {
  1888. *pFX->m_pstr += szName;
  1889. *pFX->m_pstr += '=';
  1890. }
  1891. // Fall through
  1892. case CFieldExchange::Value:
  1893. if (pFX->m_prs->IsFieldStatusDirty(nField - 1))
  1894. {
  1895. TIMESTAMP_STRUCT* pts =
  1896. (TIMESTAMP_STRUCT*)pFX->m_prs->m_pvFieldProxy[nField-1];
  1897. if (pFX->m_prs->IsFieldStatusNull(nField - 1))
  1898. {
  1899. *plLength = SQL_NULL_DATA;
  1900. }
  1901. else
  1902. {
  1903. pts->year = (SWORD)value.GetYear();
  1904. pts->month = (UWORD)value.GetMonth();
  1905. pts->day = (UWORD)value.GetDay();
  1906. pts->hour = (UWORD)value.GetHour();
  1907. pts->minute = (UWORD)value.GetMinute();
  1908. pts->second = (UWORD)value.GetSecond();
  1909. pts->fraction = 0;
  1910. *plLength = sizeof(TIMESTAMP_STRUCT);
  1911. }
  1912. // If optimizing for bulk add, only need lengths & proxy set correctly
  1913. if(!(pFX->m_prs->m_dwOptions & CRecordset::optimizeBulkAdd))
  1914. {
  1915. *pFX->m_pstr += '?';
  1916. *pFX->m_pstr += pFX->m_lpszSeparator;
  1917. pFX->m_nParamFields++;
  1918. // Assumes all bound fields BEFORE unbound fields
  1919. CODBCFieldInfo* pODBCInfo =
  1920. &pFX->m_prs->m_rgODBCFieldInfos[nField - 1];
  1921. AFX_SQL_SYNC(::SQLBindParameter(pFX->m_hstmt,
  1922. (UWORD)pFX->m_nParamFields, SQL_PARAM_INPUT,
  1923. SQL_C_TIMESTAMP, pODBCInfo->m_nSQLType,
  1924. TIMESTAMP_PRECISION, 0, pts, 0, plLength));
  1925. }
  1926. }
  1927. return;
  1928. case CFieldExchange::RebindParam:
  1929. {
  1930. *plLength = pFX->m_prs->IsParamStatusNull(nField - 1) ?
  1931. SQL_NULL_DATA : sizeof(TIMESTAMP_STRUCT);
  1932. if (pFX->m_prs->m_nProxyParams != 0)
  1933. {
  1934. // Fill buffer (expected by SQLBindParameter) with new param data
  1935. TIMESTAMP_STRUCT* pts;
  1936. pts = (TIMESTAMP_STRUCT *)pFX->m_prs->m_pvParamProxy[nField-1];
  1937. pts->year = (SWORD)value.GetYear();
  1938. pts->month = (UWORD)value.GetMonth();
  1939. pts->day = (UWORD)value.GetDay();
  1940. pts->hour = (UWORD)value.GetHour();
  1941. pts->minute = (UWORD)value.GetMinute();
  1942. pts->second = (UWORD)value.GetSecond();
  1943. pts->fraction = 0;
  1944. }
  1945. }
  1946. return;
  1947. case CFieldExchange::BindFieldForUpdate:
  1948. if (pFX->m_prs->m_nProxyFields != 0)
  1949. {
  1950. // Fill buffer (expected by SQLSetPos) with new field data
  1951. TIMESTAMP_STRUCT* pts;
  1952. pts = (TIMESTAMP_STRUCT *)pFX->m_prs->m_pvFieldProxy[nField-1];
  1953. pts->year = (SWORD)value.GetYear();
  1954. pts->month = (UWORD)value.GetMonth();
  1955. pts->day = (UWORD)value.GetDay();
  1956. pts->hour = (UWORD)value.GetHour();
  1957. pts->minute = (UWORD)value.GetMinute();
  1958. pts->second = (UWORD)value.GetSecond();
  1959. pts->fraction = 0;
  1960. pFX->Default(szName, (void *)pts, plLength, SQL_C_TIMESTAMP,
  1961. sizeof(TIMESTAMP_STRUCT), TIMESTAMP_PRECISION);
  1962. }
  1963. return;
  1964. case CFieldExchange::LoadField:
  1965. {
  1966. // Get the field data
  1967. CFieldInfo* pInfo = &pFX->m_prs->m_rgFieldInfos[nField - 1];
  1968. // Restore the status
  1969. pFX->m_prs->SetFieldStatus(nField - 1, pInfo->m_bStatus);
  1970. // If not NULL, restore the value, length and proxy
  1971. if (!pFX->m_prs->IsFieldStatusNull(nField - 1))
  1972. {
  1973. AfxCopyValueByRef(pInfo->m_pvDataCache, &value,
  1974. plLength, pInfo->m_nDataType);
  1975. // Restore proxy for correct WHERE CURRENT OF operations
  1976. TIMESTAMP_STRUCT* pts =
  1977. (TIMESTAMP_STRUCT*)pFX->m_prs->m_pvFieldProxy[nField-1];
  1978. pts->year = (SWORD)value.GetYear();
  1979. pts->month = (UWORD)value.GetMonth();
  1980. pts->day = (UWORD)value.GetDay();
  1981. pts->hour = (UWORD)value.GetHour();
  1982. pts->minute = (UWORD)value.GetMinute();
  1983. pts->second = (UWORD)value.GetSecond();
  1984. pts->fraction = 0;
  1985. }
  1986. else
  1987. *plLength = SQL_NULL_DATA;
  1988. #ifdef _DEBUG
  1989. // Buffer address must not change - ODBC's SQLBindCol depends upon this
  1990. if (pInfo->m_pvBindAddress != pFX->m_prs->m_pvFieldProxy[nField-1])
  1991. {
  1992. TRACE1("Error: CString buffer (column %u) address has changed!\n",
  1993. nField);
  1994. ASSERT(FALSE);
  1995. }
  1996. #endif // _DEBUG
  1997. }
  1998. return;
  1999. case CFieldExchange::BindFieldToColumn:
  2000. {
  2001. #ifdef _DEBUG
  2002. // Assumes all bound fields BEFORE unbound fields
  2003. CODBCFieldInfo* pODBCInfo =
  2004. &pFX->m_prs->m_rgODBCFieldInfos[nField - 1];
  2005. if (pODBCInfo->m_nSQLType != SQL_DATE &&
  2006. pODBCInfo->m_nSQLType != SQL_TIME &&
  2007. pODBCInfo->m_nSQLType != SQL_TIMESTAMP)
  2008. {
  2009. // Warn of possible field schema mismatch
  2010. if (afxTraceFlags & traceDatabase)
  2011. TRACE1("Warning: COleDateTime converted from SQL type %ld.\n",
  2012. pODBCInfo->m_nSQLType);
  2013. }
  2014. #endif // _DEBUG
  2015. // Allocate proxy array if necessary
  2016. if (pFX->m_prs->m_pvFieldProxy == NULL)
  2017. {
  2018. pFX->m_prs->m_pvFieldProxy = new void*[pFX->m_prs->m_nFields];
  2019. memset(pFX->m_prs->m_pvFieldProxy, 0,
  2020. pFX->m_prs->m_nFields*sizeof(void*));
  2021. pFX->m_prs->m_nProxyFields = pFX->m_prs->m_nFields;
  2022. }
  2023. // Allocate TIMESTAMP_STRUCT for SQLBindCol (not necessary on Requery)
  2024. if (pFX->m_prs->m_pvFieldProxy[nField-1] == NULL)
  2025. pFX->m_prs->m_pvFieldProxy[nField-1] = new TIMESTAMP_STRUCT;
  2026. AFX_SQL_SYNC(::SQLBindCol(pFX->m_prs->m_hstmt, (UWORD)nField,
  2027. SQL_C_TIMESTAMP, pFX->m_prs->m_pvFieldProxy[nField-1],
  2028. sizeof(TIMESTAMP_STRUCT), plLength));
  2029. if (!pFX->m_prs->Check(nRetCode))
  2030. pFX->m_prs->ThrowDBException(nRetCode);
  2031. // Add the member address to the field map
  2032. pFX->m_prs->m_mapFieldIndex.SetAt(&value, (void*)nField);
  2033. }
  2034. return;
  2035. default:
  2036. LDefault:
  2037. pFX->Default(szName, &value, plLength, SQL_C_TIMESTAMP,
  2038. sizeof(value), TIMESTAMP_PRECISION);
  2039. return;
  2040. case CFieldExchange::AllocCache:
  2041. {
  2042. CFieldInfo* pInfo = &pFX->m_prs->m_rgFieldInfos[nField - 1];
  2043. pInfo->m_pvDataCache = new COleDateTime;
  2044. pInfo->m_nDataType = AFX_RFX_OLEDATE;
  2045. }
  2046. return;
  2047. case CFieldExchange::Fixup:
  2048. if (*plLength == SQL_NULL_DATA)
  2049. {
  2050. pFX->m_prs->SetNullFieldStatus(nField - 1);
  2051. value.SetStatus(COleDateTime::null);
  2052. }
  2053. else
  2054. {
  2055. TIMESTAMP_STRUCT* pts =
  2056. (TIMESTAMP_STRUCT*)pFX->m_prs->m_pvFieldProxy[nField-1];
  2057. #ifdef _DEBUG
  2058. if ((afxTraceFlags & traceDatabase) && pts->fraction != 0)
  2059. TRACE0("Warning: ignoring milliseconds.\n");
  2060. #endif
  2061. value = COleDateTime(pts->year, pts->month, pts->day,
  2062. pts->hour, pts->minute, pts->second);
  2063. }
  2064. return;
  2065. case CFieldExchange::SetFieldNull:
  2066. if ((pFX->m_pvField == NULL &&
  2067. pFX->m_nFieldType == CFieldExchange::outputColumn) ||
  2068. pFX->m_pvField == &value)
  2069. {
  2070. if (pFX->m_bField)
  2071. {
  2072. // Mark fields null
  2073. pFX->m_prs->SetNullFieldStatus(nField - 1);
  2074. value.SetStatus(COleDateTime::null);
  2075. *plLength = SQL_NULL_DATA;
  2076. }
  2077. else
  2078. {
  2079. pFX->m_prs->ClearNullFieldStatus(nField - 1);
  2080. *plLength = sizeof(TIMESTAMP_STRUCT);
  2081. }
  2082. #ifdef _DEBUG
  2083. pFX->m_nFieldFound = nField;
  2084. #endif
  2085. }
  2086. return;
  2087. case CFieldExchange::MarkForAddNew:
  2088. // can force writing of psuedo-null value (as a non-null) by setting field dirty
  2089. if (value.GetStatus() != COleDateTime::null)
  2090. {
  2091. pFX->m_prs->SetDirtyFieldStatus(nField - 1);
  2092. pFX->m_prs->ClearNullFieldStatus(nField - 1);
  2093. }
  2094. return;
  2095. case CFieldExchange::MarkForUpdate:
  2096. if (value.GetStatus() != COleDateTime::null)
  2097. pFX->m_prs->ClearNullFieldStatus(nField - 1);
  2098. goto LDefault;
  2099. #ifdef _DEBUG
  2100. case CFieldExchange::DumpField:
  2101. CString str;
  2102. str = value.Format();
  2103. *pFX->m_pdcDump << "\n" << str;
  2104. return;
  2105. #endif // _DEBUG
  2106. }
  2107. }
  2108. void AFXAPI RFX_LongBinary(CFieldExchange* pFX, LPCTSTR szName,
  2109. CLongBinary& value)
  2110. {
  2111. ASSERT(AfxIsValidAddress(pFX, sizeof(CFieldExchange)));
  2112. ASSERT(AfxIsValidString(szName));
  2113. RETCODE nRetCode;
  2114. UINT nField;
  2115. if (!pFX->IsFieldType(&nField))
  2116. return;
  2117. LONG* plLength = pFX->m_prs->GetFieldLengthBuffer(
  2118. nField - 1, pFX->m_nFieldType);
  2119. switch (pFX->m_nOperation)
  2120. {
  2121. case CFieldExchange::Name:
  2122. pFX->m_prs->m_bLongBinaryColumns = TRUE;
  2123. pFX->Default(szName, &value, plLength, SQL_C_DEFAULT, 0, 0);
  2124. return;
  2125. case CFieldExchange::BindFieldToColumn:
  2126. // Don't bind if using update SQL, simply do SQLGetData on Fixup
  2127. if (!pFX->m_prs->m_bUseUpdateSQL && pFX->m_prs->CanUpdate())
  2128. {
  2129. // Bind for updates with cb=0 now. Driver may not support post Execute or ExtendedFetch binding
  2130. AFX_SQL_SYNC(::SQLBindCol(pFX->m_prs->m_hstmt, (UWORD)nField, SQL_C_DEFAULT,
  2131. &value, 0, plLength));
  2132. if (!pFX->m_prs->Check(nRetCode))
  2133. pFX->m_prs->ThrowDBException(nRetCode);
  2134. }
  2135. // Add the member address to the field map
  2136. pFX->m_prs->m_mapFieldIndex.SetAt(&value, (void*)nField);
  2137. return;
  2138. #ifdef _DEBUG
  2139. case CFieldExchange::BindParam:
  2140. // CLongBinary parameters are not supported
  2141. ASSERT(FALSE);
  2142. case CFieldExchange::MarkForAddNew:
  2143. case CFieldExchange::MarkForUpdate:
  2144. // We do not archive LongBinary values
  2145. case CFieldExchange::StoreField:
  2146. case CFieldExchange::LoadField:
  2147. // We do not archive LongBinary values
  2148. #endif // _DEBUG
  2149. default:
  2150. return;
  2151. case CFieldExchange::Fixup:
  2152. // Get the size of the long binary field
  2153. *plLength = pFX->GetLongBinarySize(nField);
  2154. // Get the data if necessary
  2155. if (*plLength != SQL_NULL_DATA)
  2156. pFX->GetLongBinaryData(nField, value, plLength);
  2157. // Set the status and length
  2158. if (*plLength == SQL_NULL_DATA)
  2159. {
  2160. // Field NULL, set length and status
  2161. value.m_dwDataLength = 0;
  2162. pFX->m_prs->SetNullFieldStatus(nField - 1);
  2163. }
  2164. else
  2165. {
  2166. // Field not NULL, clear the status (length already set)
  2167. pFX->m_prs->ClearNullFieldStatus(nField - 1);
  2168. }
  2169. return;
  2170. case CFieldExchange::NameValue:
  2171. if (pFX->m_prs->IsFieldStatusDirty(nField - 1))
  2172. {
  2173. *pFX->m_pstr += szName;
  2174. *pFX->m_pstr += '=';
  2175. }
  2176. // Fall through
  2177. case CFieldExchange::Value:
  2178. if (pFX->m_prs->IsFieldStatusDirty(nField - 1))
  2179. {
  2180. // If user marked column NULL, reflect this in length
  2181. if (pFX->m_prs->IsFieldStatusNull(nField - 1))
  2182. *plLength = SQL_NULL_DATA;
  2183. else
  2184. {
  2185. // Indicate data will be sent after SQLExecute
  2186. // Length is signed value, it's limited by LONG_MAX
  2187. if (value.m_dwDataLength >
  2188. (ULONG)(LONG_MAX - labs(SQL_LEN_DATA_AT_EXEC_OFFSET)))
  2189. {
  2190. ASSERT(FALSE);
  2191. *plLength = LONG_MAX - labs(SQL_LEN_DATA_AT_EXEC_OFFSET);
  2192. }
  2193. else
  2194. *plLength = value.m_dwDataLength;
  2195. *plLength = SQL_LEN_DATA_AT_EXEC(*plLength);
  2196. }
  2197. // If optimizing for bulk add, only need lengths set correctly
  2198. if(!(pFX->m_prs->m_dwOptions & CRecordset::optimizeBulkAdd))
  2199. {
  2200. *pFX->m_pstr += '?';
  2201. *pFX->m_pstr += pFX->m_lpszSeparator;
  2202. pFX->m_nParamFields++;
  2203. // Assumes all bound fields BEFORE unbound fields
  2204. CODBCFieldInfo* pODBCInfo =
  2205. &pFX->m_prs->m_rgODBCFieldInfos[nField - 1];
  2206. AFX_SQL_SYNC(::SQLBindParameter(pFX->m_hstmt,
  2207. (UWORD)pFX->m_nParamFields, SQL_PARAM_INPUT,
  2208. SQL_C_DEFAULT, pODBCInfo->m_nSQLType,
  2209. value.m_dwDataLength, 0, &value, 0, plLength));
  2210. if (nRetCode != SQL_SUCCESS)
  2211. pFX->m_prs->ThrowDBException(nRetCode, pFX->m_hstmt);
  2212. }
  2213. }
  2214. return;
  2215. case CFieldExchange::BindFieldForUpdate:
  2216. if (pFX->m_prs->IsFieldStatusDirty(nField - 1))
  2217. {
  2218. // If user marked column NULL, reflect this in length
  2219. if (pFX->m_prs->IsFieldStatusNull(nField - 1))
  2220. *plLength = SQL_NULL_DATA;
  2221. else
  2222. {
  2223. // Length is signed value, it's limited by LONG_MAX
  2224. if (value.m_dwDataLength >
  2225. (ULONG)(LONG_MAX - labs(SQL_LEN_DATA_AT_EXEC_OFFSET)))
  2226. {
  2227. ASSERT(FALSE);
  2228. *plLength = LONG_MAX - labs(SQL_LEN_DATA_AT_EXEC_OFFSET);
  2229. }
  2230. else
  2231. *plLength = value.m_dwDataLength;
  2232. *plLength = SQL_LEN_DATA_AT_EXEC(*plLength);
  2233. }
  2234. }
  2235. else
  2236. *plLength = SQL_IGNORE;
  2237. return;
  2238. case CFieldExchange::UnbindFieldForUpdate:
  2239. *plLength = value.m_dwDataLength;
  2240. return;
  2241. case CFieldExchange::SetFieldNull:
  2242. if ((pFX->m_pvField == NULL &&
  2243. pFX->m_nFieldType == CFieldExchange::outputColumn) ||
  2244. pFX->m_pvField == &value)
  2245. {
  2246. if (pFX->m_bField)
  2247. {
  2248. // Mark fields null
  2249. pFX->m_prs->SetNullFieldStatus(nField - 1);
  2250. value.m_dwDataLength = 0;
  2251. *plLength = SQL_NULL_DATA;
  2252. }
  2253. else
  2254. {
  2255. pFX->m_prs->ClearNullFieldStatus(nField - 1);
  2256. // Length is signed value, it's limited by LONG_MAX
  2257. if (value.m_dwDataLength >
  2258. (ULONG)(LONG_MAX - labs(SQL_LEN_DATA_AT_EXEC_OFFSET)))
  2259. {
  2260. ASSERT(FALSE);
  2261. *plLength = LONG_MAX - labs(SQL_LEN_DATA_AT_EXEC_OFFSET);
  2262. }
  2263. else
  2264. *plLength = value.m_dwDataLength;
  2265. *plLength = SQL_LEN_DATA_AT_EXEC(*plLength);
  2266. }
  2267. #ifdef _DEBUG
  2268. pFX->m_nFieldFound = nField;
  2269. #endif
  2270. }
  2271. return;
  2272. case CFieldExchange::AllocCache:
  2273. // Caching not supported for long binary
  2274. return;
  2275. #ifdef _DEBUG
  2276. case CFieldExchange::DumpField:
  2277. *pFX->m_pdcDump << "\n" << szName << " = ";
  2278. value.Dump(*pFX->m_pdcDump);
  2279. return;
  2280. #endif // _DEBUG
  2281. }
  2282. }
  2283. long CFieldExchange::GetLongBinarySize(int nField)
  2284. {
  2285. RETCODE nRetCode;
  2286. int nDummy;
  2287. long lSize;
  2288. // Give empty buffer to find size of entire LongBinary
  2289. AFX_ODBC_CALL(::SQLGetData(m_prs->m_hstmt,
  2290. (UWORD)nField, SQL_C_DEFAULT, &nDummy, 0, &lSize));
  2291. switch (nRetCode)
  2292. {
  2293. case SQL_SUCCESS:
  2294. break;
  2295. case SQL_SUCCESS_WITH_INFO:
  2296. #ifdef _DEBUG
  2297. if (afxTraceFlags & traceDatabase)
  2298. {
  2299. CDBException* e = new CDBException(nRetCode);
  2300. e->BuildErrorString(m_prs->m_pDatabase,
  2301. m_prs->m_hstmt, FALSE);
  2302. // Ignore data truncated messages
  2303. if (e->m_strStateNativeOrigin.Find(_T("State:01004")) < 0)
  2304. {
  2305. TRACE0("Warning: ODBC Success With Info, ");
  2306. e->TraceErrorMessage(e->m_strError);
  2307. e->TraceErrorMessage(e->m_strStateNativeOrigin);
  2308. }
  2309. e->Delete();
  2310. }
  2311. #endif // _DEBUG
  2312. break;
  2313. default:
  2314. m_prs->ThrowDBException(nRetCode);
  2315. }
  2316. return lSize;
  2317. }
  2318. void CFieldExchange::GetLongBinaryData(int nField, CLongBinary& lb,
  2319. long* plSize)
  2320. {
  2321. RETCODE nRetCode;
  2322. long lActualDataSize = 0;
  2323. long lChunkDataSize;
  2324. long lReallocSize;
  2325. const BYTE* lpLongBinary;
  2326. lb.m_dwDataLength = 0;
  2327. // Determine initial chunk sizes
  2328. if (*plSize == SQL_NO_TOTAL)
  2329. {
  2330. lChunkDataSize = m_lDefaultLBFetchSize;
  2331. lReallocSize = m_lDefaultLBReallocSize;
  2332. }
  2333. else
  2334. {
  2335. lChunkDataSize = *plSize;
  2336. lReallocSize = *plSize;
  2337. }
  2338. do
  2339. {
  2340. // Check if CLongBianary is big enough
  2341. lpLongBinary = ReallocLongBinary(lb,
  2342. (long)lb.m_dwDataLength + lChunkDataSize,
  2343. (long)lb.m_dwDataLength + lReallocSize);
  2344. // Adjust the pointer so that data added at end
  2345. lpLongBinary += lb.m_dwDataLength;
  2346. AFX_ODBC_CALL(::SQLGetData(m_prs->m_hstmt, (UWORD)nField,
  2347. SQL_C_BINARY, (UCHAR*)lpLongBinary, lChunkDataSize, &lActualDataSize));
  2348. ::GlobalUnlock(lb.m_hData);
  2349. switch (nRetCode)
  2350. {
  2351. case SQL_NO_DATA_FOUND:
  2352. m_prs->SetNullFieldStatus(nField - 1);
  2353. *plSize = SQL_NULL_DATA;
  2354. break;
  2355. case SQL_SUCCESS:
  2356. // All data fetched
  2357. lb.m_dwDataLength += lActualDataSize;
  2358. *plSize = (long)lb.m_dwDataLength;
  2359. return;
  2360. case SQL_SUCCESS_WITH_INFO:
  2361. {
  2362. CDBException* e = new CDBException(nRetCode);
  2363. e->BuildErrorString(m_prs->m_pDatabase, m_prs->m_hstmt,
  2364. FALSE);
  2365. // Ignore data truncated messages
  2366. if (e->m_strStateNativeOrigin.Find(_T("State:01004")) < 0)
  2367. {
  2368. #ifdef _DEBUG
  2369. if (afxTraceFlags & traceDatabase)
  2370. {
  2371. TRACE0("Warning: ODBC Success With Info, ");
  2372. e->TraceErrorMessage(e->m_strError);
  2373. e->TraceErrorMessage(e->m_strStateNativeOrigin);
  2374. }
  2375. #endif // _DEBUG
  2376. // Must be some other warning, should be finished
  2377. lb.m_dwDataLength += lActualDataSize;
  2378. }
  2379. else
  2380. {
  2381. // Should only happen if further calls to SQLGetData necessary
  2382. // Increment the length by the chunk size for subsequent SQLGetData call
  2383. lb.m_dwDataLength += lChunkDataSize;
  2384. // Recalculate chunk and alloc sizes
  2385. lChunkDataSize = m_prs->GetLBFetchSize(lChunkDataSize);
  2386. lReallocSize = m_prs->GetLBReallocSize(lReallocSize);
  2387. // force loop to repeat
  2388. lActualDataSize = SQL_NO_TOTAL;
  2389. }
  2390. *plSize = (long)lb.m_dwDataLength;
  2391. e->Delete();
  2392. }
  2393. break;
  2394. default:
  2395. m_prs->ThrowDBException(nRetCode);
  2396. }
  2397. } while (lActualDataSize == SQL_NO_TOTAL);
  2398. }
  2399. BYTE* CFieldExchange::ReallocLongBinary(CLongBinary& lb, long lSizeRequired,
  2400. long lReallocSize)
  2401. {
  2402. // realloc max of lSizeRequired, lReallocSize (m_dwDataLength untouched)
  2403. if (lSizeRequired < 0)
  2404. {
  2405. ASSERT(FALSE);
  2406. lSizeRequired = 0;
  2407. }
  2408. HGLOBAL hOldData = NULL;
  2409. // Allocate or Realloc as req'd
  2410. if (lb.m_hData == NULL)
  2411. lb.m_hData = ::GlobalAlloc(GMEM_MOVEABLE, lReallocSize);
  2412. else
  2413. {
  2414. DWORD dwSize = ::GlobalSize(lb.m_hData);
  2415. if (dwSize < (DWORD)lSizeRequired)
  2416. {
  2417. // Save the old handle in case ReAlloc fails
  2418. hOldData = lb.m_hData;
  2419. // Allocate more memory if necessary
  2420. lb.m_hData = ::GlobalReAlloc(lb.m_hData,
  2421. __max(lSizeRequired, lReallocSize), GMEM_MOVEABLE);
  2422. }
  2423. }
  2424. // Validate the memory was allocated and can be locked
  2425. if (lb.m_hData == NULL)
  2426. {
  2427. // Restore the old handle (not NULL if Realloc failed)
  2428. lb.m_hData = hOldData;
  2429. AfxThrowMemoryException();
  2430. }
  2431. BYTE* lpLongBinary = (BYTE*)::GlobalLock(lb.m_hData);
  2432. if (lpLongBinary == NULL)
  2433. {
  2434. ::GlobalFree(lb.m_hData);
  2435. lb.m_hData = NULL;
  2436. AfxThrowMemoryException();
  2437. }
  2438. return lpLongBinary;
  2439. }
  2440. //////////////////////////////////////////////////////////////////////////////
  2441. // Recordset Field Exchange Helpers
  2442. void AFXAPI AfxStoreField(CRecordset& rs, UINT nField, void* pvField)
  2443. {
  2444. // Get the field data
  2445. CFieldInfo* pInfo = &rs.m_rgFieldInfos[nField - 1];
  2446. // Cache the status
  2447. pInfo->m_bStatus = rs.GetFieldStatus(nField - 1);
  2448. // Save the data
  2449. if (!rs.IsFieldStatusNull(nField - 1))
  2450. {
  2451. // Don't need to save length for variable len
  2452. // objects as CString and CByteArray track len internally
  2453. long nDummyLength;
  2454. if (pInfo->m_nDataType == AFX_RFX_BOOL ||
  2455. pInfo->m_nDataType == AFX_RFX_BYTE ||
  2456. pInfo->m_nDataType == AFX_RFX_INT ||
  2457. pInfo->m_nDataType == AFX_RFX_LONG ||
  2458. pInfo->m_nDataType == AFX_RFX_SINGLE)
  2459. {
  2460. // If caching data by value, pass a ref
  2461. AfxCopyValueByRef(pvField, &pInfo->m_pvDataCache,
  2462. &nDummyLength, pInfo->m_nDataType);
  2463. }
  2464. else
  2465. {
  2466. AfxCopyValueByRef(pvField, pInfo->m_pvDataCache,
  2467. &nDummyLength, pInfo->m_nDataType);
  2468. }
  2469. }
  2470. #ifdef _DEBUG
  2471. // Cache the bind address expected by ODBC
  2472. switch(pInfo->m_nDataType)
  2473. {
  2474. default:
  2475. // All types that are bound directly
  2476. pInfo->m_pvBindAddress = pvField;
  2477. break;
  2478. case AFX_RFX_TEXT:
  2479. #ifdef _UNICODE
  2480. pInfo->m_pvBindAddress = rs.m_pvFieldProxy[nField-1];
  2481. #else
  2482. pInfo->m_pvBindAddress = ((CString*)pvField)->GetBuffer(0);
  2483. ((CString*)pvField)->ReleaseBuffer();
  2484. #endif
  2485. break;
  2486. case AFX_RFX_LPTSTR:
  2487. #ifdef _UNICODE
  2488. pInfo->m_pvBindAddress = rs.m_pvFieldProxy[nField-1];
  2489. #else
  2490. pInfo->m_pvBindAddress = pvField;
  2491. #endif
  2492. break;
  2493. case AFX_RFX_DATE:
  2494. case AFX_RFX_OLEDATE:
  2495. pInfo->m_pvBindAddress = rs.m_pvFieldProxy[nField-1];
  2496. break;
  2497. case AFX_RFX_BINARY:
  2498. pInfo->m_pvBindAddress = ((CByteArray*)pvField)->GetData();
  2499. break;
  2500. }
  2501. #endif
  2502. }
  2503. void AFXAPI AfxLoadField(CRecordset& rs, UINT nField,
  2504. void* pvField, long* plLength)
  2505. {
  2506. // Get the field data
  2507. CFieldInfo* pInfo = &rs.m_rgFieldInfos[nField - 1];
  2508. // Assumes old field status cleared out
  2509. rs.SetFieldStatus(nField - 1, pInfo->m_bStatus);
  2510. // If not NULL, restore the value and the length
  2511. if (!rs.IsFieldStatusNull(nField - 1))
  2512. {
  2513. if (pInfo->m_nDataType == AFX_RFX_BOOL ||
  2514. pInfo->m_nDataType == AFX_RFX_BYTE ||
  2515. pInfo->m_nDataType == AFX_RFX_INT ||
  2516. pInfo->m_nDataType == AFX_RFX_LONG ||
  2517. pInfo->m_nDataType == AFX_RFX_SINGLE)
  2518. {
  2519. // If caching data by value, pass a ref
  2520. AfxCopyValueByRef(&pInfo->m_pvDataCache, pvField,
  2521. plLength, pInfo->m_nDataType);
  2522. }
  2523. else
  2524. {
  2525. AfxCopyValueByRef(pInfo->m_pvDataCache, pvField,
  2526. plLength, pInfo->m_nDataType);
  2527. }
  2528. }
  2529. else
  2530. *plLength = SQL_NULL_DATA;
  2531. #ifdef _DEBUG
  2532. // Buffer address must not change - ODBC's SQLBindCol depends upon this
  2533. if (pInfo->m_nDataType == AFX_RFX_BINARY)
  2534. {
  2535. // Change pvField to point to the data of the CByteArray
  2536. pvField = ((CByteArray*)pvField)->GetData();
  2537. }
  2538. if (pInfo->m_pvBindAddress != pvField)
  2539. {
  2540. TRACE1("Error: field address (column %u) has changed!\n",
  2541. nField);
  2542. ASSERT(FALSE);
  2543. }
  2544. #endif // _DEBUG
  2545. }
  2546. BOOL AFXAPI AfxCompareValueByRef(void* pvSrc, void* pvDest, int nSrcType)
  2547. {
  2548. ASSERT(pvSrc != NULL);
  2549. ASSERT(pvDest != NULL);
  2550. BOOL bCompare = FALSE;
  2551. switch(nSrcType)
  2552. {
  2553. case AFX_RFX_LONGBINARY:
  2554. // Caching long binary Src not supported
  2555. default:
  2556. ASSERT(FALSE);
  2557. break;
  2558. case AFX_RFX_LPTSTR:
  2559. if (lstrcmp((LPTSTR) pvDest, (LPTSTR) pvSrc) == 0)
  2560. bCompare = TRUE;
  2561. break;
  2562. case AFX_RFX_TEXT:
  2563. if (*(CString*)pvDest == *(CString*)pvSrc)
  2564. bCompare = TRUE;
  2565. break;
  2566. case AFX_RFX_BINARY:
  2567. {
  2568. CByteArray* pByteArraySrc = (CByteArray*)pvSrc;
  2569. CByteArray* pByteArrayDest = (CByteArray*)pvDest;
  2570. // If sizes compare, compare the Src
  2571. int nSize = pByteArraySrc->GetSize();
  2572. if (nSize == pByteArrayDest->GetSize())
  2573. {
  2574. if (memcmp(&pByteArrayDest[0], &pByteArraySrc[0], nSize) == 0)
  2575. bCompare = TRUE;
  2576. }
  2577. }
  2578. break;
  2579. case AFX_RFX_BOOL:
  2580. if (*(BOOL*)pvDest == *(BOOL*)pvSrc)
  2581. bCompare = TRUE;
  2582. break;
  2583. case AFX_RFX_BYTE:
  2584. if (*(BYTE*)pvDest == *(BYTE*)pvSrc)
  2585. bCompare = TRUE;
  2586. break;
  2587. case AFX_RFX_INT:
  2588. if (*(int*)pvDest == *(int*)pvSrc)
  2589. bCompare = TRUE;
  2590. break;
  2591. case AFX_RFX_LONG:
  2592. if (*(long*)pvDest == *(long*)pvSrc)
  2593. bCompare = TRUE;
  2594. break;
  2595. case AFX_RFX_SINGLE:
  2596. if (*(float*)pvDest == *(float*)pvSrc)
  2597. bCompare = TRUE;
  2598. break;
  2599. case AFX_RFX_DOUBLE:
  2600. if (*(double*)pvDest == *(double*)pvSrc)
  2601. bCompare = TRUE;
  2602. break;
  2603. case AFX_RFX_OLEDATE:
  2604. if (*(COleDateTime*)pvDest == *(COleDateTime*)pvSrc)
  2605. bCompare = TRUE;
  2606. break;
  2607. case AFX_RFX_DATE:
  2608. if (*(CTime*)pvDest == *(CTime*)pvSrc)
  2609. bCompare = TRUE;
  2610. break;
  2611. case AFX_RFX_TIMESTAMP:
  2612. {
  2613. TIMESTAMP_STRUCT* pSrc = (TIMESTAMP_STRUCT*)pvSrc;
  2614. TIMESTAMP_STRUCT* pDest = (TIMESTAMP_STRUCT*)pvDest;
  2615. if ((pSrc->year == pDest->year &&
  2616. pSrc->month == pDest->month &&
  2617. pSrc->day == pDest->day &&
  2618. pSrc->hour == pDest->hour &&
  2619. pSrc->minute == pDest->minute &&
  2620. pSrc->second == pDest->second &&
  2621. pSrc->fraction == pDest->fraction))
  2622. {
  2623. bCompare = TRUE;
  2624. }
  2625. }
  2626. break;
  2627. }
  2628. return bCompare;
  2629. }
  2630. void AFXAPI AfxCopyValueByRef(void* pvSrc, void* pvDest, long* plLength, int nDestType)
  2631. {
  2632. ASSERT(pvSrc != NULL);
  2633. ASSERT(pvDest != NULL);
  2634. ASSERT(plLength != NULL);
  2635. switch (nDestType)
  2636. {
  2637. case AFX_RFX_LONGBINARY:
  2638. // Caching long binary Dest not supported
  2639. default:
  2640. ASSERT(FALSE);
  2641. break;
  2642. case AFX_RFX_LPTSTR:
  2643. lstrcpy((LPTSTR) pvDest, (LPTSTR) pvSrc);
  2644. *plLength = lstrlen((LPTSTR) pvDest);
  2645. break;
  2646. case AFX_RFX_TEXT:
  2647. *(CString*)pvDest = *(CString*)pvSrc;
  2648. *plLength = ((CString*)pvSrc)->GetLength();
  2649. break;
  2650. case AFX_RFX_BINARY:
  2651. ((CByteArray*)pvDest)->Copy(*(CByteArray*)pvSrc);
  2652. *plLength = ((CByteArray*)pvSrc)->GetSize();
  2653. break;
  2654. case AFX_RFX_BOOL:
  2655. *(BOOL*)pvDest = *(BOOL*)pvSrc;
  2656. *plLength = sizeof(BOOL);
  2657. break;
  2658. case AFX_RFX_BYTE:
  2659. *(BYTE*)pvDest = *(BYTE*)pvSrc;
  2660. *plLength = sizeof(BYTE);
  2661. break;
  2662. case AFX_RFX_INT:
  2663. *(int*)pvDest = *(int*)pvSrc;
  2664. *plLength = sizeof(int);
  2665. break;
  2666. case AFX_RFX_LONG:
  2667. *(long*)pvDest = *(long*)pvSrc;
  2668. *plLength = sizeof(long);
  2669. break;
  2670. case AFX_RFX_SINGLE:
  2671. *(float*)pvDest = *(float*)pvSrc;
  2672. *plLength = sizeof(float);
  2673. break;
  2674. case AFX_RFX_DOUBLE:
  2675. *(double*)pvDest = *(double*)pvSrc;
  2676. *plLength = sizeof(double);
  2677. break;
  2678. case AFX_RFX_DATE:
  2679. *(CTime*)pvDest = *(CTime*)pvSrc;
  2680. *plLength = sizeof(TIMESTAMP_STRUCT);
  2681. break;
  2682. case AFX_RFX_OLEDATE:
  2683. *(COleDateTime*)pvDest = *(COleDateTime*)pvSrc;
  2684. *plLength = sizeof(TIMESTAMP_STRUCT);
  2685. break;
  2686. case AFX_RFX_TIMESTAMP:
  2687. {
  2688. TIMESTAMP_STRUCT* pDest = (TIMESTAMP_STRUCT*)pvDest;
  2689. TIMESTAMP_STRUCT* pSrc = (TIMESTAMP_STRUCT*)pvSrc;
  2690. pDest->year = pSrc->year;
  2691. pDest->month = pSrc->month;
  2692. pDest->day = pSrc->day;
  2693. pDest->hour = pSrc->hour;
  2694. pDest->minute = pSrc->minute;
  2695. pDest->second = pSrc->second;
  2696. pDest->fraction = pSrc->fraction;
  2697. *plLength = sizeof(TIMESTAMP_STRUCT);
  2698. }
  2699. break;
  2700. }
  2701. }
  2702. //////////////////////////////////////////////////////////////////////////////
  2703. // Bulk Recordset Field Exchange
  2704. void AFXAPI RFX_Text_Bulk(CFieldExchange* pFX, LPCTSTR szName,
  2705. LPSTR* prgStrVals, long** prgLengths, int nMaxLength)
  2706. {
  2707. ASSERT(AfxIsValidAddress(pFX, sizeof(CFieldExchange)));
  2708. ASSERT(AfxIsValidString(szName));
  2709. UINT nField;
  2710. if (!pFX->IsFieldType(&nField))
  2711. return;
  2712. switch (pFX->m_nOperation)
  2713. {
  2714. case CFieldExchange::AllocMultiRowBuffer:
  2715. {
  2716. // The buffer pointer better be initialized to NULL
  2717. // or cleanup in exceptional cases mail fail
  2718. ASSERT(*prgStrVals == NULL);
  2719. ASSERT(*prgLengths == NULL);
  2720. int nRowsetSize = pFX->m_prs->GetRowsetSize();
  2721. // Allocate buffers to hold data and length
  2722. *prgStrVals = new char[nRowsetSize * nMaxLength];
  2723. *prgLengths = new long[nRowsetSize];
  2724. }
  2725. break;
  2726. case CFieldExchange::DeleteMultiRowBuffer:
  2727. delete [] *prgStrVals;
  2728. *prgStrVals = NULL;
  2729. delete [] *prgLengths;
  2730. *prgLengths = NULL;
  2731. break;
  2732. default:
  2733. AfxRFXBulkDefault(pFX, szName, *prgStrVals, *prgLengths,
  2734. SQL_C_CHAR, nMaxLength);
  2735. break;
  2736. }
  2737. }
  2738. void AFXAPI RFX_Bool_Bulk(CFieldExchange* pFX, LPCTSTR szName,
  2739. BOOL** prgBoolVals, long** prgLengths)
  2740. {
  2741. ASSERT(AfxIsValidAddress(pFX, sizeof(CFieldExchange)));
  2742. ASSERT(AfxIsValidString(szName));
  2743. UINT nField;
  2744. if (!pFX->IsFieldType(&nField))
  2745. return;
  2746. switch (pFX->m_nOperation)
  2747. {
  2748. case CFieldExchange::AllocMultiRowBuffer:
  2749. {
  2750. // The buffer pointer better be initialized to NULL
  2751. // or cleanup in exceptional cases mail fail
  2752. ASSERT(*prgBoolVals == NULL);
  2753. ASSERT(*prgLengths == NULL);
  2754. int nRowsetSize = pFX->m_prs->GetRowsetSize();
  2755. // Allocate buffers to hold data and length
  2756. *prgBoolVals = new BOOL[nRowsetSize];
  2757. *prgLengths = new long[nRowsetSize];
  2758. }
  2759. break;
  2760. case CFieldExchange::DeleteMultiRowBuffer:
  2761. delete [] *prgBoolVals;
  2762. *prgBoolVals = NULL;
  2763. delete [] *prgLengths;
  2764. *prgLengths = NULL;
  2765. break;
  2766. default:
  2767. AfxRFXBulkDefault(pFX, szName, *prgBoolVals, *prgLengths,
  2768. SQL_C_LONG, sizeof(BOOL));
  2769. break;
  2770. }
  2771. }
  2772. void AFXAPI RFX_Int_Bulk(CFieldExchange* pFX, LPCTSTR szName,
  2773. int** prgIntVals, long** prgLengths)
  2774. {
  2775. ASSERT(AfxIsValidAddress(pFX, sizeof(CFieldExchange)));
  2776. ASSERT(AfxIsValidString(szName));
  2777. UINT nField;
  2778. if (!pFX->IsFieldType(&nField))
  2779. return;
  2780. switch (pFX->m_nOperation)
  2781. {
  2782. case CFieldExchange::AllocMultiRowBuffer:
  2783. {
  2784. // The buffer pointer better be initialized to NULL
  2785. // or cleanup in exceptional cases mail fail
  2786. ASSERT(*prgIntVals == NULL);
  2787. ASSERT(*prgLengths == NULL);
  2788. int nRowsetSize = pFX->m_prs->GetRowsetSize();
  2789. // Allocate buffers to hold data and length
  2790. *prgIntVals = new int[nRowsetSize];
  2791. *prgLengths = new long[nRowsetSize];
  2792. }
  2793. break;
  2794. case CFieldExchange::DeleteMultiRowBuffer:
  2795. delete [] *prgIntVals;
  2796. *prgIntVals = NULL;
  2797. delete [] *prgLengths;
  2798. *prgLengths = NULL;
  2799. break;
  2800. default:
  2801. AfxRFXBulkDefault(pFX, szName, *prgIntVals, *prgLengths,
  2802. SQL_C_LONG, sizeof(int));
  2803. break;
  2804. }
  2805. }
  2806. void AFXAPI RFX_Long_Bulk(CFieldExchange* pFX, LPCTSTR szName,
  2807. long** prgLongVals, long** prgLengths)
  2808. {
  2809. ASSERT(AfxIsValidAddress(pFX, sizeof(CFieldExchange)));
  2810. ASSERT(AfxIsValidString(szName));
  2811. UINT nField;
  2812. if (!pFX->IsFieldType(&nField))
  2813. return;
  2814. switch (pFX->m_nOperation)
  2815. {
  2816. case CFieldExchange::AllocMultiRowBuffer:
  2817. {
  2818. // The buffer pointer better be initialized to NULL
  2819. // or cleanup in exceptional cases mail fail
  2820. ASSERT(*prgLongVals == NULL);
  2821. ASSERT(*prgLengths == NULL);
  2822. int nRowsetSize = pFX->m_prs->GetRowsetSize();
  2823. // Allocate buffers to hold data and length
  2824. *prgLongVals = new long[nRowsetSize];
  2825. *prgLengths = new long[nRowsetSize];
  2826. }
  2827. break;
  2828. case CFieldExchange::DeleteMultiRowBuffer:
  2829. delete [] *prgLongVals;
  2830. *prgLongVals = NULL;
  2831. delete [] *prgLengths;
  2832. *prgLengths = NULL;
  2833. break;
  2834. default:
  2835. AfxRFXBulkDefault(pFX, szName, *prgLongVals, *prgLengths,
  2836. SQL_C_LONG, sizeof(long));
  2837. break;
  2838. }
  2839. }
  2840. void AFXAPI RFX_Date_Bulk(CFieldExchange* pFX, LPCTSTR szName,
  2841. TIMESTAMP_STRUCT** prgTSVals, long** prgLengths)
  2842. {
  2843. ASSERT(AfxIsValidAddress(pFX, sizeof(CFieldExchange)));
  2844. ASSERT(AfxIsValidString(szName));
  2845. UINT nField;
  2846. if (!pFX->IsFieldType(&nField))
  2847. return;
  2848. switch (pFX->m_nOperation)
  2849. {
  2850. case CFieldExchange::AllocMultiRowBuffer:
  2851. {
  2852. // The buffer pointer better be initialized to NULL
  2853. // or cleanup in exceptional cases mail fail
  2854. ASSERT(*prgTSVals == NULL);
  2855. ASSERT(*prgLengths == NULL);
  2856. int nRowsetSize = pFX->m_prs->GetRowsetSize();
  2857. // Allocate buffers to hold data and length
  2858. *prgTSVals = new TIMESTAMP_STRUCT[nRowsetSize];
  2859. *prgLengths = new long[nRowsetSize];
  2860. }
  2861. break;
  2862. case CFieldExchange::DeleteMultiRowBuffer:
  2863. delete [] *prgTSVals;
  2864. *prgTSVals = NULL;
  2865. delete [] *prgLengths;
  2866. *prgLengths = NULL;
  2867. break;
  2868. default:
  2869. AfxRFXBulkDefault(pFX, szName, *prgTSVals, *prgLengths,
  2870. SQL_C_TIMESTAMP, sizeof(TIMESTAMP_STRUCT));
  2871. break;
  2872. }
  2873. }
  2874. void AFXAPI RFX_Byte_Bulk(CFieldExchange* pFX, LPCTSTR szName,
  2875. BYTE** prgByteVals, long** prgLengths)
  2876. {
  2877. ASSERT(AfxIsValidAddress(pFX, sizeof(CFieldExchange)));
  2878. ASSERT(AfxIsValidString(szName));
  2879. UINT nField;
  2880. if (!pFX->IsFieldType(&nField))
  2881. return;
  2882. switch (pFX->m_nOperation)
  2883. {
  2884. case CFieldExchange::AllocMultiRowBuffer:
  2885. {
  2886. // The buffer pointer better be initialized to NULL
  2887. // or cleanup in exceptional cases mail fail
  2888. ASSERT(*prgByteVals == NULL);
  2889. ASSERT(*prgLengths == NULL);
  2890. int nRowsetSize = pFX->m_prs->GetRowsetSize();
  2891. // Allocate buffers to hold data and length
  2892. *prgByteVals = new BYTE[nRowsetSize];
  2893. *prgLengths = new long[nRowsetSize];
  2894. }
  2895. break;
  2896. case CFieldExchange::DeleteMultiRowBuffer:
  2897. delete [] *prgByteVals;
  2898. *prgByteVals = NULL;
  2899. delete [] *prgLengths;
  2900. *prgLengths = NULL;
  2901. break;
  2902. default:
  2903. AfxRFXBulkDefault(pFX, szName, *prgByteVals, *prgLengths,
  2904. SQL_C_TINYINT, sizeof(BYTE));
  2905. break;
  2906. }
  2907. }
  2908. void AFXAPI RFX_Binary_Bulk(CFieldExchange* pFX, LPCTSTR szName,
  2909. BYTE** prgByteVals, long** prgLengths, int nMaxLength)
  2910. {
  2911. ASSERT(AfxIsValidAddress(pFX, sizeof(CFieldExchange)));
  2912. ASSERT(AfxIsValidString(szName));
  2913. UINT nField;
  2914. if (!pFX->IsFieldType(&nField))
  2915. return;
  2916. switch (pFX->m_nOperation)
  2917. {
  2918. case CFieldExchange::AllocMultiRowBuffer:
  2919. {
  2920. // The buffer pointer better be initialized to NULL
  2921. // or cleanup in exceptional cases mail fail
  2922. ASSERT(*prgByteVals == NULL);
  2923. ASSERT(*prgLengths == NULL);
  2924. int nRowsetSize = pFX->m_prs->GetRowsetSize();
  2925. // Allocate buffers to hold data and length
  2926. *prgByteVals = new BYTE[nRowsetSize * nMaxLength];
  2927. *prgLengths = new long[nRowsetSize];
  2928. }
  2929. break;
  2930. case CFieldExchange::DeleteMultiRowBuffer:
  2931. delete [] *prgByteVals;
  2932. *prgByteVals = NULL;
  2933. delete [] *prgLengths;
  2934. *prgLengths = NULL;
  2935. break;
  2936. default:
  2937. AfxRFXBulkDefault(pFX, szName, *prgByteVals, *prgLengths,
  2938. SQL_C_BINARY, nMaxLength);
  2939. break;
  2940. }
  2941. }
  2942. void AFXAPI AfxRFXBulkDefault(CFieldExchange* pFX, LPCTSTR szName,
  2943. void* pv, long* rgLengths, int nCType, UINT cbValue)
  2944. {
  2945. RETCODE nRetCode;
  2946. switch(pFX->m_nOperation)
  2947. {
  2948. default:
  2949. // Operation not valid for bulk fetch
  2950. ASSERT(FALSE);
  2951. return;
  2952. case CFieldExchange::Name:
  2953. // We require a name
  2954. ASSERT(lstrlen(szName) != 0);
  2955. *pFX->m_pstr += szName;
  2956. *pFX->m_pstr += pFX->m_lpszSeparator;
  2957. break;
  2958. case CFieldExchange::BindFieldToColumn:
  2959. AFX_SQL_SYNC(::SQLBindCol(pFX->m_prs->m_hstmt,
  2960. (UWORD)pFX->m_nFields, (SWORD)nCType, pv, cbValue, rgLengths));
  2961. if (!pFX->m_prs->Check(nRetCode))
  2962. pFX->m_prs->ThrowDBException(nRetCode);
  2963. break;
  2964. }
  2965. }
  2966. //////////////////////////////////////////////////////////////////////////////
  2967. // Inline function declarations expanded out-of-line
  2968. #ifndef _AFX_ENABLE_INLINES
  2969. static char _szAfxDbInl[] = "afxdb.inl";
  2970. #undef THIS_FILE
  2971. #define THIS_FILE _szAfxDbInl
  2972. #define _AFXDBRFX_INLINE
  2973. #include "afxdb.inl"
  2974. #endif
  2975. #ifdef AFX_INIT_SEG
  2976. #pragma code_seg(AFX_INIT_SEG)
  2977. #endif
  2978. /////////////////////////////////////////////////////////////////////////////