DCL 3.7.4
Loading...
Searching...
No Matches
MyQuery Class Reference

#include <MyQuery.h>

Inheritance diagram for MyQuery:
SQL::Query Object

Public Member Functions

 MyQuery (MyConnection *pConnection)
virtual ~MyQuery ()
virtual void __destroy ()
virtual bool __prepare (const char *_sql, size_t _sqllen, size_t _paramCount)
virtual bool __execute ()
virtual bool __fetch ()
virtual bool __moreResults (bool *_moreResults)
virtual bool __getField (size_t _index, SQL::Field **_fieldHandleOut)
virtual bool __getParam (size_t _index, SQL::Param **_paramHandleOut)
Public Member Functions inherited from Object
virtual String toString () const
virtual void destroy ()
String className () const
bool isInstanceOf (const std::type_info &typeinfo) const
virtual const std::type_info & typeInfo () const

Protected Member Functions

bool reset ()
bool initFields ()
bool initParams (size_t _paramCount)
Protected Member Functions inherited from SQL::Query
 Query (Connection *_connHandle)
virtual ~Query ()
Protected Member Functions inherited from Object
virtual ~Object ()
 Object ()

Protected Attributes

MYSQL_STMT * __stmt
MYSQL_BIND * __inBINDs
MYSQL_BIND * __outBINDs
MyParam__params
MyField__fields
Protected Attributes inherited from SQL::Query
Connection__connHandle
bool __eof
int64_t __affectedRows
size_t __fieldCount
size_t __paramCount
wchar_t __placeholder
unsigned int __states

Additional Inherited Members

Public Types inherited from SQL::Query
enum  State { stStandBy = (unsigned int) 0x0001 , stPrepared = 0x0002 , stExecuted = 0x0004 , stFetched = 0x0008 }

Detailed Description

Definition at line 9 of file MyQuery.h.

Constructor & Destructor Documentation

◆ MyQuery()

MyQuery::MyQuery ( MyConnection * pConnection)

◆ ~MyQuery()

MyQuery::~MyQuery ( )
virtual

Definition at line 59 of file MyQuery.cpp.

60{
61#ifdef __DCL_DEBUG
62 if (!reset()) {
63 char buf[256];
64 size_t buflen = sizeof(buf) - 1;
65 bool b = conn()->__getErrorMessage(buf, &buflen);
66 buf[b ? buflen : 0] = '\0';
67 __DCL_TRACE1(L"Warning! Query reset error! %hs\n", buf);
68 }
69#else
70 (void)reset();
71#endif
72}
#define __DCL_TRACE1(fmt, arg1)
Definition Object.h:399
bool reset()
Definition MyQuery.cpp:79

Member Function Documentation

◆ __destroy()

void MyQuery::__destroy ( )
virtual

Implements SQL::Query.

Definition at line 74 of file MyQuery.cpp.

75{
76 delete this;
77}

◆ __execute()

bool MyQuery::__execute ( )
virtual

Implements SQL::Query.

Definition at line 375 of file MyQuery.cpp.

376{
377 // char*, byte_t*인 경우 데이터의 복사본을 유지하지 않는다.
378 // execute 전 매번 bind 한다.
379 if (Query::__paramCount) {
381 if (mysql_stmt_bind_param(__stmt, __inBINDs)) {
382 __SET_ERROR_MSG(ByteString::format("(%u) %hs",
383 mysql_stmt_errno(__stmt),
384 mysql_stmt_error(__stmt))
385 );
386 return false;
387 }
388 }
389
390 // 파라미터 값이 InputStream인 경우 mysql_stmt_send_long_data
391 for (size_t i = 0; i < Query::__paramCount; i++) {
392 if (!__params[i].onBeforeExecute()) {
393 return false;
394 }
395 }
396
397 if (mysql_stmt_execute(__stmt)) {
398 __SET_ERROR_MSG(ByteString::format("(%u) %hs",
399 mysql_stmt_errno(__stmt),
400 mysql_stmt_error(__stmt))
401 );
402 return false;
403 }
404
405 // execute 후 파라미터 값을 nil로 설정한다.
406 for (size_t i = 0; i < Query::__paramCount; i++) {
407 __params[i].onAfterExecute();
408 }
409
410#if __TRACE_THIS && 1
411 __DCL_TRACE2_N(L"state[%d] result.data[%p]\n",
412 __stmt->state, __stmt->result.data);
413 __DCL_TRACE2_N(L"fields[%u][%p]\n",
414 __stmt->field_count, __stmt->fields);
415 for (unsigned int i = 0; i < __stmt->field_count; i++) {
416 MYSQL_FIELD* e = &(__stmt->fields[i]);
417 __DCL_TRACE4_N(L"field %02u [%14hs][%10u][%16ls]\n",
418 i, e->name, e->length, __dataTypeName(e->type, e->flags));
419 }
420 if (conn()->connHandle()->server_status & SERVER_PS_OUT_PARAMS) {
421 __DCL_TRACE1_N(L"OUT/INOUT parameter [%u]\n", __stmt->field_count);
422 }
423#endif
424
425 // UPDATE, INSERT, DELETE만 eof 이어야 한다.
426 // 필드가 있는 경우, fetch에서 eof를 판별한다.
427 Query::__eof = __stmt->field_count == 0;
428 Query::__affectedRows = -1;
429
430 if (__stmt->field_count) {
431 if (!initFields()) {
432 return false;
433 }
434 if (conn()->storeResult()) {
435 __DCL_TRACE0_N(L"mysql_stmt_store_result\n");
436 if (mysql_stmt_store_result(__stmt)) {
437 __SET_ERROR_MSG(ByteString::format("(%u) %hs",
438 mysql_stmt_errno(__stmt),
439 mysql_stmt_error(__stmt))
440 );
441 return false;
442 }
443 }
444 }
445 else {
446 // UPDATE, INSERT, DELETE, etc, ...
447 Query::__affectedRows = mysql_stmt_affected_rows(__stmt);
448 __DCL_TRACE1_N(L"affectedRows[%lld]\n", Query::__affectedRows);
449 }
450
451 return true;
452}
#define __DCL_TRACE1_N(fmt, arg)
#define __DCL_TRACE2_N(fmt, arg1, arg2)
#define __DCL_TRACE4_N(fmt, arg1, arg2, arg3, arg4)
#define __SET_ERROR_MSG(_message)
#define __DCL_TRACE0_N(fmt)
const wchar_t * __dataTypeName(const ifx_sqlvar_t *_sqlvar)
Definition IFXField.cpp:304
#define __DCL_ASSERT(expr)
Definition Object.h:394
MYSQL_BIND * __inBINDs
Definition MyQuery.h:18
MyParam * __params
Definition MyQuery.h:21
MYSQL_STMT * __stmt
Definition MyQuery.h:17
bool initFields()
Definition MyQuery.cpp:212

◆ __fetch()

bool MyQuery::__fetch ( )
virtual

Implements SQL::Query.

Definition at line 454 of file MyQuery.cpp.

455{
456 __DCL_ASSERT(!Query::__eof);
457 int r = mysql_stmt_fetch(__stmt);
458 switch (r) {
459 case MYSQL_NO_DATA: {
460 // Success, no more data exists.
461 Query::__eof = true;
462 return true;
463 }
464 case MYSQL_DATA_TRUNCATED: {
465 // BLOB, MEDIUM_BLOB, LONG_BLOB은 mysql_stmt_fetch_column을 사용한다.
466 // 이 셋의 MYSQL_FIELD.length의 값은 0이다.
467 // Data truncation occurred.
468 // Check the error members of the MYSQL_BIND
469 __DCL_TRACE0_N(L"Warning!! MYSQL_DATA_TRUNCATED\n");
470
471#if __TRACE_THIS && 1
472 for (unsigned int i = 0; i < __stmt->field_count; i++) {
473 MYSQL_BIND& b = __stmt->bind[i];
474 __DCL_TRACE2(L"field[%u] [%u]\n", i, b.error ? *b.error : 0);
475 }
476#endif
477 }
478 case 0: {
479 // Success, the dta has been fetched to application data buffers.
480 return true;
481 }
482 case 1 :
483 // Error occurred. Error code and message can be obtained by calling
484 // mysql_stmt_errno() and mysql_stmt_error().
485 default:
486 ;
487 }
488
489 __SET_ERROR_MSG(ByteString::format("(%u) %hs",
490 mysql_stmt_errno(__stmt),
491 mysql_stmt_error(__stmt))
492 );
493 return false;
494}
IOException *size_t r
Definition MediaInfo.cpp:82
#define __DCL_TRACE2(fmt, arg1, arg2)
Definition Object.h:400

◆ __getField()

bool MyQuery::__getField ( size_t _index,
SQL::Field ** _fieldHandleOut )
virtual

Implements SQL::Query.

Definition at line 597 of file MyQuery.cpp.

598{
599 __DCL_ASSERT(Query::__fieldCount > 0);
600 __DCL_ASSERT((0 <= _index) && (_index < Query::__fieldCount));
601 *_fieldHandleOut = &__fields[_index];
602 return true;
603}
MyField * __fields
Definition MyQuery.h:22

◆ __getParam()

bool MyQuery::__getParam ( size_t _index,
SQL::Param ** _paramHandleOut )
virtual

Implements SQL::Query.

Definition at line 605 of file MyQuery.cpp.

606{
607 __DCL_ASSERT(Query::__paramCount > 0);
608 __DCL_ASSERT((0 <= _index) && (_index < Query::__paramCount));
609 *_paramHandleOut = &__params[_index];
610 return true;
611}

◆ __moreResults()

bool MyQuery::__moreResults ( bool * _moreResults)
virtual

Reimplemented from SQL::Query.

Definition at line 496 of file MyQuery.cpp.

497{
498 if (__fields) {
499 __DCL_ASSERT(Query::__fieldCount > 0);
500 delete[] __fields;
501 __fields = NULL;
502 Query::__fieldCount = 0;
503 }
504
505 if (__outBINDs) {
506 free(__outBINDs);
508 }
509
510 __DCL_TRACE2_N(L"state[%d] result.data[%p]\n",
511 __stmt->state, __stmt->result.data);
512 if (__stmt->state >= MYSQL_STMT_USE_OR_STORE_CALLED) {
513 if (mysql_stmt_free_result(__stmt)) {
514 __SET_ERROR_MSG(ByteString::format("(%u) %hs",
515 mysql_stmt_errno(__stmt),
516 mysql_stmt_error(__stmt))
517 );
518 return false;
519 }
520 }
521
522 int r = mysql_stmt_next_result(__stmt);
523 switch (r) {
524 case -1: {
525 // https://dev.mysql.com 메뉴얼에는 설명하고 있으나,
526 // MariaDB에서는 이 값을 반환하지 않는다.
527 // MariaDB는 ODBC의 경우처럼 INSERT, UPDATE, DELETE를 포함하는
528 // 다중 SQL에 대하여 동작하지 않는것으로 추정된다.
529 // 오직 SELECT를 동반한 프로시저이서만 동작하는것 같다.
530 Query::__affectedRows = (size_t)-1;
531 Query::__eof = true;
532 *_moreResults = false;
533 return true;
534 }
535 case 0: {
536 *_moreResults = true;
537 break;
538 }
539 default: {
540 __SET_ERROR_MSG(ByteString::format("(%u) %hs",
541 mysql_stmt_errno(__stmt),
542 mysql_stmt_error(__stmt))
543 );
544 return false;
545 }
546 }
547
548#if __TRACE_THIS && 1
549 __DCL_TRACE2_N(L"state[%d] result.data[%p]\n",
550 __stmt->state, __stmt->result.data);
551 __DCL_TRACE3_N(L"next_[%d] fields[%u][%p]\n",
552 r, __stmt->field_count, __stmt->fields);
553 for (unsigned int i = 0; i < __stmt->field_count; i++) {
554 MYSQL_FIELD* e = &(__stmt->fields[i]);
555 __DCL_TRACE4_N(L"field %02u [%14hs][%10u][%16ls]\n",
556 i, e->name, e->length, __dataTypeName(e->type, e->flags));
557 }
558 if (conn()->connHandle()->server_status & SERVER_PS_OUT_PARAMS) {
559 __DCL_TRACE1_N(L"OUT/INOUT parameter [%u]\n", __stmt->field_count);
560 }
561#endif
562
563 // UPDATE, INSERT, DELETE만 eof 이어야 한다.
564 // 필드가 있는 경우, fetch에서 eof를 판별한다.
565 Query::__eof = __stmt->field_count == 0;
566 Query::__affectedRows = -1;
567
568 if (__stmt->field_count) {
569 if (!initFields()) {
570 return false;
571 }
572 if (conn()->storeResult()) {
573 __DCL_TRACE0_N(L"mysql_stmt_store_result\n");
574 if (mysql_stmt_store_result(__stmt)) {
575 __SET_ERROR_MSG(ByteString::format("(%u) %hs",
576 mysql_stmt_errno(__stmt),
577 mysql_stmt_error(__stmt))
578 );
579 return false;
580 }
581 }
582 }
583 else {
584 // UPDATE, INSERT, DELETE, etc, ...
585 Query::__affectedRows = mysql_stmt_affected_rows(__stmt);
586 __DCL_TRACE1_N(L"affectedRows[%lld]\n", Query::__affectedRows);
587 }
588
589 // __stmt->field_count == 0인 경우에도
590 // mysql_stmt_affected_rows는 항상 0을 반환한다.
591 // MariaDB는 ODBC의 경우처럼 INSERT, UPDATE, DELETE를 포함하는
592 // 다중 SQL에 대하여 동작하지 않는것으로 추정된다.
593 *_moreResults = !Query::__eof;
594 return true;
595}
#define NULL
Definition Config.h:312
#define __DCL_TRACE3_N(fmt, arg1, arg2, arg3)
MYSQL_BIND * __outBINDs
Definition MyQuery.h:19

◆ __prepare()

bool MyQuery::__prepare ( const char * _sql,
size_t _sqllen,
size_t _paramCount )
virtual

Implements SQL::Query.

Definition at line 329 of file MyQuery.cpp.

331{
332 if(!reset())
333 return false;
334
335 if ((__stmt = mysql_stmt_init(conn()->connHandle())) == NULL) {
337 return false;
338 }
339
340 int r = mysql_stmt_prepare(__stmt, _sql, (unsigned long)_sqllen);
341 if (r) {
342 __SET_ERROR_MSG(ByteString::format("(%u) %hs",
343 mysql_stmt_errno(__stmt),
344 mysql_stmt_error(__stmt))
345 );
346 return false;
347 }
348
349#if __TRACE_THIS && 1
350 __DCL_TRACE2_N(L"state[%d] result.data[%p]\n",
351 __stmt->state, __stmt->result.data);
352 __DCL_TRACE4_N(L"params[%u][%p] fields[%u][%p]\n",
353 __stmt->param_count, __stmt->params,
354 __stmt->field_count, __stmt->fields);
355 for (unsigned int i = 0; i < __stmt->param_count; i++) {
356 MYSQL_BIND* e = &(__stmt->params[i]);
357 __DCL_TRACE4_N(L"param %02u buf[%p][%5u][%16ls]\n",
358 i, e->buffer, e->buffer_length, __dataTypeName(e->buffer_type, e->flags));
359 }
360 for (unsigned int i = 0; i < __stmt->field_count; i++) {
361 MYSQL_FIELD* e = &(__stmt->fields[i]);
362 __DCL_TRACE4_N(L"field %02u [%14hs][%10u][%16ls]\n",
363 i, e->name, e->length, __dataTypeName(e->type, e->flags));
364 }
365#endif
366
367 if (_paramCount > 0) {
368 if (!initParams(_paramCount))
369 return false;
370 }
371
372 return true;
373}
#define __SET_ERROR_HANDLE(_SQLCODE)
bool initParams(size_t _paramCount)
Definition MyQuery.cpp:296
@ eOutOfMemory
Definition SQLCore.h:24

◆ initFields()

bool MyQuery::initFields ( )
protected

Definition at line 212 of file MyQuery.cpp.

213{
215 && (__stmt->field_count > 0)
216 && (Query::__fieldCount == 0)
217 && (__fields == NULL)
218 && (__outBINDs == NULL)
219 );
220
221 size_t alloc = sizeof(MYSQL_BIND) * __stmt->field_count;
222 __DCL_TRACE1_N(L"outBINDs alloc [%zd]\n", alloc);
223 __outBINDs = (MYSQL_BIND*)malloc(alloc);
224 if (!__outBINDs) {
226 return false;
227 }
228 memset(__outBINDs, 0, alloc);
229
230 // __outBINDs에 적용할, 레코드 버퍼 크기를 계산한다.
231 size_t offset = 0;
232 for (unsigned int i = 0; i < __stmt->field_count; i++) {
233 MYSQL_FIELD* field = __stmt->fields + i;
234 offset = __TYPE_ALIGN(offset, field);
235 // 1000문자(3 * 1000바이트)를 초과하면 __TYPE_SIZE은 0이다.
236 __DCL_TRACE3_N(L"offset [%4zd][%4zd] [%hs]\n",
237 offset, __TYPE_SIZE(field), field.name);
238 offset += __TYPE_SIZE(field);
239 }
240
241 __DCL_TRACE1_N(L"alloc [%zd]\n", offset);
242 // 모든 필드의 __TYPE_SIZE(field) == 0인 경우가 있을 수 있다.
243 // 모든 필드가 3000바이트 이상인 VARCHAR, VARBINARY, TEXT, BLOB이면
244 // offset의 값이 0이다.
245 if (offset > 0) {
246 __outBINDs = (MYSQL_BIND*)realloc(__outBINDs, alloc + offset);
247 if (__outBINDs == NULL) {
249 return false;
250 }
251 }
252
253 char* outBuffer = (char*)(__outBINDs + __stmt->field_count);
254 __DCL_TRACE2_N(L"__outBINDs[%p] outBuffer[%p]\n", __outBINDs, outBuffer);
255 offset = 0;
256 for (unsigned int i = 0; i < __stmt->field_count; i++) {
257 MYSQL_FIELD* field = __stmt->fields + i;
258 MYSQL_BIND* bind = __outBINDs + i;
259
260 offset = __TYPE_ALIGN(offset, field);
261 bind->buffer_length = __TYPE_SIZE(field);
262 bind->buffer_type = field->type;
263 bind->buffer = outBuffer + offset;
264 offset += bind->buffer_length;
265
266 bind->length = &(bind->length_value);
267 bind->is_null = &(bind->is_null_value);
268 bind->error = &(bind->error_value);
269 }
270
271 if (mysql_stmt_bind_result(__stmt, __outBINDs)) {
272 __SET_ERROR_MSG(ByteString::format("(%u) %hs",
273 mysql_stmt_errno(__stmt),
274 mysql_stmt_error(__stmt))
275 );
276 return false;
277 }
278
279 Query::__fieldCount = __stmt->field_count;
280 __fields = new MyField[Query::__fieldCount];
281 if (!__fields) {
283 return false;
284 }
285
286 for(unsigned int i = 0; i < Query::__fieldCount; i++) {
287 MYSQL_FIELD* field = __stmt->fields + i;
288 MYSQL_BIND* bind = __outBINDs + i;
289 if (!__fields[i].init(this, i, field, bind))
290 return false;
291 }
292
293 return true;
294}

◆ initParams()

bool MyQuery::initParams ( size_t _paramCount)
protected

Definition at line 296 of file MyQuery.cpp.

297{
298 __DCL_ASSERT((Query::__paramCount == 0)
299 && (__params == NULL)
300 && (__stmt != NULL)
301 && (__stmt->param_count > 0));
302 __DCL_ASSERT(__stmt->param_count == _paramCount);
303
304 Query::__paramCount = __stmt->param_count;
305 size_t alloc = sizeof(MYSQL_BIND) * Query::__paramCount;
306 __inBINDs = (MYSQL_BIND*)malloc(alloc);
307 if (!__inBINDs) {
309 return false;
310 }
311 memset(__inBINDs, 0, alloc);
312
313 __params = new MyParam[Query::__paramCount];
314 if (__params == NULL) {
316 return false;
317 }
318
319 for(unsigned int i = 0; i < Query::__paramCount; i++) {
320 MYSQL_BIND* bind = __inBINDs + i;
321 bind->is_null = &bind->is_null_value;
322 if (!__params[i].init(this, i, bind))
323 return false;
324 }
325
326 return true;
327}

◆ reset()

bool MyQuery::reset ( )
protected

Definition at line 79 of file MyQuery.cpp.

80{
81 Query::__eof = true;
82 Query::__affectedRows = -1;
83
84 if (__fields) {
85 __DCL_ASSERT(Query::__fieldCount > 0);
86 delete[] __fields;
87 __fields = NULL;
88 Query::__fieldCount = 0;
89 }
90
91 if (__params) {
92 __DCL_ASSERT(Query::__paramCount > 0);
93 delete[] __params;
94 __params = NULL;
95 Query::__paramCount = 0;
96 }
97
98 if (__outBINDs) {
99 free(__outBINDs);
101 }
102
103 if (__inBINDs) {
104 free(__inBINDs);
105 __inBINDs = NULL;
106 }
107
108 bool r = true;
109 if (__stmt) {
110 __DCL_TRACE2_N(L"state[%d] result.data[%p]\n",
111 __stmt->state, __stmt->result.data);
112 if (__stmt->state >= MYSQL_STMT_USE_OR_STORE_CALLED) {
113 if (mysql_stmt_free_result(__stmt)) {
114 __SET_ERROR_MSG(ByteString::format("(%u) %hs",
115 mysql_stmt_errno(__stmt),
116 mysql_stmt_error(__stmt))
117 );
118 return false;
119 }
120 }
121 if (mysql_stmt_close(__stmt)) {
122 __SET_ERROR_MSG(ByteString::format("(%u) %hs",
123 mysql_errno(conn()->connHandle()),
124 mysql_error(conn()->connHandle()))
125 );
126 r = false;
127 }
128 __stmt = NULL;
129 }
130
131 return r;
132}

Member Data Documentation

◆ __fields

MyField* MyQuery::__fields
protected

Definition at line 22 of file MyQuery.h.

◆ __inBINDs

MYSQL_BIND* MyQuery::__inBINDs
protected

Definition at line 18 of file MyQuery.h.

◆ __outBINDs

MYSQL_BIND* MyQuery::__outBINDs
protected

Definition at line 19 of file MyQuery.h.

◆ __params

MyParam* MyQuery::__params
protected

Definition at line 21 of file MyQuery.h.

◆ __stmt

MYSQL_STMT* MyQuery::__stmt
protected

Definition at line 17 of file MyQuery.h.


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