extensions/sqlite/driver/SqDatabase.cpp
author David Anderson <dvander@alliedmods.net>
Sun Aug 30 01:54:45 2009 -0700 (2009-08-30)
changeset 2790 6dd851ba15fd
parent 2289 44045ead61cd
child 3271 acc921bc57ef
permissions -rw-r--r--
Fixed extension version reporting.
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
dvander@1912
   189
IPreparedQuery *SqDatabase::PrepareQuery(const char *query, 
dvander@1912
   190
										 char *error, 
dvander@1912
   191
										 size_t maxlength, 
dvander@1912
   192
										 int *errCode/* =NULL */)
dvander@1203
   193
{
dvander@1203
   194
	sqlite3_stmt *stmt = NULL;
dvander@1203
   195
	if ((m_LastErrorCode = sqlite3_prepare_v2(m_sq3, query, -1, &stmt, NULL)) != SQLITE_OK
dvander@1203
   196
		|| !stmt)
dvander@1203
   197
	{
dvander@1203
   198
		const char *msg;
dvander@1203
   199
		if (m_LastErrorCode != SQLITE_OK)
dvander@1203
   200
		{
dvander@1203
   201
			msg = sqlite3_errmsg(m_sq3);
dvander@1203
   202
		} else {
dvander@1203
   203
			msg = "Invalid query string";
dvander@1448
   204
			m_LastErrorCode = SQLITE_ERROR;
dvander@1203
   205
		}
dvander@1203
   206
		if (error)
dvander@1203
   207
		{
dvander@1203
   208
			strncopy(error, msg, maxlength);
dvander@1203
   209
		}
dvander@1203
   210
		m_LastError.assign(msg);
dvander@1912
   211
		return NULL;
dvander@1912
   212
	}
dvander@1912
   213
	return new SqQuery(this, stmt);
dvander@1912
   214
}
dvander@1912
   215
dvander@1912
   216
IPreparedQuery *SqDatabase::PrepareQueryEx(const char *query, 
dvander@1912
   217
										   size_t len, 
dvander@1912
   218
										   char *error, 
dvander@1912
   219
										   size_t maxlength, 
dvander@1912
   220
										   int *errCode/* =NULL */)
dvander@1912
   221
{
dvander@1912
   222
	sqlite3_stmt *stmt = NULL;
dvander@1912
   223
	if ((m_LastErrorCode = sqlite3_prepare_v2(m_sq3, query, len, &stmt, NULL)) != SQLITE_OK
dvander@1912
   224
		|| !stmt)
dvander@1912
   225
	{
dvander@1912
   226
		const char *msg;
dvander@1912
   227
		if (m_LastErrorCode != SQLITE_OK)
dvander@1203
   228
		{
dvander@1912
   229
			msg = sqlite3_errmsg(m_sq3);
dvander@1912
   230
		} else {
dvander@1912
   231
			msg = "Invalid query string";
dvander@1912
   232
			m_LastErrorCode = SQLITE_ERROR;
dvander@1203
   233
		}
dvander@1912
   234
		if (error)
dvander@1912
   235
		{
dvander@1912
   236
			strncopy(error, msg, maxlength);
dvander@1912
   237
		}
dvander@1912
   238
		m_LastError.assign(msg);
dvander@1203
   239
		return NULL;
dvander@1203
   240
	}
dvander@1203
   241
	return new SqQuery(this, stmt);
dvander@1203
   242
}
dvander@1203
   243
dvander@1203
   244
sqlite3 *SqDatabase::GetDb()
dvander@1203
   245
{
dvander@1203
   246
	return m_sq3;
dvander@1203
   247
}