1 /* Copyright 2014 Hewlett-Packard Development Company, L.P.
2 based on the Drizzle driver:
3 Copyright (C) 2009 Sun Microsystems, Inc.
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19
20 #ifdef HAVE_CONFIG_H
21 # include "config.h"
22 #endif
23
24 #ifdef HAVE_STRING_H
25 # include <string.h>
26 #endif
27 #ifdef HAVE_STRINGS_H
28 # include <strings.h>
29 #endif
30 #include <stdio.h>
31
32 #include <stdint.h>
33 #include <libattachsql-1.0/attachsql.h>
34
35 #include "sb_options.h"
36
37 #include "db_driver.h"
38
39 #define DEBUG(format, ...) do { if (db_globals.debug) log_text(LOG_DEBUG, format, __VA_ARGS__); } while (0)
40
41 /* Drizzle driver arguments */
42
43 static sb_arg_t attachsql_drv_args[] =
44 {
45 {"attachsql-host", "libAttachSQL server host", SB_ARG_TYPE_LIST, "localhost"},
46 {"attachsql-port", "libAttachSQL server port", SB_ARG_TYPE_INT, "4427"},
47 {"attachsql-socket", "libAttachSQL socket", SB_ARG_TYPE_STRING, NULL},
48 {"attachsql-user", "libAttachSQL user", SB_ARG_TYPE_STRING, ""},
49 {"attachsql-password", "libAttachSQL password", SB_ARG_TYPE_STRING, ""},
50 {"attachsql-db", "libAttachSQL database name", SB_ARG_TYPE_STRING, "sbtest"},
51 {NULL, NULL, SB_ARG_TYPE_NULL, NULL}
52 };
53
54 typedef struct
55 {
56 sb_list_t *hosts;
57 unsigned int port;
58 char *socket;
59 char *user;
60 char *password;
61 char *db;
62 } attachsql_drv_args_t;
63
64 /* AttachSQL driver capabilities
65 * At a later date we will add prepared statements to this
66 */
67
68 static drv_caps_t attachsql_drv_caps =
69 {
70 .multi_rows_insert = 1,
71 .prepared_statements = 1,
72 .auto_increment = 1,
73 .serial = 0,
74 .unsigned_int = 0,
75 };
76
77 static attachsql_drv_args_t args; /* driver args */
78
79 static sb_list_item_t *hosts_pos;
80
81 static pthread_mutex_t hosts_mutex;
82
83 /* libAttachSQL driver operations */
84
85 static int attachsql_drv_init(void);
86 static int attachsql_drv_describe(drv_caps_t *);
87 static int attachsql_drv_connect(db_conn_t *);
88 static int attachsql_drv_disconnect(db_conn_t *);
89 static int attachsql_drv_prepare(db_stmt_t *, const char *, size_t);
90 static int attachsql_drv_bind_param(db_stmt_t *, db_bind_t *, size_t);
91 static int attachsql_drv_bind_result(db_stmt_t *, db_bind_t *, size_t);
92 static db_error_t attachsql_drv_execute(db_stmt_t *, db_result_t *);
93 static int attachsql_drv_fetch(db_result_t *);
94 static int attachsql_drv_fetch_row(db_result_t *, db_row_t *);
95 static db_error_t attachsql_drv_query(db_conn_t *, const char *, size_t,
96 db_result_t *);
97 static int attachsql_drv_free_results(db_result_t *);
98 static int attachsql_drv_close(db_stmt_t *);
99 static int attachsql_drv_store_results(db_result_t *);
100 static int attachsql_drv_done(void);
101
102 /* libAttachSQL driver definition */
103
104 static db_driver_t attachsql_driver =
105 {
106 .sname = "attachsql",
107 .lname = "libAttachSQL driver",
108 .args = attachsql_drv_args,
109 .ops =
110 {
111 .init = attachsql_drv_init,
112 .describe = attachsql_drv_describe,
113 .connect = attachsql_drv_connect,
114 .disconnect = attachsql_drv_disconnect,
115 .prepare = attachsql_drv_prepare,
116 .bind_param = attachsql_drv_bind_param,
117 .bind_result = attachsql_drv_bind_result,
118 .execute = attachsql_drv_execute,
119 .fetch = attachsql_drv_fetch,
120 .fetch_row = attachsql_drv_fetch_row,
121 .free_results = attachsql_drv_free_results,
122 .close = attachsql_drv_close,
123 .query = attachsql_drv_query,
124 .store_results = attachsql_drv_store_results,
125 .done = attachsql_drv_done
126 }
127 };
128
129
130 /* Local functions */
131
132 /* Register libAttachSQL driver */
133
134
register_driver_attachsql(sb_list_t * drivers)135 int register_driver_attachsql(sb_list_t *drivers)
136 {
137 SB_LIST_ADD_TAIL(&attachsql_driver.listitem, drivers);
138
139 return 0;
140 }
141
142
143 /* libAttachSQL driver initialization */
144
145
attachsql_drv_init(void)146 int attachsql_drv_init(void)
147 {
148 args.hosts = sb_get_value_list("attachsql-host");
149 if (SB_LIST_IS_EMPTY(args.hosts))
150 {
151 log_text(LOG_FATAL, "No libAttachSQL hosts specified, aborting");
152 return 1;
153 }
154 hosts_pos = args.hosts;
155 pthread_mutex_init(&hosts_mutex, NULL);
156
157 args.port = (unsigned int)sb_get_value_int("attachsql-port");
158 args.socket = sb_get_value_string("attachsql-socket");
159 args.user = sb_get_value_string("attachsql-user");
160 args.password = sb_get_value_string("attachsql-password");
161 args.db = sb_get_value_string("attachsql-db");
162 attachsql_library_init();
163 return 0;
164 }
165
166
167 /* Describe database capabilities (possibly depending on table type) */
168
169
attachsql_drv_describe(drv_caps_t * caps)170 int attachsql_drv_describe(drv_caps_t *caps )
171 {
172 *caps = attachsql_drv_caps;
173
174 return 0;
175 }
176
177
178 /* Connect to libAttachSQL database */
179
180
attachsql_drv_connect(db_conn_t * sb_conn)181 int attachsql_drv_connect(db_conn_t *sb_conn)
182 {
183 attachsql_connect_t *con= NULL;
184 const char *host;
185 attachsql_error_t *error= NULL;
186 attachsql_return_t aret= ATTACHSQL_RETURN_NONE;
187
188 if (args.socket)
189 {
190 DEBUG("attachsql_connect_create(\"%s\", \"%s\", \"%s\", \"%s\")",
191 args.socket,
192 args.user,
193 args.password,
194 args.db);
195 con= attachsql_connect_create(args.socket,
196 0,
197 args.user,
198 args.password,
199 args.db,
200 &error);
201 } else {
202
203 pthread_mutex_lock(&hosts_mutex);
204 hosts_pos = SB_LIST_ITEM_NEXT(hosts_pos);
205 if (hosts_pos == args.hosts)
206 hosts_pos = SB_LIST_ITEM_NEXT(hosts_pos);
207 host = SB_LIST_ENTRY(hosts_pos, value_t, listitem)->data;
208 pthread_mutex_unlock(&hosts_mutex);
209
210 DEBUG("attachsql_connect_create(\"%s\", %u, \"%s\", \"%s\", \"%s\")",
211 host,
212 args.port,
213 args.user,
214 args.password,
215 args.db);
216 con= attachsql_connect_create(host,
217 args.port,
218 args.user,
219 args.password,
220 args.db,
221 &error);
222 }
223 if (con == NULL)
224 {
225 log_text(LOG_FATAL, "unable to Add libAttachSQL Connection, aborting...");
226 log_text(LOG_FATAL, "error %d: %s", attachsql_error_code(error), attachsql_error_message(error));
227 attachsql_error_free(error);
228 return 1;
229 }
230 attachsql_connect_set_option(con, ATTACHSQL_OPTION_SEMI_BLOCKING, NULL);
231
232 if (!attachsql_connect(con, &error))
233 {
234 log_text(LOG_FATAL, "unable to connect to libAttachSQL server");
235 log_text(LOG_FATAL, "error %d: %s", attachsql_error_code(error), attachsql_error_message(error));
236 attachsql_error_free(error);
237 attachsql_connect_destroy(con);
238 return 1;
239
240 }
241
242 while (aret != ATTACHSQL_RETURN_IDLE)
243 {
244 aret = attachsql_connect_poll(con, &error);
245
246 if (error)
247 {
248 log_text(LOG_FATAL, "unable to connect to libAttachSQL server");
249 log_text(LOG_FATAL, "error %d: %s", attachsql_error_code(error), attachsql_error_message(error));
250 attachsql_error_free(error);
251 attachsql_connect_destroy(con);
252 return 1;
253 }
254 }
255
256 sb_conn->ptr = con;
257
258 return 0;
259 }
260
261
262 /* Disconnect from libAttachSQL database */
263
264
attachsql_drv_disconnect(db_conn_t * sb_conn)265 int attachsql_drv_disconnect(db_conn_t *sb_conn)
266 {
267 attachsql_connect_t *con = (attachsql_connect_t *)sb_conn->ptr;
268
269 if (con != NULL)
270 {
271 DEBUG("attachsql_connect_destroy(%p)", con);
272 attachsql_connect_destroy(con);
273 }
274 return 0;
275 }
276
277
278 /* Prepare statement */
279
280
attachsql_drv_prepare(db_stmt_t * stmt,const char * query,size_t len)281 int attachsql_drv_prepare(db_stmt_t *stmt, const char *query, size_t len)
282 {
283 attachsql_connect_t *con= (attachsql_connect_t *)stmt->connection->ptr;
284 attachsql_error_t *error= NULL;
285 attachsql_return_t aret= ATTACHSQL_RETURN_NONE;
286 attachsql_statement_prepare(con, len, query, &error);
287 while(aret != ATTACHSQL_RETURN_EOF)
288 {
289 aret= attachsql_connect_poll(con, &error);
290 if (error)
291 {
292 log_text(LOG_ALERT, "libAttachSQL Prepare Failed: %u:%s", attachsql_error_code(error), attachsql_error_message(error));
293 attachsql_error_free(error);
294 return DB_ERROR_FATAL;
295 }
296 }
297
298 return 0;
299 }
300
301
302 /* Bind parameters for prepared statement */
attachsql_drv_bind_param(db_stmt_t * stmt,db_bind_t * params,size_t len)303 int attachsql_drv_bind_param(db_stmt_t *stmt, db_bind_t *params, size_t len)
304 {
305 /* libAttachSQL doesn't do this, you do this during execute
306 * this is because sysbench doesn't set the values until that time
307 */
308
309 if (stmt->bound_param != NULL)
310 free(stmt->bound_param);
311 stmt->bound_param = (db_bind_t *)malloc(len * sizeof(db_bind_t));
312 if (stmt->bound_param == NULL)
313 return 1;
314 memcpy(stmt->bound_param, params, len * sizeof(db_bind_t));
315 stmt->bound_param_len = len;
316
317 return 0;
318
319 }
320
321
322 /* Bind results for prepared statement */
attachsql_drv_bind_result(db_stmt_t * stmt,db_bind_t * params,size_t len)323 int attachsql_drv_bind_result(db_stmt_t *stmt, db_bind_t *params, size_t len)
324 {
325 (void)stmt;
326 (void)params;
327 (void)len;
328 /* libAttachSQL doesn't do this, you get after execute */
329 return 0;
330 }
331
332
333 /* Execute prepared statement */
334
335
attachsql_drv_execute(db_stmt_t * stmt,db_result_t * rs)336 db_error_t attachsql_drv_execute(db_stmt_t *stmt, db_result_t *rs)
337 {
338 (void) rs;
339 attachsql_connect_t *con= (attachsql_connect_t *)stmt->connection->ptr;
340 attachsql_return_t aret= ATTACHSQL_RETURN_NONE;
341 attachsql_error_t *error= NULL;
342
343 uint16_t i;
344 int8_t tinyint;
345 int16_t smallint;
346 int32_t normalint;
347 int64_t bigint;
348 float float_type;
349 double double_type;
350 db_time_t *time_data;
351 if (con == NULL)
352 return 1;
353
354 for (i= 0; i < stmt->bound_param_len; i++)
355 {
356 db_bind_t *param= &stmt->bound_param[i];
357 switch(param->type)
358 {
359 case DB_TYPE_TINYINT:
360 tinyint= *(int8_t*)param->buffer;
361 attachsql_statement_set_int(con, i, tinyint, NULL);
362 break;
363 case DB_TYPE_SMALLINT:
364 smallint= *(int16_t*)param->buffer;
365 attachsql_statement_set_int(con, i, smallint, NULL);
366 break;
367 case DB_TYPE_INT:
368 normalint= *(int32_t*)param->buffer;
369 attachsql_statement_set_int(con, i, normalint, NULL);
370 break;
371 case DB_TYPE_BIGINT:
372 bigint= *(int64_t*)param->buffer;
373 attachsql_statement_set_bigint(con, i, bigint, NULL);
374 break;
375 case DB_TYPE_FLOAT:
376 float_type= *(float*)param->buffer;
377 attachsql_statement_set_float(con, i, float_type, NULL);
378 break;
379 case DB_TYPE_DOUBLE:
380 double_type= *(double*)param->buffer;
381 attachsql_statement_set_double(con, i, double_type, NULL);
382 break;
383 case DB_TYPE_TIME:
384 time_data= (db_time_t*)param->buffer;
385 attachsql_statement_set_time(con, i, time_data->hour, time_data->minute, time_data->second, 0, false, NULL);
386 break;
387 case DB_TYPE_DATE:
388 case DB_TYPE_DATETIME:
389 case DB_TYPE_TIMESTAMP:
390 time_data= (db_time_t*)param->buffer;
391 attachsql_statement_set_datetime(con, i, time_data->year, time_data->month, time_data->day, time_data->hour, time_data->minute, time_data->second, 0, NULL);
392 break;
393 case DB_TYPE_CHAR:
394 case DB_TYPE_VARCHAR:
395 attachsql_statement_set_string(con, i, param->max_len, param->buffer, NULL);
396 case DB_TYPE_NONE:
397 default:
398 attachsql_statement_set_null(con, i, NULL);
399 /* Not supported */
400 }
401 }
402
403 attachsql_statement_execute(con, &error);
404
405 while(aret != ATTACHSQL_RETURN_EOF)
406 {
407 aret= attachsql_connect_poll(con, &error);
408 if (aret == ATTACHSQL_RETURN_ROW_READY)
409 {
410 return 0;
411 }
412 if (error)
413 {
414 log_text(LOG_ALERT, "libAttachSQL Execute Failed: %u:%s", attachsql_error_code(error), attachsql_error_message(error));
415 attachsql_error_free(error);
416 return DB_ERROR_FATAL;
417 }
418 }
419
420 return DB_ERROR_NONE;
421 }
422
423
424 /* Execute SQL query */
425
426
attachsql_drv_query(db_conn_t * sb_conn,const char * query,size_t len,db_result_t * rs)427 db_error_t attachsql_drv_query(db_conn_t *sb_conn, const char *query,
428 size_t len, db_result_t *rs)
429 {
430 (void) rs;
431 attachsql_connect_t *con = sb_conn->ptr;
432 unsigned int rc;
433 attachsql_error_t *error= NULL;
434 attachsql_return_t aret= ATTACHSQL_RETURN_NONE;
435
436 /* Close any previous query */
437 attachsql_query_close(con);
438
439 DEBUG("attachsql_query(%p, \"%s\", %u)",
440 con,
441 query,
442 len);
443 attachsql_query(con, len, query, 0, NULL, &error);
444
445 while((aret != ATTACHSQL_RETURN_EOF) && (aret != ATTACHSQL_RETURN_ROW_READY))
446 {
447 aret= attachsql_connect_poll(con, &error);
448
449 if (error)
450 {
451 rc= attachsql_error_code(error);
452 if (rc == 1213 || rc == 1205 || rc == 1020)
453 {
454 attachsql_error_free(error);
455 return DB_ERROR_IGNORABLE;
456 }
457 log_text(LOG_ALERT, "libAttachSQL Query Failed: %u:%s", attachsql_error_code(error), attachsql_error_message(error));
458 attachsql_error_free(error);
459 return DB_ERROR_FATAL;
460 }
461 }
462 //rs->connection->ptr= con;
463 DEBUG("attachsql_query \"%s\" returned %d", query, aret);
464
465 return DB_ERROR_NONE;
466 }
467
468
469 /* Fetch row from result set of a prepared statement */
470
471
attachsql_drv_fetch(db_result_t * rs)472 int attachsql_drv_fetch(db_result_t *rs)
473 {
474 /* NYI */
475 attachsql_connect_t *con = rs->connection->ptr;
476 size_t tmp_len;
477 uint16_t columns, col;
478 attachsql_return_t aret= ATTACHSQL_RETURN_NONE;
479 attachsql_error_t *error= NULL;
480
481 while((aret != ATTACHSQL_RETURN_EOF) && (aret != ATTACHSQL_RETURN_ROW_READY))
482 {
483 aret= attachsql_connect_poll(con, &error);
484
485 if (error)
486 {
487 log_text(LOG_ALERT, "libAttachSQL Query Failed: %u:%s", attachsql_error_code(error), attachsql_error_message(error));
488 attachsql_error_free(error);
489 return 1;
490 }
491 }
492 if (aret == ATTACHSQL_RETURN_EOF)
493 {
494 return 1;
495 }
496 attachsql_statement_row_get(con, NULL);
497 columns= attachsql_query_column_count(con);
498 for (col= 0; col < columns; col++)
499 {
500 switch (attachsql_statement_get_column_type(con, col))
501 {
502 case ATTACHSQL_COLUMN_TYPE_TINY:
503 case ATTACHSQL_COLUMN_TYPE_SHORT:
504 case ATTACHSQL_COLUMN_TYPE_LONG:
505 case ATTACHSQL_COLUMN_TYPE_YEAR:
506 case ATTACHSQL_COLUMN_TYPE_INT24:
507 attachsql_statement_get_int(con, col, &error);
508 break;
509 case ATTACHSQL_COLUMN_TYPE_LONGLONG:
510 attachsql_statement_get_bigint(con, col, &error);
511 break;
512 case ATTACHSQL_COLUMN_TYPE_FLOAT:
513 attachsql_statement_get_float(con, col, &error);
514 break;
515 case ATTACHSQL_COLUMN_TYPE_DOUBLE:
516 attachsql_statement_get_double(con, col, &error);
517 break;
518 default:
519 attachsql_statement_get_char(con, col, &tmp_len, &error);
520 break;
521 }
522 }
523 attachsql_query_row_next(con);
524
525 return 0;
526 }
527
528
529 /* Fetch row from result set of a query */
530
531
attachsql_drv_fetch_row(db_result_t * rs,db_row_t * row)532 int attachsql_drv_fetch_row(db_result_t *rs, db_row_t *row)
533 {
534 attachsql_error_t *error= NULL;
535 attachsql_return_t aret= ATTACHSQL_RETURN_NONE;
536
537 /* NYI */
538
539 attachsql_connect_t *con = rs->connection->ptr;
540
541 while((aret != ATTACHSQL_RETURN_EOF) && (aret != ATTACHSQL_RETURN_ROW_READY))
542 {
543 aret= attachsql_connect_poll(con, &error);
544
545 if (error)
546 {
547 log_text(LOG_ALERT, "libAttachSQL Query Failed: %u:%s", attachsql_error_code(error), attachsql_error_message(error));
548 attachsql_error_free(error);
549 return 1;
550 }
551 }
552 if (aret == ATTACHSQL_RETURN_EOF)
553 {
554 return 1;
555 }
556 row->ptr= attachsql_query_row_get(con, NULL);
557 attachsql_query_row_next(con);
558
559 return 0;
560 }
561
562
563 /* Store results from the last query */
564
565
attachsql_drv_store_results(db_result_t * rs)566 int attachsql_drv_store_results(db_result_t *rs)
567 {
568 int ret= 0;
569 db_row_t row;
570 /* libAttachSQL can't do things in this order */
571 while (ret == 0)
572 {
573 if (rs->statement != NULL)
574 {
575 ret= attachsql_drv_fetch(rs);
576 }
577 else
578 {
579 ret= attachsql_drv_fetch_row(rs, &row);
580 }
581 }
582
583 return DB_ERROR_NONE;
584 }
585
586
587 /* Free result set */
588
589
attachsql_drv_free_results(db_result_t * rs)590 int attachsql_drv_free_results(db_result_t *rs)
591 {
592
593 if (rs->connection->ptr != NULL)
594 {
595 DEBUG("attachsql_query_close(%p)", rs->connection->ptr);
596 attachsql_query_close(rs->connection->ptr);
597 rs->connection->ptr = NULL;
598 return 0;
599 }
600
601 return 1;
602 }
603
604
605 /* Close prepared statement */
606
607
attachsql_drv_close(db_stmt_t * stmt)608 int attachsql_drv_close(db_stmt_t *stmt)
609 {
610 attachsql_connect_t *con= (attachsql_connect_t *)stmt->connection->ptr;
611 attachsql_statement_close(con);
612
613 return 0;
614 }
615
616
617 /* Uninitialize driver */
attachsql_drv_done(void)618 int attachsql_drv_done(void)
619 {
620 return 0;
621 }
622
623