1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
|
#ifndef SQL_API_PRIVATE_H
#define SQL_API_PRIVATE_H
#include "sql-api.h"
#include "module-context.h"
enum sql_db_state {
/* not connected to database */
SQL_DB_STATE_DISCONNECTED,
/* waiting for connection attempt to succeed or fail */
SQL_DB_STATE_CONNECTING,
/* connected, allowing more queries */
SQL_DB_STATE_IDLE,
/* connected, no more queries allowed */
SQL_DB_STATE_BUSY
};
/* Minimum delay between reconnecting to same server */
#define SQL_CONNECT_MIN_DELAY 1
/* Maximum time to avoiding reconnecting to same server */
#define SQL_CONNECT_MAX_DELAY (60*30)
/* If no servers are connected but a query is requested, try reconnecting to
next server which has been disconnected longer than this (with a single
server setup this is really the "max delay" and the SQL_CONNECT_MAX_DELAY
is never used). */
#define SQL_CONNECT_RESET_DELAY 15
/* Abort connect() if it can't connect within this time. */
#define SQL_CONNECT_TIMEOUT_SECS 5
/* Abort queries after this many seconds */
#define SQL_QUERY_TIMEOUT_SECS 60
/* Default max. number of connections to create per host */
#define SQL_DEFAULT_CONNECTION_LIMIT 5
#define SQL_DB_IS_READY(db) \
((db)->state == SQL_DB_STATE_IDLE)
#define SQL_ERRSTR_NOT_CONNECTED "Not connected to database"
/* What is considered slow query */
#define SQL_SLOW_QUERY_MSEC 1000
#define SQL_QUERY_FINISHED "sql_query_finished"
#define SQL_CONNECTION_FINISHED "sql_connection_finished"
#define SQL_TRANSACTION_FINISHED "sql_transaction_finished"
#define SQL_QUERY_FINISHED_FMT "Finished query '%s' in %u msecs"
struct sql_db_module_register {
unsigned int id;
};
union sql_db_module_context {
struct sql_db_module_register *reg;
};
extern struct sql_db_module_register sql_db_module_register;
extern struct event_category event_category_sql;
struct sql_transaction_query {
struct sql_transaction_query *next;
struct sql_transaction_context *trans;
const char *query;
unsigned int *affected_rows;
};
struct sql_db_vfuncs {
struct sql_db *(*init)(const char *connect_string);
int (*init_full)(const struct sql_settings *set, struct sql_db **db_r,
const char **error);
void (*deinit)(struct sql_db *db);
void (*unref)(struct sql_db *db);
void (*wait) (struct sql_db *db);
enum sql_db_flags (*get_flags)(struct sql_db *db);
int (*connect)(struct sql_db *db);
void (*disconnect)(struct sql_db *db);
const char *(*escape_string)(struct sql_db *db, const char *string);
void (*exec)(struct sql_db *db, const char *query);
void (*query)(struct sql_db *db, const char *query,
sql_query_callback_t *callback, void *context);
struct sql_result *(*query_s)(struct sql_db *db, const char *query);
struct sql_transaction_context *(*transaction_begin)(struct sql_db *db);
void (*transaction_commit)(struct sql_transaction_context *ctx,
sql_commit_callback_t *callback,
void *context);
int (*transaction_commit_s)(struct sql_transaction_context *ctx,
const char **error_r);
void (*transaction_rollback)(struct sql_transaction_context *ctx);
void (*update)(struct sql_transaction_context *ctx, const char *query,
unsigned int *affected_rows);
const char *(*escape_blob)(struct sql_db *db,
const unsigned char *data, size_t size);
struct sql_prepared_statement *
(*prepared_statement_init)(struct sql_db *db,
const char *query_template);
void (*prepared_statement_deinit)(struct sql_prepared_statement *prep_stmt);
struct sql_statement *
(*statement_init)(struct sql_db *db, const char *query_template);
struct sql_statement *
(*statement_init_prepared)(struct sql_prepared_statement *prep_stmt);
void (*statement_abort)(struct sql_statement *stmt);
void (*statement_set_timestamp)(struct sql_statement *stmt,
const struct timespec *ts);
void (*statement_bind_str)(struct sql_statement *stmt,
unsigned int column_idx, const char *value);
void (*statement_bind_binary)(struct sql_statement *stmt,
unsigned int column_idx, const void *value,
size_t value_size);
void (*statement_bind_int64)(struct sql_statement *stmt,
unsigned int column_idx, int64_t value);
void (*statement_query)(struct sql_statement *stmt,
sql_query_callback_t *callback, void *context);
struct sql_result *(*statement_query_s)(struct sql_statement *stmt);
void (*update_stmt)(struct sql_transaction_context *ctx,
struct sql_statement *stmt,
unsigned int *affected_rows);
};
struct sql_db {
const char *name;
enum sql_db_flags flags;
int refcount;
struct sql_db_vfuncs v;
ARRAY(union sql_db_module_context *) module_contexts;
void (*state_change_callback)(struct sql_db *db,
enum sql_db_state prev_state,
void *context);
void *state_change_context;
struct event *event;
HASH_TABLE(char *, struct sql_prepared_statement *) prepared_stmt_hash;
enum sql_db_state state;
/* last time we started connecting to this server
(which may or may not have succeeded) */
time_t last_connect_try;
unsigned int connect_delay;
unsigned int connect_failure_count;
struct timeout *to_reconnect;
uint64_t succeeded_queries;
uint64_t failed_queries;
/* includes both succeeded and failed */
uint64_t slow_queries;
bool no_reconnect:1;
};
struct sql_result_vfuncs {
void (*free)(struct sql_result *result);
int (*next_row)(struct sql_result *result);
unsigned int (*get_fields_count)(struct sql_result *result);
const char *(*get_field_name)(struct sql_result *result,
unsigned int idx);
int (*find_field)(struct sql_result *result, const char *field_name);
const char *(*get_field_value)(struct sql_result *result,
unsigned int idx);
const unsigned char *
(*get_field_value_binary)(struct sql_result *result,
unsigned int idx,
size_t *size_r);
const char *(*find_field_value)(struct sql_result *result,
const char *field_name);
const char *const *(*get_values)(struct sql_result *result);
const char *(*get_error)(struct sql_result *result);
void (*more)(struct sql_result **result, bool async,
sql_query_callback_t *callback, void *context);
};
struct sql_prepared_statement {
struct sql_db *db;
int refcount;
char *query_template;
};
struct sql_statement {
struct sql_db *db;
pool_t pool;
const char *query_template;
ARRAY_TYPE(const_string) args;
};
struct sql_field_map {
enum sql_field_type type;
size_t offset;
};
struct sql_result {
struct sql_result_vfuncs v;
int refcount;
struct sql_db *db;
const struct sql_field_def *fields;
unsigned int map_size;
struct sql_field_map *map;
void *fetch_dest;
struct event *event;
size_t fetch_dest_size;
enum sql_result_error_type error_type;
bool failed:1;
bool failed_try_retry:1;
bool callback:1;
};
struct sql_transaction_context {
struct sql_db *db;
struct event *event;
/* commit() must use this query list if head is non-NULL. */
struct sql_transaction_query *head, *tail;
};
ARRAY_DEFINE_TYPE(sql_drivers, const struct sql_db *);
extern ARRAY_TYPE(sql_drivers) sql_drivers;
extern struct sql_result sql_not_connected_result;
void sql_init_common(struct sql_db *db);
struct sql_db *
driver_sqlpool_init(const char *connect_string, const struct sql_db *driver);
int driver_sqlpool_init_full(const struct sql_settings *set, const struct sql_db *driver,
struct sql_db **db_r, const char **error_r);
void sql_db_set_state(struct sql_db *db, enum sql_db_state state);
void sql_transaction_add_query(struct sql_transaction_context *ctx, pool_t pool,
const char *query, unsigned int *affected_rows);
const char *sql_statement_get_query(struct sql_statement *stmt);
void sql_connection_log_finished(struct sql_db *db);
struct event_passthrough *
sql_query_finished_event(struct sql_db *db, struct event *event, const char *query,
bool success, int *duration_r);
struct event_passthrough *sql_transaction_finished_event(struct sql_transaction_context *ctx);
#endif
|