OregonCore  revision fb2a440-git
Your Favourite TBC server
QueryResult.cpp
Go to the documentation of this file.
1 /*
2  * This file is part of the OregonCore Project. See AUTHORS file for Copyright information
3  *
4  * This program is free software; you can redistribute it and/or modify it
5  * under the terms of the GNU General Public License as published by the
6  * Free Software Foundation; either version 2 of the License, or (at your
7  * option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12  * more details.
13  *
14  * You should have received a copy of the GNU General Public License along
15  * with this program. If not, see <http://www.gnu.org/licenses/>.
16  */
17 
18 #include "DatabaseEnv.h"
19 #include "QueryResult.h"
20 
21 QueryResult::QueryResult(MYSQL_RES* result, MYSQL_FIELD* fields, uint64 rowCount, uint32 fieldCount)
22  : mFieldCount(fieldCount)
23  , mRowCount(rowCount)
24  , mFields(fields)
25  , mResult(result)
26 {
29 
30  for (uint32 i = 0; i < mFieldCount; i++)
31  mCurrentRow[i].SetType(fields[i].type);
32 }
33 
34 PreparedQueryResult::PreparedQueryResult(MYSQL_STMT* stmt) : mCursor(0)
35 {
36  // as mysql prepared statements c api is not thread safe,
37  // we need to copy all result data to a different location
38  // so another thread can execute this statement again
39 
40  mFieldCount = mysql_stmt_field_count(stmt);
41  mRowCount = mysql_stmt_num_rows(stmt);
42 
43  MYSQL_BIND* binding = new MYSQL_BIND[mFieldCount];
44  my_bool* isNull = new my_bool[mFieldCount];
45  unsigned long* length = new unsigned long[mFieldCount];
46 
47  memset(binding, 0, sizeof(MYSQL_BIND) * mFieldCount);
48  memset(isNull, 0, sizeof(my_bool) * mFieldCount);
49  memset(length, 0, sizeof(unsigned long) * mFieldCount);
50 
51  mMetaData = mysql_stmt_result_metadata(stmt);
52  mFields = mysql_fetch_fields(mMetaData);
53  for (size_t i = 0; i < mFieldCount; ++i)
54  {
55  // if its a string, reserve one byte for ascii nul
56  size_t size = mFields[i].max_length + 1;
57  binding[i].buffer_type = mFields[i].type;
58  binding[i].buffer = malloc(size);
59  binding[i].buffer_length = size;
60  binding[i].length = &length[i];
61  binding[i].is_null = &isNull[i];
62  binding[i].error = NULL;
63  binding[i].is_unsigned = mFields[i].flags & UNSIGNED_FLAG;
64 
65  memset(binding[i].buffer, 0, size);
66  }
67 
68  if (mysql_stmt_bind_result(stmt, binding))
69  {
70  // should never happen
71  sLog.outError("mysql_stmt_bind_result() failed!");
72  goto PreparedQuery_Cleanup; // after this point, destiny is bond...
73  }
74 
75  mRows.resize(mRowCount, NULL);
76  for (size_t i = 0; i < mRowCount; ++i)
77  {
78  mRows[i] = new Field[mFieldCount];
79 
80  switch (mysql_stmt_fetch(stmt))
81  {
82  case 0: // success
83  break;
84  case 1: // error
85  sLog.outError("mysql_stmt_fetch() failed: %s", mysql_stmt_error(stmt));
86  /* FALLTHROUGH */
87  case MYSQL_NO_DATA: // no more data exists
88  mRowCount = i;
89  goto PreparedQuery_Break_2;
90  case MYSQL_DATA_TRUNCATED:
91  sLog.outDetail("mysql_stmt_fetch() - data truncated");
92  break;
93  }
94 
95  for (size_t j = 0; j < mFieldCount; ++j)
96  mRows[i][j].SetBinaryValue(binding[j].buffer, length[i], mFields[j].type);
97  }
98 
99 PreparedQuery_Break_2:
100 
101  mCurrentRow = mRows[0];
103 
104 PreparedQuery_Cleanup:
105 
106  delete[] binding;
107  delete[] isNull;
108  delete[] length;
109 
110  mysql_stmt_free_result(stmt);
111  mysql_stmt_reset(stmt);
112 }
113 
115 {
116  EndQuery();
117 }
118 
120 {
121  if (++mCursor >= mRows.size())
122  {
123  EndQuery();
124  return false;
125  }
126 
128  return true;
129 }
130 
132 {
133  for (size_t i = 0; i < mRows.size(); ++i)
134  delete[] mRows[i];
135  mRows.clear();
136 
137  if (mMetaData)
138  mysql_free_result(mMetaData);
139 }
140 
142 {
143  EndQuery();
144 }
145 
147 {
148  MYSQL_ROW row;
149 
150  if (!mResult)
151  return false;
152 
153  row = mysql_fetch_row(mResult);
154  if (!row)
155  {
156  EndQuery();
157  return false;
158  }
159 
160  for (uint32 i = 0; i < mFieldCount; i++)
161  mCurrentRow[i].SetValue(row[i]);
162 
163  return true;
164 }
165 
167 {
168  if (mCurrentRow)
169  {
170  delete [] mCurrentRow;
171  mCurrentRow = 0;
172  }
173 
174  if (mResult)
175  {
176  mysql_free_result(mResult);
177  mResult = 0;
178  }
179 }
180 #if 0
181 enum Field::DataTypes QueryResult::ConvertNativeType(enum_field_types mysqlType) const
182 {
183  switch (mysqlType)
184  {
185  case FIELD_TYPE_TIMESTAMP:
186  case FIELD_TYPE_DATE:
187  case FIELD_TYPE_TIME:
188  case FIELD_TYPE_DATETIME:
189  case FIELD_TYPE_YEAR:
190  case FIELD_TYPE_STRING:
191  case FIELD_TYPE_VAR_STRING:
192  case FIELD_TYPE_BLOB:
193  case FIELD_TYPE_SET:
194  case FIELD_TYPE_NULL:
195  return Field::DB_TYPE_STRING;
196  case FIELD_TYPE_TINY:
197 
198  case FIELD_TYPE_SHORT:
199  case FIELD_TYPE_LONG:
200  case FIELD_TYPE_INT24:
201  case FIELD_TYPE_LONGLONG:
202  case FIELD_TYPE_ENUM:
203  return Field::DB_TYPE_INTEGER;
204  case FIELD_TYPE_DECIMAL:
205  case FIELD_TYPE_FLOAT:
206  case FIELD_TYPE_DOUBLE:
207  return Field::DB_TYPE_FLOAT;
208  default:
209  return Field::DB_TYPE_UNKNOWN;
210  }
211 }
212 #endif
void EndQuery()
PreparedQueryResult(MYSQL_STMT *stmt)
Definition: QueryResult.cpp:34
Definition: Field.h:24
#define sLog
Log class singleton.
Definition: Log.h:187
uint32 mFieldCount
Definition: QueryResult.h:62
std::vector< Field * > mRows
Definition: QueryResult.h:108
MYSQL_FIELD * mFields
Definition: QueryResult.h:103
QueryResult(MYSQL_RES *result, MYSQL_FIELD *fields, uint64 rowCount, uint32 fieldCount)
Definition: QueryResult.cpp:21
MYSQL_RES * mMetaData
Definition: QueryResult.h:110
ACE_UINT64 uint64
Definition: Define.h:70
Field * mCurrentRow
Definition: QueryResult.h:61
#define ASSERT
Definition: Errors.h:29
ACE_UINT32 uint32
Definition: Define.h:71
bool NextRow()