extensions/sqlite/driver/SqDatabase.cpp
author John Schoenick <john@pointysoftware.net>
Sat May 14 20:21:37 2011 -0700 (2011-05-14)
changeset 3271 acc921bc57ef
parent 2289 44045ead61cd
child 3947 999d29e113db
permissions -rw-r--r--
Make SQL_LastInsertId and SQL_GetAffectedRows work on query handles, allowing their use with threaded queries
     1 /**
     2  * vim: set ts=4 :
     3  * =============================================================================
     4  * SourceMod SQLite Extension
     5  * Copyright (C) 2004-2008 AlliedModders LLC.  All rights reserved.
     6  * =============================================================================
     7  *
     8  * This program is free software; you can redistribute it and/or modify it under
     9  * the terms of the GNU General Public License, version 3.0, as published by the
    10  * Free Software Foundation.
    11  * 
    12  * This program is distributed in the hope that it will be useful, but WITHOUT
    13  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
    14  * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
    15  * details.
    16  *
    17  * You should have received a copy of the GNU General Public License along with
    18  * this program.  If not, see <http://www.gnu.org/licenses/>.
    19  *
    20  * As a special exception, AlliedModders LLC gives you permission to link the
    21  * code of this program (as well as its derivative works) to "Half-Life 2," the
    22  * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
    23  * by the Valve Corporation.  You must obey the GNU General Public License in
    24  * all respects for all other code used.  Additionally, AlliedModders LLC grants
    25  * this exception to all derivative works.  AlliedModders LLC defines further
    26  * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
    27  * or <http://www.sourcemod.net/license.php>.
    28  *
    29  * Version: $Id$
    30  */
    31 
    32 #include "extension.h"
    33 #include "SqDatabase.h"
    34 #include "SqQuery.h"
    35 
    36 SqDatabase::SqDatabase(sqlite3 *sq3, bool persistent) : 
    37 	m_sq3(sq3), m_refcount(1), m_pFullLock(NULL), m_Persistent(persistent)
    38 {
    39 	m_pRefLock = threader->MakeMutex();
    40 }
    41 
    42 SqDatabase::~SqDatabase()
    43 {
    44 	m_pRefLock->DestroyThis();
    45 	if (m_pFullLock)
    46 	{
    47 		m_pFullLock->DestroyThis();
    48 	}
    49 	sqlite3_close(m_sq3);
    50 }
    51 
    52 void SqDatabase::IncReferenceCount()
    53 {
    54 	m_pRefLock->Lock();
    55 	m_refcount++;
    56 	m_pRefLock->Unlock();
    57 }
    58 
    59 bool SqDatabase::Close()
    60 {
    61 	m_pRefLock->Lock();
    62 	if (m_refcount > 1)
    63 	{
    64 		m_refcount--;
    65 		m_pRefLock->Unlock();
    66 		return false;
    67 	}
    68 	m_pRefLock->Unlock();
    69 
    70 	if (m_Persistent)
    71 	{
    72 		g_SqDriver.RemovePersistent(this);
    73 	}
    74 
    75 	delete this;
    76 
    77 	return true;
    78 }
    79 
    80 const char *SqDatabase::GetError(int *errorCode/* =NULL */)
    81 {
    82 	return sqlite3_errmsg(m_sq3);
    83 }
    84 
    85 bool SqDatabase::LockForFullAtomicOperation()
    86 {
    87 	if (!m_pFullLock)
    88 	{
    89 		m_pFullLock = threader->MakeMutex();
    90 		if (!m_pFullLock)
    91 		{
    92 			return false;
    93 		}
    94 	}
    95 
    96 	m_pFullLock->Lock();
    97 
    98 	return true;
    99 }
   100 
   101 void SqDatabase::UnlockFromFullAtomicOperation()
   102 {
   103 	if (m_pFullLock)
   104 	{
   105 		m_pFullLock->Unlock();
   106 	}
   107 }
   108 
   109 IDBDriver *SqDatabase::GetDriver()
   110 {
   111 	return &g_SqDriver;
   112 }
   113 
   114 bool SqDatabase::QuoteString(const char *str, char buffer[], size_t maxlen, size_t *newSize)
   115 {
   116 	char *res = sqlite3_snprintf(static_cast<int>(maxlen), buffer, "%q", str);
   117 
   118 	if (res != NULL && newSize != NULL)
   119 	{
   120 		*newSize = strlen(buffer);
   121 	}
   122 
   123 	return (res != NULL);
   124 }
   125 
   126 unsigned int SqDatabase::GetInsertID()
   127 {
   128 	return (unsigned int)sqlite3_last_insert_rowid(m_sq3);
   129 }
   130 
   131 unsigned int SqDatabase::GetAffectedRows()
   132 {
   133 	return (unsigned int)sqlite3_changes(m_sq3);
   134 }
   135 
   136 bool SqDatabase::DoSimpleQuery(const char *query)
   137 {
   138 	IQuery *pQuery = DoQuery(query);
   139 	if (!pQuery)
   140 	{
   141 		return false;
   142 	}
   143 	pQuery->Destroy();
   144 	return true;
   145 }
   146 
   147 /* this sounds like daiquiri.. i'm tired. */
   148 IQuery *SqDatabase::DoQuery(const char *query)
   149 {
   150 	IPreparedQuery *pQuery = PrepareQuery(query, NULL, 0, NULL);
   151 	if (!pQuery)
   152 	{
   153 		return NULL;
   154 	}
   155 	if (!pQuery->Execute())
   156 	{
   157 		pQuery->Destroy();
   158 		return NULL;
   159 	}
   160 	return pQuery;
   161 }
   162 
   163 bool SqDatabase::DoSimpleQueryEx(const char *query, size_t len)
   164 {
   165 	IQuery *pQuery = DoQueryEx(query, len);
   166 	if (!pQuery)
   167 	{
   168 		return false;
   169 	}
   170 	pQuery->Destroy();
   171 	return true;
   172 }
   173 
   174 IQuery *SqDatabase::DoQueryEx(const char *query, size_t len)
   175 {
   176 	IPreparedQuery *pQuery = PrepareQueryEx(query, len, NULL, 0, NULL);
   177 	if (!pQuery)
   178 	{
   179 		return NULL;
   180 	}
   181 	if (!pQuery->Execute())
   182 	{
   183 		pQuery->Destroy();
   184 		return NULL;
   185 	}
   186 	return pQuery;
   187 }
   188 
   189 unsigned int SqDatabase::GetAffectedRowsForQuery(IQuery *query)
   190 {
   191 	return static_cast<SqQuery*>(query)->GetAffectedRows();
   192 }
   193 unsigned int SqDatabase::GetInsertIDForQuery(IQuery *query)
   194 {
   195 	return static_cast<SqQuery*>(query)->GetInsertID();
   196 }
   197 
   198 IPreparedQuery *SqDatabase::PrepareQuery(const char *query, 
   199 										 char *error, 
   200 										 size_t maxlength, 
   201 										 int *errCode/* =NULL */)
   202 {
   203 	sqlite3_stmt *stmt = NULL;
   204 	if ((m_LastErrorCode = sqlite3_prepare_v2(m_sq3, query, -1, &stmt, NULL)) != SQLITE_OK
   205 		|| !stmt)
   206 	{
   207 		const char *msg;
   208 		if (m_LastErrorCode != SQLITE_OK)
   209 		{
   210 			msg = sqlite3_errmsg(m_sq3);
   211 		} else {
   212 			msg = "Invalid query string";
   213 			m_LastErrorCode = SQLITE_ERROR;
   214 		}
   215 		if (error)
   216 		{
   217 			strncopy(error, msg, maxlength);
   218 		}
   219 		m_LastError.assign(msg);
   220 		return NULL;
   221 	}
   222 	return new SqQuery(this, stmt);
   223 }
   224 
   225 IPreparedQuery *SqDatabase::PrepareQueryEx(const char *query, 
   226 										   size_t len, 
   227 										   char *error, 
   228 										   size_t maxlength, 
   229 										   int *errCode/* =NULL */)
   230 {
   231 	sqlite3_stmt *stmt = NULL;
   232 	if ((m_LastErrorCode = sqlite3_prepare_v2(m_sq3, query, len, &stmt, NULL)) != SQLITE_OK
   233 		|| !stmt)
   234 	{
   235 		const char *msg;
   236 		if (m_LastErrorCode != SQLITE_OK)
   237 		{
   238 			msg = sqlite3_errmsg(m_sq3);
   239 		} else {
   240 			msg = "Invalid query string";
   241 			m_LastErrorCode = SQLITE_ERROR;
   242 		}
   243 		if (error)
   244 		{
   245 			strncopy(error, msg, maxlength);
   246 		}
   247 		m_LastError.assign(msg);
   248 		return NULL;
   249 	}
   250 	return new SqQuery(this, stmt);
   251 }
   252 
   253 sqlite3 *SqDatabase::GetDb()
   254 {
   255 	return m_sq3;
   256 }