extensions/clientprefs/query.cpp
author David Anderson <dvander@alliedmods.net>
Mon Aug 10 22:16:58 2009 -0400 (2009-08-10)
changeset 2767 c1f37afdcbb9
parent 2668 a6c7e8d7f8c9
child 3804 90159516acd3
permissions -rw-r--r--
Fixed incorrect escaping in clientprefs SQLite queries (bug 3904, r+a12=pred).
pred@2009
     1
/**
pred@2009
     2
 * vim: set ts=4 :
pred@2009
     3
 * =============================================================================
pred@2009
     4
 * SourceMod Client Preferences Extension
pred@2009
     5
 * Copyright (C) 2004-2008 AlliedModders LLC.  All rights reserved.
pred@2009
     6
 * =============================================================================
pred@2009
     7
 *
pred@2009
     8
 * This program is free software; you can redistribute it and/or modify it under
pred@2009
     9
 * the terms of the GNU General Public License, version 3.0, as published by the
pred@2009
    10
 * Free Software Foundation.
pred@2009
    11
 * 
pred@2009
    12
 * This program is distributed in the hope that it will be useful, but WITHOUT
pred@2009
    13
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
pred@2009
    14
 * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
pred@2009
    15
 * details.
pred@2009
    16
 *
pred@2009
    17
 * You should have received a copy of the GNU General Public License along with
pred@2009
    18
 * this program.  If not, see <http://www.gnu.org/licenses/>.
pred@2009
    19
 *
pred@2009
    20
 * As a special exception, AlliedModders LLC gives you permission to link the
pred@2009
    21
 * code of this program (as well as its derivative works) to "Half-Life 2," the
pred@2009
    22
 * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
pred@2009
    23
 * by the Valve Corporation.  You must obey the GNU General Public License in
pred@2009
    24
 * all respects for all other code used.  Additionally, AlliedModders LLC grants
pred@2009
    25
 * this exception to all derivative works.  AlliedModders LLC defines further
pred@2009
    26
 * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
pred@2009
    27
 * or <http://www.sourcemod.net/license.php>.
pred@2009
    28
 *
pred@2009
    29
 * Version: $Id$
pred@2009
    30
 */
pred@2009
    31
pred@2009
    32
#include "query.h"
pred@2009
    33
pred@2009
    34
pred@2009
    35
void TQueryOp::RunThinkPart()
pred@2009
    36
{
pred@2009
    37
	//handler for threaded sql queries
pred@2009
    38
pred@2207
    39
	if (m_type == Query_Connect)
pred@2207
    40
	{
pred@2207
    41
		return;
pred@2207
    42
	}
pred@2207
    43
dvander@2373
    44
	switch (m_type)
pred@2009
    45
	{
dvander@2373
    46
		case Query_InsertCookie:
pred@2009
    47
		{
dvander@2373
    48
			g_CookieManager.InsertCookieCallback(m_pCookie, m_insertId);
dvander@2373
    49
			break;
dvander@2373
    50
		}
pred@2207
    51
dvander@2373
    52
		case Query_SelectData:
dvander@2373
    53
		{
pred@2592
    54
			g_CookieManager.ClientConnectCallback(m_serial, m_pResult);
dvander@2373
    55
			break;
dvander@2373
    56
		}
pred@2207
    57
dvander@2373
    58
		case Query_SelectId:
dvander@2373
    59
		{
dvander@2373
    60
			g_CookieManager.SelectIdCallback(m_pCookie, m_pResult);
dvander@2373
    61
			break;
dvander@2373
    62
		}
pred@2207
    63
dvander@2373
    64
		default:
dvander@2373
    65
		{
dvander@2373
    66
			break;
pred@2009
    67
		}
pred@2009
    68
	}
pred@2009
    69
}
pred@2009
    70
pred@2009
    71
void TQueryOp::RunThreadPart()
pred@2009
    72
{
pred@2207
    73
	if (m_type == Query_Connect)
pred@2207
    74
	{
pred@2207
    75
		g_ClientPrefs.DatabaseConnect();
pred@2207
    76
	}
pred@2207
    77
	else
pred@2009
    78
	{
dvander@2359
    79
		assert(m_database != NULL);
pred@2207
    80
dvander@2373
    81
		/* I don't think this is needed anymore... keeping for now. */
pred@2207
    82
		m_database->LockForFullAtomicOperation();
pred@2009
    83
pred@2207
    84
		if (!BindParamsAndRun())
pred@2207
    85
		{
dvander@2364
    86
			g_pSM->LogError(myself, 
pred@2592
    87
							"Failed SQL Query, Error: \"%s\" (Query id %i - serial %i)", 
dvander@2373
    88
							m_database->GetError(),
dvander@2364
    89
							m_type, 
pred@2592
    90
							m_serial);
pred@2207
    91
		}
pred@2009
    92
pred@2207
    93
		m_database->UnlockFromFullAtomicOperation();
pred@2207
    94
	}
pred@2009
    95
}
pred@2009
    96
pred@2009
    97
IDBDriver *TQueryOp::GetDriver()
pred@2009
    98
{
dvander@2359
    99
	assert(m_database != NULL);
pred@2207
   100
pred@2207
   101
	return m_database->GetDriver();
pred@2009
   102
}
dvander@2373
   103
pred@2009
   104
IdentityToken_t *TQueryOp::GetOwner()
pred@2009
   105
{
pred@2009
   106
	return myself->GetIdentity();
pred@2009
   107
}
pred@2220
   108
pred@2009
   109
void TQueryOp::Destroy()
pred@2009
   110
{
dvander@2373
   111
	if (m_pResult != NULL)
dvander@2373
   112
	{
dvander@2373
   113
		m_pResult->Destroy();
dvander@2373
   114
	}
pred@2009
   115
	delete this;
pred@2009
   116
}
pred@2009
   117
pred@2592
   118
TQueryOp::TQueryOp(enum querytype type, int serial)
pred@2009
   119
{
pred@2009
   120
	m_type = type;
pred@2592
   121
	m_serial = serial;
pred@2207
   122
	m_database = NULL;
dvander@2373
   123
	m_insertId = -1;
dvander@2373
   124
	m_pResult = NULL;
pred@2207
   125
}
pred@2009
   126
pred@2207
   127
TQueryOp::TQueryOp(enum querytype type, Cookie *cookie)
pred@2207
   128
{
pred@2207
   129
	m_type = type;
pred@2207
   130
	m_pCookie = cookie;
pred@2207
   131
	m_database = NULL;
dvander@2373
   132
	m_insertId = -1;
dvander@2373
   133
	m_pResult = NULL;
pred@2207
   134
}
pred@2207
   135
dvander@2373
   136
void TQueryOp::SetDatabase(IDatabase *db)
pred@2207
   137
{
pred@2207
   138
	m_database = db;
pred@2207
   139
	m_database->IncReferenceCount();
pred@2009
   140
}
pred@2009
   141
pred@2207
   142
bool TQueryOp::BindParamsAndRun()
pred@2207
   143
{
dvander@2373
   144
	size_t ignore;
dvander@2373
   145
	char query[2048];
pred@2207
   146
pred@2207
   147
	switch (m_type)
pred@2207
   148
	{
pred@2207
   149
		case Query_InsertCookie:
pred@2207
   150
		{
dvander@2373
   151
			char safe_name[MAX_NAME_LENGTH*2 + 1];
dvander@2373
   152
			char safe_desc[MAX_DESC_LENGTH*2 + 1];
dvander@2373
   153
			
dvander@2373
   154
			m_database->QuoteString(m_params.cookie->name, 
dvander@2373
   155
				safe_name, 
dvander@2373
   156
				sizeof(safe_name),
dvander@2373
   157
				&ignore);
dvander@2373
   158
			m_database->QuoteString(m_params.cookie->description,
dvander@2373
   159
				safe_desc,
dvander@2373
   160
				sizeof(safe_desc),
dvander@2373
   161
				&ignore);
pred@2207
   162
dvander@2373
   163
			if (g_DriverType == Driver_MySQL)
dvander@2373
   164
			{
dvander@2373
   165
				UTIL_Format(query,
dvander@2373
   166
					sizeof(query),
dvander@2373
   167
					"INSERT IGNORE INTO sm_cookies (name, description, access) \
dvander@2373
   168
					 VALUES (\"%s\", \"%s\", %d)",
dvander@2373
   169
					safe_name,
dvander@2373
   170
					safe_desc,
dvander@2373
   171
					m_params.cookie->access);
dvander@2373
   172
			}
dvander@2373
   173
			else if (g_DriverType == Driver_SQLite)
dvander@2373
   174
			{
dvander@2373
   175
				UTIL_Format(query,
dvander@2373
   176
					sizeof(query),
dvander@2373
   177
					"INSERT OR IGNORE INTO sm_cookies (name, description, access) \
dvander@2767
   178
					 VALUES ('%s', '%s', %d)",
dvander@2373
   179
					 safe_name,
dvander@2373
   180
					 safe_desc,
dvander@2373
   181
					 m_params.cookie->access);
dvander@2373
   182
			}
dvander@2373
   183
dvander@2373
   184
			if (!m_database->DoSimpleQuery(query))
dvander@2373
   185
			{
dvander@2373
   186
				return false;
dvander@2373
   187
			}
dvander@2373
   188
dvander@2373
   189
			m_insertId = m_database->GetInsertID();
dvander@2373
   190
dvander@2373
   191
			return true;
pred@2207
   192
		}
pred@2207
   193
pred@2207
   194
		case Query_SelectData:
pred@2207
   195
		{
dvander@2373
   196
			char safe_str[128];
dvander@2373
   197
dvander@2373
   198
			m_database->QuoteString(m_params.steamId, safe_str, sizeof(safe_str), &ignore);
pred@2207
   199
dvander@2373
   200
			UTIL_Format(query,
dvander@2373
   201
				sizeof(query),
dvander@2373
   202
				"SELECT sm_cookies.name, sm_cookie_cache.value, sm_cookies.description, \
pred@2668
   203
						sm_cookies.access, sm_cookie_cache.timestamp 	\
dvander@2373
   204
				FROM sm_cookies				\
dvander@2373
   205
				JOIN sm_cookie_cache		\
dvander@2373
   206
				ON sm_cookies.id = sm_cookie_cache.cookie_id \
dvander@2767
   207
				WHERE player = '%s'",
dvander@2373
   208
				safe_str);
dvander@2373
   209
dvander@2373
   210
			m_pResult = m_database->DoQuery(query);
dvander@2373
   211
dvander@2373
   212
			return (m_pResult != NULL);
pred@2207
   213
		}
pred@2207
   214
pred@2207
   215
		case Query_InsertData:
pred@2207
   216
		{
dvander@2373
   217
			char safe_id[128];
dvander@2373
   218
			char safe_val[MAX_VALUE_LENGTH*2 + 1];
dvander@2373
   219
dvander@2373
   220
			m_database->QuoteString(m_params.steamId,
dvander@2373
   221
				safe_id,
dvander@2373
   222
				sizeof(safe_id),
dvander@2373
   223
				&ignore);
dvander@2373
   224
			m_database->QuoteString(m_params.data->value,
dvander@2373
   225
				safe_val,
dvander@2373
   226
				sizeof(safe_val),
dvander@2373
   227
				&ignore);
pred@2207
   228
dvander@2373
   229
			if (g_DriverType == Driver_MySQL)
pred@2207
   230
			{
dvander@2373
   231
				UTIL_Format(query, 
dvander@2373
   232
					sizeof(query),
dvander@2373
   233
					"INSERT INTO sm_cookie_cache (player, cookie_id, value, timestamp) 	\
dvander@2373
   234
					 VALUES (\"%s\", %d, \"%s\", %d)									\
dvander@2373
   235
					 ON DUPLICATE KEY UPDATE											\
dvander@2373
   236
					 value = \"%s\", timestamp = %d",
dvander@2373
   237
					safe_id,
dvander@2373
   238
					m_params.cookieId,
dvander@2373
   239
					safe_val,
pred@2668
   240
					(unsigned int)m_params.data->timestamp,
dvander@2373
   241
					safe_val,
pred@2668
   242
					(unsigned int)m_params.data->timestamp);
dvander@2373
   243
			}
dvander@2373
   244
			else if (g_DriverType == Driver_SQLite)
dvander@2373
   245
			{
dvander@2373
   246
				UTIL_Format(query,
dvander@2373
   247
					sizeof(query),
dvander@2373
   248
					"INSERT OR REPLACE INTO sm_cookie_cache						\
dvander@2373
   249
					 (player, cookie_id, value, timestamp)						\
dvander@2767
   250
					 VALUES ('%s', %d, '%s', %d)",
dvander@2373
   251
					safe_id,
dvander@2373
   252
					m_params.cookieId,
dvander@2373
   253
					safe_val,
pred@2668
   254
					(unsigned int)m_params.data->timestamp);
pred@2207
   255
			}
pred@2207
   256
dvander@2373
   257
			if (!m_database->DoSimpleQuery(query))
dvander@2373
   258
			{
dvander@2373
   259
				return false;
dvander@2373
   260
			}
dvander@2373
   261
dvander@2373
   262
			m_insertId = m_database->GetInsertID();
dvander@2373
   263
dvander@2373
   264
			return true;
pred@2207
   265
		}
pred@2207
   266
pred@2207
   267
		case Query_SelectId:
pred@2207
   268
		{
dvander@2373
   269
			char safe_name[MAX_NAME_LENGTH*2 + 1];
dvander@2373
   270
pred@2207
   271
			/* the steamId var was actually used to store the name of the cookie - Save duplicating vars */
dvander@2373
   272
			m_database->QuoteString(m_params.steamId, 
dvander@2373
   273
				safe_name,
dvander@2373
   274
				sizeof(safe_name),
dvander@2373
   275
				&ignore);
pred@2207
   276
dvander@2373
   277
			UTIL_Format(query, 
dvander@2373
   278
				sizeof(query),
dvander@2767
   279
				"SELECT id FROM sm_cookies WHERE name = '%s'",
dvander@2373
   280
				safe_name);
dvander@2373
   281
dvander@2373
   282
			m_pResult = m_database->DoQuery(query);
dvander@2373
   283
dvander@2373
   284
			return (m_pResult != NULL);
pred@2207
   285
		}
pred@2207
   286
pred@2207
   287
		default:
pred@2207
   288
		{
pred@2207
   289
			break;
pred@2207
   290
		}
pred@2207
   291
			
pred@2207
   292
	}
pred@2207
   293
dvander@2373
   294
	assert(false);
pred@2207
   295
dvander@2373
   296
	return false;
pred@2207
   297
}
pred@2009
   298
pred@2207
   299
ParamData::~ParamData()
pred@2207
   300
{
pred@2207
   301
	if (cookie)
pred@2207
   302
	{
pred@2207
   303
		g_ClientPrefs.cookieMutex->Lock();
pred@2207
   304
		cookie->usedInQuery--;
pred@2207
   305
pred@2207
   306
		if (cookie->shouldDelete && cookie->usedInQuery <= 0)
pred@2207
   307
		{
pred@2207
   308
			g_ClientPrefs.cookieMutex->Unlock();
pred@2207
   309
			delete cookie;
pred@2207
   310
			cookie = NULL;
pred@2207
   311
		}
pred@2207
   312
pred@2207
   313
		g_ClientPrefs.cookieMutex->Unlock();	
pred@2207
   314
	}
pred@2207
   315
pred@2207
   316
	if (data)
pred@2207
   317
	{
pred@2207
   318
		/* Data is only ever passed in a client disconnect query and always needs to be deleted */
pred@2207
   319
		delete data;
pred@2207
   320
		data = NULL;
pred@2207
   321
	}
pred@2207
   322
}
pred@2207
   323
pred@2207
   324
ParamData::ParamData()
pred@2207
   325
{
pred@2207
   326
	cookie = NULL;
pred@2207
   327
	data = NULL;
pred@2207
   328
	steamId[0] = '\0';
pred@2207
   329
	cookieId = 0;
pred@2208
   330
}
dvander@2373
   331