Statistics
| Branch: | Tag: | Revision:

one / src / sql / MySqlDB.cc @ 822602ca

History | View | Annotate | Download (8.05 KB)

1
/* -------------------------------------------------------------------------- */
2
/* Copyright 2002-2017, OpenNebula Project, OpenNebula Systems                */
3
/*                                                                            */
4
/* Licensed under the Apache License, Version 2.0 (the "License"); you may    */
5
/* not use this file except in compliance with the License. You may obtain    */
6
/* a copy of the License at                                                   */
7
/*                                                                            */
8
/* http://www.apache.org/licenses/LICENSE-2.0                                 */
9
/*                                                                            */
10
/* Unless required by applicable law or agreed to in writing, software        */
11
/* distributed under the License is distributed on an "AS IS" BASIS,          */
12
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   */
13
/* See the License for the specific language governing permissions and        */
14
/* limitations under the License.                                             */
15
/* -------------------------------------------------------------------------- */
16

    
17
#include "MySqlDB.h"
18
#include <mysql/errmsg.h>
19

    
20
/*********
21
 * Doc: http://dev.mysql.com/doc/refman/5.5/en/c-api-function-overview.html
22
 ********/
23

    
24
const int MySqlDB::DB_CONNECT_SIZE = 10;
25

    
26
/* -------------------------------------------------------------------------- */
27

    
28
MySqlDB::MySqlDB(
29
        const string& _server,
30
        int           _port,
31
        const string& _user,
32
        const string& _password,
33
        const string& _database)
34
{
35
    vector<MYSQL *> connections(DB_CONNECT_SIZE);
36
    MYSQL * rc;
37

    
38
    ostringstream oss;
39

    
40
    server   = _server;
41
    port     = _port;
42
    user     = _user;
43
    password = _password;
44
    database = _database;
45

    
46
    // Initialize the MySQL library
47
    mysql_library_init(0, NULL, NULL);
48

    
49
    // Create connection pool to the server
50
    for (int i=0 ; i < DB_CONNECT_SIZE ; i++)
51
    {
52
        connections[i] = mysql_init(NULL);
53

    
54
        rc = mysql_real_connect(connections[i],
55
                                server.c_str(),
56
                                user.c_str(),
57
                                password.c_str(),
58
                                0,
59
                                port,
60
                                NULL,
61
                                0);
62
        if ( rc == NULL)
63
        {
64
            throw runtime_error("Could not open connect to database server.");
65
        }
66
    }
67

    
68
    db_escape_connect = mysql_init(NULL);
69

    
70
    rc = mysql_real_connect(db_escape_connect,
71
                            server.c_str(),
72
                            user.c_str(),
73
                            password.c_str(),
74
                            0,
75
                            port,
76
                            NULL,
77
                            0);
78

    
79
    if ( rc == NULL)
80
    {
81
        throw runtime_error("Could not open connect to database server.");
82
    }
83

    
84
    //Connect to the database & initialize connection pool
85
    oss << "CREATE DATABASE IF NOT EXISTS " << database;
86

    
87
    if ( mysql_query(connections[0], oss.str().c_str()) != 0 )
88
    {
89
        throw runtime_error("Could not create the database.");
90
    }
91

    
92
    oss.str("");
93
    oss << "USE " << database;
94

    
95
    for (int i=0 ; i < DB_CONNECT_SIZE ; i++)
96
    {
97
        if ( mysql_query(connections[i], oss.str().c_str()) != 0 )
98
        {
99
            throw runtime_error("Could not connect to the database.");
100
        }
101

    
102
        db_connect.push(connections[i]);
103
    }
104

    
105
    pthread_mutex_init(&mutex,0);
106

    
107
    pthread_cond_init(&cond,0);
108
}
109

    
110
/* -------------------------------------------------------------------------- */
111

    
112
MySqlDB::~MySqlDB()
113
{
114
    // Close the connections to the MySQL server
115
    while (!db_connect.empty())
116
    {
117
        MYSQL * db = db_connect.front();
118
        db_connect.pop();
119

    
120
        mysql_close(db);
121
    }
122

    
123
    mysql_close(db_escape_connect);
124

    
125
    // End use of the MySQL library
126
    mysql_library_end();
127

    
128
    pthread_mutex_destroy(&mutex);
129

    
130
    pthread_cond_destroy(&cond);
131
}
132

    
133
/* -------------------------------------------------------------------------- */
134

    
135
bool MySqlDB::multiple_values_support()
136
{
137
    return true;
138
}
139

    
140
/* -------------------------------------------------------------------------- */
141

    
142
int MySqlDB::exec(ostringstream& cmd, Callbackable* obj, bool quiet)
143
{
144
    int          rc;
145

    
146
    const char * c_str;
147
    string       str;
148

    
149
    str   = cmd.str();
150
    c_str = str.c_str();
151

    
152
    Log::MessageType error_level = quiet ? Log::DDEBUG : Log::ERROR;
153

    
154
    MYSQL *db;
155

    
156
    db = get_db_connection();
157

    
158
    rc = mysql_query(db, c_str);
159

    
160
    if (rc != 0)
161
    {
162
        ostringstream   oss;
163
        const char *    err_msg = mysql_error(db);
164
        int             err_num = mysql_errno(db);
165

    
166
        if( err_num == CR_SERVER_GONE_ERROR || err_num == CR_SERVER_LOST )
167
        {
168
            oss << "MySQL connection error " << err_num << " : " << err_msg;
169

    
170
            // Try to re-connect
171
            if (mysql_real_connect(db, server.c_str(), user.c_str(),
172
                                    password.c_str(), database.c_str(),
173
                                    port, NULL, 0))
174
            {
175
                oss << "... Reconnected.";
176
            }
177
            else
178
            {
179
                oss << "... Reconnection attempt failed.";
180
            }
181
        }
182
        else
183
        {
184
            oss << "SQL command was: " << c_str;
185
            oss << ", error " << err_num << " : " << err_msg;
186
        }
187

    
188
        NebulaLog::log("ONE",error_level,oss);
189

    
190
        free_db_connection(db);
191

    
192
        return -1;
193
    }
194

    
195

    
196
    if ( (obj != 0) && (obj->isCallBackSet()) )
197
    {
198

    
199
        MYSQL_RES *         result;
200
        MYSQL_ROW           row;
201
        MYSQL_FIELD *       fields;
202
        unsigned int        num_fields;
203

    
204
        // Retrieve the entire result set all at once
205
        result = mysql_store_result(db);
206

    
207
        if (result == NULL)
208
        {
209
            ostringstream   oss;
210
            const char *    err_msg = mysql_error(db);
211
            int             err_num = mysql_errno(db);
212

    
213
            oss << "SQL command was: " << c_str;
214
            oss << ", error " << err_num << " : " << err_msg;
215

    
216
            NebulaLog::log("ONE",error_level,oss);
217

    
218
            free_db_connection(db);
219

    
220
            return -1;
221
        }
222

    
223
        // Fetch the names of the fields
224
        num_fields  = mysql_num_fields(result);
225
        fields      = mysql_fetch_fields(result);
226

    
227
        char ** names = new char*[num_fields];
228

    
229
        for(unsigned int i = 0; i < num_fields; i++)
230
        {
231
            names[i] = fields[i].name;
232
        }
233

    
234
        // Fetch each row, and call-back the object waiting for them
235
        while((row = mysql_fetch_row(result)))
236
        {
237
            if ( obj->do_callback(num_fields, row, names) != 0 )
238
            {
239
                rc = -1;
240
                break;
241
            }
242
        }
243

    
244
        // Free the result object
245
        mysql_free_result(result);
246

    
247
        delete[] names;
248
    }
249

    
250
    free_db_connection(db);
251

    
252
    return rc;
253
}
254

    
255
/* -------------------------------------------------------------------------- */
256

    
257
char * MySqlDB::escape_str(const string& str)
258
{
259
    char * result = new char[str.size()*2+1];
260

    
261
    mysql_real_escape_string(db_escape_connect, result, str.c_str(), str.size());
262

    
263
    return result;
264
}
265

    
266
/* -------------------------------------------------------------------------- */
267

    
268
void MySqlDB::free_str(char * str)
269
{
270
    delete[] str;
271
}
272

    
273
/* -------------------------------------------------------------------------- */
274

    
275
MYSQL * MySqlDB::get_db_connection()
276
{
277
    MYSQL *db;
278

    
279
    pthread_mutex_lock(&mutex);
280

    
281
    while ( db_connect.empty() == true )
282
    {
283
        pthread_cond_wait(&cond, &mutex);
284
    }
285

    
286
    db = db_connect.front();
287

    
288
    db_connect.pop();
289

    
290
    pthread_mutex_unlock(&mutex);
291

    
292
    return db;
293
}
294

    
295
/* -------------------------------------------------------------------------- */
296

    
297
void MySqlDB::free_db_connection(MYSQL * db)
298
{
299
    pthread_mutex_lock(&mutex);
300

    
301
    db_connect.push(db);
302

    
303
    pthread_cond_signal(&cond);
304

    
305
    pthread_mutex_unlock(&mutex);
306
}
307

    
308
/* -------------------------------------------------------------------------- */