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