TrinityCore
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
PreparedResultSet Class Reference

#include <QueryResult.h>

Public Member Functions

 PreparedResultSet (MYSQL_STMT *stmt, MYSQL_RES *result, uint64 rowCount, uint32 fieldCount)
 
 ~PreparedResultSet ()
 
bool NextRow ()
 
uint64 GetRowCount () const
 
uint32 GetFieldCount () const
 
FieldFetch () const
 
Field constoperator[] (uint32 index) const
 

Protected Attributes

std::vector< Fieldm_rows
 
uint64 m_rowCount
 
uint64 m_rowPosition
 
uint32 m_fieldCount
 

Private Member Functions

void CleanUp ()
 
bool _NextRow ()
 
 PreparedResultSet (PreparedResultSet const &right)=delete
 
PreparedResultSetoperator= (PreparedResultSet const &right)=delete
 

Private Attributes

MYSQL_BIND * m_rBind
 
MYSQL_STMT * m_stmt
 
MYSQL_RES * m_metadataResult
 Field metadata, returned by mysql_stmt_result_metadata. More...
 
my_bool * m_isNull
 
unsigned long * m_length
 

Constructor & Destructor Documentation

PreparedResultSet::PreparedResultSet ( MYSQL_STMT *  stmt,
MYSQL_RES *  result,
uint64  rowCount,
uint32  fieldCount 
)

All data is buffered, let go of mysql c api structures

35  :
36 m_rowCount(rowCount),
37 m_rowPosition(0),
38 m_fieldCount(fieldCount),
39 m_rBind(NULL),
40 m_stmt(stmt),
41 m_metadataResult(result),
42 m_isNull(NULL),
44 {
45  if (!m_metadataResult)
46  return;
47 
48  if (m_stmt->bind_result_done)
49  {
50  delete[] m_stmt->bind->length;
51  delete[] m_stmt->bind->is_null;
52  }
53 
54  m_rBind = new MYSQL_BIND[m_fieldCount];
55  m_isNull = new my_bool[m_fieldCount];
56  m_length = new unsigned long[m_fieldCount];
57 
58  memset(m_isNull, 0, sizeof(my_bool) * m_fieldCount);
59  memset(m_rBind, 0, sizeof(MYSQL_BIND) * m_fieldCount);
60  memset(m_length, 0, sizeof(unsigned long) * m_fieldCount);
61 
62  //- This is where we store the (entire) resultset
63  if (mysql_stmt_store_result(m_stmt))
64  {
65  TC_LOG_WARN("sql.sql", "%s:mysql_stmt_store_result, cannot bind result from MySQL server. Error: %s", __FUNCTION__, mysql_stmt_error(m_stmt));
66  delete[] m_rBind;
67  delete[] m_isNull;
68  delete[] m_length;
69  return;
70  }
71 
72  m_rowCount = mysql_stmt_num_rows(m_stmt);
73 
74  //- This is where we prepare the buffer based on metadata
75  MYSQL_FIELD* field = mysql_fetch_fields(m_metadataResult);
76  std::size_t rowSize = 0;
77  for (uint32 i = 0; i < m_fieldCount; ++i)
78  {
79  uint32 size = Field::SizeForType(&field[i]);
80  rowSize += size;
81 
82  m_rBind[i].buffer_type = field[i].type;
83  m_rBind[i].buffer_length = size;
84  m_rBind[i].length = &m_length[i];
85  m_rBind[i].is_null = &m_isNull[i];
86  m_rBind[i].error = NULL;
87  m_rBind[i].is_unsigned = field[i].flags & UNSIGNED_FLAG;
88  }
89 
90  char* dataBuffer = new char[rowSize * m_rowCount];
91  for (uint32 i = 0, offset = 0; i < m_fieldCount; ++i)
92  {
93  m_rBind[i].buffer = dataBuffer + offset;
94  offset += m_rBind[i].buffer_length;
95  }
96 
97  //- This is where we bind the bind the buffer to the statement
98  if (mysql_stmt_bind_result(m_stmt, m_rBind))
99  {
100  TC_LOG_WARN("sql.sql", "%s:mysql_stmt_bind_result, cannot bind result from MySQL server. Error: %s", __FUNCTION__, mysql_stmt_error(m_stmt));
101  mysql_stmt_free_result(m_stmt);
102  CleanUp();
103  delete[] m_isNull;
104  delete[] m_length;
105  return;
106  }
107 
108  m_rows.resize(uint32(m_rowCount) * m_fieldCount);
109  while (_NextRow())
110  {
111  for (uint32 fIndex = 0; fIndex < m_fieldCount; ++fIndex)
112  {
113  unsigned long buffer_length = m_rBind[fIndex].buffer_length;
114  unsigned long fetched_length = *m_rBind[fIndex].length;
115  if (!*m_rBind[fIndex].is_null)
116  {
117  void* buffer = m_stmt->bind[fIndex].buffer;
118  switch (m_rBind[fIndex].buffer_type)
119  {
120  case MYSQL_TYPE_TINY_BLOB:
121  case MYSQL_TYPE_MEDIUM_BLOB:
122  case MYSQL_TYPE_LONG_BLOB:
123  case MYSQL_TYPE_BLOB:
124  case MYSQL_TYPE_STRING:
125  case MYSQL_TYPE_VAR_STRING:
126  // warning - the string will not be null-terminated if there is no space for it in the buffer
127  // when mysql_stmt_fetch returned MYSQL_DATA_TRUNCATED
128  // we cannot blindly null-terminate the data either as it may be retrieved as binary blob and not specifically a string
129  // in this case using Field::GetCString will result in garbage
130  // TODO: remove Field::GetCString and use boost::string_ref (currently proposed for TS as string_view, maybe in C++17)
131  if (fetched_length < buffer_length)
132  *((char*)buffer + fetched_length) = '\0';
133  break;
134  default:
135  break;
136  }
137 
138  m_rows[uint32(m_rowPosition) * m_fieldCount + fIndex].SetByteValue(
139  buffer,
140  m_rBind[fIndex].buffer_type,
141  fetched_length);
142 
143  // move buffer pointer to next part
144  m_stmt->bind[fIndex].buffer = (char*)buffer + rowSize;
145  }
146  else
147  {
148  m_rows[uint32(m_rowPosition) * m_fieldCount + fIndex].SetByteValue(
149  nullptr,
150  m_rBind[fIndex].buffer_type,
151  *m_rBind[fIndex].length);
152  }
153 
154 #ifdef TRINITY_DEBUG
155  m_rows[uint32(m_rowPosition) * m_fieldCount + fIndex].SetMetadata(&field[fIndex], fIndex);
156 #endif
157  }
158  m_rowPosition++;
159  }
160  m_rowPosition = 0;
161 
163  mysql_stmt_free_result(m_stmt);
164 }
uint32 m_fieldCount
Definition: QueryResult.h:90
unsigned long * m_length
Definition: QueryResult.h:98
arena_t NULL
Definition: jemalloc_internal.h:624
void CleanUp()
Definition: QueryResult.cpp:240
MYSQL_RES * m_metadataResult
Field metadata, returned by mysql_stmt_result_metadata.
Definition: QueryResult.h:95
std::vector< Field > m_rows
Definition: QueryResult.h:87
MYSQL_BIND * m_rBind
Definition: QueryResult.h:93
my_bool * m_isNull
Definition: QueryResult.h:97
uint64 m_rowPosition
Definition: QueryResult.h:89
uint32_t uint32
Definition: Define.h:150
float length(float v)
Definition: vectorMath.h:208
MYSQL_STMT * m_stmt
Definition: QueryResult.h:94
uint64 m_rowCount
Definition: QueryResult.h:88
#define TC_LOG_WARN(filterType__,...)
Definition: Log.h:204
uint32_t uint32
Definition: g3dmath.h:168
static uint32 SizeForType(MYSQL_FIELD *field)
Definition: Field.h:336
bool _NextRow()
Definition: QueryResult.cpp:214

+ Here is the call graph for this function:

PreparedResultSet::~PreparedResultSet ( )
172 {
173  CleanUp();
174 }
void CleanUp()
Definition: QueryResult.cpp:240

+ Here is the call graph for this function:

PreparedResultSet::PreparedResultSet ( PreparedResultSet const right)
privatedelete

Member Function Documentation

bool PreparedResultSet::_NextRow ( )
private

Only called in low-level code, namely the constructor Will iterate over every row of data and buffer it

215 {
218  if (m_rowPosition >= m_rowCount)
219  return false;
220 
221  int retval = mysql_stmt_fetch(m_stmt);
222  return retval == 0 || retval == MYSQL_DATA_TRUNCATED;
223 }
uint64 m_rowPosition
Definition: QueryResult.h:89
MYSQL_STMT * m_stmt
Definition: QueryResult.h:94
uint64 m_rowCount
Definition: QueryResult.h:88

+ Here is the caller graph for this function:

void PreparedResultSet::CleanUp ( )
private
241 {
242  if (m_metadataResult)
243  mysql_free_result(m_metadataResult);
244 
245  if (m_rBind)
246  {
247  delete[](char*)m_rBind->buffer;
248  delete[] m_rBind;
249  m_rBind = nullptr;
250  }
251 }
MYSQL_RES * m_metadataResult
Field metadata, returned by mysql_stmt_result_metadata.
Definition: QueryResult.h:95
MYSQL_BIND * m_rBind
Definition: QueryResult.h:93

+ Here is the caller graph for this function:

Field* PreparedResultSet::Fetch ( ) const
inline
74  {
76  return const_cast<Field*>(&m_rows[uint32(m_rowPosition) * m_fieldCount]);
77  }
uint32 m_fieldCount
Definition: QueryResult.h:90
Class used to access individual fields of database query result.
Definition: Field.h:56
std::vector< Field > m_rows
Definition: QueryResult.h:87
uint64 m_rowPosition
Definition: QueryResult.h:89
uint64 m_rowCount
Definition: QueryResult.h:88
#define ASSERT
Definition: Errors.h:55
uint32_t uint32
Definition: g3dmath.h:168
uint32 PreparedResultSet::GetFieldCount ( ) const
inline
71 { return m_fieldCount; }
uint32 m_fieldCount
Definition: QueryResult.h:90
uint64 PreparedResultSet::GetRowCount ( ) const
inline
70 { return m_rowCount; }
uint64 m_rowCount
Definition: QueryResult.h:88

+ Here is the caller graph for this function:

bool PreparedResultSet::NextRow ( )

Only updates the m_rowPosition so upper level code knows in which element of the rows vector to look

205 {
208  if (++m_rowPosition >= m_rowCount)
209  return false;
210 
211  return true;
212 }
uint64 m_rowPosition
Definition: QueryResult.h:89
uint64 m_rowCount
Definition: QueryResult.h:88
PreparedResultSet& PreparedResultSet::operator= ( PreparedResultSet const right)
privatedelete
Field const& PreparedResultSet::operator[] ( uint32  index) const
inline
80  {
82  ASSERT(index < m_fieldCount);
83  return m_rows[uint32(m_rowPosition) * m_fieldCount + index];
84  }
uint32 m_fieldCount
Definition: QueryResult.h:90
std::vector< Field > m_rows
Definition: QueryResult.h:87
uint64 m_rowPosition
Definition: QueryResult.h:89
uint64 m_rowCount
Definition: QueryResult.h:88
#define ASSERT
Definition: Errors.h:55
uint32_t uint32
Definition: g3dmath.h:168

Member Data Documentation

uint32 PreparedResultSet::m_fieldCount
protected
my_bool* PreparedResultSet::m_isNull
private
unsigned long* PreparedResultSet::m_length
private
MYSQL_RES* PreparedResultSet::m_metadataResult
private

Field metadata, returned by mysql_stmt_result_metadata.

MYSQL_BIND* PreparedResultSet::m_rBind
private
uint64 PreparedResultSet::m_rowCount
protected
uint64 PreparedResultSet::m_rowPosition
protected
std::vector<Field> PreparedResultSet::m_rows
protected
MYSQL_STMT* PreparedResultSet::m_stmt
private

The documentation for this class was generated from the following files: