aboutsummaryrefslogtreecommitdiff
path: root/src/server/database/Database/QueryResult.cpp
diff options
context:
space:
mode:
authorStormBytePP <stormbyte@gmail.com>2015-08-15 02:19:10 +0200
committerStormBytePP <stormbyte@gmail.com>2015-08-16 21:23:15 +0200
commit1f66d719f2cbbcb144b5080c89dd73fcae261798 (patch)
tree6a3778749b629c92de95cef7eb3d1d8c2630bdc4 /src/server/database/Database/QueryResult.cpp
parent222eaccc51b8d358c7b60d8def40d6461244ed31 (diff)
Core/BuildSystem: Merge collision, debugging, threading, utilities and configuration into "common" which does not depend on shared anymore and moved database out of shared library
These changes enables to build tools only without even having MySQL installed
Diffstat (limited to 'src/server/database/Database/QueryResult.cpp')
-rw-r--r--src/server/database/Database/QueryResult.cpp224
1 files changed, 224 insertions, 0 deletions
diff --git a/src/server/database/Database/QueryResult.cpp b/src/server/database/Database/QueryResult.cpp
new file mode 100644
index 00000000000..02352f221a0
--- /dev/null
+++ b/src/server/database/Database/QueryResult.cpp
@@ -0,0 +1,224 @@
+/*
+ * Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
+ *
+ * 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 MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "DatabaseEnv.h"
+#include "Log.h"
+
+ResultSet::ResultSet(MYSQL_RES *result, MYSQL_FIELD *fields, uint64 rowCount, uint32 fieldCount) :
+_rowCount(rowCount),
+_fieldCount(fieldCount),
+_result(result),
+_fields(fields)
+{
+ _currentRow = new Field[_fieldCount];
+ ASSERT(_currentRow);
+}
+
+PreparedResultSet::PreparedResultSet(MYSQL_STMT* stmt, MYSQL_RES *result, uint64 rowCount, uint32 fieldCount) :
+m_rowCount(rowCount),
+m_rowPosition(0),
+m_fieldCount(fieldCount),
+m_rBind(NULL),
+m_stmt(stmt),
+m_res(result),
+m_isNull(NULL),
+m_length(NULL)
+{
+ if (!m_res)
+ return;
+
+ if (m_stmt->bind_result_done)
+ {
+ delete[] m_stmt->bind->length;
+ delete[] m_stmt->bind->is_null;
+ }
+
+ m_rBind = new MYSQL_BIND[m_fieldCount];
+ m_isNull = new my_bool[m_fieldCount];
+ m_length = new unsigned long[m_fieldCount];
+
+ 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))
+ {
+ TC_LOG_WARN("sql.sql", "%s:mysql_stmt_store_result, cannot bind result from MySQL server. Error: %s", __FUNCTION__, mysql_stmt_error(m_stmt));
+ delete[] m_rBind;
+ delete[] m_isNull;
+ delete[] m_length;
+ return;
+ }
+
+ //- This is where we prepare the buffer based on metadata
+ uint32 i = 0;
+ MYSQL_FIELD* field = mysql_fetch_field(m_res);
+ while (field)
+ {
+ size_t size = Field::SizeForType(field);
+
+ m_rBind[i].buffer_type = field->type;
+ 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];
+ m_rBind[i].error = NULL;
+ m_rBind[i].is_unsigned = field->flags & UNSIGNED_FLAG;
+
+ ++i;
+ field = mysql_fetch_field(m_res);
+ }
+
+ //- This is where we bind the bind the buffer to the statement
+ if (mysql_stmt_bind_result(m_stmt, m_rBind))
+ {
+ TC_LOG_WARN("sql.sql", "%s:mysql_stmt_bind_result, cannot bind result from MySQL server. Error: %s", __FUNCTION__, mysql_stmt_error(m_stmt));
+ delete[] m_rBind;
+ delete[] m_isNull;
+ delete[] m_length;
+ return;
+ }
+
+ m_rowCount = mysql_stmt_num_rows(m_stmt);
+
+ m_rows.resize(uint32(m_rowCount));
+ while (_NextRow())
+ {
+ m_rows[uint32(m_rowPosition)] = new Field[m_fieldCount];
+ for (uint64 fIndex = 0; fIndex < m_fieldCount; ++fIndex)
+ {
+ if (!*m_rBind[fIndex].is_null)
+ m_rows[uint32(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[uint32(m_rowPosition)][fIndex].SetByteValue("",
+ m_rBind[fIndex].buffer_length,
+ m_rBind[fIndex].buffer_type,
+ *m_rBind[fIndex].length);
+ break;
+ default:
+ m_rows[uint32(m_rowPosition)][fIndex].SetByteValue(nullptr,
+ m_rBind[fIndex].buffer_length,
+ m_rBind[fIndex].buffer_type,
+ *m_rBind[fIndex].length);
+ }
+ }
+ m_rowPosition++;
+ }
+ m_rowPosition = 0;
+
+ /// All data is buffered, let go of mysql c api structures
+ CleanUp();
+}
+
+ResultSet::~ResultSet()
+{
+ CleanUp();
+}
+
+PreparedResultSet::~PreparedResultSet()
+{
+ for (uint32 i = 0; i < uint32(m_rowCount); ++i)
+ delete[] m_rows[i];
+}
+
+bool ResultSet::NextRow()
+{
+ MYSQL_ROW row;
+
+ if (!_result)
+ return false;
+
+ row = mysql_fetch_row(_result);
+ if (!row)
+ {
+ CleanUp();
+ return false;
+ }
+
+ for (uint32 i = 0; i < _fieldCount; i++)
+ _currentRow[i].SetStructuredValue(row[i], _fields[i].type);
+
+ return true;
+}
+
+bool PreparedResultSet::NextRow()
+{
+ /// 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;
+
+ return true;
+}
+
+bool PreparedResultSet::_NextRow()
+{
+ /// 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;
+
+ int retval = mysql_stmt_fetch(m_stmt);
+ return retval == 0 || retval == MYSQL_DATA_TRUNCATED;
+}
+
+void ResultSet::CleanUp()
+{
+ if (_currentRow)
+ {
+ delete [] _currentRow;
+ _currentRow = NULL;
+ }
+
+ if (_result)
+ {
+ mysql_free_result(_result);
+ _result = NULL;
+ }
+}
+
+void PreparedResultSet::CleanUp()
+{
+ /// 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);
+
+ FreeBindBuffer();
+ mysql_stmt_free_result(m_stmt);
+
+ delete[] m_rBind;
+}
+
+void PreparedResultSet::FreeBindBuffer()
+{
+ for (uint32 i = 0; i < m_fieldCount; ++i)
+ free (m_rBind[i].buffer);
+}