1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/extensions/sqlite/driver/SqResults.cpp Sun Mar 30 07:00:22 2008 +0000
1.3 @@ -0,0 +1,482 @@
1.4 +/**
1.5 + * vim: set ts=4 :
1.6 + * =============================================================================
1.7 + * SourceMod SQLite Extension
1.8 + * Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
1.9 + * =============================================================================
1.10 + *
1.11 + * This program is free software; you can redistribute it and/or modify it under
1.12 + * the terms of the GNU General Public License, version 3.0, as published by the
1.13 + * Free Software Foundation.
1.14 + *
1.15 + * This program is distributed in the hope that it will be useful, but WITHOUT
1.16 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
1.17 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
1.18 + * details.
1.19 + *
1.20 + * You should have received a copy of the GNU General Public License along with
1.21 + * this program. If not, see <http://www.gnu.org/licenses/>.
1.22 + *
1.23 + * As a special exception, AlliedModders LLC gives you permission to link the
1.24 + * code of this program (as well as its derivative works) to "Half-Life 2," the
1.25 + * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
1.26 + * by the Valve Corporation. You must obey the GNU General Public License in
1.27 + * all respects for all other code used. Additionally, AlliedModders LLC grants
1.28 + * this exception to all derivative works. AlliedModders LLC defines further
1.29 + * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
1.30 + * or <http://www.sourcemod.net/license.php>.
1.31 + *
1.32 + * Version: $Id$
1.33 + */
1.34 +
1.35 +#include <stdlib.h>
1.36 +#include "extension.h"
1.37 +#include "SqResults.h"
1.38 +#include "SqQuery.h"
1.39 +
1.40 +SqResults::SqResults(SqQuery *query) :
1.41 + m_pStmt(query->GetStmt()), m_Strings(1024),
1.42 + m_RowCount(0), m_MaxRows(0), m_Rows(NULL),
1.43 + m_CurRow(0), m_NextRow(0)
1.44 +{
1.45 + m_ColCount = sqlite3_column_count(m_pStmt);
1.46 + if (m_ColCount)
1.47 + {
1.48 + m_ColNames = new String[m_ColCount];
1.49 + for (unsigned int i=0; i<m_ColCount; i++)
1.50 + {
1.51 + m_ColNames[i].assign(sqlite3_column_name(m_pStmt, i));
1.52 + }
1.53 + } else {
1.54 + m_ColNames = NULL;
1.55 + }
1.56 +
1.57 + m_pMemory = m_Strings.GetMemTable();
1.58 +}
1.59 +
1.60 +SqResults::~SqResults()
1.61 +{
1.62 + delete [] m_ColNames;
1.63 + free(m_Rows);
1.64 +}
1.65 +
1.66 +unsigned int SqResults::GetRowCount()
1.67 +{
1.68 + return m_RowCount;
1.69 +}
1.70 +
1.71 +unsigned int SqResults::GetFieldCount()
1.72 +{
1.73 + return m_ColCount;
1.74 +}
1.75 +
1.76 +const char *SqResults::FieldNumToName(unsigned int columnId)
1.77 +{
1.78 + if (columnId >= m_ColCount)
1.79 + {
1.80 + return NULL;
1.81 + }
1.82 +
1.83 + return m_ColNames[columnId].c_str();
1.84 +}
1.85 +
1.86 +bool SqResults::FieldNameToNum(const char *name, unsigned int *columnId)
1.87 +{
1.88 + for (unsigned int i=0; i<m_ColCount; i++)
1.89 + {
1.90 + if (m_ColNames[i].compare(name) == 0)
1.91 + {
1.92 + if (columnId)
1.93 + {
1.94 + *columnId = i;
1.95 + }
1.96 + return true;
1.97 + }
1.98 + }
1.99 + return false;
1.100 +}
1.101 +
1.102 +void SqResults::ResetResultCount()
1.103 +{
1.104 + m_RowCount = 0;
1.105 + m_CurRow = 0;
1.106 + m_NextRow = 0;
1.107 + m_pMemory->Reset();
1.108 +}
1.109 +
1.110 +void SqResults::PushResult()
1.111 +{
1.112 + /* First make sure we can fit one more row */
1.113 + if (m_RowCount + 1 > m_MaxRows)
1.114 + {
1.115 + /* Create a new array */
1.116 + if (!m_Rows)
1.117 + {
1.118 + m_MaxRows = 8;
1.119 + m_Rows = (SqField *)malloc(sizeof(SqField) * m_ColCount * m_MaxRows);
1.120 + } else {
1.121 + m_MaxRows *= 2;
1.122 + m_Rows = (SqField *)realloc(m_Rows, sizeof(SqField) * m_ColCount * m_MaxRows);
1.123 + }
1.124 + }
1.125 +
1.126 + SqField *row = &m_Rows[m_RowCount * m_ColCount];
1.127 + for (unsigned int i=0; i<m_ColCount; i++)
1.128 + {
1.129 + row[i].type = sqlite3_column_type(m_pStmt, i);
1.130 + if (row[i].type == SQLITE_INTEGER)
1.131 + {
1.132 + row[i].u.idx = sqlite3_column_int(m_pStmt, i);
1.133 + row[i].size = sizeof(int);
1.134 + } else if (row[i].type == SQLITE_FLOAT) {
1.135 + row[i].u.f = (float)sqlite3_column_double(m_pStmt, i);
1.136 + row[i].size = sizeof(float);
1.137 + } else if (row[i].type == SQLITE_BLOB) {
1.138 + int bytes = sqlite3_column_bytes(m_pStmt, i);
1.139 + const void *pOrig;
1.140 + if ((pOrig = sqlite3_column_blob(m_pStmt, i)) != NULL)
1.141 + {
1.142 + void *pAddr;
1.143 + row[i].u.idx = m_pMemory->CreateMem(bytes, &pAddr);
1.144 + memcpy(pAddr, pOrig, bytes);
1.145 + } else {
1.146 + row[i].u.idx = -1;
1.147 + }
1.148 + row[i].size = sqlite3_column_bytes(m_pStmt, i);
1.149 + } else if (row[i].type == SQLITE_TEXT) {
1.150 + const char *str = (const char *)sqlite3_column_text(m_pStmt, i);
1.151 + if (str)
1.152 + {
1.153 + row[i].u.idx = m_Strings.AddString(str);
1.154 + } else {
1.155 + row[i].u.idx = -1;
1.156 + }
1.157 + row[i].size = sqlite3_column_bytes(m_pStmt, i);
1.158 + } else {
1.159 + row[i].size = 0;
1.160 + }
1.161 + }
1.162 +
1.163 + /* Finally, increase the row count */
1.164 + m_RowCount++;
1.165 +}
1.166 +
1.167 +bool SqResults::MoreRows()
1.168 +{
1.169 + return (m_CurRow < m_RowCount);
1.170 +}
1.171 +
1.172 +IResultRow *SqResults::FetchRow()
1.173 +{
1.174 + m_CurRow = m_NextRow;
1.175 + if (m_CurRow >= m_RowCount)
1.176 + {
1.177 + return NULL;
1.178 + }
1.179 + m_NextRow++;
1.180 + return this;
1.181 +}
1.182 +
1.183 +IResultRow *SqResults::CurrentRow()
1.184 +{
1.185 + if (!m_RowCount || m_CurRow >= m_RowCount)
1.186 + {
1.187 + return NULL;
1.188 + }
1.189 + return this;
1.190 +}
1.191 +
1.192 +bool SqResults::Rewind()
1.193 +{
1.194 + m_CurRow = 0;
1.195 + m_NextRow = 0;
1.196 + return true;
1.197 +}
1.198 +
1.199 +SqField *SqResults::GetField(unsigned int col)
1.200 +{
1.201 + if (m_CurRow >= m_RowCount || col >= m_ColCount)
1.202 + {
1.203 + return NULL;
1.204 + }
1.205 +
1.206 + return &m_Rows[(m_CurRow * m_ColCount) + col];
1.207 +}
1.208 +
1.209 +DBType SqResults::GetFieldType(unsigned int field)
1.210 +{
1.211 + /* Leaving unimplemented... */
1.212 + return DBType_Unknown;
1.213 +}
1.214 +
1.215 +DBType SqResults::GetFieldDataType(unsigned int field)
1.216 +{
1.217 + /* Leaving unimplemented... */
1.218 + return DBType_Unknown;
1.219 +}
1.220 +
1.221 +DBResult SqResults::GetString(unsigned int columnId, const char **pString, size_t *_length)
1.222 +{
1.223 + SqField *field = GetField(columnId);
1.224 + if (!field)
1.225 + {
1.226 + return DBVal_Error;
1.227 + }
1.228 +
1.229 + DBResult res = DBVal_Data;
1.230 + const char *ptr = NULL;
1.231 + size_t length = 0;
1.232 + if (field->type == SQLITE_TEXT || field->type == SQLITE_BLOB)
1.233 + {
1.234 + ptr = m_Strings.GetString(field->u.idx);
1.235 + length = field->size;
1.236 + } else if (field->type == SQLITE_INTEGER) {
1.237 + char number[24];
1.238 + field->size = UTIL_Format(number, sizeof(number), "%d", field->u.idx);
1.239 + field->type = SQLITE_TEXT;
1.240 + field->u.idx = m_Strings.AddString(number);
1.241 + ptr = m_Strings.GetString(field->u.idx);
1.242 + length = field->size;
1.243 + } else if (field->type == SQLITE_FLOAT) {
1.244 + char number[24];
1.245 + field->size = UTIL_Format(number, sizeof(number), "%f", field->u.f);
1.246 + field->type = SQLITE_TEXT;
1.247 + field->u.idx = m_Strings.AddString(number);
1.248 + ptr = m_Strings.GetString(field->u.idx);
1.249 + length = field->size;
1.250 + } else if (field->type == SQLITE_NULL) {
1.251 + res = DBVal_Null;
1.252 + }
1.253 +
1.254 + if (!ptr)
1.255 + {
1.256 + ptr = "";
1.257 + }
1.258 +
1.259 + if (pString)
1.260 + {
1.261 + *pString = ptr;
1.262 + }
1.263 + if (_length)
1.264 + {
1.265 + *_length = length;
1.266 + }
1.267 +
1.268 + return res;
1.269 +}
1.270 +
1.271 +DBResult SqResults::CopyString(unsigned int columnId, char *buffer, size_t maxlength, size_t *written)
1.272 +{
1.273 + SqField *field = GetField(columnId);
1.274 + if (!field)
1.275 + {
1.276 + return DBVal_Error;
1.277 + }
1.278 +
1.279 + DBResult res = DBVal_Data;
1.280 + if (field->type == SQLITE_TEXT || field->type == SQLITE_BLOB)
1.281 + {
1.282 + const char *ptr = m_Strings.GetString(field->u.idx);
1.283 + if (!ptr)
1.284 + {
1.285 + ptr = "";
1.286 + field->type = SQLITE_TEXT;
1.287 + res = DBVal_Null;
1.288 + }
1.289 + size_t wr = 0;
1.290 + if (field->type == SQLITE_TEXT)
1.291 + {
1.292 + wr = strncopy(buffer, ptr, maxlength);
1.293 + } else if (field->type == SQLITE_BLOB) {
1.294 + wr = (maxlength < field->size) ? maxlength : field->size;
1.295 + memcpy(buffer, ptr, wr);
1.296 + }
1.297 + if (written)
1.298 + {
1.299 + *written = wr;
1.300 + }
1.301 + return res;
1.302 + } else if (field->type == SQLITE_INTEGER) {
1.303 + size_t wr = 0;
1.304 + if (buffer)
1.305 + {
1.306 + wr = UTIL_Format(buffer, maxlength, "%d", field->u.idx);
1.307 + }
1.308 + if (written)
1.309 + {
1.310 + *written = wr;
1.311 + }
1.312 + return DBVal_Data;
1.313 + } else if (field->type == SQLITE_FLOAT) {
1.314 + size_t wr = 0;
1.315 + if (buffer)
1.316 + {
1.317 + wr = UTIL_Format(buffer, maxlength, "%f", field->u.f);
1.318 + }
1.319 + if (written)
1.320 + {
1.321 + *written = wr;
1.322 + }
1.323 + return DBVal_Data;
1.324 + }
1.325 +
1.326 + if (buffer)
1.327 + {
1.328 + strncopy(buffer, "", maxlength);
1.329 + }
1.330 + if (written)
1.331 + {
1.332 + *written = 0;
1.333 + }
1.334 +
1.335 + return DBVal_Null;
1.336 +}
1.337 +
1.338 +bool SqResults::IsNull(unsigned int columnId)
1.339 +{
1.340 + SqField *field = GetField(columnId);
1.341 + if (!field)
1.342 + {
1.343 + return true;
1.344 + }
1.345 +
1.346 + return (field->type == SQLITE_NULL);
1.347 +}
1.348 +
1.349 +unsigned int SqResults::GetDataSize(unsigned int columnId)
1.350 +{
1.351 + SqField *field = GetField(columnId);
1.352 + if (!field)
1.353 + {
1.354 + return 0;
1.355 + }
1.356 +
1.357 + return field->size;
1.358 +}
1.359 +
1.360 +DBResult SqResults::GetFloat(unsigned int columnId, float *pFloat)
1.361 +{
1.362 + SqField *field = GetField(columnId);
1.363 + if (!field)
1.364 + {
1.365 + return DBVal_Error;
1.366 + } else if (field->type == SQLITE_BLOB) {
1.367 + return DBVal_Error;
1.368 + }
1.369 +
1.370 + float fVal = 0.0f;
1.371 + if (field->type == SQLITE_FLOAT)
1.372 + {
1.373 + fVal = field->u.f;
1.374 + } else if (field->type == SQLITE_TEXT) {
1.375 + const char *ptr = m_Strings.GetString(field->u.idx);
1.376 + if (ptr)
1.377 + {
1.378 + fVal = (float)atof(ptr);
1.379 + }
1.380 + } else if (field->type == SQLITE_INTEGER) {
1.381 + fVal = (float)field->u.idx;
1.382 + }
1.383 +
1.384 + if (pFloat)
1.385 + {
1.386 + *pFloat = fVal;
1.387 + }
1.388 +
1.389 + return (field->type == SQLITE_NULL) ? DBVal_Null : DBVal_Data;
1.390 +}
1.391 +
1.392 +DBResult SqResults::GetInt(unsigned int columnId, int *pInt)
1.393 +{
1.394 + SqField *field = GetField(columnId);
1.395 + if (!field)
1.396 + {
1.397 + return DBVal_Error;
1.398 + } else if (field->type == SQLITE_BLOB) {
1.399 + return DBVal_Error;
1.400 + }
1.401 +
1.402 + int val = 0;
1.403 + if (field->type == SQLITE_INTEGER)
1.404 + {
1.405 + val = field->u.idx;
1.406 + } else if (field->type == SQLITE_TEXT) {
1.407 + const char *ptr = m_Strings.GetString(field->u.idx);
1.408 + if (ptr)
1.409 + {
1.410 + val = atoi(ptr);
1.411 + }
1.412 + } else if (field->type == SQLITE_FLOAT) {
1.413 + val = (int)field->u.f;
1.414 + }
1.415 +
1.416 + if (pInt)
1.417 + {
1.418 + *pInt = val;
1.419 + }
1.420 +
1.421 + return (field->type == SQLITE_NULL) ? DBVal_Null : DBVal_Data;
1.422 +}
1.423 +
1.424 +DBResult SqResults::GetBlob(unsigned int columnId, const void **pData, size_t *length)
1.425 +{
1.426 + SqField *field = GetField(columnId);
1.427 + if (!field)
1.428 + {
1.429 + return DBVal_Error;
1.430 + }
1.431 +
1.432 + void *addr = NULL;
1.433 +
1.434 + if (field->type == SQLITE_TEXT || field->type == SQLITE_BLOB)
1.435 + {
1.436 + addr = m_pMemory->GetAddress(field->u.idx);
1.437 + } else if (field->type == SQLITE_FLOAT || field->type == SQLITE_INTEGER) {
1.438 + addr = &(field->u);
1.439 + }
1.440 +
1.441 + if (pData)
1.442 + {
1.443 + *pData = addr;
1.444 + }
1.445 +
1.446 + if (length)
1.447 + {
1.448 + *length = field->size;
1.449 + }
1.450 +
1.451 + return (field->type == SQLITE_NULL) ? DBVal_Null : DBVal_Data;
1.452 +}
1.453 +
1.454 +DBResult SqResults::CopyBlob(unsigned int columnId, void *buffer, size_t maxlength, size_t *written)
1.455 +{
1.456 + SqField *field = GetField(columnId);
1.457 + if (!field)
1.458 + {
1.459 + return DBVal_Error;
1.460 + }
1.461 +
1.462 + void *addr = NULL;
1.463 +
1.464 + if (field->type == SQLITE_TEXT || field->type == SQLITE_BLOB)
1.465 + {
1.466 + addr = m_pMemory->GetAddress(field->u.idx);
1.467 + } else if (field->type == SQLITE_FLOAT || field->type == SQLITE_INTEGER) {
1.468 + addr = &(field->u);
1.469 + }
1.470 +
1.471 + size_t toCopy = field->size > maxlength ? maxlength : field->size;
1.472 + if (buffer && addr && toCopy)
1.473 + {
1.474 + memcpy(buffer, addr, toCopy);
1.475 + } else {
1.476 + toCopy = 0;
1.477 + }
1.478 +
1.479 + if (written)
1.480 + {
1.481 + *written = toCopy;
1.482 + }
1.483 +
1.484 + return (field->type == SQLITE_NULL) ? DBVal_Null : DBVal_Data;
1.485 +}