initial import of sqlite extension

--HG--
extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%401209
This commit is contained in:
David Anderson
2007-07-29 01:15:31 +00:00
parent 2f3c518eb1
commit 9f6a67ba17
82 changed files with 70359 additions and 0 deletions
+186
View File
@@ -0,0 +1,186 @@
/**
* vim: set ts=4 :
* ===============================================================
* SourceMod SQLite Driver Extension
* Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
* ===============================================================
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Version: $Id$
*/
#include "extension.h"
#include "SqDatabase.h"
#include "SqQuery.h"
SqDatabase::SqDatabase(sqlite3 *sq3, bool persistent) :
m_sq3(sq3), m_refcount(1), m_pFullLock(NULL), m_Persistent(persistent)
{
m_pRefLock = threader->MakeMutex();
}
SqDatabase::~SqDatabase()
{
m_pRefLock->DestroyThis();
if (m_pFullLock)
{
m_pFullLock->DestroyThis();
}
sqlite3_close(m_sq3);
}
void SqDatabase::IncReferenceCount()
{
m_pRefLock->Lock();
m_refcount++;
m_pRefLock->Unlock();
}
bool SqDatabase::Close()
{
m_pRefLock->Lock();
if (m_refcount > 1)
{
m_refcount--;
m_pRefLock->Unlock();
return false;
}
m_pRefLock->Unlock();
if (m_Persistent)
{
g_SqDriver.RemovePersistent(this);
}
delete this;
return true;
}
const char *SqDatabase::GetError(int *errorCode/* =NULL */)
{
return sqlite3_errmsg(m_sq3);
}
bool SqDatabase::LockForFullAtomicOperation()
{
if (!m_pFullLock)
{
m_pFullLock = threader->MakeMutex();
if (!m_pFullLock)
{
return false;
}
}
m_pFullLock->Lock();
return true;
}
void SqDatabase::UnlockFromFullAtomicOperation()
{
if (m_pFullLock)
{
m_pFullLock->Unlock();
}
}
IDBDriver *SqDatabase::GetDriver()
{
return &g_SqDriver;
}
bool SqDatabase::QuoteString(const char *str, char buffer[], size_t maxlen, size_t *newSize)
{
char *res = sqlite3_snprintf(static_cast<int>(maxlen), buffer, "%q", str);
if (res != NULL && newSize != NULL)
{
*newSize = strlen(buffer);
}
return (res != NULL);
}
unsigned int SqDatabase::GetInsertID()
{
return (unsigned int)sqlite3_last_insert_rowid(m_sq3);
}
unsigned int SqDatabase::GetAffectedRows()
{
return (unsigned int)sqlite3_changes(m_sq3);
}
bool SqDatabase::DoSimpleQuery(const char *query)
{
IQuery *pQuery = DoQuery(query);
if (!pQuery)
{
return false;
}
pQuery->Destroy();
return true;
}
/* this sounds like daiquiri.. i'm tired. */
IQuery *SqDatabase::DoQuery(const char *query)
{
IPreparedQuery *pQuery = PrepareQuery(query, NULL, 0, NULL);
if (!pQuery)
{
return NULL;
}
if (!pQuery->Execute())
{
pQuery->Destroy();
return NULL;
}
return pQuery;
}
IPreparedQuery *SqDatabase::PrepareQuery(const char *query, char *error, size_t maxlength, int *errCode/* =NULL */)
{
sqlite3_stmt *stmt = NULL;
if ((m_LastErrorCode = sqlite3_prepare_v2(m_sq3, query, -1, &stmt, NULL)) != SQLITE_OK
|| !stmt)
{
const char *msg;
if (m_LastErrorCode != SQLITE_OK)
{
msg = sqlite3_errmsg(m_sq3);
} else {
msg = "Invalid query string";
m_LastErrorCode = SQLITE_MISUSE;
}
if (error)
{
strncopy(error, msg, maxlength);
}
m_LastError.assign(msg);
if (stmt)
{
sqlite3_finalize(stmt);
}
return NULL;
}
return new SqQuery(this, stmt);
}
sqlite3 *SqDatabase::GetDb()
{
return m_sq3;
}
+60
View File
@@ -0,0 +1,60 @@
/**
* vim: set ts=4 :
* ===============================================================
* SourceMod SQLite Driver Extension
* Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
* ===============================================================
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Version: $Id$
*/
#ifndef _INCLUDE_SQLITE_SOURCEMOD_DATABASE_H_
#define _INCLUDE_SQLITE_SOURCEMOD_DATABASE_H_
#include <IThreader.h>
#include "SqDriver.h"
class SqDatabase : public IDatabase
{
public:
SqDatabase(sqlite3 *sq3, bool persistent);
~SqDatabase();
public:
bool Close();
const char *GetError(int *errorCode=NULL);
bool DoSimpleQuery(const char *query);
IQuery *DoQuery(const char *query);
IPreparedQuery *PrepareQuery(const char *query, char *error, size_t maxlength, int *errCode=NULL);
bool QuoteString(const char *str, char buffer[], size_t maxlen, size_t *newSize);
unsigned int GetAffectedRows();
unsigned int GetInsertID();
bool LockForFullAtomicOperation();
void UnlockFromFullAtomicOperation();
void IncReferenceCount();
IDBDriver *GetDriver();
public:
sqlite3 *GetDb();
private:
sqlite3 *m_sq3;
unsigned int m_refcount;
IMutex *m_pFullLock;
IMutex *m_pRefLock;
bool m_Persistent;
String m_LastError;
int m_LastErrorCode;
};
#endif //_INCLUDE_SQLITE_SOURCEMOD_DATABASE_H_
+244
View File
@@ -0,0 +1,244 @@
/**
* vim: set ts=4 :
* ===============================================================
* SourceMod SQLite Driver Extension
* Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
* ===============================================================
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Version: $Id$
*/
#include <sm_platform.h>
#include "extension.h"
#include "SqDriver.h"
#include "SqDatabase.h"
SqDriver g_SqDriver;
unsigned int strncopy(char *dest, const char *src, size_t count)
{
if (!count)
{
return 0;
}
char *start = dest;
while ((*src) && (--count))
{
*dest++ = *src++;
}
*dest = '\0';
return (dest - start);
}
SqDriver::SqDriver()
{
m_Handle = BAD_HANDLE;
m_pOpenLock = NULL;
}
void SqDriver::Initialize()
{
m_pOpenLock = threader->MakeMutex();
}
void SqDriver::Shutdown()
{
if (m_pOpenLock)
{
m_pOpenLock->DestroyThis();
}
}
bool SqDriver::IsThreadSafe()
{
return true;
}
bool SqDriver::InitializeThreadSafety()
{
/* sqlite should be thread safe if the locks are done right.
* we don't enable the "shared cache" because it can corrupt
* open databases!
*/
return true;
}
void SqDriver::ShutdownThreadSafety()
{
return;
}
IdentityToken_t *SqDriver::GetIdentity()
{
return myself->GetIdentity();
}
const char *SqDriver::GetProductName()
{
return "SQLite";
}
const char *SqDriver::GetIdentifier()
{
return "sqlite";
}
Handle_t SqDriver::GetHandle()
{
if (m_Handle == BAD_HANDLE)
{
m_Handle = dbi->CreateHandle(DBHandle_Driver, this, myself->GetIdentity());
}
return m_Handle;
}
inline bool IsPathSepChar(char c)
{
#if defined PLATFORM_WINDOWS
return (c == '\\' || c == '/');
#elif defined PLATFORM_LINUX
return (c == '/');
#endif
}
IDatabase *SqDriver::Connect(const DatabaseInfo *info, bool persistent, char *error, size_t maxlength)
{
/* We wrap most of the open process in a mutex just to be safe */
m_pOpenLock->Lock();
/* Format our path */
char path[PLATFORM_MAX_PATH];
size_t len = libsys->PathFormat(path, sizeof(path), "sqlite/%s", info->database);
/* Chop any filename off */
for (size_t i = len-1;
i >= 0 && i <= len-1;
i--)
{
if (IsPathSepChar(path[i]))
{
path[i] = '\0';
break;
}
}
/* Test the full path */
char fullpath[PLATFORM_MAX_PATH];
g_pSM->BuildPath(Path_SM, fullpath, sizeof(fullpath), "data/%s", path);
if (!libsys->IsPathDirectory(fullpath))
{
/* Make sure the data folder exists */
len = g_pSM->BuildPath(Path_SM, fullpath, sizeof(fullpath), "data");
if (!libsys->IsPathDirectory(fullpath))
{
if (!libsys->CreateFolder(fullpath))
{
strncopy(error, "Could not create or open \"data\" folder\"", maxlength);
m_pOpenLock->Unlock();
return NULL;
}
}
/* The data folder exists - create each subdir as needed! */
char *cur_ptr = path;
do
{
/* Find the next suitable path */
char *next_ptr = cur_ptr;
while (*next_ptr != '\0')
{
if (IsPathSepChar(*next_ptr))
{
*next_ptr = '\0';
next_ptr++;
break;
}
next_ptr++;
}
if (*next_ptr == '\0')
{
next_ptr = NULL;
}
len += libsys->PathFormat(&fullpath[len], sizeof(fullpath)-len, "/%s", cur_ptr);
if (!libsys->IsPathDirectory(fullpath) && !libsys->CreateFolder(fullpath))
{
break;
}
cur_ptr = next_ptr;
} while (cur_ptr);
}
/* Build the FINAL path. */
g_pSM->BuildPath(Path_SM, fullpath, sizeof(fullpath), "data/sqlite/%s.sq3", info->database);
/* If we're requesting a persistent connection, see if something is already open */
if (persistent)
{
/* See if anything in the cache matches */
List<SqDbInfo>::iterator iter;
for (iter = m_Cache.begin(); iter != m_Cache.end(); iter++)
{
if ((*iter).path.compare(fullpath) == 0)
{
(*iter).db->IncReferenceCount();
m_pOpenLock->Unlock();
return (*iter).db;
}
}
}
/* Try to open a new connection */
sqlite3 *sql;
int err = sqlite3_open(fullpath, &sql);
if (err != SQLITE_OK)
{
strncopy(error, sqlite3_errmsg(sql), maxlength);
sqlite3_close(sql);
m_pOpenLock->Unlock();
return NULL;
}
SqDatabase *pdb = new SqDatabase(sql, persistent);
if (persistent)
{
SqDbInfo pinfo;
pinfo.path = fullpath;
pinfo.db = pdb;
m_Cache.push_back(pinfo);
}
m_pOpenLock->Unlock();
return pdb;
}
void SqDriver::RemovePersistent(IDatabase *pdb)
{
List<SqDbInfo>::iterator iter;
for (iter = m_Cache.begin(); iter != m_Cache.end(); iter++)
{
if ((*iter).db == pdb)
{
iter = m_Cache.erase(iter);
return;
}
}
}
+73
View File
@@ -0,0 +1,73 @@
/**
* vim: set ts=4 :
* ===============================================================
* SourceMod SQLite Driver Extension
* Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
* ===============================================================
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Version: $Id$
*/
#ifndef _INCLUDE_SQLITE_SOURCEMOD_DRIVER_H_
#define _INCLUDE_SQLITE_SOURCEMOD_DRIVER_H_
#include <IDBDriver.h>
#include <IThreader.h>
#include <sh_list.h>
#include <sh_string.h>
#include "sqlite-source/sqlite3.h"
using namespace SourceMod;
using namespace SourceHook;
struct SqDbInfo
{
String path;
IDatabase *db;
};
/**
* Tee-hee.. sounds like "screw driver," except maybe if
* Elmer Fudd was saying it.
*/
class SqDriver : public IDBDriver
{
public:
SqDriver();
void Initialize();
void Shutdown();
public:
IDatabase *Connect(const DatabaseInfo *info, bool persistent, char *error, size_t maxlength);
const char *GetIdentifier();
const char *GetProductName();
Handle_t GetHandle();
IdentityToken_t *GetIdentity();
bool IsThreadSafe();
bool InitializeThreadSafety();
void ShutdownThreadSafety();
public:
void RemovePersistent(IDatabase *pdb);
private:
Handle_t m_Handle;
IMutex *m_pOpenLock;
List<SqDbInfo> m_Cache;
};
extern SqDriver g_SqDriver;
unsigned int strncopy(char *dest, const char *src, size_t count);
#endif //_INCLUDE_SQLITE_SOURCEMOD_DRIVER_H_
+186
View File
@@ -0,0 +1,186 @@
/**
* vim: set ts=4 :
* ===============================================================
* SourceMod SQLite Driver Extension
* Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
* ===============================================================
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Version: $Id$
*/
#include "SqQuery.h"
SqQuery::SqQuery(SqDatabase *parent, sqlite3_stmt *stmt) :
m_pParent(parent), m_pStmt(stmt), m_pResults(NULL), m_AffectedRows(0), m_InsertID(0)
{
m_ParamCount = sqlite3_bind_parameter_count(m_pStmt);
m_pParent->IncReferenceCount();
}
SqQuery::~SqQuery()
{
delete m_pResults;
sqlite3_finalize(m_pStmt);
m_pParent->Close();
}
IResultSet *SqQuery::GetResultSet()
{
return m_pResults;
}
bool SqQuery::FetchMoreResults()
{
/* We never have multiple result sets */
return false;
}
void SqQuery::Destroy()
{
delete this;
}
bool SqQuery::BindParamFloat(unsigned int param, float f)
{
/* SQLite is 1 indexed */
param++;
if (param > m_ParamCount)
{
return false;
}
return (sqlite3_bind_double(m_pStmt, param, (double)f) == SQLITE_OK);
}
bool SqQuery::BindParamNull(unsigned int param)
{
/* SQLite is 1 indexed */
param++;
if (param > m_ParamCount)
{
return false;
}
return (sqlite3_bind_null(m_pStmt, param) == SQLITE_OK);
}
bool SqQuery::BindParamString(unsigned int param, const char *text, bool copy)
{
/* SQLite is 1 indexed */
param++;
if (param > m_ParamCount)
{
return false;
}
return (sqlite3_bind_text(m_pStmt, param, text, -1, copy ? SQLITE_TRANSIENT : SQLITE_STATIC) == SQLITE_OK);
}
bool SqQuery::BindParamInt(unsigned int param, int num, bool signd/* =true */)
{
/* SQLite is 1 indexed */
param++;
if (param > m_ParamCount)
{
return false;
}
return (sqlite3_bind_int(m_pStmt, param, num) == SQLITE_OK);
}
bool SqQuery::BindParamBlob(unsigned int param, const void *data, size_t length, bool copy)
{
/* SQLite is 1 indexed */
param++;
if (param > m_ParamCount)
{
return false;
}
return (sqlite3_bind_blob(m_pStmt, param, data, length, copy ? SQLITE_TRANSIENT : SQLITE_STATIC) == SQLITE_OK);
}
sqlite3_stmt *SqQuery::GetStmt()
{
return m_pStmt;
}
bool SqQuery::Execute()
{
int rc;
/* If we've got results, throw them away */
if (m_pResults)
{
m_pResults->ResetResultCount();
}
while ((rc = sqlite3_step(m_pStmt)) == SQLITE_ROW)
{
/* Delay creation as long as possible... */
if (!m_pResults)
{
m_pResults = new SqResults(this);
}
m_pResults->PushResult();
}
sqlite3 *db = m_pParent->GetDb();
if (rc != SQLITE_OK && rc != SQLITE_DONE && rc == sqlite3_errcode(db))
{
/* Something happened... */
m_LastErrorCode = rc;
m_LastError.assign(sqlite3_errmsg(db));
m_AffectedRows = 0;
m_InsertID = 0;
} else {
m_LastErrorCode = SQLITE_OK;
m_AffectedRows = (unsigned int)sqlite3_changes(db);
m_InsertID = (unsigned int)sqlite3_last_insert_rowid(db);
}
/* Reset everything for the next execute */
sqlite3_reset(m_pStmt);
sqlite3_clear_bindings(m_pStmt);
return (m_LastErrorCode == SQLITE_OK);
}
const char *SqQuery::GetError(int *errCode/* =NULL */)
{
if (errCode)
{
*errCode = m_LastErrorCode;
}
return m_LastError.c_str();
}
unsigned int SqQuery::GetAffectedRows()
{
return m_AffectedRows;
}
unsigned int SqQuery::GetInsertID()
{
return m_InsertID;
}
+86
View File
@@ -0,0 +1,86 @@
/**
* vim: set ts=4 :
* ===============================================================
* SourceMod SQLite Driver Extension
* Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
* ===============================================================
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Version: $Id$
*/
#ifndef _INCLUDE_SQLITE_SOURCEMOD_QUERY_H_
#define _INCLUDE_SQLITE_SOURCEMOD_QUERY_H_
#include "SqDatabase.h"
#include "SqResults.h"
class SqQuery :
public IPreparedQuery
{
public:
SqQuery(SqDatabase *parent, sqlite3_stmt *stmt);
~SqQuery();
public: //IQuery
IResultSet *GetResultSet();
bool FetchMoreResults();
void Destroy();
public: //IPreparedQuery
bool BindParamInt(unsigned int param, int num, bool signd=true);
bool BindParamFloat(unsigned int param, float f);
bool BindParamNull(unsigned int param);
bool BindParamString(unsigned int param, const char *text, bool copy);
bool BindParamBlob(unsigned int param, const void *data, size_t length, bool copy);
bool Execute();
const char *GetError(int *errCode=NULL);
unsigned int GetAffectedRows();
unsigned int GetInsertID();
public: //IResultSet
unsigned int GetRowCount();
unsigned int GetFieldCount();
const char *FieldNumToName(unsigned int columnId);
bool FieldNameToNum(const char *name, unsigned int *columnId);
bool MoreRows();
IResultRow *FetchRow();
IResultRow *CurrentRow();
bool Rewind();
DBType GetFieldType(unsigned int field);
DBType GetFieldDataType(unsigned int field);
public: //IResultRow
DBResult GetString(unsigned int columnId, const char **pString, size_t *length);
DBResult CopyString(unsigned int columnId,
char *buffer,
size_t maxlength,
size_t *written);
DBResult GetFloat(unsigned int columnId, float *pFloat);
DBResult GetInt(unsigned int columnId, int *pInt);
bool IsNull(unsigned int columnId);
size_t GetDataSize(unsigned int columnId);
DBResult GetBlob(unsigned int columnId, const void **pData, size_t *length);
DBResult CopyBlob(unsigned int columnId, void *buffer, size_t maxlength, size_t *written);
public:
sqlite3_stmt *GetStmt();
private:
SqDatabase *m_pParent;
sqlite3_stmt *m_pStmt;
SqResults *m_pResults;
unsigned int m_ParamCount;
String m_LastError;
int m_LastErrorCode;
unsigned int m_AffectedRows;
unsigned int m_InsertID;
};
#endif //_INCLUDE_SQLITE_SOURCEMOD_QUERY_H_
+474
View File
@@ -0,0 +1,474 @@
/**
* vim: set ts=4 :
* ===============================================================
* SourceMod SQLite Driver Extension
* Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
* ===============================================================
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Version: $Id$
*/
#include <stdlib.h>
#include "extension.h"
#include "SqResults.h"
#include "SqQuery.h"
SqResults::SqResults(SqQuery *query) :
m_pStmt(query->GetStmt()), m_Strings(1024),
m_RowCount(0), m_MaxRows(0), m_Rows(NULL),
m_CurRow(0), m_NextRow(0)
{
m_ColCount = sqlite3_column_count(m_pStmt);
if (m_ColCount)
{
m_ColNames = new String[m_ColCount];
for (unsigned int i=0; i<m_ColCount; i++)
{
m_ColNames[i].assign(sqlite3_column_name(m_pStmt, i));
}
} else {
m_ColNames = NULL;
}
m_pMemory = m_Strings.GetMemTable();
}
SqResults::~SqResults()
{
delete [] m_ColNames;
free(m_Rows);
}
unsigned int SqResults::GetRowCount()
{
return m_RowCount;
}
unsigned int SqResults::GetFieldCount()
{
return m_ColCount;
}
const char *SqResults::FieldNumToName(unsigned int columnId)
{
if (columnId >= m_ColCount)
{
return NULL;
}
return m_ColNames[columnId].c_str();
}
bool SqResults::FieldNameToNum(const char *name, unsigned int *columnId)
{
for (unsigned int i=0; i<m_ColCount; i++)
{
if (m_ColNames[i].compare(name) == 0)
{
if (columnId)
{
*columnId = i;
}
return true;
}
}
return false;
}
void SqResults::ResetResultCount()
{
m_RowCount = 0;
m_CurRow = 0;
m_NextRow = 0;
m_pMemory->Reset();
}
void SqResults::PushResult()
{
/* First make sure we can fit one more row */
if (m_RowCount + 1 > m_MaxRows)
{
/* Create a new array */
if (!m_Rows)
{
m_MaxRows = 8;
m_Rows = (SqField *)malloc(sizeof(SqField) * m_ColCount * m_MaxRows);
} else {
m_MaxRows *= 2;
m_Rows = (SqField *)realloc(m_Rows, sizeof(SqField) * m_ColCount * m_MaxRows);
}
}
SqField *row = &m_Rows[m_RowCount * m_ColCount];
for (unsigned int i=0; i<m_ColCount; i++)
{
row[i].type = sqlite3_column_type(m_pStmt, i);
if (row[i].type == SQLITE_INTEGER)
{
row[i].u.idx = sqlite3_column_int(m_pStmt, i);
row[i].size = sizeof(int);
} else if (row[i].type == SQLITE_FLOAT) {
row[i].u.f = (float)sqlite3_column_double(m_pStmt, i);
row[i].size = sizeof(float);
} else if (row[i].type == SQLITE_BLOB) {
int bytes = sqlite3_column_bytes(m_pStmt, i);
const void *pOrig;
if ((pOrig = sqlite3_column_blob(m_pStmt, i)) != NULL)
{
void *pAddr;
row[i].u.idx = m_pMemory->CreateMem(bytes, &pAddr);
memcpy(pAddr, pOrig, bytes);
} else {
row[i].u.idx = -1;
}
row[i].size = sqlite3_column_bytes(m_pStmt, i);
} else if (row[i].type == SQLITE_TEXT) {
const char *str = (const char *)sqlite3_column_text(m_pStmt, i);
if (str)
{
row[i].u.idx = m_Strings.AddString(str);
} else {
row[i].u.idx = -1;
}
row[i].size = sqlite3_column_bytes(m_pStmt, i);
} else {
row[i].size = 0;
}
}
/* Finally, increase the row count */
m_RowCount++;
}
bool SqResults::MoreRows()
{
return (m_CurRow < m_RowCount);
}
IResultRow *SqResults::FetchRow()
{
m_CurRow = m_NextRow;
if (m_CurRow >= m_RowCount)
{
return NULL;
}
m_NextRow++;
return this;
}
IResultRow *SqResults::CurrentRow()
{
if (!m_RowCount || m_CurRow >= m_RowCount)
{
return NULL;
}
return this;
}
bool SqResults::Rewind()
{
m_CurRow = 0;
m_NextRow = 0;
return true;
}
SqField *SqResults::GetField(unsigned int col)
{
if (m_CurRow >= m_RowCount || col >= m_ColCount)
{
return NULL;
}
return &m_Rows[(m_CurRow * m_ColCount) + col];
}
DBType SqResults::GetFieldType(unsigned int field)
{
/* Leaving unimplemented... */
return DBType_Unknown;
}
DBType SqResults::GetFieldDataType(unsigned int field)
{
/* Leaving unimplemented... */
return DBType_Unknown;
}
DBResult SqResults::GetString(unsigned int columnId, const char **pString, size_t *_length)
{
SqField *field = GetField(columnId);
if (!field)
{
return DBVal_Error;
}
DBResult res = DBVal_Data;
const char *ptr = NULL;
size_t length = 0;
if (field->type == SQLITE_TEXT || field->type == SQLITE_BLOB)
{
ptr = m_Strings.GetString(field->u.idx);
length = field->size;
} else if (field->type == SQLITE_INTEGER) {
char number[24];
field->size = UTIL_Format(number, sizeof(number), "%d", field->u.idx);
field->type = SQLITE_TEXT;
field->u.idx = m_Strings.AddString(number);
ptr = m_Strings.GetString(field->u.idx);
length = field->size;
} else if (field->type == SQLITE_FLOAT) {
char number[24];
field->size = UTIL_Format(number, sizeof(number), "%f", field->u.f);
field->type = SQLITE_TEXT;
field->u.idx = m_Strings.AddString(number);
ptr = m_Strings.GetString(field->u.idx);
length = field->size;
} else if (field->type == SQLITE_NULL) {
res = DBVal_Null;
}
if (!ptr)
{
ptr = "";
}
if (*pString)
{
*pString = ptr;
}
if (_length)
{
*_length = length;
}
return res;
}
DBResult SqResults::CopyString(unsigned int columnId, char *buffer, size_t maxlength, size_t *written)
{
SqField *field = GetField(columnId);
if (!field)
{
return DBVal_Error;
}
DBResult res = DBVal_Data;
if (field->type == SQLITE_TEXT || field->type == SQLITE_BLOB)
{
const char *ptr = m_Strings.GetString(field->u.idx);
if (!ptr)
{
ptr = "";
field->type = SQLITE_TEXT;
res = DBVal_Null;
}
size_t wr;
if (field->type == SQLITE_TEXT)
{
wr = strncopy(buffer, ptr, maxlength);
} else if (field->type == SQLITE_BLOB) {
wr = (maxlength < field->size) ? maxlength : field->size;
memcpy(buffer, ptr, wr);
}
if (written)
{
*written = wr;
}
return res;
} else if (field->type == SQLITE_INTEGER) {
size_t wr = 0;
if (buffer)
{
wr = UTIL_Format(buffer, maxlength, "%d", field->u.idx);
}
if (written)
{
*written = wr;
}
return DBVal_Data;
} else if (field->type == SQLITE_FLOAT) {
size_t wr = 0;
if (buffer)
{
wr = UTIL_Format(buffer, maxlength, "%f", field->u.f);
}
if (written)
{
*written = wr;
}
return DBVal_Data;
}
if (buffer)
{
strncopy(buffer, "", maxlength);
}
if (written)
{
*written = 0;
}
return DBVal_Null;
}
bool SqResults::IsNull(unsigned int columnId)
{
SqField *field = GetField(columnId);
if (!field)
{
return true;
}
return (field->type == SQLITE_NULL);
}
unsigned int SqResults::GetDataSize(unsigned int columnId)
{
SqField *field = GetField(columnId);
if (!field)
{
return 0;
}
return field->size;
}
DBResult SqResults::GetFloat(unsigned int columnId, float *pFloat)
{
SqField *field = GetField(columnId);
if (!field)
{
return DBVal_Error;
} else if (field->type == SQLITE_BLOB) {
return DBVal_Error;
}
float fVal = 0.0f;
if (field->type == SQLITE_FLOAT)
{
fVal = field->u.f;
} else if (field->type == SQLITE_TEXT) {
const char *ptr = m_Strings.GetString(field->u.idx);
if (ptr)
{
fVal = (float)atof(ptr);
}
} else if (field->type == SQLITE_INTEGER) {
fVal = (float)field->u.idx;
}
if (pFloat)
{
*pFloat = fVal;
}
return (field->type == SQLITE_NULL) ? DBVal_Null : DBVal_Data;
}
DBResult SqResults::GetInt(unsigned int columnId, int *pInt)
{
SqField *field = GetField(columnId);
if (!field)
{
return DBVal_Error;
} else if (field->type == SQLITE_BLOB) {
return DBVal_Error;
}
int val = 0;
if (field->type == SQLITE_INTEGER)
{
val = field->u.idx;
} else if (field->type == SQLITE_TEXT) {
const char *ptr = m_Strings.GetString(field->u.idx);
if (ptr)
{
val = atoi(ptr);
}
} else if (field->type == SQLITE_FLOAT) {
val = (int)field->u.f;
}
if (pInt)
{
*pInt = val;
}
return (field->type == SQLITE_NULL) ? DBVal_Null : DBVal_Data;
}
DBResult SqResults::GetBlob(unsigned int columnId, const void **pData, size_t *length)
{
SqField *field = GetField(columnId);
if (!field)
{
return DBVal_Error;
}
void *addr = NULL;
if (field->type == SQLITE_TEXT || field->type == SQLITE_BLOB)
{
addr = m_pMemory->GetAddress(field->u.idx);
} else if (field->type == SQLITE_FLOAT || field->type == SQLITE_INTEGER) {
addr = &(field->u);
}
if (pData)
{
*pData = addr;
}
if (length)
{
*length = field->size;
}
return (field->type == SQLITE_NULL) ? DBVal_Null : DBVal_Data;
}
DBResult SqResults::CopyBlob(unsigned int columnId, void *buffer, size_t maxlength, size_t *written)
{
SqField *field = GetField(columnId);
if (!field)
{
return DBVal_Error;
}
void *addr = NULL;
if (field->type == SQLITE_TEXT || field->type == SQLITE_BLOB)
{
addr = m_pMemory->GetAddress(field->u.idx);
} else if (field->type == SQLITE_FLOAT || field->type == SQLITE_INTEGER) {
addr = &(field->u);
}
size_t toCopy = field->size > maxlength ? maxlength : field->size;
if (buffer && addr && toCopy)
{
memcpy(buffer, addr, toCopy);
} else {
toCopy = 0;
}
if (written)
{
*written = toCopy;
}
return (field->type == SQLITE_NULL) ? DBVal_Null : DBVal_Data;
}
+92
View File
@@ -0,0 +1,92 @@
/**
* vim: set ts=4 :
* ===============================================================
* SourceMod SQLite Driver Extension
* Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
* ===============================================================
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Version: $Id$
*/
#ifndef _INCLUDE_SQLITE_SOURCEMOD_RESULT_SET_H_
#define _INCLUDE_SQLITE_SOURCEMOD_RESULT_SET_H_
#include "SqDriver.h"
#include "sm_memtable.h"
class SqQuery;
struct SqField
{
int type;
union
{
int idx;
float f;
} u;
size_t size;
};
class SqResults :
public IResultSet,
public IResultRow
{
friend class SqQuery;
public:
SqResults(SqQuery *query);
~SqResults();
public: //IResultSet
unsigned int GetRowCount();
unsigned int GetFieldCount();
const char *FieldNumToName(unsigned int columnId);
bool FieldNameToNum(const char *name, unsigned int *columnId);
bool MoreRows();
IResultRow *FetchRow();
IResultRow *CurrentRow();
bool Rewind();
DBType GetFieldType(unsigned int field);
DBType GetFieldDataType(unsigned int field);
public: //IResultRow
DBResult GetString(unsigned int columnId, const char **pString, size_t *length);
DBResult CopyString(unsigned int columnId,
char *buffer,
size_t maxlength,
size_t *written);
DBResult GetFloat(unsigned int columnId, float *pFloat);
DBResult GetInt(unsigned int columnId, int *pInt);
bool IsNull(unsigned int columnId);
size_t GetDataSize(unsigned int columnId);
DBResult GetBlob(unsigned int columnId, const void **pData, size_t *length);
DBResult CopyBlob(unsigned int columnId, void *buffer, size_t maxlength, size_t *written);
public:
void ResetResultCount();
void PushResult();
private:
SqField *GetField(unsigned int col);
private:
sqlite3_stmt *m_pStmt; /** DOES NOT CHANGE */
String *m_ColNames; /** DOES NOT CHANGE */
unsigned int m_ColCount; /** DOES NOT CHANGE */
unsigned int m_RowCount;
unsigned int m_MaxRows;
BaseMemTable *m_pMemory; /** DOES NOT CHANGE */
BaseStringTable m_Strings; /** DOES NOT CHANGE */
SqField *m_Rows;
unsigned int m_CurRow;
unsigned int m_NextRow;
};
#endif //_INCLUDE_SQLITE_SOURCEMOD_RESULT_SET_H_