Planeshift
|
00001 // 00002 // Database Abstraction Layer 00003 // Keith Fulton <[email protected]> 00004 // 02/14/02 00005 // 00006 00007 #ifndef __DAL_H__ 00008 #define __DAL_H__ 00009 00010 #include <idal.h> 00011 00012 #include <csutil/scf.h> 00013 #include <csutil/scf_implementation.h> 00014 #include <csutil/threading/thread.h> 00015 00016 #include "iutil/comp.h" 00017 00018 #include "net/netbase.h" // Make sure that winsock is included. 00019 00020 #include <mysql.h> 00021 00022 #include <csutil/csstring.h> 00023 #include "util/stringarray.h" 00024 #include "util/dbprofile.h" 00025 00026 using namespace CS::Threading; 00027 00028 struct iObjectRegistry; 00029 00030 CS_PLUGIN_NAMESPACE_BEGIN(dbmysql) 00031 { 00032 #ifdef USE_DELAY_QUERY 00033 #define THREADED_BUFFER_SIZE 300 00034 class DelayedQueryManager : public CS::Threading::Runnable 00035 { 00036 public: 00037 DelayedQueryManager(const char *host, unsigned int port, const char *database, 00038 const char *user, const char *pwd); 00039 00040 virtual void Run (); 00041 void Push(csString query); 00042 void Stop(); 00043 private: 00044 MYSQL* m_conn; 00045 csString arr[THREADED_BUFFER_SIZE]; 00046 size_t start, end; 00047 CS::Threading::Mutex mutex; 00048 CS::Threading::RecursiveMutex mutexArray; 00049 CS::Threading::Condition datacondition; 00050 bool m_Close; 00051 psDBProfiles profs; 00052 csString m_host; 00053 unsigned int m_port; 00054 csString m_db; 00055 csString m_user; 00056 csString m_pwd; 00057 }; 00058 #endif 00059 00060 class psMysqlConnection : public scfImplementation2<psMysqlConnection, iComponent, iDataConnection> 00061 { 00062 protected: 00063 MYSQL mydb; // Mysql connection 00064 MYSQL *conn; // Points to mydb after a successfull connection to the db 00065 csString lastquery; 00066 iObjectRegistry *objectReg; 00067 psDBProfiles profs; 00068 csString profileDump; 00069 LogCSV* logcsv; 00070 00071 public: 00072 psMysqlConnection(iBase *iParent); 00073 virtual ~psMysqlConnection(); 00074 00075 bool Initialize (iObjectRegistry *objectreg); 00076 bool Initialize(const char *host, unsigned int port, const char *database, 00077 const char *user, const char *pwd, LogCSV* logcsv); 00078 virtual bool Close(); 00079 00080 int IsValid(void); 00081 00086 void Escape(csString& to, const char *from); 00087 00088 iResultSet *Select(const char *sql,...); 00089 int SelectSingleNumber(const char *sql, ...); 00090 unsigned long Command(const char *sql,...); 00091 unsigned long CommandPump(const char *sql,...); 00092 00093 uint64 GenericInsertWithID(const char *table,const char **fieldnames,psStringArray& fieldvalues); 00094 bool GenericUpdateWithID(const char *table,const char *idfield,const char *id,const char **fieldnames,psStringArray& fieldvalues); 00095 bool GenericUpdateWithID(const char *table,const char *idfield,const char *id,psStringArray& fields); 00096 00097 const char *GetLastError(void); 00098 const char *GetLastQuery(void) 00099 { 00100 return lastquery; 00101 }; 00102 uint64 GetLastInsertID(); 00103 00104 const char *uint64tostring(uint64 value,csString& recv); 00105 00106 virtual const char* DumpProfile(); 00107 virtual void ResetProfile(); 00108 00109 iRecord* NewUpdatePreparedStatement(const char* table, const char* idfield, unsigned int count, const char* file, unsigned int line); 00110 iRecord* NewInsertPreparedStatement(const char* table, unsigned int count, const char* file, unsigned int line); 00111 00112 #ifdef USE_DELAY_QUERY 00113 csRef<DelayedQueryManager> dqm; 00114 csRef<Thread> dqmThread; 00115 #endif 00116 }; 00117 00118 00119 class psResultRow : public iResultRow 00120 { 00121 protected: 00122 MYSQL_ROW rr; 00123 MYSQL_RES *rs; 00124 int max; 00125 int last_index; 00126 00127 public: 00128 psResultRow() 00129 { 00130 rr = NULL; 00131 rs = NULL; 00132 last_index=0; 00133 }; 00134 00135 void SetMaxFields(int fields) { max = fields; }; 00136 void SetResultSet(void* resultsettoken); 00137 00138 int Fetch(int row); 00139 00140 const char *operator[](int whichfield); 00141 const char *operator[](const char *fieldname); 00142 00143 const char* GetString(int whichfield); 00144 const char* GetString(const char *fieldname); 00145 00146 int GetInt(int whichfield); 00147 int GetInt(const char *fieldname); 00148 00149 unsigned long GetUInt32(int whichfield); 00150 unsigned long GetUInt32(const char *fieldname); 00151 00152 float GetFloat(int whichfield); 00153 float GetFloat(const char *fieldname); 00154 00155 uint64 GetUInt64(int whichfield); 00156 uint64 GetUInt64(const char *fieldname); 00157 00158 uint64 stringtouint64(const char *stringbuf); 00159 const char *uint64tostring(uint64 value,char *stringbuf,int buflen); 00160 }; 00161 00162 class psResultSet : public iResultSet 00163 { 00164 protected: 00165 MYSQL_RES *rs; 00166 unsigned long rows, fields, current; 00167 psResultRow row; 00168 00169 public: 00170 psResultSet(MYSQL *conn); 00171 virtual ~psResultSet(); 00172 00173 void Release(void) { delete this; }; 00174 00175 iResultRow& operator[](unsigned long whichrow); 00176 00177 unsigned long Count(void) { return rows; }; 00178 }; 00179 00180 class dbRecord : public iRecord 00181 { 00182 protected: 00183 const char* table; 00184 const char* idfield; 00185 00186 MYSQL* conn; 00187 00188 psStringArray command; 00189 bool prepared; 00190 00191 MYSQL_BIND* bind; 00192 MYSQL_STMT* stmt; 00193 00194 unsigned int index; 00195 unsigned int count; 00196 00197 // Useful for debugging 00198 LogCSV* logcsv; 00199 const char* file; 00200 unsigned int line; 00201 00202 // This is a holding structure to ensure the data is available as long as the binding needs it. 00203 typedef struct{ 00204 int iValue; 00205 // On *nix and Windows, uint32 is equivalent to unsigned int 00206 // this is important for SQL 00207 unsigned int uiValue; 00208 unsigned short usValue; 00209 float fValue; 00210 csString string; 00211 unsigned long length; 00212 } dataType; 00213 00214 dataType* temp; 00215 00216 virtual void AddToStatement(const char* fname) = 0; 00217 00218 virtual void SetID(uint32 uid) = 0; 00219 00220 public: 00221 dbRecord(MYSQL* db, const char* Table, const char* Idfield, unsigned int count, LogCSV* logcsv, const char* file, unsigned int line) 00222 { 00223 conn = db; 00224 table = Table; 00225 idfield = Idfield; 00226 bind = new MYSQL_BIND[count]; 00227 memset(bind, 0, sizeof(MYSQL_BIND) * count); 00228 temp = new dataType[count]; 00229 index = 0; 00230 this->count = count; 00231 this->logcsv = logcsv; 00232 this->file = file; 00233 this->line = line; 00234 00235 stmt = (MYSQL_STMT*) mysql_stmt_init(conn); 00236 prepared = false; 00237 } 00238 00239 virtual ~dbRecord() 00240 { 00241 mysql_stmt_close(stmt); 00242 delete[] bind; 00243 delete[] temp; 00244 } 00245 00246 void Reset() 00247 { 00248 index = 0; 00249 memset(bind, 0, sizeof(MYSQL_BIND) * count); 00250 command.Empty(); //clears the command array to avoid restarting from a wrong position. 00251 } 00252 00253 00254 void AddField(const char* fname, float fValue); 00255 00256 void AddField(const char* fname, int iValue); 00257 00258 void AddField(const char* fname, unsigned int uiValue); 00259 00260 void AddField(const char* fname, unsigned short usValue); 00261 00262 void AddField(const char* fname, const char* sValue); 00263 00264 void AddFieldNull(const char* fname); 00265 00266 virtual bool Prepare() = 0; 00267 00268 virtual bool Execute(uint32 uid); 00269 }; 00270 00271 class dbInsert : public dbRecord 00272 { 00273 virtual void AddToStatement(const char* fname) 00274 { 00275 if(!prepared) 00276 command.Push(fname); 00277 } 00278 00279 virtual void SetID(uint32 /*uid*/) { }; 00280 00281 public: 00282 dbInsert(MYSQL* db, const char* Table, unsigned int count, LogCSV* logcsv, const char* file, unsigned int line) 00283 : dbRecord(db, Table, "", count, logcsv, file, line) { } 00284 00285 virtual bool Prepare(); 00286 }; 00287 00288 class dbUpdate : public dbRecord 00289 { 00290 virtual void AddToStatement(const char* fname) 00291 { 00292 if(!prepared) 00293 command.FormatPush("%s = ?", fname); 00294 } 00295 00296 virtual void SetID(uint32 uid) 00297 { 00298 temp[index].uiValue = uid; 00299 bind[index].buffer_type = MYSQL_TYPE_LONG; 00300 bind[index].buffer = &(temp[index].uiValue); 00301 bind[index].is_unsigned = true; 00302 index++; 00303 } 00304 public: 00305 dbUpdate(MYSQL* db, const char* Table, const char* Idfield, unsigned int count, LogCSV* logcsv, const char* file, unsigned int line) 00306 : dbRecord(db, Table, Idfield, count, logcsv, file, line) { } 00307 00308 virtual bool Prepare(); 00309 00310 }; 00311 } 00312 CS_PLUGIN_NAMESPACE_END(dbmysql) 00313 #endif 00314