dvander@1203: /** dvander@1203: * vim: set ts=4 : ds@1330: * ============================================================================= dvander@1226: * SourceMod SQLite Extension ds@1947: * Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved. ds@1330: * ============================================================================= dvander@1203: * ds@1330: * This program is free software; you can redistribute it and/or modify it under ds@1330: * the terms of the GNU General Public License, version 3.0, as published by the ds@1330: * Free Software Foundation. dvander@1226: * ds@1330: * This program is distributed in the hope that it will be useful, but WITHOUT ds@1330: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS ds@1330: * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more ds@1330: * details. dvander@1226: * ds@1330: * You should have received a copy of the GNU General Public License along with ds@1330: * this program. If not, see . dvander@1226: * ds@1330: * As a special exception, AlliedModders LLC gives you permission to link the ds@1330: * code of this program (as well as its derivative works) to "Half-Life 2," the ds@1330: * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software ds@1330: * by the Valve Corporation. You must obey the GNU General Public License in ds@1330: * all respects for all other code used. Additionally, AlliedModders LLC grants ds@1330: * this exception to all derivative works. AlliedModders LLC defines further ds@1330: * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), ds@1330: * or . dvander@1203: * dvander@1203: * Version: $Id$ dvander@1203: */ dvander@1203: dvander@1203: #include "extension.h" dvander@1203: #include "SqDatabase.h" dvander@1203: #include "SqQuery.h" dvander@1203: dvander@1203: SqDatabase::SqDatabase(sqlite3 *sq3, bool persistent) : dvander@1203: m_sq3(sq3), m_refcount(1), m_pFullLock(NULL), m_Persistent(persistent) dvander@1203: { dvander@1203: m_pRefLock = threader->MakeMutex(); dvander@1203: } dvander@1203: dvander@1203: SqDatabase::~SqDatabase() dvander@1203: { dvander@1203: m_pRefLock->DestroyThis(); dvander@1203: if (m_pFullLock) dvander@1203: { dvander@1203: m_pFullLock->DestroyThis(); dvander@1203: } dvander@1203: sqlite3_close(m_sq3); dvander@1203: } dvander@1203: dvander@1203: void SqDatabase::IncReferenceCount() dvander@1203: { dvander@1203: m_pRefLock->Lock(); dvander@1203: m_refcount++; dvander@1203: m_pRefLock->Unlock(); dvander@1203: } dvander@1203: dvander@1203: bool SqDatabase::Close() dvander@1203: { dvander@1203: m_pRefLock->Lock(); dvander@1203: if (m_refcount > 1) dvander@1203: { dvander@1203: m_refcount--; dvander@1203: m_pRefLock->Unlock(); dvander@1203: return false; dvander@1203: } dvander@1203: m_pRefLock->Unlock(); dvander@1203: dvander@1203: if (m_Persistent) dvander@1203: { dvander@1203: g_SqDriver.RemovePersistent(this); dvander@1203: } dvander@1203: dvander@1203: delete this; dvander@1203: dvander@1203: return true; dvander@1203: } dvander@1203: dvander@1203: const char *SqDatabase::GetError(int *errorCode/* =NULL */) dvander@1203: { dvander@1203: return sqlite3_errmsg(m_sq3); dvander@1203: } dvander@1203: dvander@1203: bool SqDatabase::LockForFullAtomicOperation() dvander@1203: { dvander@1203: if (!m_pFullLock) dvander@1203: { dvander@1203: m_pFullLock = threader->MakeMutex(); dvander@1203: if (!m_pFullLock) dvander@1203: { dvander@1203: return false; dvander@1203: } dvander@1203: } dvander@1203: dvander@1203: m_pFullLock->Lock(); dvander@1203: dvander@1203: return true; dvander@1203: } dvander@1203: dvander@1203: void SqDatabase::UnlockFromFullAtomicOperation() dvander@1203: { dvander@1203: if (m_pFullLock) dvander@1203: { dvander@1203: m_pFullLock->Unlock(); dvander@1203: } dvander@1203: } dvander@1203: dvander@1203: IDBDriver *SqDatabase::GetDriver() dvander@1203: { dvander@1203: return &g_SqDriver; dvander@1203: } dvander@1203: dvander@1203: bool SqDatabase::QuoteString(const char *str, char buffer[], size_t maxlen, size_t *newSize) dvander@1203: { dvander@1203: char *res = sqlite3_snprintf(static_cast(maxlen), buffer, "%q", str); dvander@1203: dvander@1203: if (res != NULL && newSize != NULL) dvander@1203: { dvander@1203: *newSize = strlen(buffer); dvander@1203: } dvander@1203: dvander@1203: return (res != NULL); dvander@1203: } dvander@1203: dvander@1203: unsigned int SqDatabase::GetInsertID() dvander@1203: { dvander@1203: return (unsigned int)sqlite3_last_insert_rowid(m_sq3); dvander@1203: } dvander@1203: dvander@1203: unsigned int SqDatabase::GetAffectedRows() dvander@1203: { dvander@1203: return (unsigned int)sqlite3_changes(m_sq3); dvander@1203: } dvander@1203: dvander@1203: bool SqDatabase::DoSimpleQuery(const char *query) dvander@1203: { dvander@1203: IQuery *pQuery = DoQuery(query); dvander@1203: if (!pQuery) dvander@1203: { dvander@1203: return false; dvander@1203: } dvander@1203: pQuery->Destroy(); dvander@1203: return true; dvander@1203: } dvander@1203: dvander@1203: /* this sounds like daiquiri.. i'm tired. */ dvander@1203: IQuery *SqDatabase::DoQuery(const char *query) dvander@1203: { dvander@1203: IPreparedQuery *pQuery = PrepareQuery(query, NULL, 0, NULL); dvander@1203: if (!pQuery) dvander@1203: { dvander@1203: return NULL; dvander@1203: } dvander@1203: if (!pQuery->Execute()) dvander@1203: { dvander@1203: pQuery->Destroy(); dvander@1203: return NULL; dvander@1203: } dvander@1203: return pQuery; dvander@1203: } dvander@1203: dvander@1912: bool SqDatabase::DoSimpleQueryEx(const char *query, size_t len) dvander@1912: { dvander@1912: IQuery *pQuery = DoQueryEx(query, len); dvander@1912: if (!pQuery) dvander@1912: { dvander@1912: return false; dvander@1912: } dvander@1912: pQuery->Destroy(); dvander@1912: return true; dvander@1912: } dvander@1912: dvander@1912: IQuery *SqDatabase::DoQueryEx(const char *query, size_t len) dvander@1912: { dvander@1912: IPreparedQuery *pQuery = PrepareQueryEx(query, len, NULL, 0, NULL); dvander@1912: if (!pQuery) dvander@1912: { dvander@1912: return NULL; dvander@1912: } dvander@1912: if (!pQuery->Execute()) dvander@1912: { dvander@1912: pQuery->Destroy(); dvander@1912: return NULL; dvander@1912: } dvander@1912: return pQuery; dvander@1912: } dvander@1912: dvander@1912: IPreparedQuery *SqDatabase::PrepareQuery(const char *query, dvander@1912: char *error, dvander@1912: size_t maxlength, dvander@1912: int *errCode/* =NULL */) dvander@1203: { dvander@1203: sqlite3_stmt *stmt = NULL; dvander@1203: if ((m_LastErrorCode = sqlite3_prepare_v2(m_sq3, query, -1, &stmt, NULL)) != SQLITE_OK dvander@1203: || !stmt) dvander@1203: { dvander@1203: const char *msg; dvander@1203: if (m_LastErrorCode != SQLITE_OK) dvander@1203: { dvander@1203: msg = sqlite3_errmsg(m_sq3); dvander@1203: } else { dvander@1203: msg = "Invalid query string"; dvander@1448: m_LastErrorCode = SQLITE_ERROR; dvander@1203: } dvander@1203: if (error) dvander@1203: { dvander@1203: strncopy(error, msg, maxlength); dvander@1203: } dvander@1203: m_LastError.assign(msg); dvander@1912: return NULL; dvander@1912: } dvander@1912: return new SqQuery(this, stmt); dvander@1912: } dvander@1912: dvander@1912: IPreparedQuery *SqDatabase::PrepareQueryEx(const char *query, dvander@1912: size_t len, dvander@1912: char *error, dvander@1912: size_t maxlength, dvander@1912: int *errCode/* =NULL */) dvander@1912: { dvander@1912: sqlite3_stmt *stmt = NULL; dvander@1912: if ((m_LastErrorCode = sqlite3_prepare_v2(m_sq3, query, len, &stmt, NULL)) != SQLITE_OK dvander@1912: || !stmt) dvander@1912: { dvander@1912: const char *msg; dvander@1912: if (m_LastErrorCode != SQLITE_OK) dvander@1203: { dvander@1912: msg = sqlite3_errmsg(m_sq3); dvander@1912: } else { dvander@1912: msg = "Invalid query string"; dvander@1912: m_LastErrorCode = SQLITE_ERROR; dvander@1203: } dvander@1912: if (error) dvander@1912: { dvander@1912: strncopy(error, msg, maxlength); dvander@1912: } dvander@1912: m_LastError.assign(msg); dvander@1203: return NULL; dvander@1203: } dvander@1203: return new SqQuery(this, stmt); dvander@1203: } dvander@1203: dvander@1203: sqlite3 *SqDatabase::GetDb() dvander@1203: { dvander@1203: return m_sq3; dvander@1203: }