Samchon Framework for CPP  1.0.0
SQLStatement.cpp
1 #include <samchon/library/SQLStatement.hpp>
2 
3 #include <memory>
4 #include <mutex>
5 #include <vector>
6 #include <samchon/library/SQLi.hpp>
7 #include <samchon/library/CriticalSet.hpp>
8 #include <samchon/library/XML.hpp>
9 
10 #define WIN32_LEAN_AND_MEAN
11 #include <windows.h>
12 #include <sql.h>
13 #include <sqlext.h>
14 
15 #define _SQLNCLI_ODBC_
16 #include <sqlncli.h>
17 
18 using namespace std;
19 using namespace samchon;
20 using namespace samchon::library;
21 
22 SQLStatement::SQLStatement(SQLi *sqli)
23 {
24  this->sqli = sqli;
25  bindParameterCount = 0;
26 
27  SQLAllocHandle(SQL_HANDLE_STMT, sqli->hdbc, &hstmt);
28 }
29 SQLStatement::~SQLStatement()
30 {
31  free();
32 }
33 
34 void SQLStatement::reset(SQLi *sqli)
35 {
36  free();
37  this->sqli = sqli;
38 
39  SQLAllocHandle(SQL_HANDLE_STMT, sqli->hdbc, &hstmt);
40 }
41 void SQLStatement::free()
42 {
43  SQLFreeHandle(SQL_HANDLE_STMT, hstmt);
44 
45  bindParameterCount = 0;
46 
47  if (sqli == nullptr || sqli->stmt != this)
48  return;
49 
50  sqli->stmt = nullptr;
51  sqli->stmtMutex.unlock();
52 }
53 void SQLStatement::refresh()
54 {
55  reset(this->sqli);
56 }
57 
58 /* --------------------------------------------------------------------------------------
59  QUERY
60  - PREPARE
61  - EXECUTE
62  - EXECUTE_DIRECTLY
63 -------------------------------------------------------------------------------------- */
64 void SQLStatement::prepare(const std::string &sql)
65 {
66  refresh();
67 
68  sqli->stmtMutex.lock();
69  sqli->stmt = this;
70 
71  SQLPrepareA(hstmt, (SQLCHAR*)&sql[0], SQL_NTS);
72 }
73 void SQLStatement::prepare(const std::wstring &sql)
74 {
75  refresh();
76 
77  sqli->stmtMutex.lock();
78  sqli->stmt = this;
79 
80  SQLPrepareW(hstmt, (SQLWCHAR*)&sql[0], SQL_NTS);
81 }
82 
83 void SQLStatement::execute()
84 {
85  SQLRETURN res = SQLExecute(hstmt);
86  if (res == SQL_ERROR)
87  throw exception(sqli->getErrorMessage(SQL_HANDLE_STMT).c_str());
88 }
89 void SQLStatement::executeDirectly(const std::string &sql)
90 {
91  prepare(sql);
92  execute();
93 }
94 void SQLStatement::executeDirectly(const std::wstring &sql)
95 {
96  prepare(sql);
97  execute();
98 }
99 
100 /* --------------------------------------------------------------------------------------
101  CURSOR
102  - NEXT
103  - FETCH
104 -------------------------------------------------------------------------------------- */
105 auto SQLStatement::next() const -> bool
106 {
107  return (SQLMoreResults(hstmt) != SQL_NO_DATA);
108 }
109 auto SQLStatement::fetch() const -> bool
110 {
111  do
112  {
113  SQLSMALLINT colSize = 0;
114  SQLNumResultCols(hstmt, &colSize);
115 
116  if (colSize > 0)
117  break;
118  } while (next() == true);
119 
120  return (SQLFetch(hstmt) == SQL_SUCCESS);
121 }
122 
123 auto SQLStatement::size() const -> size_t
124 {
125  SQLSMALLINT val = 0;
126 
127  SQLNumResultCols(hstmt, &val);
128  return (size_t)val;
129 }
130 
131 /* -------------------------------------------------------------------
132  TO_XML
133 ------------------------------------------------------------------- */
134 auto SQLStatement::toXML() const -> shared_ptr<XML>
135 {
136  shared_ptr<XML> xml(new XML());
137  return xml;
138 }
139 
140 /* --------------------------------------------------------------------------------------
141  BIND PARAMETER
142 -------------------------------------------------------------------------------------- */
143 template<> void SQLStatement::bindParameter(const std::string &val)
144 {
145  ::SQLBindParameter(hstmt, (SQLUSMALLINT)++bindParameterCount, SQL_PARAM_INPUT, SQL_C_TCHAR, SQL_VARCHAR, val.size(), 0, (char*)&val[0], 0, NULL);
146 }
147 template<> void SQLStatement::bindParameter(const std::wstring &val)
148 {
149  ::SQLBindParameter(hstmt, (SQLUSMALLINT)++bindParameterCount, SQL_PARAM_INPUT, SQL_C_WCHAR, SQL_WVARCHAR, val.size(), 0, (wchar_t*)&val[0], 0, NULL);
150 }
151 template<> void SQLStatement::bindParameter(const ByteArray &val)
152 {
153  bindParameterBASizeMap.set(++bindParameterCount, (SQL_SIZE_T)val.size());
154 
155  ::SQLBindParameter(hstmt, (SQLUSMALLINT)bindParameterCount, SQL_PARAM_INPUT, SQL_C_BINARY, SQL_LONGVARBINARY, val.size(), 0, (unsigned char*)&val[0], 0, &bindParameterBASizeMap.get(bindParameterCount));
156 }
157 
158 /* -------------------------------------------------------------------
159  ODBC'S FUNCTION
160 ------------------------------------------------------------------- */
161 void SQLStatement::sql_get_data(size_t index, short type, void *listener) const
162 {
163  //SQLGetData(hstmt, index, SQL_C_FLOAT, &value, 0, NULL);
164  ::SQLGetData(hstmt, (SQLUSMALLINT)index, type, listener, 0, nullptr);
165 }
166 void SQLStatement::sql_bind_parameter(short cppType, short sqlType, void *val)
167 {
168  //::SQLBindParameter(hstmt, (SQLSMALLINT)++bindParameterCount, SQL_PARAM_INPUT, SQL_C_BIT, SQL_BIT, 0, 0, (bool*)&val, 0, NULL);
169  ::SQLBindParameter(hstmt, (SQLUSMALLINT)++bindParameterCount, SQL_PARAM_INPUT, cppType, sqlType, 0, 0, val, 0, nullptr);
170 }
171 
172 /* -------------------------------------------------------------------
173  C-TYPE
174 ------------------------------------------------------------------- */
175 template<> auto SQLStatement::C_TYPE(const bool &) const -> short
176 {
177  return SQL_C_BIT;
178 }
179 template<> auto SQLStatement::C_TYPE(const char &) const -> short
180 {
181  return SQL_CHAR;
182 }
183 template<> auto SQLStatement::C_TYPE(const short &) const -> short
184 {
185  return SQL_C_SSHORT;
186 }
187 template<> auto SQLStatement::C_TYPE(const long &) const -> short
188 {
189  return SQL_C_SLONG;
190 }
191 template<> auto SQLStatement::C_TYPE(const long long &) const -> short
192 {
193  return SQL_C_SBIGINT;
194 }
195 template<> auto SQLStatement::C_TYPE(const int &) const -> short
196 {
197  return SQL_C_SLONG;
198 }
199 template<> auto SQLStatement::C_TYPE(const float &) const -> short
200 {
201  return SQL_C_FLOAT;
202 }
203 template<> auto SQLStatement::C_TYPE(const double &) const -> short
204 {
205  return SQL_C_DOUBLE;
206 }
207 
208 template<> auto SQLStatement::C_TYPE(const unsigned char &) const -> short
209 {
210  return SQL_C_BINARY;
211 }
212 template<> auto SQLStatement::C_TYPE(const unsigned short &) const -> short
213 {
214  return SQL_C_USHORT;
215 }
216 template<> auto SQLStatement::C_TYPE(const unsigned long &) const -> short
217 {
218  return SQL_C_ULONG;
219 }
220 template<> auto SQLStatement::C_TYPE(const unsigned long long &) const -> short
221 {
222  return SQL_C_UBIGINT;
223 }
224 template<> auto SQLStatement::C_TYPE(const unsigned int &) const -> short
225 {
226  return SQL_C_UBIGINT;
227 }
228 template<> auto SQLStatement::C_TYPE(const long double &) const -> short
229 {
230  return SQL_C_DOUBLE;
231 }
232 
233 template<> auto SQLStatement::C_TYPE(const string &) const -> short
234 {
235  return SQL_C_CHAR;
236 }
237 template<> auto SQLStatement::C_TYPE(const wstring &) const -> short
238 {
239  return SQL_C_WCHAR;
240 }
241 template<> auto SQLStatement::C_TYPE(const ByteArray &) const -> short
242 {
243  return SQL_C_BINARY;
244 }
245 
246 /* -------------------------------------------------------------------
247  SQL-TYPE
248 ------------------------------------------------------------------- */
249 template<> auto SQLStatement::SQL_TYPE(const bool &) const -> short
250 {
251  return SQL_BIT;
252 }
253 template<> auto SQLStatement::SQL_TYPE(const char &) const -> short
254 {
255  return SQL_CHAR;
256 }
257 template<> auto SQLStatement::SQL_TYPE(const short &) const -> short
258 {
259  return SQL_TINYINT;
260 }
261 template<> auto SQLStatement::SQL_TYPE(const long &) const -> short
262 {
263  return SQL_INTEGER;
264 }
265 template<> auto SQLStatement::SQL_TYPE(const long long &) const -> short
266 {
267  return SQL_BIGINT;
268 }
269 template<> auto SQLStatement::SQL_TYPE(const int &) const -> short
270 {
271  return SQL_INTEGER;
272 }
273 template<> auto SQLStatement::SQL_TYPE(const float &) const -> short
274 {
275  return SQL_FLOAT;
276 }
277 template<> auto SQLStatement::SQL_TYPE(const double &) const -> short
278 {
279  return SQL_DOUBLE;
280 }
281 
282 template<> auto SQLStatement::SQL_TYPE(const unsigned char &) const -> short
283 {
284  return SQL_BINARY;
285 }
286 template<> auto SQLStatement::SQL_TYPE(const unsigned short &) const -> short
287 {
288  return SQL_TINYINT;
289 }
290 template<> auto SQLStatement::SQL_TYPE(const unsigned long &) const -> short
291 {
292  return SQL_INTEGER;
293 }
294 template<> auto SQLStatement::SQL_TYPE(const unsigned long long &) const -> short
295 {
296  return SQL_BIGINT;
297 }
298 template<> auto SQLStatement::SQL_TYPE(const unsigned int &) const -> short
299 {
300  return SQL_INTEGER;
301 }
302 template<> auto SQLStatement::SQL_TYPE(const long double &) const -> short
303 {
304  return SQL_DOUBLE;
305 }
306 
307 template<> auto SQLStatement::SQL_TYPE(const string &) const -> short
308 {
309  return SQL_CHAR;
310 }
311 template<> auto SQLStatement::SQL_TYPE(const wstring &) const -> short
312 {
313  return SQL_WCHAR;
314 }
315 template<> auto SQLStatement::SQL_TYPE(const ByteArray &) const -> short
316 {
317  return SQL_BINARY;
318 }
319 
320 /* -------------------------------------------------------------------
321  HIDDEN TEMPLATE HELPERS
322 ------------------------------------------------------------------- */
323 auto SQLStatement::_atAsString(size_t index) const -> std::string
324 {
325  index++;
326 
327  std::string str(1, NULL);
328  SQLLEN size = 0;
329 
330  if (::SQLGetData(hstmt, (SQLUSMALLINT)index, SQL_C_CHAR, &str[0], 0, &size) != SQL_SUCCESS && size != 0)
331  {
332  str.assign((size_t)size, NULL);
333  ::SQLGetData(hstmt, (SQLUSMALLINT)index, SQL_C_CHAR, &str[0], sizeof(char)*size, NULL);
334  }
335 
336  // ERASE ZERO-CHARS
337  long long i;
338  for (i = str.size() - 1; i >= 0; i--)
339  if (str[i] != NULL)
340  break;
341 
342  if (i != str.size() - 1)
343  str.erase(str.begin() + i + 1, str.end());
344 
345  return str;
346 }
347 auto SQLStatement::_atAsWString(size_t index) const -> std::wstring
348 {
349  index++;
350 
351  std::wstring str(1, NULL);
352  SQLLEN size = 0;
353 
354  if (::SQLGetData(hstmt, (SQLUSMALLINT)index, SQL_C_WCHAR, &str[0], 0, &size) != SQL_SUCCESS && size != 0)
355  {
356  str.assign((size_t)size, NULL);
357  ::SQLGetData(hstmt, (SQLUSMALLINT)index, SQL_C_WCHAR, &str[0], sizeof(wchar_t)*size, NULL);
358  }
359  return str;
360 }
361 auto SQLStatement::_atAsByteArray(size_t index) const -> ByteArray
362 {
363  index++;
364 
365  ByteArray data;
366  SQLLEN size = 0;
367 
368  if (::SQLGetData(hstmt, (SQLUSMALLINT)index, SQL_C_BINARY, &data[0], 0, &size) != SQL_SUCCESS && size != 0)
369  {
370  data.assign(size, NULL);
371  ::SQLGetData(hstmt, (SQLUSMALLINT)index, SQL_C_BINARY, &data[0], data.size(), NULL);
372  }
373  return data;
374 }
std::mutex stmtMutex
Mutex ensuring concurrency with SQLStatement.
Definition: SQLi.hpp:86
void * hdbc
Handler of DB-connector.
Definition: SQLi.hpp:76
Definition: RWMutex.hpp:4
Package of libraries.
Definition: library.hpp:84
A SQL interface; DBMS connector.
Definition: SQLi.hpp:42
Binary data class.
Definition: ByteArray.hpp:30
SQLStatement * stmt
SQLStatement&#39;s pointer linked with the SQLi.
Definition: SQLi.hpp:81
XML is a class representing xml object.
Definition: XML.hpp:72
Top level namespace of products built from samchon.
Definition: ByteArray.hpp:7