Files
TCPlayerbotCore/src/server/shared/Database/QueryResult.cpp
T

230 lines
6.6 KiB
C++
Raw Normal View History

/*
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
2008-10-14 11:57:03 -05:00
*
2010-01-16 20:19:18 +03:00
* Copyright (C) 2008-2010 Trinity <http://www.trinitycore.org/>
2008-10-02 16:23:55 -05:00
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
2008-10-14 11:57:03 -05:00
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2008-10-02 16:23:55 -05:00
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
2008-10-14 11:57:03 -05:00
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
2008-10-02 16:23:55 -05:00
*/
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
#include "DatabaseEnv.h"
2010-09-11 21:10:54 +02:00
#include "Log.h"
2009-10-17 15:51:44 -07:00
2010-09-24 22:16:21 +02:00
ResultSet::ResultSet(MYSQL_RES *result, MYSQL_FIELD *fields, uint64 rowCount, uint32 fieldCount) :
m_rowCount(rowCount),
2010-09-28 14:48:17 +02:00
m_fieldCount(fieldCount),
m_result(result),
m_fields(fields)
2010-09-24 22:16:21 +02:00
{
m_currentRow = new Field[m_fieldCount];
ASSERT(m_currentRow);
}
PreparedResultSet::PreparedResultSet(MYSQL_STMT* stmt, MYSQL_RES *result, uint64 rowCount, uint32 fieldCount) :
2010-09-28 14:48:17 +02:00
m_rowCount(rowCount),
m_rowPosition(0),
m_fieldCount(fieldCount),
2010-09-24 22:16:21 +02:00
m_rBind(NULL),
m_stmt(stmt),
m_res(result),
m_isNull(NULL),
2010-09-28 14:48:17 +02:00
m_length(NULL)
2008-10-02 16:23:55 -05:00
{
2010-09-12 11:02:58 +02:00
if (!m_res)
return;
2010-09-24 22:36:35 +02:00
if (m_stmt->bind_result_done)
{
delete[] m_stmt->bind->length;
delete[] m_stmt->bind->is_null;
}
2010-09-12 11:02:58 +02:00
m_rBind = new MYSQL_BIND[m_fieldCount];
m_isNull = new my_bool[m_fieldCount];
m_length = new unsigned long[m_fieldCount];
2010-09-12 11:02:58 +02:00
memset(m_isNull, 0, sizeof(my_bool) * m_fieldCount);
memset(m_rBind, 0, sizeof(MYSQL_BIND) * m_fieldCount);
memset(m_length, 0, sizeof(unsigned long) * m_fieldCount);
//- This is where we store the (entire) resultset
if (mysql_stmt_store_result(m_stmt))
{
sLog.outSQLDriver("%s:mysql_stmt_store_result, cannot bind result from MySQL server. Error: %s", __FUNCTION__, mysql_stmt_error(m_stmt));
return;
}
2010-09-12 01:40:27 +02:00
//- This is where we prepare the buffer based on metadata
uint32 i = 0;
MYSQL_FIELD* field;
while ((field = mysql_fetch_field(m_res)))
{
2010-09-24 22:16:21 +02:00
size_t size = Field::SizeForType(field);
m_rBind[i].buffer_type = field->type;
2010-09-12 11:02:58 +02:00
m_rBind[i].buffer = malloc(size);
memset(m_rBind[i].buffer, 0, size);
m_rBind[i].buffer_length = size;
m_rBind[i].length = &m_length[i];
m_rBind[i].is_null = &m_isNull[i];
2010-09-11 21:10:54 +02:00
m_rBind[i].error = NULL;
m_rBind[i].is_unsigned = field->flags & UNSIGNED_FLAG;
2010-09-12 01:40:27 +02:00
++i;
}
2010-09-12 01:40:27 +02:00
//- This is where we bind the bind the buffer to the statement
if (mysql_stmt_bind_result(m_stmt, m_rBind))
{
sLog.outSQLDriver("%s:mysql_stmt_bind_result, cannot bind result from MySQL server. Error: %s", __FUNCTION__, mysql_stmt_error(m_stmt));
2010-09-12 11:02:58 +02:00
delete[] m_rBind;
delete[] m_isNull;
delete[] m_length;
return;
}
2010-09-12 01:40:27 +02:00
2010-09-24 22:16:21 +02:00
m_rowCount = mysql_stmt_num_rows(m_stmt);
2010-09-24 22:16:21 +02:00
m_rows.resize(m_rowCount);
while (_NextRow())
{
m_rows[m_rowPosition] = new Field[m_fieldCount];
for (uint64 fIndex = 0; fIndex < m_fieldCount; ++fIndex)
{
if (!*m_rBind[fIndex].is_null)
m_rows[m_rowPosition][fIndex].SetByteValue( m_rBind[fIndex].buffer,
m_rBind[fIndex].buffer_length,
m_rBind[fIndex].buffer_type,
*m_rBind[fIndex].length );
else
switch (m_rBind[fIndex].buffer_type)
{
case MYSQL_TYPE_TINY_BLOB:
case MYSQL_TYPE_MEDIUM_BLOB:
case MYSQL_TYPE_LONG_BLOB:
case MYSQL_TYPE_BLOB:
case MYSQL_TYPE_STRING:
case MYSQL_TYPE_VAR_STRING:
m_rows[m_rowPosition][fIndex].SetByteValue( "",
m_rBind[fIndex].buffer_length,
m_rBind[fIndex].buffer_type,
*m_rBind[fIndex].length );
break;
default:
m_rows[m_rowPosition][fIndex].SetByteValue( 0,
m_rBind[fIndex].buffer_length,
m_rBind[fIndex].buffer_type,
*m_rBind[fIndex].length );
}
}
m_rowPosition++;
}
m_rowPosition = 0;
2010-09-24 22:16:21 +02:00
/// All data is buffered, let go of mysql c api structures
CleanUp();
}
2010-09-24 22:16:21 +02:00
ResultSet::~ResultSet()
2010-09-19 15:25:50 +02:00
{
2010-09-24 22:16:21 +02:00
CleanUp();
2010-09-19 15:25:50 +02:00
}
2010-09-24 22:16:21 +02:00
PreparedResultSet::~PreparedResultSet()
{
2010-09-24 22:16:21 +02:00
for (uint64 i = 0; i < m_rowCount; ++i)
delete[] m_rows[i];
}
2010-09-24 22:16:21 +02:00
bool ResultSet::NextRow()
{
2010-09-24 22:16:21 +02:00
MYSQL_ROW row;
2010-09-24 22:16:21 +02:00
if (!m_result)
return false;
2010-09-24 22:16:21 +02:00
row = mysql_fetch_row(m_result);
if (!row)
{
CleanUp();
return false;
}
2010-09-24 22:16:21 +02:00
for (uint32 i = 0; i < m_fieldCount; i++)
m_currentRow[i].SetStructuredValue(row[i], m_fields[i].type);
2010-09-24 22:16:21 +02:00
return true;
}
2010-09-24 22:16:21 +02:00
bool PreparedResultSet::NextRow()
{
2010-09-24 22:16:21 +02:00
/// Only updates the m_rowPosition so upper level code knows in which element
/// of the rows vector to look
if (++m_rowPosition >= m_rowCount)
return false;
2010-09-24 22:16:21 +02:00
return true;
}
2010-09-24 22:16:21 +02:00
bool PreparedResultSet::_NextRow()
{
2010-09-24 22:16:21 +02:00
/// Only called in low-level code, namely the constructor
/// Will iterate over every row of data and buffer it
if (m_rowPosition >= m_rowCount)
return false;
2010-09-24 22:16:21 +02:00
int retval = mysql_stmt_fetch( m_stmt );
2010-09-24 22:16:21 +02:00
if (!retval || retval == MYSQL_DATA_TRUNCATED)
retval = true;
2010-09-24 22:16:21 +02:00
if (retval == MYSQL_NO_DATA)
retval = false;
2010-09-12 11:02:58 +02:00
2010-09-24 22:16:21 +02:00
return retval;
2010-09-12 11:02:58 +02:00
}
2010-09-24 22:16:21 +02:00
void ResultSet::CleanUp()
2010-09-12 11:02:58 +02:00
{
2010-09-24 22:16:21 +02:00
if (m_currentRow)
{
delete [] m_currentRow;
m_currentRow = NULL;
}
2010-09-12 11:02:58 +02:00
2010-09-24 22:16:21 +02:00
if (m_result)
{
mysql_free_result(m_result);
m_result = NULL;
}
2010-09-12 11:02:58 +02:00
}
2010-09-24 22:16:21 +02:00
void PreparedResultSet::CleanUp()
{
2010-09-24 22:16:21 +02:00
/// More of the in our code allocated sources are deallocated by the poorly documented mysql c api
if (m_res)
mysql_free_result(m_res);
2010-09-11 21:10:54 +02:00
2010-09-24 22:16:21 +02:00
FreeBindBuffer();
mysql_stmt_free_result(m_stmt);
delete[] m_rBind;
}
2010-09-24 22:16:21 +02:00
void PreparedResultSet::FreeBindBuffer()
2010-09-11 21:10:54 +02:00
{
2010-09-24 22:16:21 +02:00
for (uint32 i = 0; i < m_fieldCount; ++i)
free (m_rBind[i].buffer);
}