source: sources/src/dataBaseMysql.cc @ 1500:872b0b69e0d5

Revision 1500:872b0b69e0d5, 17.5 KB checked in by niam, 12 months ago (diff)

{issue #103} added implementation of sl- and dl- lists

Line 
1/***************************************************************************
2 *            dataBaseMysql.cc
3 *
4 *  Thu Apr  30 2005
5 *  Copyright  2005  Dmytro Milinevskyy
6 *  milinevskyy@gmail.com
7 ****************************************************************************/
8
9/*
10 *  This program is free software; you can redistribute it and/or modify
11 *  it under the terms of the GNU Lesser General Public License version 2.1 as published by
12 *  the Free Software Foundation;
13 *
14 *  This program is distributed in the hope that it will be useful,
15 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 *  GNU Library General Public License for more details.
18 *
19 *  You should have received a copy of the GNU Lesser General Public License
20 *  along with this program; if not, write to the Free Software
21 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22 */
23
24/**
25 * vim indentation settings
26 * set tabstop=4
27 * set shiftwidth=4
28 */
29
30#include <libdodo/directives.h>
31
32#ifdef MYSQL_EXT
33#include <mysql.h>
34#include <errmsg.h>
35#include <string.h>
36
37#include <libdodo/dataBaseMysql.h>
38#include <libdodo/dataBaseMysqlEx.h>
39
40namespace dodo {
41    namespace data {
42        namespace base {
43            /**
44             * @struct __mysql__
45             * @brief defines internal handlers for MySQL DBMS interaction
46             */
47            struct __mysql__ {
48                /**
49                 * constructor
50                 */
51                __mysql__() : handle(NULL),
52                              result(NULL)
53                {
54                }
55
56                MYSQL         *handle;  ///< DB handle
57                MYSQL_RES     *result;  ///< handle to result
58            };
59        };
60    };
61};
62
63using namespace dodo::data::base;
64
65mysql::__connection_options__::__connection_options__(const dodo::string &db,
66                                                      const dodo::string &host,
67                                                      const dodo::string &user,
68                                                      const dodo::string &password,
69                                                      const dodo::string &path,
70                                                      unsigned int     port,
71                                                      unsigned long    type) : type(type),
72                                                                               db(db),
73                                                                               host(host),
74                                                                               user(user),
75                                                                               password(password),
76                                                                               path(path),
77                                                                               port(port)
78{
79}
80
81//-------------------------------------------------------------------
82
83mysql::__connection_options__::__connection_options__() : type(TYPE_MULTI_STATEMENTS)
84{
85}
86
87//-------------------------------------------------------------------
88
89mysql::mysql() : handle(new __mysql__)
90
91{
92#ifndef DATABASE_WO_XEXEC
93    collectedData.setExecObject(xexec::OBJECT_DATABASEMYSQL);
94#endif
95
96    handle->handle = mysql_init(NULL);
97}
98
99//-------------------------------------------------------------------
100
101mysql::mysql(const data::base::__connection_options__ &a_info) : handle(new __mysql__),
102                                                                 info(*dynamic_cast<const mysql::__connection_options__ *>(&a_info))
103{
104#ifndef DATABASE_WO_XEXEC
105    collectedData.setExecObject(xexec::OBJECT_DATABASEMYSQL);
106#endif
107
108    handle->handle = mysql_init(NULL);
109
110    unsigned long type = 0;
111
112    if (info.type & __connection_options__::TYPE_MULTI_STATEMENTS)
113        type |= CLIENT_MULTI_STATEMENTS;
114
115    if (info.type & __connection_options__::TYPE_COMPRESS)
116        type |= CLIENT_COMPRESS;
117
118    if (mysql_ssl_set(handle->handle,
119                      info.ssl.key.size() == 0 ? NULL : info.ssl.key.data(),
120                      info.ssl.cert.size() == 0 ? NULL : info.ssl.cert.data(),
121                      info.ssl.ca.size() == 0 ? NULL : info.ssl.ca.data(),
122                      info.ssl.capath.size() == 0 ? NULL : info.ssl.capath.data(),
123                      info.ssl.cipher.size() == 0 ? NULL : info.ssl.cipher.data()) == 0)
124        type |= CLIENT_SSL;
125
126    dodo_try {
127        if (!mysql_real_connect(handle->handle,
128                                info.host.size() == 0 ? NULL : info.host.data(),
129                                info.user.size() == 0 ? NULL : info.user.data(),
130                                info.password.size() == 0 ? NULL : info.password.data(),
131                                info.db.size() == 0 ? NULL : info.db.data(),
132                                info.port,
133                                info.path.size() == 0 ? NULL : info.path.data(),
134                                type))
135            dodo_throw exception::basic(exception::MODULE_DATABASEMYSQL, MYSQLEX_MYSQL, exception::ERRNO_MYSQL, mysql_errno(handle->handle), mysql_error(handle->handle), __LINE__, __FILE__);
136    } dodo_catch (exception::basic *e UNUSED) {
137        mysql_close(handle->handle);
138
139        delete handle;
140
141        dodo_rethrow;
142    }
143
144#ifndef MYSQL_NO_OPT_RECONNECT
145    if (reconnect) {
146        my_bool rc = 1;
147
148        mysql_options(handle->handle, MYSQL_OPT_RECONNECT, &rc);
149    }
150#endif
151}
152
153//-------------------------------------------------------------------
154
155mysql::mysql(mysql &)
156{
157}
158
159//-------------------------------------------------------------------
160
161mysql::~mysql()
162{
163    if (handle->handle != NULL) {
164        if (handle->result)
165            mysql_free_result(handle->result);
166
167        mysql_close(handle->handle);
168    }
169
170    delete handle;
171}
172
173//-------------------------------------------------------------------
174
175void
176mysql::connect(const data::base::__connection_options__ &a_info)
177{
178#ifndef DATABASE_WO_XEXEC
179    performPreExec(OPERATION_CONNECT);
180#endif
181
182    info = *dynamic_cast<const mysql::__connection_options__ *>(&a_info);
183
184    if (handle->handle != NULL) {
185        if (handle->result) {
186            mysql_free_result(handle->result);
187            handle->result = NULL;
188        }
189
190        mysql_close(handle->handle);
191        handle->handle = NULL;
192    }
193
194    handle->handle = mysql_init(NULL);
195
196    unsigned long type = 0;
197
198    if (info.type & __connection_options__::TYPE_MULTI_STATEMENTS)
199        type |= CLIENT_MULTI_STATEMENTS;
200
201    if (info.type & __connection_options__::TYPE_COMPRESS)
202        type |= CLIENT_COMPRESS;
203
204    if (mysql_ssl_set(handle->handle,
205                      info.ssl.key.size() == 0 ? NULL : info.ssl.key.data(),
206                      info.ssl.cert.size() == 0 ? NULL : info.ssl.cert.data(),
207                      info.ssl.ca.size() == 0 ? NULL : info.ssl.ca.data(),
208                      info.ssl.capath.size() == 0 ? NULL : info.ssl.capath.data(),
209                      info.ssl.cipher.size() == 0 ? NULL : info.ssl.cipher.data()) == 0)
210        type |= CLIENT_SSL;
211
212    if (!mysql_real_connect(handle->handle,
213                            info.host.size() == 0 ? NULL : info.host.data(),
214                            info.user.size() == 0 ? NULL : info.user.data(),
215                            info.password.size() == 0 ? NULL : info.password.data(),
216                            info.db.size() == 0 ? NULL : info.db.data(),
217                            info.port,
218                            info.path.size() == 0 ? NULL : info.path.data(),
219                            type))
220        dodo_throw exception::basic(exception::MODULE_DATABASEMYSQL, MYSQLEX_CONNECT, exception::ERRNO_MYSQL, mysql_errno(handle->handle), mysql_error(handle->handle), __LINE__, __FILE__);
221
222#ifndef MYSQL_NO_OPT_RECONNECT
223    if (reconnect) {
224        my_bool rc = 1;
225
226        mysql_options(handle->handle, MYSQL_OPT_RECONNECT, &rc);
227    }
228#endif
229
230#ifndef DATABASE_WO_XEXEC
231    performPostExec(OPERATION_CONNECT);
232#endif
233}
234
235//-------------------------------------------------------------------
236
237void
238mysql::disconnect()
239{
240    if (handle->handle != NULL) {
241#ifndef DATABASE_WO_XEXEC
242        performPreExec(OPERATION_DISCONNECT);
243#endif
244
245        if (handle->result) {
246            mysql_free_result(handle->result);
247            handle->result = NULL;
248        }
249
250        mysql_close(handle->handle);
251        handle->handle = NULL;
252
253#ifndef DATABASE_WO_XEXEC
254        performPostExec(OPERATION_DISCONNECT);
255#endif
256    }
257}
258
259//-------------------------------------------------------------------
260
261void
262mysql::fetchedRows(data::base::rows &a_rows) const
263{
264    sql::rows *rows = dynamic_cast<sql::rows *>(&a_rows);
265
266#ifndef DATABASE_WO_XEXEC
267    performPreExec(OPERATION_FETCHEDROWS);
268#endif
269
270    rows->fields.clear();
271    rows->values.clear();
272
273    if (!handle->result) // FIXME: dodo_throw exception?
274        return;
275
276    mysql_data_seek(handle->result, 0);
277    mysql_field_seek(handle->result, 0);
278
279    unsigned int numFields = mysql_num_fields(handle->result);
280    MYSQL_FIELD *mysqlFields = mysql_fetch_fields(handle->result);
281
282    rows->fields.reserve(numFields);
283
284    rows->values.reserve(mysql_num_rows(handle->result));
285
286    unsigned long *length, j;
287
288    dodoStringArray values;
289
290    MYSQL_ROW mysqlRow;
291
292    values.reserve(numFields);
293
294    for (unsigned int i(0); i < numFields; ++i)
295        rows->fields.push_back(mysqlFields[i].name);
296
297    while ((mysqlRow = mysql_fetch_row(handle->result)) != NULL) {
298        length = mysql_fetch_lengths(handle->result);
299
300        for (j = 0; j < numFields; ++j) {
301            if (mysqlRow[j] != NULL)
302                values.push_back(dodo::string(mysqlRow[j], length[j]));
303            else
304                values.push_back(statements[sql::constructor::STATEMENT_NULL]);
305        }
306
307        rows->values.push_back(values);
308
309        values.clear();
310    }
311
312#ifndef DATABASE_WO_XEXEC
313    performPostExec(OPERATION_FETCHEDROWS);
314#endif
315}
316
317//-------------------------------------------------------------------
318
319unsigned int
320mysql::fetchedRows() const
321{
322    if (handle->result == NULL)
323        dodo_throw exception::basic(exception::MODULE_DATABASEMYSQL, MYSQLEX_FETCHEDROWS, exception::ERRNO_LIBDODO, MYSQLEX_NOTOPENED, DATABASEMYSQLEX_NOTOPENED_STR, __LINE__, __FILE__);
324
325    return mysql_num_rows(handle->result);
326}
327
328//-------------------------------------------------------------------
329
330unsigned int
331mysql::affectedRows() const
332{
333    if (handle->handle == NULL)
334        dodo_throw exception::basic(exception::MODULE_DATABASEMYSQL, MYSQLEX_AFFECTEDROWS, exception::ERRNO_LIBDODO, MYSQLEX_NOTOPENED, DATABASEMYSQLEX_NOTOPENED_STR, __LINE__, __FILE__);
335
336    return mysql_affected_rows(handle->handle);
337}
338
339//-------------------------------------------------------------------
340
341void
342mysql::requestFieldsTypes(const dodo::string &table)
343{
344    if (handle->handle == NULL)
345        dodo_throw exception::basic(exception::MODULE_DATABASEMYSQL, MYSQLEX_REQUESTFIELDSTYPES, exception::ERRNO_LIBDODO, MYSQLEX_NOTOPENED, DATABASEMYSQLEX_NOTOPENED_STR, __LINE__, __FILE__);
346
347    dodoMap<dodo::string, dodoMap<dodo::string, short, dodoMapICaseStringCompare>, dodoMapICaseStringCompare>::iterator types = fieldTypes.find(table);
348
349    if (types == fieldTypes.end())
350        types = fieldTypes.insert(std::make_pair(table, dodoMap<dodo::string, short, dodoMapICaseStringCompare>())).first;
351
352    dodo::string request = "describe " + table;
353
354    if (mysql_real_query(handle->handle, request.data(), request.size()) != 0) {
355        int mysqlErrno = mysql_errno(handle->handle);
356        if (reconnect && (mysqlErrno == CR_SERVER_GONE_ERROR || mysqlErrno == CR_SERVER_LOST)) {
357            connect(info);
358            if (mysql_real_query(handle->handle, request.data(), request.size()) != 0)
359                dodo_throw exception::basic(exception::MODULE_DATABASEMYSQL, MYSQLEX_REQUESTFIELDSTYPES, exception::ERRNO_MYSQL, mysqlErrno, mysql_error(handle->handle), __LINE__, __FILE__, request);
360        } else
361            dodo_throw exception::basic(exception::MODULE_DATABASEMYSQL, MYSQLEX_REQUESTFIELDSTYPES, exception::ERRNO_MYSQL, mysqlErrno, mysql_error(handle->handle), __LINE__, __FILE__, request);
362    }
363
364    handle->result = mysql_store_result(handle->handle);
365    if (handle->result == NULL)
366        dodo_throw exception::basic(exception::MODULE_DATABASEMYSQL, MYSQLEX_REQUESTFIELDSTYPES, exception::ERRNO_MYSQL, mysql_errno(handle->handle), mysql_error(handle->handle), __LINE__, __FILE__);
367
368    MYSQL_ROW mysqlRow;
369
370    dodoMap<dodo::string, short, dodoMapICaseStringCompare>::iterator field, fieldsEnd = types->second.end();
371
372    while ((mysqlRow = mysql_fetch_row(handle->result)) != NULL) {
373        field = types->second.find(mysqlRow[0]);
374
375        if (field == fieldsEnd) {
376            if (strcasestr(mysqlRow[1], "char") != NULL ||
377                strcasestr(mysqlRow[1], "date") != NULL ||
378                strcasestr(mysqlRow[1], "time") != NULL ||
379                strcasestr(mysqlRow[1], "text") != NULL ||
380                strcasestr(mysqlRow[1], "enum") != NULL ||
381                strcasestr(mysqlRow[1], "set") != NULL) {
382                types->second.insert(std::make_pair(dodo::string(mysqlRow[0]), sql::FIELD_TEXT));
383            } else {
384                if (strcasestr(mysqlRow[1], "blob") != NULL)
385                    types->second.insert(std::make_pair(dodo::string(mysqlRow[0]), sql::FIELD_BINARY));
386                else
387                    types->second.insert(std::make_pair(dodo::string(mysqlRow[0]), sql::FIELD_NUMERIC));
388            }
389        } else {
390            if (strcasestr(mysqlRow[1], "char") != NULL ||
391                strcasestr(mysqlRow[1], "date") != NULL ||
392                strcasestr(mysqlRow[1], "time") != NULL ||
393                strcasestr(mysqlRow[1], "text") != NULL ||
394                strcasestr(mysqlRow[1], "enum") != NULL ||
395                strcasestr(mysqlRow[1], "set") != NULL) {
396                field->second = sql::FIELD_TEXT;
397            } else {
398                if (strcasestr(mysqlRow[1], "blob") != NULL)
399                    field->second = sql::FIELD_BINARY;
400                else
401                    field->second = sql::FIELD_NUMERIC;
402            }
403        }
404    }
405
406    mysql_free_result(handle->result);
407    handle->result = NULL;
408}
409
410//-------------------------------------------------------------------
411
412void
413mysql::exec()
414{
415    exec(sql::query(construct()));
416}
417
418//-------------------------------------------------------------------
419
420void
421mysql::exec(const query &a_query)
422{
423    dodo_try {
424        collectedData.query = dynamic_cast<const sql::query *>(&a_query);
425
426        if (handle->handle == NULL)
427            dodo_throw exception::basic(exception::MODULE_DATABASEMYSQL, MYSQLEX_EXEC, exception::ERRNO_LIBDODO, MYSQLEX_NOTOPENED, DATABASEMYSQLEX_NOTOPENED_STR, __LINE__, __FILE__);
428
429#ifndef DATABASE_WO_XEXEC
430        performPreExec(OPERATION_EXEC);
431#endif
432        if (handle->result) {
433            mysql_free_result(handle->result);
434            handle->result = NULL;
435        }
436
437        if (mysql_real_query(handle->handle, collectedData.query->sql.data(), collectedData.query->sql.size()) != 0) {
438            int mysqlErrno = mysql_errno(handle->handle);
439            if (reconnect && (mysqlErrno == CR_SERVER_GONE_ERROR || mysqlErrno == CR_SERVER_LOST)) {
440                connect(info);
441                if (mysql_real_query(handle->handle, collectedData.query->sql.data(), collectedData.query->sql.size()) != 0)
442                    dodo_throw exception::basic(exception::MODULE_DATABASEMYSQL, MYSQLEX_EXEC, exception::ERRNO_MYSQL, mysqlErrno, mysql_error(handle->handle), __LINE__, __FILE__, collectedData.query->sql);
443            } else {
444                dodo_throw exception::basic(exception::MODULE_DATABASEMYSQL, MYSQLEX_EXEC, exception::ERRNO_MYSQL, mysqlErrno, mysql_error(handle->handle), __LINE__, __FILE__, collectedData.query->sql);
445            }
446        }
447
448        if (mysql_field_count(handle->handle) != 0) {
449            handle->result = mysql_store_result(handle->handle);
450            if (handle->result == NULL)
451                dodo_throw exception::basic(exception::MODULE_DATABASEMYSQL, MYSQLEX_EXEC, exception::ERRNO_MYSQL, mysql_errno(handle->handle), mysql_error(handle->handle), __LINE__, __FILE__);
452        }
453
454#ifndef DATABASE_WO_XEXEC
455        performPostExec(OPERATION_EXEC);
456#endif
457
458        collectedData.clear();
459    } dodo_catch (exception::basic *e UNUSED) {
460        collectedData.clear();
461
462        dodo_rethrow;
463    }
464}
465
466//-------------------------------------------------------------------
467
468void
469mysql::setCharset(const dodo::string &charset)
470{
471    if (handle->handle == NULL)
472        dodo_throw exception::basic(exception::MODULE_DATABASEMYSQL, MYSQLEX_SETCHARSET, exception::ERRNO_LIBDODO, MYSQLEX_NOTOPENED, DATABASEMYSQLEX_NOTOPENED_STR, __LINE__, __FILE__);
473
474    mysql_options(handle->handle, MYSQL_SET_CHARSET_NAME, charset.data());
475}
476
477//-------------------------------------------------------------------
478
479void
480mysql::setConnectionTimeout(unsigned int time)
481{
482    if (handle->handle == NULL)
483        dodo_throw exception::basic(exception::MODULE_DATABASEMYSQL, MYSQLEX_SETCONNECTIONTIMEOUT, exception::ERRNO_LIBDODO, MYSQLEX_NOTOPENED, DATABASEMYSQLEX_NOTOPENED_STR, __LINE__, __FILE__);
484
485    mysql_options(handle->handle, MYSQL_OPT_CONNECT_TIMEOUT, (char *)&time);
486}
487
488//-------------------------------------------------------------------
489
490dodo::string
491mysql::charset() const
492{
493    if (handle->handle == NULL)
494        dodo_throw exception::basic(exception::MODULE_DATABASEMYSQL, MYSQLEX_CHARSET, exception::ERRNO_LIBDODO, MYSQLEX_NOTOPENED, DATABASEMYSQLEX_NOTOPENED_STR, __LINE__, __FILE__);
495
496    return mysql_character_set_name(handle->handle);
497}
498
499#endif
500
501//-------------------------------------------------------------------
502
Note: See TracBrowser for help on using the repository browser.