extensions/sqlite/driver/SqDatabase.cpp
author David Anderson <dvander@alliedmods.net>
Fri Aug 23 00:18:13 2013 -0700 (2013-08-23)
changeset 4040 b6924c1a1d71
parent 3947 999d29e113db
permissions -rw-r--r--
Add atomic reference counting and port DBI (bug 5876 part 3, r=ds).
     1 /**
     2  * vim: set ts=4 sw=4 tw=99 noet :
     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_Persistent(persistent)
    38 {
    39 }
    40 
    41 SqDatabase::~SqDatabase()
    42 {
    43 	if (m_Persistent)
    44 		g_SqDriver.RemovePersistent(this);
    45 	sqlite3_close(m_sq3);
    46 }
    47 
    48 void SqDatabase::IncReferenceCount()
    49 {
    50 	AddRef();
    51 }
    52 
    53 bool SqDatabase::Close()
    54 {
    55 	return !Release();
    56 }
    57 
    58 const char *SqDatabase::GetError(int *errorCode/* =NULL */)
    59 {
    60 	return sqlite3_errmsg(m_sq3);
    61 }
    62 
    63 bool SqDatabase::LockForFullAtomicOperation()
    64 {
    65 	if (!m_FullLock)
    66 		m_FullLock = new ke::Mutex();
    67 
    68 	m_FullLock->Lock();
    69 	return true;
    70 }
    71 
    72 void SqDatabase::UnlockFromFullAtomicOperation()
    73 {
    74 	if (m_FullLock)
    75 		m_FullLock->Unlock();
    76 }
    77 
    78 IDBDriver *SqDatabase::GetDriver()
    79 {
    80 	return &g_SqDriver;
    81 }
    82 
    83 bool SqDatabase::QuoteString(const char *str, char buffer[], size_t maxlen, size_t *newSize)
    84 {
    85 	char *res = sqlite3_snprintf(static_cast<int>(maxlen), buffer, "%q", str);
    86 
    87 	if (res != NULL && newSize != NULL)
    88 	{
    89 		*newSize = strlen(buffer);
    90 	}
    91 
    92 	return (res != NULL);
    93 }
    94 
    95 unsigned int SqDatabase::GetInsertID()
    96 {
    97 	return (unsigned int)sqlite3_last_insert_rowid(m_sq3);
    98 }
    99 
   100 unsigned int SqDatabase::GetAffectedRows()
   101 {
   102 	return (unsigned int)sqlite3_changes(m_sq3);
   103 }
   104 
   105 bool SqDatabase::DoSimpleQuery(const char *query)
   106 {
   107 	IQuery *pQuery = DoQuery(query);
   108 	if (!pQuery)
   109 	{
   110 		return false;
   111 	}
   112 	pQuery->Destroy();
   113 	return true;
   114 }
   115 
   116 /* this sounds like daiquiri.. i'm tired. */
   117 IQuery *SqDatabase::DoQuery(const char *query)
   118 {
   119 	IPreparedQuery *pQuery = PrepareQuery(query, NULL, 0, NULL);
   120 	if (!pQuery)
   121 	{
   122 		return NULL;
   123 	}
   124 	if (!pQuery->Execute())
   125 	{
   126 		pQuery->Destroy();
   127 		return NULL;
   128 	}
   129 	return pQuery;
   130 }
   131 
   132 bool SqDatabase::DoSimpleQueryEx(const char *query, size_t len)
   133 {
   134 	IQuery *pQuery = DoQueryEx(query, len);
   135 	if (!pQuery)
   136 	{
   137 		return false;
   138 	}
   139 	pQuery->Destroy();
   140 	return true;
   141 }
   142 
   143 IQuery *SqDatabase::DoQueryEx(const char *query, size_t len)
   144 {
   145 	IPreparedQuery *pQuery = PrepareQueryEx(query, len, NULL, 0, NULL);
   146 	if (!pQuery)
   147 	{
   148 		return NULL;
   149 	}
   150 	if (!pQuery->Execute())
   151 	{
   152 		pQuery->Destroy();
   153 		return NULL;
   154 	}
   155 	return pQuery;
   156 }
   157 
   158 unsigned int SqDatabase::GetAffectedRowsForQuery(IQuery *query)
   159 {
   160 	return static_cast<SqQuery*>(query)->GetAffectedRows();
   161 }
   162 unsigned int SqDatabase::GetInsertIDForQuery(IQuery *query)
   163 {
   164 	return static_cast<SqQuery*>(query)->GetInsertID();
   165 }
   166 
   167 IPreparedQuery *SqDatabase::PrepareQuery(const char *query, 
   168 										 char *error, 
   169 										 size_t maxlength, 
   170 										 int *errCode/* =NULL */)
   171 {
   172 	sqlite3_stmt *stmt = NULL;
   173 	if ((m_LastErrorCode = sqlite3_prepare_v2(m_sq3, query, -1, &stmt, NULL)) != SQLITE_OK
   174 		|| !stmt)
   175 	{
   176 		const char *msg;
   177 		if (m_LastErrorCode != SQLITE_OK)
   178 		{
   179 			msg = sqlite3_errmsg(m_sq3);
   180 		} else {
   181 			msg = "Invalid query string";
   182 			m_LastErrorCode = SQLITE_ERROR;
   183 		}
   184 		if (error)
   185 		{
   186 			strncopy(error, msg, maxlength);
   187 		}
   188 		m_LastError.assign(msg);
   189 		return NULL;
   190 	}
   191 	return new SqQuery(this, stmt);
   192 }
   193 
   194 IPreparedQuery *SqDatabase::PrepareQueryEx(const char *query, 
   195 										   size_t len, 
   196 										   char *error, 
   197 										   size_t maxlength, 
   198 										   int *errCode/* =NULL */)
   199 {
   200 	sqlite3_stmt *stmt = NULL;
   201 	if ((m_LastErrorCode = sqlite3_prepare_v2(m_sq3, query, len, &stmt, NULL)) != SQLITE_OK
   202 		|| !stmt)
   203 	{
   204 		const char *msg;
   205 		if (m_LastErrorCode != SQLITE_OK)
   206 		{
   207 			msg = sqlite3_errmsg(m_sq3);
   208 		} else {
   209 			msg = "Invalid query string";
   210 			m_LastErrorCode = SQLITE_ERROR;
   211 		}
   212 		if (error)
   213 		{
   214 			strncopy(error, msg, maxlength);
   215 		}
   216 		m_LastError.assign(msg);
   217 		return NULL;
   218 	}
   219 	return new SqQuery(this, stmt);
   220 }
   221 
   222 sqlite3 *SqDatabase::GetDb()
   223 {
   224 	return m_sq3;
   225 }
   226 
   227 bool SqDatabase::SetCharacterSet(const char *characterset)
   228 {
   229 	// sqlite only supports utf8 and utf16 - by the time the database is created. It's too late here.
   230 	return false;
   231 }