extensions/sqlite/driver/SqResults.cpp
author David Anderson <dvander@alliedmods.net>
Sun Jul 29 14:56:24 2007 +0000 (2007-07-29)
changeset 1210 18e60c8737a2
parent 1206 538a33346fad
child 1224 623fa8637134
permissions -rw-r--r--
fixed an sqlite bug where empty results would count as no result set
dvander@1203
     1
/**
dvander@1203
     2
 * vim: set ts=4 :
dvander@1203
     3
 * ===============================================================
dvander@1203
     4
 * SourceMod SQLite Driver Extension
dvander@1203
     5
 * Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
dvander@1203
     6
 * ===============================================================
dvander@1203
     7
 *
dvander@1203
     8
 * This program is free software; you can redistribute it and/or
dvander@1203
     9
 * modify it under the terms of the GNU General Public License
dvander@1203
    10
 * as published by the Free Software Foundation; either version 2
dvander@1203
    11
 * of the License, or (at your option) any later version.
dvander@1203
    12
 * This program is distributed in the hope that it will be useful,
dvander@1203
    13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
dvander@1203
    14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
dvander@1203
    15
 * GNU General Public License for more details.
dvander@1203
    16
 * 
dvander@1203
    17
 * You should have received a copy of the GNU General Public License
dvander@1203
    18
 * along with this program; if not, write to the Free Software
dvander@1203
    19
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
dvander@1203
    20
 *
dvander@1203
    21
 * Version: $Id$
dvander@1203
    22
 */
dvander@1203
    23
dvander@1203
    24
#include <stdlib.h>
dvander@1203
    25
#include "extension.h"
dvander@1203
    26
#include "SqResults.h"
dvander@1203
    27
#include "SqQuery.h"
dvander@1203
    28
dvander@1203
    29
SqResults::SqResults(SqQuery *query) : 
dvander@1203
    30
	m_pStmt(query->GetStmt()), m_Strings(1024),
dvander@1203
    31
	m_RowCount(0), m_MaxRows(0), m_Rows(NULL),
dvander@1203
    32
	m_CurRow(0), m_NextRow(0)
dvander@1203
    33
{
dvander@1203
    34
	m_ColCount = sqlite3_column_count(m_pStmt);
dvander@1203
    35
	if (m_ColCount)
dvander@1203
    36
	{
dvander@1203
    37
		m_ColNames = new String[m_ColCount];
dvander@1203
    38
		for (unsigned int i=0; i<m_ColCount; i++)
dvander@1203
    39
		{
dvander@1203
    40
			m_ColNames[i].assign(sqlite3_column_name(m_pStmt, i));
dvander@1203
    41
		}
dvander@1203
    42
	} else {
dvander@1203
    43
		m_ColNames = NULL;
dvander@1203
    44
	}
dvander@1203
    45
dvander@1203
    46
	m_pMemory = m_Strings.GetMemTable();
dvander@1203
    47
}
dvander@1203
    48
dvander@1203
    49
SqResults::~SqResults()
dvander@1203
    50
{
dvander@1203
    51
	delete [] m_ColNames;
dvander@1203
    52
	free(m_Rows);
dvander@1203
    53
}
dvander@1203
    54
dvander@1203
    55
unsigned int SqResults::GetRowCount()
dvander@1203
    56
{
dvander@1203
    57
	return m_RowCount;
dvander@1203
    58
}
dvander@1203
    59
dvander@1203
    60
unsigned int SqResults::GetFieldCount()
dvander@1203
    61
{
dvander@1203
    62
	return m_ColCount;
dvander@1203
    63
}
dvander@1203
    64
dvander@1203
    65
const char *SqResults::FieldNumToName(unsigned int columnId)
dvander@1203
    66
{
dvander@1203
    67
	if (columnId >= m_ColCount)
dvander@1203
    68
	{
dvander@1203
    69
		return NULL;
dvander@1203
    70
	}
dvander@1203
    71
dvander@1203
    72
	return m_ColNames[columnId].c_str();
dvander@1203
    73
}
dvander@1203
    74
dvander@1203
    75
bool SqResults::FieldNameToNum(const char *name, unsigned int *columnId)
dvander@1203
    76
{
dvander@1203
    77
	for (unsigned int i=0; i<m_ColCount; i++)
dvander@1203
    78
	{
dvander@1203
    79
		if (m_ColNames[i].compare(name) == 0)
dvander@1203
    80
		{
dvander@1203
    81
			if (columnId)
dvander@1203
    82
			{
dvander@1203
    83
				*columnId = i;
dvander@1203
    84
			}
dvander@1203
    85
			return true;
dvander@1203
    86
		}
dvander@1203
    87
	}
dvander@1203
    88
	return false;
dvander@1203
    89
}
dvander@1203
    90
dvander@1203
    91
void SqResults::ResetResultCount()
dvander@1203
    92
{
dvander@1203
    93
	m_RowCount = 0;
dvander@1203
    94
	m_CurRow = 0;
dvander@1203
    95
	m_NextRow = 0;
dvander@1203
    96
	m_pMemory->Reset();
dvander@1203
    97
}
dvander@1203
    98
dvander@1203
    99
void SqResults::PushResult()
dvander@1203
   100
{
dvander@1203
   101
	/* First make sure we can fit one more row */
dvander@1203
   102
	if (m_RowCount + 1 > m_MaxRows)
dvander@1203
   103
	{
dvander@1203
   104
		/* Create a new array */
dvander@1203
   105
		if (!m_Rows)
dvander@1203
   106
		{
dvander@1203
   107
			m_MaxRows = 8;
dvander@1203
   108
			m_Rows = (SqField *)malloc(sizeof(SqField) * m_ColCount * m_MaxRows);
dvander@1203
   109
		} else {
dvander@1203
   110
			m_MaxRows *= 2;
dvander@1203
   111
			m_Rows = (SqField *)realloc(m_Rows, sizeof(SqField) * m_ColCount * m_MaxRows);
dvander@1203
   112
		}
dvander@1203
   113
	}
dvander@1203
   114
dvander@1203
   115
	SqField *row = &m_Rows[m_RowCount * m_ColCount];
dvander@1203
   116
	for (unsigned int i=0; i<m_ColCount; i++)
dvander@1203
   117
	{
dvander@1203
   118
		row[i].type = sqlite3_column_type(m_pStmt, i);
dvander@1203
   119
		if (row[i].type == SQLITE_INTEGER)
dvander@1203
   120
		{
dvander@1203
   121
			row[i].u.idx = sqlite3_column_int(m_pStmt, i);
dvander@1203
   122
			row[i].size = sizeof(int);
dvander@1203
   123
		} else if (row[i].type == SQLITE_FLOAT) {
dvander@1203
   124
			row[i].u.f = (float)sqlite3_column_double(m_pStmt, i);
dvander@1203
   125
			row[i].size = sizeof(float);
dvander@1203
   126
		} else if (row[i].type == SQLITE_BLOB) {
dvander@1203
   127
			int bytes = sqlite3_column_bytes(m_pStmt, i);
dvander@1203
   128
			const void *pOrig;
dvander@1203
   129
			if ((pOrig = sqlite3_column_blob(m_pStmt, i)) != NULL)
dvander@1203
   130
			{
dvander@1203
   131
				void *pAddr;
dvander@1203
   132
				row[i].u.idx = m_pMemory->CreateMem(bytes, &pAddr);
dvander@1203
   133
				memcpy(pAddr, pOrig, bytes);
dvander@1203
   134
			} else {
dvander@1203
   135
				row[i].u.idx = -1;
dvander@1203
   136
			}
dvander@1203
   137
			row[i].size = sqlite3_column_bytes(m_pStmt, i);
dvander@1203
   138
		} else if (row[i].type == SQLITE_TEXT) {
dvander@1203
   139
			const char *str = (const char *)sqlite3_column_text(m_pStmt, i);
dvander@1203
   140
			if (str)
dvander@1203
   141
			{
dvander@1203
   142
				row[i].u.idx = m_Strings.AddString(str);
dvander@1203
   143
			} else {
dvander@1203
   144
				row[i].u.idx = -1;
dvander@1203
   145
			}
dvander@1203
   146
			row[i].size = sqlite3_column_bytes(m_pStmt, i);
dvander@1203
   147
		} else {
dvander@1203
   148
			row[i].size = 0;
dvander@1203
   149
		}
dvander@1203
   150
	}
dvander@1203
   151
dvander@1203
   152
	/* Finally, increase the row count */
dvander@1203
   153
	m_RowCount++;
dvander@1203
   154
}
dvander@1203
   155
dvander@1203
   156
bool SqResults::MoreRows()
dvander@1203
   157
{
dvander@1203
   158
	return (m_CurRow < m_RowCount);
dvander@1203
   159
}
dvander@1203
   160
dvander@1203
   161
IResultRow *SqResults::FetchRow()
dvander@1203
   162
{
dvander@1203
   163
	m_CurRow = m_NextRow;
dvander@1203
   164
	if (m_CurRow >= m_RowCount)
dvander@1203
   165
	{
dvander@1203
   166
		return NULL;
dvander@1203
   167
	}
dvander@1203
   168
	m_NextRow++;
dvander@1203
   169
	return this;
dvander@1203
   170
}
dvander@1203
   171
dvander@1203
   172
IResultRow *SqResults::CurrentRow()
dvander@1203
   173
{
dvander@1203
   174
	if (!m_RowCount || m_CurRow >= m_RowCount)
dvander@1203
   175
	{
dvander@1203
   176
		return NULL;
dvander@1203
   177
	}
dvander@1203
   178
	return this;
dvander@1203
   179
}
dvander@1203
   180
dvander@1203
   181
bool SqResults::Rewind()
dvander@1203
   182
{
dvander@1203
   183
	m_CurRow = 0;
dvander@1203
   184
	m_NextRow = 0;
dvander@1203
   185
	return true;
dvander@1203
   186
}
dvander@1203
   187
dvander@1203
   188
SqField *SqResults::GetField(unsigned int col)
dvander@1203
   189
{
dvander@1203
   190
	if (m_CurRow >= m_RowCount || col >= m_ColCount)
dvander@1203
   191
	{
dvander@1203
   192
		return NULL;
dvander@1203
   193
	}
dvander@1203
   194
dvander@1203
   195
	return &m_Rows[(m_CurRow * m_ColCount) + col];
dvander@1203
   196
}
dvander@1203
   197
dvander@1203
   198
DBType SqResults::GetFieldType(unsigned int field)
dvander@1203
   199
{
dvander@1203
   200
	/* Leaving unimplemented... */
dvander@1203
   201
	return DBType_Unknown;
dvander@1203
   202
}
dvander@1203
   203
dvander@1203
   204
DBType SqResults::GetFieldDataType(unsigned int field)
dvander@1203
   205
{
dvander@1203
   206
	/* Leaving unimplemented... */
dvander@1203
   207
	return DBType_Unknown;
dvander@1203
   208
}
dvander@1203
   209
dvander@1203
   210
DBResult SqResults::GetString(unsigned int columnId, const char **pString, size_t *_length)
dvander@1203
   211
{
dvander@1203
   212
	SqField *field = GetField(columnId);
dvander@1203
   213
	if (!field)
dvander@1203
   214
	{
dvander@1203
   215
		return DBVal_Error;
dvander@1203
   216
	}
dvander@1203
   217
dvander@1203
   218
	DBResult res = DBVal_Data;
dvander@1203
   219
	const char *ptr = NULL;
dvander@1203
   220
	size_t length = 0;
dvander@1203
   221
	if (field->type == SQLITE_TEXT || field->type == SQLITE_BLOB)
dvander@1203
   222
	{
dvander@1203
   223
		ptr = m_Strings.GetString(field->u.idx);
dvander@1203
   224
		length = field->size;
dvander@1203
   225
	} else if (field->type == SQLITE_INTEGER) {
dvander@1203
   226
		char number[24];
dvander@1203
   227
		field->size = UTIL_Format(number, sizeof(number), "%d", field->u.idx);
dvander@1203
   228
		field->type = SQLITE_TEXT;
dvander@1203
   229
		field->u.idx = m_Strings.AddString(number);
dvander@1203
   230
		ptr = m_Strings.GetString(field->u.idx);
dvander@1203
   231
		length = field->size;
dvander@1203
   232
	} else if (field->type == SQLITE_FLOAT) {
dvander@1203
   233
		char number[24];
dvander@1203
   234
		field->size = UTIL_Format(number, sizeof(number), "%f", field->u.f);
dvander@1203
   235
		field->type = SQLITE_TEXT;
dvander@1203
   236
		field->u.idx = m_Strings.AddString(number);
dvander@1203
   237
		ptr = m_Strings.GetString(field->u.idx);
dvander@1203
   238
		length = field->size;
dvander@1203
   239
	} else if (field->type == SQLITE_NULL) {
dvander@1203
   240
		res = DBVal_Null;
dvander@1203
   241
	}
dvander@1203
   242
dvander@1203
   243
	if (!ptr)
dvander@1203
   244
	{
dvander@1203
   245
		ptr = "";
dvander@1203
   246
	}
dvander@1203
   247
dvander@1203
   248
	if (*pString)
dvander@1203
   249
	{
dvander@1203
   250
		*pString = ptr;
dvander@1203
   251
	}
dvander@1203
   252
	if (_length)
dvander@1203
   253
	{
dvander@1203
   254
		*_length = length;
dvander@1203
   255
	}
dvander@1203
   256
dvander@1203
   257
	return res;
dvander@1203
   258
}
dvander@1203
   259
dvander@1203
   260
DBResult SqResults::CopyString(unsigned int columnId, char *buffer, size_t maxlength, size_t *written)
dvander@1203
   261
{
dvander@1203
   262
	SqField *field = GetField(columnId);
dvander@1203
   263
	if (!field)
dvander@1203
   264
	{
dvander@1203
   265
		return DBVal_Error;
dvander@1203
   266
	}
dvander@1203
   267
dvander@1203
   268
	DBResult res = DBVal_Data;
dvander@1203
   269
	if (field->type == SQLITE_TEXT || field->type == SQLITE_BLOB)
dvander@1203
   270
	{
dvander@1203
   271
		const char *ptr = m_Strings.GetString(field->u.idx);
dvander@1203
   272
		if (!ptr)
dvander@1203
   273
		{
dvander@1203
   274
			ptr = "";
dvander@1203
   275
			field->type = SQLITE_TEXT;
dvander@1203
   276
			res = DBVal_Null;
dvander@1203
   277
		}
dvander@1206
   278
		size_t wr = 0;
dvander@1203
   279
		if (field->type == SQLITE_TEXT)
dvander@1203
   280
		{
dvander@1203
   281
			wr = strncopy(buffer, ptr, maxlength);
dvander@1203
   282
		} else if (field->type == SQLITE_BLOB) {
dvander@1203
   283
			wr = (maxlength < field->size) ? maxlength : field->size;
dvander@1203
   284
			memcpy(buffer, ptr, wr);
dvander@1203
   285
		}
dvander@1203
   286
		if (written)
dvander@1203
   287
		{
dvander@1203
   288
			*written = wr;
dvander@1203
   289
		}
dvander@1203
   290
		return res;
dvander@1203
   291
	} else if (field->type == SQLITE_INTEGER) {
dvander@1203
   292
		size_t wr = 0;
dvander@1203
   293
		if (buffer)
dvander@1203
   294
		{
dvander@1203
   295
			wr = UTIL_Format(buffer, maxlength, "%d", field->u.idx);
dvander@1203
   296
		}
dvander@1203
   297
		if (written)
dvander@1203
   298
		{
dvander@1203
   299
			*written = wr;
dvander@1203
   300
		}
dvander@1203
   301
		return DBVal_Data;
dvander@1203
   302
	} else if (field->type == SQLITE_FLOAT) {
dvander@1203
   303
		size_t wr = 0;
dvander@1203
   304
		if (buffer)
dvander@1203
   305
		{
dvander@1203
   306
			wr = UTIL_Format(buffer, maxlength, "%f", field->u.f);
dvander@1203
   307
		}
dvander@1203
   308
		if (written)
dvander@1203
   309
		{
dvander@1203
   310
			*written = wr;
dvander@1203
   311
		}
dvander@1203
   312
		return DBVal_Data;
dvander@1203
   313
	}
dvander@1203
   314
dvander@1203
   315
	if (buffer)
dvander@1203
   316
	{
dvander@1203
   317
		strncopy(buffer, "", maxlength);
dvander@1203
   318
	}
dvander@1203
   319
	if (written)
dvander@1203
   320
	{
dvander@1203
   321
		*written = 0;
dvander@1203
   322
	}
dvander@1203
   323
dvander@1203
   324
	return DBVal_Null;
dvander@1203
   325
}
dvander@1203
   326
dvander@1203
   327
bool SqResults::IsNull(unsigned int columnId)
dvander@1203
   328
{
dvander@1203
   329
	SqField *field = GetField(columnId);
dvander@1203
   330
	if (!field)
dvander@1203
   331
	{
dvander@1203
   332
		return true;
dvander@1203
   333
	}
dvander@1203
   334
dvander@1203
   335
	return (field->type == SQLITE_NULL);
dvander@1203
   336
}
dvander@1203
   337
dvander@1203
   338
unsigned int SqResults::GetDataSize(unsigned int columnId)
dvander@1203
   339
{
dvander@1203
   340
	SqField *field = GetField(columnId);
dvander@1203
   341
	if (!field)
dvander@1203
   342
	{
dvander@1203
   343
		return 0;
dvander@1203
   344
	}
dvander@1203
   345
dvander@1203
   346
	return field->size;
dvander@1203
   347
}
dvander@1203
   348
dvander@1203
   349
DBResult SqResults::GetFloat(unsigned int columnId, float *pFloat)
dvander@1203
   350
{
dvander@1203
   351
	SqField *field = GetField(columnId);
dvander@1203
   352
	if (!field)
dvander@1203
   353
	{
dvander@1203
   354
		return DBVal_Error;
dvander@1203
   355
	} else if (field->type == SQLITE_BLOB) {
dvander@1203
   356
		return DBVal_Error;
dvander@1203
   357
	}
dvander@1203
   358
dvander@1203
   359
	float fVal = 0.0f;
dvander@1203
   360
	if (field->type == SQLITE_FLOAT)
dvander@1203
   361
	{
dvander@1203
   362
		fVal = field->u.f;
dvander@1203
   363
	} else if (field->type == SQLITE_TEXT) {
dvander@1203
   364
		const char *ptr = m_Strings.GetString(field->u.idx);
dvander@1203
   365
		if (ptr)
dvander@1203
   366
		{
dvander@1203
   367
			fVal = (float)atof(ptr);
dvander@1203
   368
		}
dvander@1203
   369
	} else if (field->type == SQLITE_INTEGER) {
dvander@1203
   370
		fVal = (float)field->u.idx;
dvander@1203
   371
	}
dvander@1203
   372
dvander@1203
   373
	if (pFloat)
dvander@1203
   374
	{
dvander@1203
   375
		*pFloat = fVal;
dvander@1203
   376
	}
dvander@1203
   377
dvander@1203
   378
	return (field->type == SQLITE_NULL) ? DBVal_Null : DBVal_Data;
dvander@1203
   379
}
dvander@1203
   380
dvander@1203
   381
DBResult SqResults::GetInt(unsigned int columnId, int *pInt)
dvander@1203
   382
{
dvander@1203
   383
	SqField *field = GetField(columnId);
dvander@1203
   384
	if (!field)
dvander@1203
   385
	{
dvander@1203
   386
		return DBVal_Error;
dvander@1203
   387
	} else if (field->type == SQLITE_BLOB) {
dvander@1203
   388
		return DBVal_Error;
dvander@1203
   389
	}
dvander@1203
   390
dvander@1203
   391
	int val = 0;
dvander@1203
   392
	if (field->type == SQLITE_INTEGER)
dvander@1203
   393
	{
dvander@1203
   394
		val = field->u.idx;
dvander@1203
   395
	} else if (field->type == SQLITE_TEXT) {
dvander@1203
   396
		const char *ptr = m_Strings.GetString(field->u.idx);
dvander@1203
   397
		if (ptr)
dvander@1203
   398
		{
dvander@1203
   399
			val = atoi(ptr);
dvander@1203
   400
		}
dvander@1203
   401
	} else if (field->type == SQLITE_FLOAT) {
dvander@1203
   402
		val = (int)field->u.f;
dvander@1203
   403
	}
dvander@1203
   404
dvander@1203
   405
	if (pInt)
dvander@1203
   406
	{
dvander@1203
   407
		*pInt = val;
dvander@1203
   408
	}
dvander@1203
   409
dvander@1203
   410
	return (field->type == SQLITE_NULL) ? DBVal_Null : DBVal_Data;
dvander@1203
   411
}
dvander@1203
   412
dvander@1203
   413
DBResult SqResults::GetBlob(unsigned int columnId, const void **pData, size_t *length)
dvander@1203
   414
{
dvander@1203
   415
	SqField *field = GetField(columnId);
dvander@1203
   416
	if (!field)
dvander@1203
   417
	{
dvander@1203
   418
		return DBVal_Error;
dvander@1203
   419
	} 
dvander@1203
   420
dvander@1203
   421
	void *addr = NULL;
dvander@1203
   422
dvander@1203
   423
	if (field->type == SQLITE_TEXT || field->type == SQLITE_BLOB)
dvander@1203
   424
	{
dvander@1203
   425
		addr = m_pMemory->GetAddress(field->u.idx);
dvander@1203
   426
	} else if (field->type == SQLITE_FLOAT || field->type == SQLITE_INTEGER) {
dvander@1203
   427
		addr = &(field->u);
dvander@1203
   428
	}
dvander@1203
   429
dvander@1203
   430
	if (pData)
dvander@1203
   431
	{
dvander@1203
   432
		*pData = addr;
dvander@1203
   433
	}
dvander@1203
   434
dvander@1203
   435
	if (length)
dvander@1203
   436
	{
dvander@1203
   437
		*length = field->size;
dvander@1203
   438
	}
dvander@1203
   439
dvander@1203
   440
	return (field->type == SQLITE_NULL) ? DBVal_Null : DBVal_Data;
dvander@1203
   441
}
dvander@1203
   442
dvander@1203
   443
DBResult SqResults::CopyBlob(unsigned int columnId, void *buffer, size_t maxlength, size_t *written)
dvander@1203
   444
{
dvander@1203
   445
	SqField *field = GetField(columnId);
dvander@1203
   446
	if (!field)
dvander@1203
   447
	{
dvander@1203
   448
		return DBVal_Error;
dvander@1203
   449
	} 
dvander@1203
   450
dvander@1203
   451
	void *addr = NULL;
dvander@1203
   452
dvander@1203
   453
	if (field->type == SQLITE_TEXT || field->type == SQLITE_BLOB)
dvander@1203
   454
	{
dvander@1203
   455
		addr = m_pMemory->GetAddress(field->u.idx);
dvander@1203
   456
	} else if (field->type == SQLITE_FLOAT || field->type == SQLITE_INTEGER) {
dvander@1203
   457
		addr = &(field->u);
dvander@1203
   458
	}
dvander@1203
   459
dvander@1203
   460
	size_t toCopy = field->size > maxlength ? maxlength : field->size;
dvander@1203
   461
	if (buffer && addr && toCopy)
dvander@1203
   462
	{
dvander@1203
   463
		memcpy(buffer, addr, toCopy);
dvander@1203
   464
	} else {
dvander@1203
   465
		toCopy = 0;
dvander@1203
   466
	}
dvander@1203
   467
dvander@1203
   468
	if (written)
dvander@1203
   469
	{
dvander@1203
   470
		*written = toCopy;
dvander@1203
   471
	}
dvander@1203
   472
dvander@1203
   473
	return (field->type == SQLITE_NULL) ? DBVal_Null : DBVal_Data;
dvander@1203
   474
}