QueryDef.h
上传用户:yunnanyeer
上传日期:2007-01-03
资源大小:86k
文件大小:18k
源码类别:

数据库编程

开发平台:

Visual C++

  1. // QueryDef.h: interface for the CQueryDef class.
  2. // See accompanying document QueryDef - a complete implementation of a dynamic recordset.doc
  3. // Eugen Paval (C) 1998, 1999
  4. // Revision History:
  5. // 01/17/1998 - V1.0 - Retrieving data only thru GetSQLData
  6. // 02/23/1998 - V1.5 - Support for positioned updates and dynamic binding thru RFX_ functions
  7. // 03/14/1998 - V2.0 - Support for notifications and column descriptors
  8. // 08/25/1998 - V2.01- Bugs fixed in changing the datatype
  9. // 01/18/1999 - V2.02- Revision and fixups for known issues
  10. //
  11. // To compile the library define the symbol _QUERYDEFCOMPILE
  12. //////////////////////////////////////////////////////////////////////
  13. #if !defined(AFX_QUERYDEF_H__A94B98EA_5F3C_11D1_898E_0080C83612CB__INCLUDED_)
  14. #define AFX_QUERYDEF_H__A94B98EA_5F3C_11D1_898E_0080C83612CB__INCLUDED_
  15. #if defined(_QUERYDEFCOMPILE) // compile the library
  16. #if !defined(_AFXEXT)
  17. #define _AFXEXT // export AFX_EXT_CLASS
  18. #endif // _AFXEXT
  19. #else
  20. #if defined(_AFXEXT)
  21. #undef _AFXEXT // import AFX_EXT_CLASS
  22. #define _GUARDIAN_ANGEL // see the end of this file
  23. #endif // _AFXEXT
  24. #endif // _QUERYDEFCOMPILE
  25. #if _MSC_VER >= 1000
  26. #pragma once
  27. #endif // _MSC_VER >= 1000
  28. #if !defined(__AFXDB_H__)
  29. #define __AFXDB_H__
  30. #include <afxdb.h>
  31. #endif
  32. #include <afxdisp.h>
  33. #include <afxtempl.h>
  34. #include <Recordset2.h> // fixes a bug in CRecordset &
  35. // adds fixups to output params
  36. #define MAX_SHORT 32767
  37. #define USE_QUERYDEF using namespace QueryDef; // shortcut to namespace
  38. namespace QueryDef // use namespace required
  39. {
  40. class CQueryDefException;
  41. class CQueryVar;
  42. class CQueryVariant;
  43. class CQueryDef;
  44. class CQueryCol;
  45. class CQueryDefDefaultSink;
  46. class CTabbedString;
  47. class CSQLNull;
  48. class CQueryDefException : public CDBException // not yet implemented
  49. {
  50. };
  51. class AFX_EXT_CLASS CQueryVar : public CDBVariant
  52. {
  53. short m_decPlaces; // decimal places for float,double->string conversions
  54. CString m_dateFormat; // the implicit format for date & time values
  55. CString m_convert; // placeholder for conversion operators
  56. BYTE m_allocFlags; // shows the alloc status of the m_pxxx pointers
  57. // 0 = nothing allocated, 1 = m_pstring, 2 = m_pdate, 4 = m_pbinary
  58. void ConstructObject();
  59. LPCTSTR ToString(); // convert this object to string
  60. enum AllocFlags {
  61. eAllocNothing = 0,
  62. eAllocString = 1,
  63. eAllocDate = 2,
  64. eAllocBinary=4
  65. }; // alloc flags
  66. void ChangeDataType(int allocFlags); // changes the data type
  67. public:
  68. CQueryVar();
  69. CQueryVar(LPCTSTR str);
  70. CQueryVar(int i);
  71. CQueryVar(long l);
  72. CQueryVar(short s);
  73. CQueryVar(float f);
  74. CQueryVar(double d);
  75. CQueryVar(COleDateTime& t);
  76. CQueryVar(CLongBinary& lB);
  77. virtual ~CQueryVar();
  78. operator LPCTSTR();
  79. operator int();
  80. operator BYTE();
  81. operator long();
  82. operator short();
  83. operator float();
  84. operator double();
  85. operator void*();
  86. operator COleDateTime&();
  87. operator CLongBinary&();
  88. operator CStringArray&();
  89. CQueryVar& operator=(UCHAR ch);
  90. CQueryVar& operator=(long l);
  91. CQueryVar& operator=(int l);
  92. CQueryVar& operator=(short s);
  93. CQueryVar& operator=(float f);
  94. CQueryVar& operator=(double d);
  95. CQueryVar& operator=(LPCTSTR str);
  96. CQueryVar& operator=(COleDateTime& date);
  97. CQueryVar& operator=(CLongBinary& lB);
  98. CQueryVar& operator=(CQueryVar& v);
  99. CQueryVar& operator=(CSQLNull& sqlNull) { SetNull(); return *this; };
  100. BOOL operator==(CSQLNull& sqlNull);
  101. BOOL operator!=(CSQLNull& sqlNull);
  102. void SetNull(void) { m_dwType = DBVT_NULL; }; // sets this object to NULL (SQL Server view)
  103. BOOL IsNull(void) { return m_dwType == DBVT_NULL; };
  104. short SetDecimalDigits(short d);
  105. short GetDecimalDigits() { return m_decPlaces; };
  106. LPCSTR SetDateFormat(LPCSTR strDateFormat);
  107. LPCTSTR GetDateFormat() const { return m_dateFormat; };
  108. public:
  109. enum eException {
  110. eConversionError = 1, // conversion not supported
  111. eMemoryLimit, // CString may not exceed 32K
  112. eBoundary
  113. };
  114. friend class CQueryVariant;
  115. friend class CQueryDef;
  116. };
  117. typedef CArray<CQueryVar,CQueryVar&> CQueryVarArray; // metaclass for an array of CQueryVar
  118. // template <CQueryVar> void AFXAPI ConstructElements(CQueryVar* pNewQueryVar,int nCount);
  119. class AFX_EXT_CLASS CQueryVariant
  120. {
  121. CQueryVarArray m_varDB; // holds the columns
  122. short m_decPlaces; // decimal places for float,double->string conversions
  123. CString m_dateFormat; // the implicit format for date & time values
  124. void ConstructObject();
  125. void SetSize(int nNewSize); // shrink or grow the array m_varDB
  126. public:
  127. CQueryVariant();
  128. CQueryVariant(LPCTSTR str);
  129. CQueryVariant(int i);
  130. CQueryVariant(long l);
  131. CQueryVariant(short s);
  132. CQueryVariant(float f);
  133. CQueryVariant(double d);
  134. CQueryVariant(COleDateTime& t);
  135. CQueryVariant(CLongBinary& lB);
  136. virtual ~CQueryVariant();
  137. operator CString();
  138. operator int();
  139. operator BYTE();
  140. operator long();
  141. operator short();
  142. operator float();
  143. operator double();
  144. operator COleDateTime&();
  145. operator CLongBinary&();
  146. operator LPCTSTR();
  147. CQueryVar& operator[](int i);
  148. CQueryVariant& operator=(CQueryVariant& v);
  149. CQueryVariant& operator=(CStringArray& srcArray); // to transfer all columns to strings
  150. public:
  151. enum eException {
  152. eConversionError = 1, // conversion not supported
  153. eMemoryLimit, // CString may not exceed 32K
  154. eBoundary
  155. };
  156. short SetDecimalDigits(short d); // format float and double values with this digits
  157. LPCSTR SetDateFormat(LPCSTR strFormat); // format date-time values with this format
  158. WORD Columns() { return m_varDB.GetSize(); };
  159. friend class CQueryDef;
  160. friend class CTabbedString;
  161. };
  162. // V2.0 SQL columns descriptors
  163. class AFX_EXT_CLASS CQueryCol // describe an SQL column
  164. {
  165. CQueryVar* m_pValue;
  166. CODBCFieldInfo* m_pfldInfo;
  167. public:
  168. CQueryCol();
  169. CQueryCol(CQueryVar& qv,CODBCFieldInfo& fi);
  170. ~CQueryCol();
  171. CQueryVar& Value()  { return *m_pValue; };
  172. LPCTSTR Name() const { return m_pfldInfo->m_strName; };
  173. SWORD SQLType() const { return m_pfldInfo->m_nSQLType; };
  174. DWORD Type() const { return m_pValue->m_dwType; };
  175. UDWORD Precision() const { return m_pfldInfo->m_nPrecision; };
  176. SWORD Scale() const { return m_pfldInfo->m_nScale; };
  177. SWORD IsNullable() const { return m_pfldInfo->m_nNullability; };
  178. };
  179. // V2.0 notification events
  180. typedef POSITION EVNHANDLE;
  181. struct IQueryDefEventSink // CQueryDef event sink
  182. {
  183. // possible notifications - returning 0 means proceed with the next notification otherwise stop
  184. virtual LPARAM RSNotifyOpen(EVNHANDLE) = 0; // the recordset has been opened
  185. virtual LPARAM RSNotifyClose(EVNHANDLE) = 0; // the recordset has been closed
  186. virtual LPARAM RSNotifyMove(EVNHANDLE) = 0; // the recordset has modified the current position 
  187. virtual LPARAM RSNotifyAddNew(EVNHANDLE) = 0; // recordset is about to insert a new record (called after CQueryDef::AddNew)
  188. virtual LPARAM RSNotifyEdit(EVNHANDLE) = 0; // the current record will be modified to be updated (called after CQueryDef::Edit)
  189. virtual LPARAM RSNotifyUpdate(EVNHANDLE) = 0; // the current record will be updated (called after CQueryDef::Update)
  190. virtual LPARAM RSNotifyDelete(EVNHANDLE) = 0; // the current record was deleted
  191. virtual LPARAM RSNotifyCancelUpdate(EVNHANDLE) = 0; // the update of the current record was canceled (called after CQueryDef::CancelUpdate)
  192. virtual LPARAM RSNotifyRequery(EVNHANDLE) = 0; // the recordset was refreshed
  193. virtual LPARAM RSNotifyFormatChanged(EVNHANDLE,BYTE nFormat) = 0; // number of decimal digits or date format has been changed
  194. };
  195. // the default implementation of a sink which does nothing
  196. // derive from it and implement only the notification wanted
  197. class AFX_EXT_CLASS CQueryDefDefaultSink : public IQueryDefEventSink
  198. {
  199. public:
  200. LPARAM RSNotifyOpen(EVNHANDLE) {return 0;}; // the recordset has been opened
  201. LPARAM RSNotifyClose(EVNHANDLE) {return 0;}; // the recordset has been closed
  202. LPARAM RSNotifyMove(EVNHANDLE) {return 0;}; // the recordset has modified the current position 
  203. LPARAM RSNotifyAddNew(EVNHANDLE) {return 0;}; // recordset is about to insert a new record (called after CQueryDef::AddNew)
  204. LPARAM RSNotifyEdit(EVNHANDLE) {return 0;}; // the current record will be modified to be updated (called after CQueryDef::Edit)
  205. LPARAM RSNotifyUpdate(EVNHANDLE) {return 0;}; // the current record will be updated (called after CQueryDef::Update)
  206. LPARAM RSNotifyDelete(EVNHANDLE) {return 0;}; // the current record was deleted
  207. LPARAM RSNotifyCancelUpdate(EVNHANDLE) {return 0;}; // the update of the current record was canceled (called after CQueryDef::CancelUpdate)
  208. LPARAM RSNotifyRequery(EVNHANDLE) {return 0;}; // the recordset was refreshed
  209. LPARAM RSNotifyFormatChanged(EVNHANDLE,BYTE nFormat){return 0;}; // number of decimal digits or date format has been changed
  210. };
  211. //////////////////////////////////////////////////////////////////////////////////////////////////////////////
  212. // QueryDefinition class used for retrieving (V1.0) & updating data (V1.5) from SQL Server
  213. // It may be used with stored procedures as well
  214. // Great use in dynamic recordsets in conjunction with the CQueryVariant datatype
  215. // Usage:
  216. // select * from T where ... group by ... having ... order by ... 
  217. // {?=CALL stored_procedure(input_param1,input_param2,...,?,...,?'type-letter')}
  218. // where
  219. // ? is a placeholder for parameters (? input param, ?'type-letter' output param)
  220. //
  221. // where type-letter:
  222. // L = long, F = float, D = double, I = int, Y = byte, C = char, X = binary, T = date-time, B = bool
  223. //
  224. // Due to different behaviour of various ODBC drivers, CQueryDef cannot be used to return output parameters 
  225. // altogether with rows. There is also a limitation in returning rows and the use of SQL Server based cursors.
  226. // Rules of thumb:
  227. // 1. return rows w/o output parameters
  228. // 2. don't return rows if you're using SQL based cursors (output params are legal)
  229. //////////////////////////////////////////////////////////////////////////////////////////////////////////////
  230. struct SQueryDefEventSink
  231. {
  232. SQueryDefEventSink(IQueryDefEventSink* pSink,BOOL bFreeze)
  233. {
  234. m_pSink   = pSink;
  235. m_frozen = bFreeze;
  236. };
  237. IQueryDefEventSink* m_pSink;
  238. BOOL m_frozen;
  239. };
  240. typedef CArray<CQueryCol,CQueryCol&> CQueryColArray; // an array of SQL column descriptors
  241. typedef CList<SQueryDefEventSink*,SQueryDefEventSink*> CSinkList; // the list of event sinks for notification
  242. class AFX_EXT_CLASS CQueryDef : public CRecordset2
  243. {
  244. DECLARE_DYNAMIC(CQueryDef);
  245. CQueryVariant m_cLine; // current line
  246. CQueryVariant m_cParam; // input & output parameters
  247. char m_ioParam[256]; // a maximum of 256 Params are allowed
  248. // 0 = input, 'type-letter' = output
  249. CString m_originalQuery; // the query as given by the user
  250. CArray<CODBCFieldInfo,int> m_ODBCFieldInfo; // columns information
  251. enum { eModeNoMode,eModeAddNew,eModeEdit }; // the edit modes (see below)
  252. int m_nMode; // signal AddNew is in progress
  253. // changed from V1.0 to RFX_xxx bindings in later versions
  254. // void GetSQLData(); // fills in the current line
  255. // see ReOpen()
  256. UINT m_nOpenType; // for implementation of ReOpen()
  257. CString m_strSQL;
  258. DWORD m_dwOptions;
  259. public:
  260. CQueryDef(CDatabase* pDB = NULL);
  261. CQueryDef(CDatabase* pConn,LPCSTR strSQL); // support for ad-hoc queries
  262. virtual ~CQueryDef();
  263. operator CQueryVariant&() { return m_cLine; }; // for direct access from this object
  264. CQueryVariant& Fields() { return m_cLine; }; // access to fields
  265. CQueryVar& Field(int i); // access to fields
  266. CQueryVar& Field(LPCTSTR fldName); // access to fields
  267. CQueryVariant& Params() { return m_cParam; }; // access to stored procedure's parameters
  268. CQueryVar& Param(int i); // access to stored procedure's parameters
  269. // conversion operators to use directly
  270. operator int() { return (int)m_cLine; }; // this class object when a single column
  271. operator BYTE() { return (BYTE)m_cLine; }; // or the first column are to be retrieved
  272. operator long() { return (long)m_cLine; };
  273. operator short() { return (short)m_cLine; };
  274. operator float() { return (float)m_cLine; };
  275. operator double() { return (double)m_cLine; };
  276. operator COleDateTime&() { return m_cLine.operator COleDateTime&(); };
  277. operator CLongBinary&() { return (CLongBinary&)m_cLine; };
  278. operator CStringArray&() { return (CStringArray&)m_cLine; };
  279. operator LPCTSTR() { return (LPCTSTR)m_cLine; };
  280. CQueryVar& operator[](int i); // access to fields by index
  281. CQueryVar& operator[](LPCTSTR lpszColumnName); // access to fields by column name
  282. CQueryVariant& operator=(CQueryVariant& v); // transfer the current line to a CQueryVariant
  283. virtual BOOL Open(UINT nOpenType=forwardOnly,
  284.  LPCTSTR lpszSQL = NULL,
  285.  DWORD dwOptions = readOnly|noDirtyFieldCheck|executeDirect);
  286. virtual void Close();
  287. // ReOpen() makes it possible to open again the querydef in case the database connection was broken
  288. virtual BOOL ReOpen(CDatabase* pDB); // connection broken & remade
  289. virtual void Move(long nRows,WORD wFetchType = SQL_FETCH_RELATIVE);
  290. virtual void PreBindFields(); // undocumented - called before first Move
  291. virtual void AddNew(); // needed for fixup the buffer adress change assert
  292. virtual void Edit();
  293. virtual BOOL Update();
  294. virtual void Delete();
  295. virtual BOOL Requery();
  296. void CancelUpdate(); // since this is not virtual must be explicitly called
  297. void SetFieldNull(void* pv,BOOL bNull = TRUE); // not implemented to generate a link error
  298. void SetParamNull(int nIndex,BOOL bNull = TRUE);
  299. short SetDecimalDigits(short d);
  300. LPCSTR SetDateFormat(LPCSTR strFormat);
  301. protected:
  302. virtual void DoFieldExchange(CFieldExchange* pFX);
  303. void BindParams(CFieldExchange* pFX);
  304. void BindFields(CFieldExchange* pFX);
  305. friend class CTabbedString;
  306. // V2.0
  307. private:
  308. CQueryColArray m_columns; // SQL column descriptors (V2.0)
  309. CSinkList m_evSink; // the notification sinks
  310. enum ENOTIFICATION // notification type
  311. {
  312. eNotifyOpen,
  313. eNotifyClose,
  314. eNotifyMove,
  315. eNotifyAddNew,
  316. eNotifyEdit,
  317. eNotifyUpdate,
  318. eNotifyDelete,
  319. eNotifyCancelUpdate,
  320. eNotifyRequery,
  321. eNotifyFormatChanged
  322. };
  323. enum // format changed enumerators
  324. {
  325. eFormatChangedDecimalDigits = 0xFF,
  326. eFormatChangedDate = 0xFE
  327. };
  328. void FreezeAllEvents(BOOL bFreeze=TRUE); // internal freeze
  329. void ClearEventSinkList(); // remove event sinks & cleanup
  330. public:
  331. // V2.0 notifications
  332. EVNHANDLE Advise(IQueryDefEventSink* pSink); // connects the notification sink
  333. void Unadvise(EVNHANDLE evnHandle);
  334. void FreezeEvents(EVNHANDLE evnHandle,BOOL bFreeze=TRUE); // temporarily start or stop notifications
  335. void NotifySink(ENOTIFICATION nNotify,LPARAM lp = 0); // notify all sinks
  336. // V2.0 SQL column descriptors
  337. CQueryColArray& Columns() { return m_columns; };
  338. CQueryCol& Column(int i);
  339. CQueryCol& Column(LPCTSTR colName);
  340. };
  341. //////////////////////////////////////////////////////////////////////////////////////////////////////////////
  342. // Helper classes to be used with CQueryDef and CQueryVariant
  343. //
  344. // CTabbedString - a string with <TAB> between columns
  345. //
  346. // NULL columns are represented with value <NULL> (as it is written i.e. with angle brackets)
  347. class AFX_EXT_CLASS CTabbedString : public CString
  348. {
  349. public:
  350. CTabbedString() : CString() {};
  351. CTabbedString(const CString& stringSrc) : CString(stringSrc) {};
  352. CTabbedString(TCHAR ch,int nRepeat = 1) : CString(ch,nRepeat) {};
  353. CTabbedString(LPCTSTR lpch,int nLength) : CString(lpch,nLength) {};
  354. CTabbedString(const unsigned char* psz) : CString(psz) {};
  355. CTabbedString(LPCWSTR lpsz) : CString(lpsz) {};
  356. CTabbedString(LPCSTR lpsz) : CString(lpsz) {};
  357. virtual ~CTabbedString() {};
  358. CTabbedString& operator=(CQueryDef& qDef); // get the current row from this qDef
  359. CTabbedString& operator=(CQueryVariant& qV); // get the values from this qV
  360. CTabbedString operator[](int i); // access to individual elements
  361. BOOL operator==(CSQLNull& sqlNull);
  362. BOOL operator!=(CSQLNull& sqlNull);
  363. BOOL IsNull(int i); // test the ith element for NULL value
  364. };
  365. // CSQLNull - helper class to test the above classes for SQL NULL value
  366. //
  367. class CSQLNull
  368. {
  369. public:
  370. static const int SqlNull;
  371. public:
  372. BOOL operator==(CQueryVar& qVar);
  373. BOOL operator!=(CQueryVar& qVar);
  374. BOOL operator==(CTabbedString& qVar);
  375. BOOL operator!=(CTabbedString& qVar);
  376. };
  377. inline CQueryVar& CQueryDef::Field(int i)
  378. {
  379. return operator[](i);
  380. };
  381. inline CQueryVar& CQueryDef::Field(LPCTSTR fldName)
  382. {
  383. return operator[](fldName);
  384. };
  385. inline CQueryVar& CQueryDef::Param(int i)
  386. {
  387. return m_cParam.operator[](i);
  388. };
  389. inline CQueryCol& CQueryDef::Column(int i)
  390. {
  391. if (i >= m_columns.GetSize())
  392. throw CQueryVar::eBoundary;
  393. return m_columns[i];
  394. };
  395. // global functions
  396. const char chHexDigits[] = { '0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f' };
  397. CString ConvertToHex(void* pbinary,int length); // converts a binary stream to hex representation
  398. }; // namespace QueryDef
  399. #if !defined(_QUERYDEFCOMPILE)
  400. __declspec(dllimport) QueryDef::CSQLNull SQL_NULL; // use this value to test for SQL NULL
  401. #if defined(_DEBUG)
  402. #pragma comment(lib,"QueryDefD")
  403. #else
  404. #pragma comment(lib,"QueryDef")
  405. #endif // defined(_DEBUG)
  406. #endif // defined(_AFXEXT)
  407. #if defined(_GUARDIAN_ANGEL)
  408. #define _AFXEXT
  409. #endif
  410. #endif // !defined(AFX_QUERYDEF_H__A94B98EA_5F3C_11D1_898E_0080C83612CB__INCLUDED_)