qLibc
qdatabase.c
Go to the documentation of this file.
1/******************************************************************************
2 * qLibc
3 *
4 * Copyright (c) 2010-2026 Seungyoung Kim.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions are met:
9 *
10 * 1. Redistributions of source code must retain the above copyright notice,
11 * this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright notice,
13 * this list of conditions and the following disclaimer in the documentation
14 * and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
27 *****************************************************************************/
28
29/**
30 * @file qdatabase.c Database wrapper.
31 *
32 * Database header files should be included prior to qlibcext.h in your source
33 * codes like below.
34 *
35 * @code
36 * #include "mysql.h"
37 * #include "qlibcext.h"
38 * @endcode
39 *
40 * @code
41 * qdb_t *db = NULL;
42 * qdbresult_t *result = NULL;
43 *
44 * db = qdb("MYSQL", "dbhost.qdecoder.org", 3306,
45 * "test", "secret", "sampledb", true);
46 * if (db == NULL) {
47 * printf("ERROR: Not supported database type.\n");
48 * return -1;
49 * }
50 *
51 * // try to connect
52 * if (db->open(db) == false) {
53 * printf("WARNING: Can't connect to database.\n");
54 * return -1;
55 * }
56 *
57 * // get results
58 * result = db->execute_query(db, "SELECT name, population FROM City");
59 * if (result != NULL) {
60 * printf("COLS : %d , ROWS : %d\n",
61 * result->get_cols(result), result->get_rows(result));
62 * while (result->get_next(result) == true) {
63 * char *pszName = result->get_str(result, "name");
64 * int nPopulation = result->get_int(result, "population");
65 * printf("Country : %s , Population : %d\n", pszName, nPopulation);
66 * }
67 * result->free(result);
68 * }
69 *
70 * // close connection
71 * db->close(db);
72 *
73 * // free db object
74 * db->free(db);
75 * @endcode
76 */
77
78#ifndef DISABLE_QDATABASE
79
80#if defined(ENABLE_MYSQL) || defined( _DOXYGEN_SKIP)
81
82#ifdef ENABLE_MYSQL
83#include "mysql.h"
84/* mysql specific connector options */
85#define Q_MYSQL_OPT_RECONNECT (1)
86#define Q_MYSQL_OPT_CONNECT_TIMEOUT (10)
87#define Q_MYSQL_OPT_READ_TIMEOUT (30)
88#define Q_MYSQL_OPT_WRITE_TIMEOUT (30)
89#endif
90
91#include <stdio.h>
92#include <stdlib.h>
93#include <stdbool.h>
94#include <stdarg.h>
95#include <string.h>
96#include "qinternal.h"
97#include "extensions/qdatabase.h"
98
99/*
100 * Member method protos
101 */
102#ifndef _DOXYGEN_SKIP
103// qdb_t object
104static bool open_(qdb_t *db);
105static bool close_(qdb_t *db);
106
107static int execute_update(qdb_t *db, const char *query);
108static int execute_updatef(qdb_t *db, const char *format, ...);
109static qdbresult_t *execute_query(qdb_t *db, const char *query);
110static qdbresult_t *execute_queryf(qdb_t *db, const char *format, ...);
111
112static bool begin_tran(qdb_t *db);
113static bool commit(qdb_t *db);
114static bool rollback(qdb_t *db);
115
116static bool set_fetchtype(qdb_t *db, bool use);
117static bool get_conn_status(qdb_t *db);
118static bool ping(qdb_t *db);
119static const char *get_error(qdb_t *db, unsigned int *errorno);
120static void free_(qdb_t *db);
121
122// qdbresult_t object
123static const char *_resultGetStr(qdbresult_t *result, const char *field);
124static const char *_resultGetStrAt(qdbresult_t *result, int idx);
125static int _resultGetInt(qdbresult_t *result, const char *field);
126static int _resultGetIntAt(qdbresult_t *result, int idx);
127static bool _resultGetNext(qdbresult_t *result);
128
129static int result_get_cols(qdbresult_t *result);
130static int result_get_rows(qdbresult_t *result);
131static int result_get_row(qdbresult_t *result);
132
133static void result_free(qdbresult_t *result);
134
135#endif
136
137/**
138 * Initialize the internal database connector structure.
139 *
140 * @param dbtype database server type. Currently only "MYSQL" is supported
141 * @param addr IP address or FQDN
142 * @param port port number
143 * @param username database username
144 * @param password database password
145 * @param database database name
146 * @param autocommit set autocommit on when true, or off when false
147 *
148 * @return qdb_t pointer on success, or NULL on failure.
149 *
150 * @code
151 * qdb_t *db = qdb("MYSQL",
152 * "dbhost.qdecoder.org", 3306, "test", "secret",
153 * "sampledb", true);
154 * if (db == NULL) {
155 * printf("ERROR: Not supported database type.\n");
156 * return -1;
157 * }
158 * @endcode
159 */
160qdb_t *qdb(const char *dbtype, const char *addr, int port, const char *username,
161 const char *password, const char *database, bool autocommit) {
162 // check db type
163#ifdef Q_ENABLE_MYSQL
164 if (strcmp(dbtype, "MYSQL")) return NULL;
165#else
166 return NULL;
167#endif
168 if (dbtype == NULL
169 || addr == NULL
170 || username == NULL
171 || password == NULL
172 || database == NULL) {
173 return NULL;
174 }
175
176 // initialize
177 qdb_t *db;
178 if ((db = (qdb_t *)malloc(sizeof(qdb_t))) == NULL) return NULL;
179 memset((void *)db, 0, sizeof(qdb_t));
180 db->connected = false;
181
182 // set common structure
183 db->info.dbtype = strdup(dbtype);
184 db->info.addr = strdup(addr);
185 db->info.port = port;
186 db->info.username = strdup(username);
187 db->info.password = strdup(password);
188 db->info.database = strdup(database);
189 db->info.autocommit = autocommit;
190 db->info.fetchtype = false;// store mode
191
192 // set db handler
193#ifdef Q_ENABLE_MYSQL
194 db->mysql = NULL;
195#endif
196
197 // assign methods
198 db->open = open_;
199 db->close = close_;
200
201 db->execute_update = execute_update;
202 db->execute_updatef = execute_updatef;
203 db->execute_query = execute_query;
204 db->execute_queryf = execute_queryf;
205
206 db->begin_tran = begin_tran;
207 db->commit = commit;
208 db->rollback = rollback;
209
210 db->set_fetchtype = set_fetchtype;
211 db->get_conn_status = get_conn_status;
212 db->ping = ping;
213 db->get_error = get_error;
214 db->free = free_;
215
216 // initialize recursive mutex
217 Q_MUTEX_NEW(db->qmutex, true);
218
219 return db;
220}
221
222/**
223 * qdb->open(): Connect to database server
224 *
225 * @param db pointer to qdb_t object
226 *
227 * @return true on success, otherwise false.
228 */
229static bool open_(qdb_t *db) {
230 if (db == NULL) return false;
231
232 // if connected, close first
233 if (db->connected == true) {
234 close_(db);
235 }
236
237#ifdef Q_ENABLE_MYSQL
238 Q_MUTEX_ENTER(db->qmutex);
239
240 // initialize handler
241 if (db->mysql != NULL) close_(db);
242
243 if (mysql_library_init(0, NULL, NULL) != 0) {
244 Q_MUTEX_LEAVE(db->qmutex);
245 return false;
246 }
247
248 if ((db->mysql = mysql_init(NULL)) == NULL) {
249 Q_MUTEX_LEAVE(db->qmutex);
250 return false;
251 }
252
253 // set options
254 my_bool reconnect = Q_MYSQL_OPT_RECONNECT;
255 unsigned int connect_timeout = Q_MYSQL_OPT_CONNECT_TIMEOUT;
256 unsigned int read_timeout = Q_MYSQL_OPT_READ_TIMEOUT;
257 unsigned int write_timeout = Q_MYSQL_OPT_WRITE_TIMEOUT;
258
259 if (reconnect != false) {
260 mysql_options(db->mysql,
261 MYSQL_OPT_RECONNECT,
262 (char *)&reconnect);
263 }
264 if (connect_timeout > 0) {
265 mysql_options(db->mysql,
266 MYSQL_OPT_CONNECT_TIMEOUT,
267 (char *)&connect_timeout);
268 }
269 if (read_timeout > 0) {
270 mysql_options(db->mysql,
271 MYSQL_OPT_READ_TIMEOUT,
272 (char *)&read_timeout);
273 }
274 if (write_timeout > 0) {
275 mysql_options(db->mysql,
276 MYSQL_OPT_WRITE_TIMEOUT,
277 (char *)&write_timeout);
278 }
279
280 // try to connect
281 if (mysql_real_connect(db->mysql,
282 db->info.addr,
283 db->info.username,
284 db->info.password,
285 db->info.database,
286 db->info.port, NULL, 0) == NULL) {
287 close_(db); // free mysql handler
288 Q_MUTEX_LEAVE(db->qmutex);
289 return false;
290 }
291
292 // set auto-commit
293 if (mysql_autocommit(db->mysql, db->info.autocommit) != 0) {
294 close_(db); // free mysql handler
295 Q_MUTEX_LEAVE(db->qmutex);
296 return false;
297 }
298
299 // set flag
300 db->connected = true;
301 Q_MUTEX_LEAVE(db->qmutex);
302 return true;
303#else
304 return false;
305#endif
306}
307
308/**
309 * qdb->close(): Disconnect from database server
310 *
311 * @param db pointer to qdb_t object
312 *
313 * @return true on success, otherwise false.
314 *
315 * @note
316 * Unless you call qdb->free(), qdb_t object will keep the database
317 * information. So you can re-connect to database using qdb->open().
318 */
319static bool close_(qdb_t *db) {
320 if (db == NULL) return false;
321
322#ifdef Q_ENABLE_MYSQL
323 Q_MUTEX_ENTER(db->qmutex);
324
325 if (db->mysql != NULL) {
326 mysql_close(db->mysql);
327 db->mysql = NULL;
328 mysql_library_end();
329 }
330 db->connected = false;
331
332 Q_MUTEX_LEAVE(db->qmutex);
333 return true;
334#else
335 return false;
336#endif
337}
338
339/**
340 * qdb->execute_update(): Executes the update DML
341 *
342 * @param db pointer to qdb_t object
343 * @param query query string
344 *
345 * @return a number of affected rows
346 */
347static int execute_update(qdb_t *db, const char *query) {
348 if (db == NULL || db->connected == false) return -1;
349
350#ifdef Q_ENABLE_MYSQL
351 Q_MUTEX_ENTER(db->qmutex);
352
353 int affected = -1;
354
355 // query
356 DEBUG("%s", query);
357 if (mysql_query(db->mysql, query) == 0) {
358 /* get affected rows */
359 if ((affected = mysql_affected_rows(db->mysql)) < 0) affected = -1;
360 }
361
362 Q_MUTEX_LEAVE(db->qmutex);
363 return affected;
364#else
365 return -1;
366#endif
367}
368
369/**
370 * qdb->execute_updatef(): Executes the formatted update DML
371 *
372 * @param db pointer to qdb_t object
373 * @param format query string format
374 *
375 * @return a number of affected rows, otherwise returns -1
376 */
377static int execute_updatef(qdb_t *db, const char *format, ...) {
378 char *query;
379 DYNAMIC_VSPRINTF(query, format);
380 if (query == NULL) return -1;
381
382 int affected = execute_update(db, query);
383 free(query);
384
385 return affected;
386}
387
388/**
389 * qdb->execute_query(): Execute a query.
390 *
391 * @param db pointer to qdb_t object
392 * @param query query string
393 *
394 * @return qdbresult_t pointer on success, or NULL on failure.
395 */
396static qdbresult_t *execute_query(qdb_t *db, const char *query) {
397 if (db == NULL || db->connected == false) return NULL;
398
399#ifdef Q_ENABLE_MYSQL
400 // query
401 DEBUG("%s", query);
402 if (mysql_query(db->mysql, query)) return NULL;
403
404 // store
405 qdbresult_t *result = (qdbresult_t *)malloc(sizeof(qdbresult_t));
406 if (result == NULL) return NULL;
407
408 result->fetchtype = db->info.fetchtype;
409 if (result->fetchtype == false) {
410 result->rs = mysql_store_result(db->mysql);
411 } else {
412 result->rs = mysql_use_result(db->mysql);
413 }
414 if (result->rs == NULL) {
415 free(result);
416 return NULL;
417 }
418
419 /* get meta data */
420 result->fields = NULL;
421 result->row = NULL;
422 result->cols = mysql_num_fields(result->rs);
423 result->cursor = 0;
424
425 /* assign methods */
426 result->get_str = _resultGetStr;
427 result->get_str_at = _resultGetStrAt;
428 result->get_int = _resultGetInt;
429 result->get_int_at = _resultGetIntAt;
430 result->get_next = _resultGetNext;
431
432 result->get_cols = result_get_cols;
433 result->get_rows = result_get_rows;
434 result->get_row = result_get_row;
435
436 result->free = result_free;
437
438 return result;
439#else
440 return NULL;
441#endif
442}
443
444/**
445 * qdb->execute_queryf(): Execute a formatted query.
446 *
447 * @param db pointer to qdb_t object
448 * @param format query string format
449 *
450 * @return qdbresult_t pointer on success, or NULL on failure.
451 */
452static qdbresult_t *execute_queryf(qdb_t *db, const char *format, ...) {
453 char *query;
454 DYNAMIC_VSPRINTF(query, format);
455 if (query == NULL) return NULL;
456
457 qdbresult_t *ret = db->execute_query(db, query);
458 free(query);
459 return ret;
460}
461
462/**
463 * qdb->begin_tran(): Start transaction
464 *
465 * @param db pointer to qdb_t object
466 *
467 * @return true on success, otherwise false
468 *
469 * @code
470 * db->begin_tran(db);
471 * (... insert/update/delete ...)
472 * db->commit(db);
473 * @endcode
474 */
475static bool begin_tran(qdb_t *db) {
476 if (db == NULL) return false;
477
478#ifdef Q_ENABLE_MYSQL
479 Q_MUTEX_ENTER(db->qmutex);
480 if (db->qmutex.count != 1) {
481 Q_MUTEX_LEAVE(db->qmutex);
482 return false;
483 }
484
485 qdbresult_t *result;
486 result = db->execute_query(db, "START TRANSACTION");
487 if (result == NULL) {
488 Q_MUTEX_LEAVE(db->qmutex);
489 return false;
490 }
491 result->free(result);
492 return true;
493#else
494 return false;
495#endif
496}
497
498/**
499 * qdb->commit(): Commit transaction
500 *
501 * @param db pointer to qdb_t object
502 *
503 * @return true on success, otherwise false
504 */
505static bool commit(qdb_t *db) {
506 if (db == NULL) return false;
507
508#ifdef Q_ENABLE_MYSQL
509 bool ret = false;
510 if (mysql_commit(db->mysql) == 0) {
511 ret = true;
512 }
513
514 if (db->qmutex.count > 0) {
515 Q_MUTEX_LEAVE(db->qmutex);
516 }
517 return ret;
518#else
519 return false;
520#endif
521}
522
523/**
524 * qdb->rellback(): Roll-back and abort transaction
525 *
526 * @param db pointer to qdb_t object
527 *
528 * @return true on success, otherwise false
529 */
530static bool rollback(qdb_t *db) {
531 if (db == NULL) return false;
532
533#ifdef Q_ENABLE_MYSQL
534 bool ret = false;
535 if (mysql_rollback(db->mysql) == 0) {
536 ret = true;
537 }
538
539 if (db->qmutex.count > 0) {
540 Q_MUTEX_LEAVE(db->qmutex);
541 }
542 return ret;
543#else
544 return 0;
545#endif
546}
547
548/**
549 * qdb->set_fetchtype(): Set result fetching type
550 *
551 * @param db pointer to qdb_t object
552 * @param fromdb false for storing the results to client (default mode),
553 * true for fetching directly from server,
554 *
555 * @return true if successful otherwise false
556 *
557 * @note
558 * If qdb->set_fetchtype(db, true) is called, the results does not
559 * actually read into the client. Instead, each row must be retrieved
560 * individually by making calls to qdbresult->get_next().
561 * This reads the result of a query directly from the server without storing
562 * it in local buffer, which is somewhat faster and uses much less memory than
563 * default behavior qdb->set_fetchtype(db, false).
564 */
565static bool set_fetchtype(qdb_t *db, bool fromdb) {
566 if (db == NULL) return false;
567 db->info.fetchtype = fromdb;
568 return true;
569}
570
571/**
572 * qdb->get_conn_status(): Get last connection status
573 *
574 * @param db pointer to qdb_t object
575 *
576 * @return true if the connection flag is set to alive, otherwise false
577 *
578 * @note
579 * This function just returns the connection status flag.
580 */
581static bool get_conn_status(qdb_t *db) {
582 if (db == NULL) return false;
583
584 return db->connected;
585}
586
587/**
588 * qdb->ping(): Checks whether the connection to the server is working.
589 *
590 * @param db pointer to qdb_t object
591 *
592 * @return true if connection is alive, false if connection is not available
593 * and failed to reconnect
594 *
595 * @note
596 * If the connection has gone down, an attempt to reconnect.
597 */
598static bool ping(qdb_t *db) {
599 if (db == NULL) return false;
600
601#ifdef Q_ENABLE_MYSQL
602 if (db->connected == true && mysql_ping(db->mysql) == 0) {
603 return true;
604 } else { // ping test failed
605 if (open_(db) == true) { // try re-connect
606 DEBUG("Connection recovered.");
607 return true;
608 }
609 }
610
611 return false;
612#else
613 return false;
614#endif
615}
616
617/**
618 * qdb->get_error(): Get error number and message
619 *
620 * @param db pointer to qdb_t object
621 * @param errorno if not NULL, error number will be stored
622 *
623 * @return pointer to error message string
624 *
625 * @note
626 * Do not free returned error message
627 */
628static const char *get_error(qdb_t *db, unsigned int *errorno) {
629 if (db == NULL || db->connected == false) return "(no opened db)";
630
631 unsigned int eno = 0;
632 const char *emsg;
633#ifdef Q_ENABLE_MYSQL
634 eno = mysql_errno(db->mysql);
635 if (eno == 0) emsg = "(no error)";
636 else emsg = mysql_error(db->mysql);
637#else
638 emsg = "(not implemented)";
639#endif
640
641 if (errorno != NULL) *errorno = eno;
642 return emsg;
643}
644
645/**
646 * qdb->free(): Free qdb_t structure
647 *
648 * @param db pointer to qdb_t object
649 */
650static void free_(qdb_t *db) {
651 if (db == NULL) return;
652
653 Q_MUTEX_ENTER(db->qmutex);
654
655 close_(db);
656
657 free(db->info.dbtype);
658 free(db->info.addr);
659 free(db->info.username);
660 free(db->info.password);
661 free(db->info.database);
662 free(db);
663
664 Q_MUTEX_LEAVE(db->qmutex);
665 Q_MUTEX_DESTROY(db->qmutex);
666
667 return;
668}
669
670/**
671 * qdbresult->get_str(): Get the result as a string by field name.
672 *
673 * @param result pointer to qdbresult_t
674 * @param field column name
675 *
676 * @return string pointer on success, or NULL on failure.
677 *
678 * @note
679 * Do not free returned string.
680 */
681static const char *_resultGetStr(qdbresult_t *result, const char *field) {
682#ifdef Q_ENABLE_MYSQL
683 if (result == NULL || result->rs == NULL || result->cols <= 0) return NULL;
684
685 if (result->fields == NULL) result->fields = mysql_fetch_fields(result->rs);
686
687 int i;
688 for (i = 0; i < result->cols; i++) {
689 if (!strcasecmp(result->fields[i].name, field)) {
690 return result->get_str_at(result, i + 1);
691 }
692 }
693
694 return NULL;
695#else
696 return NULL;
697#endif
698}
699
700/**
701 * qdbresult->get_str_at(): Get the result as a string by column number.
702 *
703 * @param result pointer to qdbresult_t
704 * @param idx column number (first column is 1)
705 *
706 * @return string pointer on success, or NULL on failure.
707 */
708static const char *_resultGetStrAt(qdbresult_t *result, int idx) {
709#ifdef Q_ENABLE_MYSQL
710 if (result == NULL
711 || result->rs == NULL
712 || result->cursor == 0
713 || idx <= 0
714 || idx > result->cols ) {
715 return NULL;
716 }
717 return result->row[idx-1];
718#else
719 return NULL;
720#endif
721}
722
723/**
724 * qdbresult->get_int(): Get the result as an integer by field name.
725 *
726 * @param result pointer to qdbresult_t
727 * @param field column name
728 *
729 * @return an integer converted value.
730 */
731static int _resultGetInt(qdbresult_t *result, const char *field) {
732 const char *val = result->get_str(result, field);
733 if (val == NULL) return 0;
734 return atoi(val);
735}
736
737/**
738 * qdbresult->get_int_at(): Get the result as an integer by column number.
739 *
740 * @param result pointer to qdbresult_t
741 * @param idx column number (first column is 1)
742 *
743 * @return an integer converted value.
744 */
745static int _resultGetIntAt(qdbresult_t *result, int idx) {
746 const char *val = result->get_str_at(result, idx);
747 if (val == NULL) return 0;
748 return atoi(val);
749}
750
751/**
752 * qdbresult->get_next(): Retrieves the next row of a result set
753 *
754 * @param result pointer to qdbresult_t
755 *
756 * @return true if successful, false if no more rows are left
757 */
758static bool _resultGetNext(qdbresult_t *result) {
759#ifdef Q_ENABLE_MYSQL
760 if (result == NULL || result->rs == NULL) return false;
761
762 if ((result->row = mysql_fetch_row(result->rs)) == NULL) return false;
763 result->cursor++;
764
765 return true;
766#else
767 return false;
768#endif
769}
770
771/**
772 * qdbresult->get_cols(): Get the number of columns in the result set
773 *
774 * @param result pointer to qdbresult_t
775 *
776 * @return the number of columns in the result set
777 */
778static int result_get_cols(qdbresult_t *result) {
779#ifdef Q_ENABLE_MYSQL
780 if (result == NULL || result->rs == NULL) return 0;
781 return result->cols;
782#else
783 return 0;
784#endif
785}
786
787/**
788 * qdbresult->get_rows(): Get the number of rows in the result set
789 *
790 * @param result pointer to qdbresult_t
791 *
792 * @return the number of rows in the result set
793 */
794static int result_get_rows(qdbresult_t *result) {
795#ifdef Q_ENABLE_MYSQL
796 if (result == NULL || result->rs == NULL) return 0;
797 return mysql_num_rows(result->rs);
798#else
799 return 0;
800#endif
801}
802
803/**
804 * qdbresult->get_row(): Get the current row number
805 *
806 * @param result pointer to qdbresult_t
807 *
808 * @return current fetching row number of the result set
809 *
810 * @note
811 * This number is sequential counter which is started from 1.
812 */
813static int result_get_row(qdbresult_t *result) {
814#ifdef Q_ENABLE_MYSQL
815 if (result == NULL || result->rs == NULL) return 0;
816 return result->cursor;
817#else
818 return 0;
819#endif
820}
821
822/**
823 * qdbresult->free(): Free the result
824 *
825 * @param result pointer to qdbresult_t
826 */
827static void result_free(qdbresult_t *result) {
828#ifdef Q_ENABLE_MYSQL
829 if (result == NULL) return;
830 if (result->rs != NULL) {
831 if (result->fetchtype == true) {
832 while (mysql_fetch_row(result->rs) != NULL);
833 }
834 mysql_free_result(result->rs);
835 result->rs = NULL;
836 }
837 free(result);
838 return;
839#else
840 return;
841#endif
842}
843
844#endif
845
846#endif /* DISABLE_QDATABASE */
static void free_(qaconf_t *qaconf)
qaconf_t->free(): Release resources.
Definition qaconf.c:606
static bool get_conn_status(qdb_t *db)
qdb->get_conn_status(): Get last connection status
Definition qdatabase.c:581
static qdbresult_t * execute_query(qdb_t *db, const char *query)
qdb->execute_query(): Execute a query.
Definition qdatabase.c:396
static int result_get_rows(qdbresult_t *result)
qdbresult->get_rows(): Get the number of rows in the result set
Definition qdatabase.c:794
static bool begin_tran(qdb_t *db)
qdb->begin_tran(): Start transaction
Definition qdatabase.c:475
static bool commit(qdb_t *db)
qdb->commit(): Commit transaction
Definition qdatabase.c:505
static qdbresult_t * execute_queryf(qdb_t *db, const char *format,...)
qdb->execute_queryf(): Execute a formatted query.
Definition qdatabase.c:452
static int result_get_row(qdbresult_t *result)
qdbresult->get_row(): Get the current row number
Definition qdatabase.c:813
static int execute_update(qdb_t *db, const char *query)
qdb->execute_update(): Executes the update DML
Definition qdatabase.c:347
static void result_free(qdbresult_t *result)
qdbresult->free(): Free the result
Definition qdatabase.c:827
static const char * _resultGetStr(qdbresult_t *result, const char *field)
qdbresult->get_str(): Get the result as a string by field name.
Definition qdatabase.c:681
qdb_t * qdb(const char *dbtype, const char *addr, int port, const char *username, const char *password, const char *database, bool autocommit)
Initialize the internal database connector structure.
Definition qdatabase.c:160
static const char * _resultGetStrAt(qdbresult_t *result, int idx)
qdbresult->get_str_at(): Get the result as a string by column number.
Definition qdatabase.c:708
static bool set_fetchtype(qdb_t *db, bool fromdb)
qdb->set_fetchtype(): Set result fetching type
Definition qdatabase.c:565
static int _resultGetIntAt(qdbresult_t *result, int idx)
qdbresult->get_int_at(): Get the result as an integer by column number.
Definition qdatabase.c:745
static bool rollback(qdb_t *db)
qdb->rellback(): Roll-back and abort transaction
Definition qdatabase.c:530
static bool close_(qdb_t *db)
qdb->close(): Disconnect from database server
Definition qdatabase.c:319
static int result_get_cols(qdbresult_t *result)
qdbresult->get_cols(): Get the number of columns in the result set
Definition qdatabase.c:778
static bool ping(qdb_t *db)
qdb->ping(): Checks whether the connection to the server is working.
Definition qdatabase.c:598
static int execute_updatef(qdb_t *db, const char *format,...)
qdb->execute_updatef(): Executes the formatted update DML
Definition qdatabase.c:377
static int _resultGetInt(qdbresult_t *result, const char *field)
qdbresult->get_int(): Get the result as an integer by field name.
Definition qdatabase.c:731
static bool open_(qdb_t *db)
qdb->open(): Connect to database server
Definition qdatabase.c:229
static bool _resultGetNext(qdbresult_t *result)
qdbresult->get_next(): Retrieves the next row of a result set
Definition qdatabase.c:758
static void free_(qdb_t *db)
qdb->free(): Free qdb_t structure
Definition qdatabase.c:650
static const char * get_error(qdb_t *db, unsigned int *errorno)
qdb->get_error(): Get error number and message
Definition qdatabase.c:628
static bool open_(qhttpclient_t *client)
qhttpclient->open(): Opens a connection to the remote host.