Planeshift

dal.h

Go to the documentation of this file.
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