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