Add support for result set retrieving for MySQL and PostgreSQL drivers and export it to the new Lua SQL API.
365 lines
11 KiB
C
365 lines
11 KiB
C
/* Copyright (C) 2004 MySQL AB
|
|
Copyright (C) 2004-2017 Alexey Kopytov <akopytov@gmail.com>
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 2 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
*/
|
|
|
|
#ifndef DB_DRIVER_H
|
|
#define DB_DRIVER_H
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
# include "config.h"
|
|
#endif
|
|
|
|
#include "sysbench.h"
|
|
#include "sb_list.h"
|
|
#include "sb_histogram.h"
|
|
#include "sb_util.h"
|
|
#include "ck_pr.h"
|
|
|
|
/* Prepared statements usage modes */
|
|
|
|
typedef enum
|
|
{
|
|
DB_PS_MODE_AUTO,
|
|
DB_PS_MODE_DISABLE,
|
|
} db_ps_mode_t;
|
|
|
|
/* Global DB API options */
|
|
|
|
typedef struct
|
|
{
|
|
db_ps_mode_t ps_mode; /* Requested prepared statements usage mode */
|
|
char *driver; /* Requested database driver */
|
|
unsigned char debug; /* debug flag */
|
|
} db_globals_t;
|
|
|
|
/* Driver capabilities definition */
|
|
|
|
typedef struct
|
|
{
|
|
char multi_rows_insert; /* 1 if database supports multi-row inserts */
|
|
char prepared_statements; /* 1 if database supports prepared statements */
|
|
char auto_increment; /* 1 if database supports AUTO_INCREMENT clause */
|
|
char needs_commit; /* 1 if database needs explicit commit after INSERTs */
|
|
char serial; /* 1 if database supports SERIAL clause */
|
|
char unsigned_int; /* 1 if database supports UNSIGNED INTEGER types */
|
|
} drv_caps_t;
|
|
|
|
/* Database errors definition */
|
|
|
|
typedef enum
|
|
{
|
|
DB_ERROR_NONE, /* no error(s) */
|
|
DB_ERROR_IGNORABLE, /* error should be ignored as defined by command
|
|
line arguments or a custom error handler */
|
|
DB_ERROR_FATAL /* non-ignorable error */
|
|
} db_error_t;
|
|
|
|
|
|
/* Available buffer types (for parameters binding) */
|
|
|
|
typedef enum
|
|
{
|
|
DB_TYPE_NONE,
|
|
DB_TYPE_TINYINT,
|
|
DB_TYPE_SMALLINT,
|
|
DB_TYPE_INT,
|
|
DB_TYPE_BIGINT,
|
|
DB_TYPE_FLOAT,
|
|
DB_TYPE_DOUBLE,
|
|
DB_TYPE_TIME,
|
|
DB_TYPE_DATE,
|
|
DB_TYPE_DATETIME,
|
|
DB_TYPE_TIMESTAMP,
|
|
DB_TYPE_CHAR,
|
|
DB_TYPE_VARCHAR
|
|
} db_bind_type_t;
|
|
|
|
|
|
/* Structure used to represent DATE, TIME, DATETIME and TIMESTAMP values */
|
|
|
|
typedef struct
|
|
{
|
|
unsigned int year;
|
|
unsigned int month;
|
|
unsigned int day;
|
|
unsigned int hour;
|
|
unsigned int minute;
|
|
unsigned int second;
|
|
} db_time_t;
|
|
|
|
|
|
/* Structure used to bind data for prepared statements */
|
|
|
|
typedef struct
|
|
{
|
|
db_bind_type_t type;
|
|
void *buffer;
|
|
unsigned long *data_len;
|
|
unsigned long max_len;
|
|
char *is_null;
|
|
} db_bind_t;
|
|
|
|
/* Forward declarations */
|
|
|
|
struct db_conn;
|
|
struct db_stmt;
|
|
struct db_result;
|
|
struct db_row;
|
|
|
|
/* Driver operations definition */
|
|
|
|
typedef int drv_op_init(void);
|
|
typedef int drv_op_thread_init(int);
|
|
typedef int drv_op_describe(drv_caps_t *);
|
|
typedef int drv_op_connect(struct db_conn *);
|
|
typedef int drv_op_disconnect(struct db_conn *);
|
|
typedef int drv_op_prepare(struct db_stmt *, const char *, size_t);
|
|
typedef int drv_op_bind_param(struct db_stmt *, db_bind_t *, size_t);
|
|
typedef int drv_op_bind_result(struct db_stmt *, db_bind_t *, size_t);
|
|
typedef db_error_t drv_op_execute(struct db_stmt *, struct db_result *);
|
|
typedef int drv_op_fetch(struct db_result *);
|
|
typedef int drv_op_fetch_row(struct db_result *, struct db_row *);
|
|
typedef db_error_t drv_op_query(struct db_conn *, const char *, size_t,
|
|
struct db_result *);
|
|
typedef int drv_op_free_results(struct db_result *);
|
|
typedef int drv_op_close(struct db_stmt *);
|
|
typedef int drv_op_thread_done(int);
|
|
typedef int drv_op_done(void);
|
|
|
|
typedef struct
|
|
{
|
|
drv_op_init *init; /* initializate driver */
|
|
drv_op_thread_init *thread_init; /* thread-local driver initialization */
|
|
drv_op_describe *describe; /* describe database capabilities */
|
|
drv_op_connect *connect; /* connect to database */
|
|
drv_op_disconnect *disconnect; /* disconnect from database */
|
|
drv_op_prepare *prepare; /* prepare statement */
|
|
drv_op_bind_param *bind_param; /* bind params for prepared statement */
|
|
drv_op_bind_result *bind_result; /* bind results for prepared statement */
|
|
drv_op_execute *execute; /* execute prepared statement */
|
|
drv_op_fetch *fetch; /* fetch row for prepared statement */
|
|
drv_op_fetch_row *fetch_row; /* fetch row for queries */
|
|
drv_op_free_results *free_results; /* free result set */
|
|
drv_op_close *close; /* close prepared statement */
|
|
drv_op_query *query; /* execute non-prepared statement */
|
|
drv_op_thread_done *thread_done; /* thread-local driver deinitialization */
|
|
drv_op_done *done; /* uninitialize driver */
|
|
} drv_ops_t;
|
|
|
|
/* Database driver definition */
|
|
|
|
typedef struct
|
|
{
|
|
const char *sname; /* short name */
|
|
const char *lname; /* long name */
|
|
sb_arg_t *args; /* driver command line arguments */
|
|
drv_ops_t ops; /* driver operations */
|
|
|
|
sb_list_item_t listitem; /* can be linked in a list */
|
|
bool initialized;
|
|
pthread_mutex_t mutex;
|
|
} db_driver_t;
|
|
|
|
/* Query type for statistics */
|
|
|
|
typedef enum {
|
|
DB_STAT_OTHER,
|
|
DB_STAT_READ,
|
|
DB_STAT_WRITE,
|
|
DB_STAT_TRX,
|
|
DB_STAT_ERROR,
|
|
DB_STAT_RECONNECT,
|
|
DB_STAT_MAX
|
|
} db_stat_type_t;
|
|
|
|
/* Row value definition */
|
|
|
|
typedef struct {
|
|
uint32_t len; /* Value length */
|
|
const char *ptr; /* Value string */
|
|
} db_value_t;
|
|
|
|
/* Result set row definition */
|
|
|
|
typedef struct db_row
|
|
{
|
|
void *ptr; /* Driver-specific row data */
|
|
db_value_t *values; /* Array of column values */
|
|
} db_row_t;
|
|
|
|
/* Result set definition */
|
|
|
|
typedef struct db_result
|
|
{
|
|
db_stat_type_t stat_type; /* Statistical counter type */
|
|
uint32_t nrows; /* Number of affected rows */
|
|
uint32_t nfields; /* Number of fields */
|
|
struct db_stmt *statement; /* Pointer to prepared statement (if used) */
|
|
void *ptr; /* Pointer to driver-specific data */
|
|
db_row_t row; /* Last fetched row */
|
|
} db_result_t;
|
|
|
|
typedef enum {
|
|
DB_CONN_READY,
|
|
DB_CONN_RESULT_SET,
|
|
DB_CONN_INVALID
|
|
} db_conn_state_t;
|
|
|
|
/* Database connection structure */
|
|
|
|
typedef struct db_conn
|
|
{
|
|
db_driver_t *driver; /* DB driver for this connection */
|
|
void *ptr; /* Driver-specific data */
|
|
db_error_t db_errno; /* Driver-independent error code */
|
|
db_conn_state_t state; /* Connection state */
|
|
db_result_t rs; /* Result set */
|
|
int thread_id; /* Thread this connection belongs to */
|
|
|
|
unsigned int bulk_cnt; /* Current number of rows in bulk insert buffer */
|
|
unsigned int bulk_buflen; /* Current length of bulk_buffer */
|
|
char *bulk_buffer; /* Bulk insert query buffer */
|
|
unsigned int bulk_ptr; /* Current position in bulk_buffer */
|
|
unsigned int bulk_values; /* Save value of bulk_ptr */
|
|
unsigned int bulk_commit_cnt; /* Current value of uncommitted rows */
|
|
unsigned int bulk_commit_max; /* Maximum value of uncommitted rows */
|
|
|
|
char pad[SB_CACHELINE_PAD(sizeof(void *) * 3 + sizeof(db_error_t) +
|
|
sizeof(db_conn_state_t) +
|
|
sizeof(db_result_t) +
|
|
sizeof(int) * 8)];
|
|
} db_conn_t;
|
|
|
|
/* Prepared statement definition */
|
|
|
|
typedef struct db_stmt
|
|
{
|
|
db_conn_t *connection; /* Connection which this statement belongs to */
|
|
char *query; /* Query string for emulated PS */
|
|
db_bind_t *bound_param; /* Array of bound parameters for emulated PS */
|
|
unsigned int bound_param_len; /* Length of the bound_param array */
|
|
db_bind_t *bound_res; /* Array of bound results for emulated PS */
|
|
db_bind_t *bound_res_len; /* Length of the bound_res array */
|
|
char emulated; /* Should this statement be emulated? */
|
|
db_stat_type_t stat_type; /* Query type */
|
|
void *ptr; /* Pointer to driver-specific data structure */
|
|
} db_stmt_t;
|
|
|
|
/*
|
|
sizeof(db_stats_t) must be multiple of CK_MD_CACHELINE to avoid cache
|
|
line sharing.
|
|
*/
|
|
typedef uint64_t
|
|
db_stats_t[SB_ALIGN(DB_STAT_MAX * sizeof(uint64_t), CK_MD_CACHELINE) /
|
|
sizeof(uint64_t)];
|
|
|
|
extern db_globals_t db_globals;
|
|
extern db_stats_t *thread_stats;
|
|
|
|
/* Database abstraction layer calls */
|
|
|
|
int db_register(void);
|
|
|
|
void db_print_help(void);
|
|
|
|
db_driver_t *db_create(const char *);
|
|
|
|
int db_destroy(db_driver_t *);
|
|
|
|
int db_describe(db_driver_t *, drv_caps_t *);
|
|
|
|
db_conn_t *db_connection_create(db_driver_t *);
|
|
|
|
int db_connection_close(db_conn_t *);
|
|
|
|
void db_connection_free(db_conn_t *con);
|
|
|
|
db_stmt_t *db_prepare(db_conn_t *, const char *, size_t);
|
|
|
|
int db_bind_param(db_stmt_t *, db_bind_t *, size_t);
|
|
|
|
int db_bind_result(db_stmt_t *, db_bind_t *, size_t);
|
|
|
|
db_result_t *db_execute(db_stmt_t *);
|
|
|
|
db_row_t *db_fetch_row(db_result_t *);
|
|
|
|
db_result_t *db_query(db_conn_t *, const char *, size_t len);
|
|
|
|
int db_free_results(db_result_t *);
|
|
|
|
int db_store_results(db_result_t *);
|
|
|
|
int db_close(db_stmt_t *);
|
|
|
|
void db_done(void);
|
|
|
|
int db_print_value(db_bind_t *, char *, int);
|
|
|
|
/* Initialize multi-row insert operation */
|
|
int db_bulk_insert_init(db_conn_t *, const char *, size_t);
|
|
|
|
/* Add row to multi-row insert operation */
|
|
int db_bulk_insert_next(db_conn_t *, const char *, size_t);
|
|
|
|
/* Finish multi-row insert operation */
|
|
int db_bulk_insert_done(db_conn_t *);
|
|
|
|
/* Print database-specific test stats */
|
|
void db_print_stats(sb_stat_t type);
|
|
|
|
/* Associate connection with a thread (required only for statistics */
|
|
void db_set_thread(db_conn_t *, int);
|
|
|
|
/* Initialize per-thread stats */
|
|
int db_thread_stat_init(void);
|
|
|
|
/* Increment a given stat counter for a connection */
|
|
static inline void db_thread_stat_inc(int id, db_stat_type_t type)
|
|
{
|
|
ck_pr_inc_64(&thread_stats[id][type]);
|
|
}
|
|
|
|
|
|
/* DB drivers registrars */
|
|
|
|
#ifdef USE_MYSQL
|
|
int register_driver_mysql(sb_list_t *);
|
|
#endif
|
|
|
|
#ifdef USE_DRIZZLE
|
|
int register_driver_drizzle(sb_list_t *);
|
|
#endif
|
|
|
|
#ifdef USE_ATTACHSQL
|
|
int register_driver_attachsql(sb_list_t *);
|
|
#endif
|
|
|
|
#ifdef USE_DRIZZLECLIENT
|
|
int register_driver_drizzleclient(sb_list_t *);
|
|
#endif
|
|
|
|
#ifdef USE_ORACLE
|
|
int register_driver_oracle(sb_list_t *);
|
|
#endif
|
|
|
|
#ifdef USE_PGSQL
|
|
int register_driver_pgsql(sb_list_t *);
|
|
#endif
|
|
|
|
#endif /* DB_DRIVER_H */
|