Spring Cleaning, Part Ichi (1)
Various minor things done to project files Updated sample extension project file and updated makefile to the new unified version (more changes likely on the way) Updated regex project file and makefile --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%401971
This commit is contained in:
@@ -0,0 +1,247 @@
|
||||
/**
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod SQLite Extension
|
||||
* Copyright (C) 2004-2008 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, version 3.0, as published by the
|
||||
* Free Software Foundation.
|
||||
*
|
||||
* 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* As a special exception, AlliedModders LLC gives you permission to link the
|
||||
* code of this program (as well as its derivative works) to "Half-Life 2," the
|
||||
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
|
||||
* by the Valve Corporation. You must obey the GNU General Public License in
|
||||
* all respects for all other code used. Additionally, AlliedModders LLC grants
|
||||
* this exception to all derivative works. AlliedModders LLC defines further
|
||||
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
|
||||
* or <http://www.sourcemod.net/license.php>.
|
||||
*
|
||||
* 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;
|
||||
}
|
||||
|
||||
bool SqDatabase::DoSimpleQueryEx(const char *query, size_t len)
|
||||
{
|
||||
IQuery *pQuery = DoQueryEx(query, len);
|
||||
if (!pQuery)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
pQuery->Destroy();
|
||||
return true;
|
||||
}
|
||||
|
||||
IQuery *SqDatabase::DoQueryEx(const char *query, size_t len)
|
||||
{
|
||||
IPreparedQuery *pQuery = PrepareQueryEx(query, len, 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_ERROR;
|
||||
}
|
||||
if (error)
|
||||
{
|
||||
strncopy(error, msg, maxlength);
|
||||
}
|
||||
m_LastError.assign(msg);
|
||||
return NULL;
|
||||
}
|
||||
return new SqQuery(this, stmt);
|
||||
}
|
||||
|
||||
IPreparedQuery *SqDatabase::PrepareQueryEx(const char *query,
|
||||
size_t len,
|
||||
char *error,
|
||||
size_t maxlength,
|
||||
int *errCode/* =NULL */)
|
||||
{
|
||||
sqlite3_stmt *stmt = NULL;
|
||||
if ((m_LastErrorCode = sqlite3_prepare_v2(m_sq3, query, len, &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_ERROR;
|
||||
}
|
||||
if (error)
|
||||
{
|
||||
strncopy(error, msg, maxlength);
|
||||
}
|
||||
m_LastError.assign(msg);
|
||||
return NULL;
|
||||
}
|
||||
return new SqQuery(this, stmt);
|
||||
}
|
||||
|
||||
sqlite3 *SqDatabase::GetDb()
|
||||
{
|
||||
return m_sq3;
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
/**
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod SQLite Extension
|
||||
* Copyright (C) 2004-2008 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, version 3.0, as published by the
|
||||
* Free Software Foundation.
|
||||
*
|
||||
* 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* As a special exception, AlliedModders LLC gives you permission to link the
|
||||
* code of this program (as well as its derivative works) to "Half-Life 2," the
|
||||
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
|
||||
* by the Valve Corporation. You must obey the GNU General Public License in
|
||||
* all respects for all other code used. Additionally, AlliedModders LLC grants
|
||||
* this exception to all derivative works. AlliedModders LLC defines further
|
||||
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
|
||||
* or <http://www.sourcemod.net/license.php>.
|
||||
*
|
||||
* 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);
|
||||
IPreparedQuery *PrepareQueryEx(const char *query, size_t len, 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();
|
||||
bool DoSimpleQueryEx(const char *query, size_t len);
|
||||
IQuery *DoQueryEx(const char *query, size_t len);
|
||||
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_
|
||||
@@ -0,0 +1,285 @@
|
||||
/**
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod SQLite Extension
|
||||
* Copyright (C) 2004-2008 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, version 3.0, as published by the
|
||||
* Free Software Foundation.
|
||||
*
|
||||
* 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* As a special exception, AlliedModders LLC gives you permission to link the
|
||||
* code of this program (as well as its derivative works) to "Half-Life 2," the
|
||||
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
|
||||
* by the Valve Corporation. You must obey the GNU General Public License in
|
||||
* all respects for all other code used. Additionally, AlliedModders LLC grants
|
||||
* this exception to all derivative works. AlliedModders LLC defines further
|
||||
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
|
||||
* or <http://www.sourcemod.net/license.php>.
|
||||
*
|
||||
* 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);
|
||||
}
|
||||
|
||||
int busy_handler(void *unused1, int unused2)
|
||||
{
|
||||
#if defined PLATFORM_WINDOWS
|
||||
Sleep(100);
|
||||
#elif defined PLATFORM_LINUX
|
||||
usleep(100000);
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
|
||||
SqDriver::SqDriver()
|
||||
{
|
||||
m_Handle = BAD_HANDLE;
|
||||
m_pOpenLock = NULL;
|
||||
m_bThreadSafe = false;
|
||||
}
|
||||
|
||||
void SqDriver::Initialize()
|
||||
{
|
||||
m_pOpenLock = threader->MakeMutex();
|
||||
|
||||
InitializeThreadSafety();
|
||||
}
|
||||
|
||||
void SqDriver::Shutdown()
|
||||
{
|
||||
if (m_pOpenLock)
|
||||
{
|
||||
m_pOpenLock->DestroyThis();
|
||||
}
|
||||
|
||||
if (m_bThreadSafe)
|
||||
{
|
||||
sqlite3_enable_shared_cache(0);
|
||||
}
|
||||
}
|
||||
|
||||
bool SqDriver::IsThreadSafe()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SqDriver::InitializeThreadSafety()
|
||||
{
|
||||
if (m_bThreadSafe)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (sqlite3_threadsafe() == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (sqlite3_enable_shared_cache(1) != SQLITE_OK)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
m_bThreadSafe = true;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
sqlite3_busy_handler(sql, busy_handler, 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
/**
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod SQLite Extension
|
||||
* Copyright (C) 2004-2008 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, version 3.0, as published by the
|
||||
* Free Software Foundation.
|
||||
*
|
||||
* 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* As a special exception, AlliedModders LLC gives you permission to link the
|
||||
* code of this program (as well as its derivative works) to "Half-Life 2," the
|
||||
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
|
||||
* by the Valve Corporation. You must obey the GNU General Public License in
|
||||
* all respects for all other code used. Additionally, AlliedModders LLC grants
|
||||
* this exception to all derivative works. AlliedModders LLC defines further
|
||||
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
|
||||
* or <http://www.sourcemod.net/license.php>.
|
||||
*
|
||||
* 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;
|
||||
bool m_bThreadSafe;
|
||||
};
|
||||
|
||||
extern SqDriver g_SqDriver;
|
||||
|
||||
unsigned int strncopy(char *dest, const char *src, size_t count);
|
||||
|
||||
#endif //_INCLUDE_SQLITE_SOURCEMOD_DRIVER_H_
|
||||
@@ -0,0 +1,205 @@
|
||||
/**
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod SQLite Extension
|
||||
* Copyright (C) 2004-2008 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, version 3.0, as published by the
|
||||
* Free Software Foundation.
|
||||
*
|
||||
* 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* As a special exception, AlliedModders LLC gives you permission to link the
|
||||
* code of this program (as well as its derivative works) to "Half-Life 2," the
|
||||
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
|
||||
* by the Valve Corporation. You must obey the GNU General Public License in
|
||||
* all respects for all other code used. Additionally, AlliedModders LLC grants
|
||||
* this exception to all derivative works. AlliedModders LLC defines further
|
||||
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
|
||||
* or <http://www.sourcemod.net/license.php>.
|
||||
*
|
||||
* 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_ColCount = sqlite3_column_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 don't have a result set and we have a column count,
|
||||
* create a result set pre-emptively. This is in case there
|
||||
* are no rows in the upcoming result set.
|
||||
*/
|
||||
if (!m_pResults && m_ColCount)
|
||||
{
|
||||
m_pResults = new SqResults(this);
|
||||
}
|
||||
|
||||
/* If we've got results, throw them away */
|
||||
if (m_pResults)
|
||||
{
|
||||
m_pResults->ResetResultCount();
|
||||
}
|
||||
|
||||
/* Fetch each row, if any */
|
||||
while ((rc = sqlite3_step(m_pStmt)) == SQLITE_ROW)
|
||||
{
|
||||
/* This should NEVER happen but we're being safe. */
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
/**
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod SQLite Extension
|
||||
* Copyright (C) 2004-2008 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, version 3.0, as published by the
|
||||
* Free Software Foundation.
|
||||
*
|
||||
* 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* As a special exception, AlliedModders LLC gives you permission to link the
|
||||
* code of this program (as well as its derivative works) to "Half-Life 2," the
|
||||
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
|
||||
* by the Valve Corporation. You must obey the GNU General Public License in
|
||||
* all respects for all other code used. Additionally, AlliedModders LLC grants
|
||||
* this exception to all derivative works. AlliedModders LLC defines further
|
||||
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
|
||||
* or <http://www.sourcemod.net/license.php>.
|
||||
*
|
||||
* 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;
|
||||
unsigned int m_ColCount;
|
||||
};
|
||||
|
||||
#endif //_INCLUDE_SQLITE_SOURCEMOD_QUERY_H_
|
||||
@@ -0,0 +1,482 @@
|
||||
/**
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod SQLite Extension
|
||||
* Copyright (C) 2004-2008 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, version 3.0, as published by the
|
||||
* Free Software Foundation.
|
||||
*
|
||||
* 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* As a special exception, AlliedModders LLC gives you permission to link the
|
||||
* code of this program (as well as its derivative works) to "Half-Life 2," the
|
||||
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
|
||||
* by the Valve Corporation. You must obey the GNU General Public License in
|
||||
* all respects for all other code used. Additionally, AlliedModders LLC grants
|
||||
* this exception to all derivative works. AlliedModders LLC defines further
|
||||
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
|
||||
* or <http://www.sourcemod.net/license.php>.
|
||||
*
|
||||
* 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 = 0;
|
||||
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;
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
/**
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod SQLite Extension
|
||||
* Copyright (C) 2004-2008 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, version 3.0, as published by the
|
||||
* Free Software Foundation.
|
||||
*
|
||||
* 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* As a special exception, AlliedModders LLC gives you permission to link the
|
||||
* code of this program (as well as its derivative works) to "Half-Life 2," the
|
||||
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
|
||||
* by the Valve Corporation. You must obey the GNU General Public License in
|
||||
* all respects for all other code used. Additionally, AlliedModders LLC grants
|
||||
* this exception to all derivative works. AlliedModders LLC defines further
|
||||
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
|
||||
* or <http://www.sourcemod.net/license.php>.
|
||||
*
|
||||
* 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 */
|
||||
BaseStringTable m_Strings; /** DOES NOT CHANGE */
|
||||
BaseMemTable *m_pMemory; /** DOES NOT CHANGE */
|
||||
unsigned int m_RowCount;
|
||||
unsigned int m_MaxRows;
|
||||
SqField *m_Rows;
|
||||
unsigned int m_CurRow;
|
||||
unsigned int m_NextRow;
|
||||
};
|
||||
|
||||
#endif //_INCLUDE_SQLITE_SOURCEMOD_RESULT_SET_H_
|
||||
Reference in New Issue
Block a user