Team Fortress 2 Source Code as on 22/4/2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

397 lines
7.3 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. // mysql_wrapper.cpp : Defines the entry point for the DLL application.
  8. //
  9. #include "stdafx.h"
  10. extern "C"
  11. {
  12. #include "mysql.h"
  13. };
  14. #include "imysqlwrapper.h"
  15. #include <stdio.h>
  16. static char* CopyString( const char *pStr )
  17. {
  18. if ( !pStr )
  19. {
  20. pStr = "";
  21. }
  22. char *pRet = new char[ strlen( pStr ) + 1 ];
  23. strcpy( pRet, pStr );
  24. return pRet;
  25. }
  26. BOOL APIENTRY DllMain( HANDLE hModule,
  27. DWORD ul_reason_for_call,
  28. LPVOID lpReserved
  29. )
  30. {
  31. return TRUE;
  32. }
  33. class CCopiedRow
  34. {
  35. public:
  36. ~CCopiedRow()
  37. {
  38. m_Columns.PurgeAndDeleteElements();
  39. }
  40. CUtlVector<char*> m_Columns;
  41. };
  42. class CMySQLCopiedRowSet : public IMySQLRowSet
  43. {
  44. public:
  45. ~CMySQLCopiedRowSet()
  46. {
  47. m_Rows.PurgeAndDeleteElements();
  48. m_ColumnNames.PurgeAndDeleteElements();
  49. }
  50. virtual void Release()
  51. {
  52. delete this;
  53. }
  54. virtual int NumFields()
  55. {
  56. return m_ColumnNames.Count();
  57. }
  58. virtual const char* GetFieldName( int iColumn )
  59. {
  60. return m_ColumnNames[iColumn];
  61. }
  62. virtual bool NextRow()
  63. {
  64. ++m_iCurRow;
  65. return m_iCurRow < m_Rows.Count();
  66. }
  67. virtual bool SeekToFirstRow()
  68. {
  69. m_iCurRow = 0;
  70. return m_iCurRow < m_Rows.Count();
  71. }
  72. virtual CColumnValue GetColumnValue( int iColumn )
  73. {
  74. return CColumnValue( this, iColumn );
  75. }
  76. virtual CColumnValue GetColumnValue( const char *pColumnName )
  77. {
  78. return CColumnValue( this, GetColumnIndex( pColumnName ) );
  79. }
  80. virtual const char* GetColumnValue_String( int iColumn )
  81. {
  82. if ( iColumn < 0 || iColumn >= m_ColumnNames.Count() )
  83. return "<invalid column specified>";
  84. else if ( m_iCurRow < 0 || m_iCurRow >= m_Rows.Count() )
  85. return "<invalid row specified>";
  86. else
  87. return m_Rows[m_iCurRow]->m_Columns[iColumn];
  88. }
  89. virtual long GetColumnValue_Int( int iColumn )
  90. {
  91. return atoi( GetColumnValue_String( iColumn ) );
  92. }
  93. virtual int GetColumnIndex( const char *pColumnName )
  94. {
  95. for ( int i=0; i < m_ColumnNames.Count(); i++ )
  96. {
  97. if ( stricmp( m_ColumnNames[i], pColumnName ) == 0 )
  98. return i;
  99. }
  100. return -1;
  101. }
  102. public:
  103. int m_iCurRow;
  104. CUtlVector<CCopiedRow*> m_Rows;
  105. CUtlVector<char*> m_ColumnNames;
  106. };
  107. // -------------------------------------------------------------------------------------------------------- //
  108. // CMySQL class.
  109. // -------------------------------------------------------------------------------------------------------- //
  110. class CMySQL : public IMySQL
  111. {
  112. public:
  113. CMySQL();
  114. virtual ~CMySQL();
  115. virtual bool InitMySQL( const char *pDBName, const char *pHostName, const char *pUserName, const char *pPassword );
  116. virtual void Release();
  117. virtual int Execute( const char *pString );
  118. virtual IMySQLRowSet* DuplicateRowSet();
  119. virtual unsigned long InsertID();
  120. virtual int NumFields();
  121. virtual const char* GetFieldName( int iColumn );
  122. virtual bool NextRow();
  123. virtual bool SeekToFirstRow();
  124. virtual CColumnValue GetColumnValue( int iColumn );
  125. virtual CColumnValue GetColumnValue( const char *pColumnName );
  126. virtual const char* GetColumnValue_String( int iColumn );
  127. virtual long GetColumnValue_Int( int iColumn );
  128. virtual int GetColumnIndex( const char *pColumnName );
  129. // Cancels the storage of the rows from the latest query.
  130. void CancelIteration();
  131. virtual const char * GetLastError( void );
  132. public:
  133. MYSQL *m_pSQL;
  134. MYSQL_RES *m_pResult;
  135. MYSQL_ROW m_Row;
  136. CUtlVector<MYSQL_FIELD> m_Fields;
  137. char m_szLastError[128];
  138. };
  139. EXPOSE_INTERFACE( CMySQL, IMySQL, MYSQL_WRAPPER_VERSION_NAME );
  140. // -------------------------------------------------------------------------------------------------------- //
  141. // CMySQL implementation.
  142. // -------------------------------------------------------------------------------------------------------- //
  143. CMySQL::CMySQL()
  144. {
  145. m_pSQL = NULL;
  146. m_pResult = NULL;
  147. m_Row = NULL;
  148. }
  149. CMySQL::~CMySQL()
  150. {
  151. CancelIteration();
  152. if ( m_pSQL )
  153. {
  154. mysql_close( m_pSQL );
  155. m_pSQL = NULL;
  156. }
  157. }
  158. bool CMySQL::InitMySQL( const char *pDBName, const char *pHostName, const char *pUserName, const char *pPassword )
  159. {
  160. MYSQL *pSQL = mysql_init( NULL );
  161. if ( !pSQL )
  162. return NULL;
  163. if ( !mysql_real_connect( pSQL, pHostName, pUserName, pPassword, pDBName, 0, NULL, 0 ) )
  164. {
  165. Q_strncpy( m_szLastError, mysql_error( pSQL ), sizeof(m_szLastError) );
  166. mysql_close( pSQL );
  167. return false;
  168. }
  169. m_pSQL = pSQL;
  170. return true;
  171. }
  172. void CMySQL::Release()
  173. {
  174. delete this;
  175. }
  176. int CMySQL::Execute( const char *pString )
  177. {
  178. CancelIteration();
  179. int result = mysql_query( m_pSQL, pString );
  180. if ( result == 0 )
  181. {
  182. // Is this a query with a result set?
  183. m_pResult = mysql_store_result( m_pSQL );
  184. if ( m_pResult )
  185. {
  186. // Store the field information.
  187. int count = mysql_field_count( m_pSQL );
  188. MYSQL_FIELD *pFields = mysql_fetch_fields( m_pResult );
  189. m_Fields.CopyArray( pFields, count );
  190. return 0;
  191. }
  192. else
  193. {
  194. // No result set. Was a set expected?
  195. if ( mysql_field_count( m_pSQL ) != 0 )
  196. return 1; // error! The query expected data but didn't get it.
  197. }
  198. }
  199. else
  200. {
  201. const char *pError = mysql_error( m_pSQL );
  202. pError = pError;
  203. }
  204. return result;
  205. }
  206. IMySQLRowSet* CMySQL::DuplicateRowSet()
  207. {
  208. CMySQLCopiedRowSet *pSet = new CMySQLCopiedRowSet;
  209. pSet->m_iCurRow = -1;
  210. pSet->m_ColumnNames.SetSize( m_Fields.Count() );
  211. for ( int i=0; i < m_Fields.Count(); i++ )
  212. pSet->m_ColumnNames[i] = CopyString( m_Fields[i].name );
  213. while ( NextRow() )
  214. {
  215. CCopiedRow *pRow = new CCopiedRow;
  216. pSet->m_Rows.AddToTail( pRow );
  217. pRow->m_Columns.SetSize( m_Fields.Count() );
  218. for ( int i=0; i < m_Fields.Count(); i++ )
  219. {
  220. pRow->m_Columns[i] = CopyString( m_Row[i] );
  221. }
  222. }
  223. return pSet;
  224. }
  225. unsigned long CMySQL::InsertID()
  226. {
  227. return mysql_insert_id( m_pSQL );
  228. }
  229. int CMySQL::NumFields()
  230. {
  231. return m_Fields.Count();
  232. }
  233. const char* CMySQL::GetFieldName( int iColumn )
  234. {
  235. return m_Fields[iColumn].name;
  236. }
  237. bool CMySQL::NextRow()
  238. {
  239. if ( !m_pResult )
  240. return false;
  241. m_Row = mysql_fetch_row( m_pResult );
  242. if ( m_Row == 0 )
  243. {
  244. return false;
  245. }
  246. else
  247. {
  248. return true;
  249. }
  250. }
  251. bool CMySQL::SeekToFirstRow()
  252. {
  253. if ( !m_pResult )
  254. return false;
  255. mysql_data_seek( m_pResult, 0 );
  256. return true;
  257. }
  258. CColumnValue CMySQL::GetColumnValue( int iColumn )
  259. {
  260. return CColumnValue( this, iColumn );
  261. }
  262. CColumnValue CMySQL::GetColumnValue( const char *pColumnName )
  263. {
  264. return CColumnValue( this, GetColumnIndex( pColumnName ) );
  265. }
  266. const char* CMySQL::GetColumnValue_String( int iColumn )
  267. {
  268. if ( m_Row && iColumn >= 0 && iColumn < m_Fields.Count() && m_Row[iColumn] )
  269. return m_Row[iColumn];
  270. else
  271. return "";
  272. }
  273. long CMySQL::GetColumnValue_Int( int iColumn )
  274. {
  275. return atoi( GetColumnValue_String( iColumn ) );
  276. }
  277. int CMySQL::GetColumnIndex( const char *pColumnName )
  278. {
  279. for ( int i=0; i < m_Fields.Count(); i++ )
  280. {
  281. if ( stricmp( pColumnName, m_Fields[i].name ) == 0 )
  282. {
  283. return i;
  284. }
  285. }
  286. return -1;
  287. }
  288. void CMySQL::CancelIteration()
  289. {
  290. m_Fields.Purge();
  291. if ( m_pResult )
  292. {
  293. mysql_free_result( m_pResult );
  294. m_pResult = NULL;
  295. }
  296. m_Row = NULL;
  297. }
  298. const char *CMySQL::GetLastError( void )
  299. {
  300. // Default to the last error if m_pSQL was not successfully initialized
  301. const char *pszLastError = m_szLastError;
  302. if ( m_pSQL )
  303. {
  304. pszLastError = mysql_error( m_pSQL );
  305. }
  306. return pszLastError;
  307. }