81
static unsigned char *quotify (const unsigned char *src, size_t srclen,
82
unsigned char *dst, size_t dstlen)
88
static void quotify(const string &src, string &dst)
84
90
static const char hexit[]= { '0', '1', '2', '3', '4', '5', '6', '7',
85
91
'8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
86
size_t dst_ndx; /* ndx down the dst */
87
size_t src_ndx; /* ndx down the src */
92
for (dst_ndx= 0,src_ndx= 0; src_ndx < srclen; src_ndx++)
92
string::const_iterator src_iter;
94
for (src_iter= src.begin(); src_iter < src.end(); ++src_iter)
95
/* Worst case, need 5 dst bytes for the next src byte.
96
backslash x hexit hexit null
97
so if not enough room, just terminate the string and return
99
if ((dstlen - dst_ndx) < 5)
101
dst[dst_ndx]= (unsigned char)0x00;
105
if (src[src_ndx] > 0x7f)
107
// pass thru high bit characters, they are non-ASCII UTF8 Unicode
108
dst[dst_ndx++]= src[src_ndx];
110
else if (src[src_ndx] == 0x00) // null
112
dst[dst_ndx++]= 0x5C; dst[dst_ndx++]= (unsigned char) '0';
114
else if (src[src_ndx] == 0x07) // bell
116
dst[dst_ndx++]= 0x5C; dst[dst_ndx++]= (unsigned char) 'a';
118
else if (src[src_ndx] == 0x08) // backspace
120
dst[dst_ndx++]= 0x5C; dst[dst_ndx++]= (unsigned char) 'b';
122
else if (src[src_ndx] == 0x09) // horiz tab
124
dst[dst_ndx++]= 0x5C; dst[dst_ndx++]= (unsigned char) 't';
126
else if (src[src_ndx] == 0x0a) // line feed
128
dst[dst_ndx++]= 0x5C; dst[dst_ndx++]= (unsigned char) 'n';
130
else if (src[src_ndx] == 0x0b) // vert tab
132
dst[dst_ndx++]= 0x5C; dst[dst_ndx++]= (unsigned char) 'v';
134
else if (src[src_ndx] == 0x0c) // formfeed
136
dst[dst_ndx++]= 0x5C; dst[dst_ndx++]= (unsigned char) 'f';
138
else if (src[src_ndx] == 0x0d) // carrage return
140
dst[dst_ndx++]= 0x5C; dst[dst_ndx++]= (unsigned char) 'r';
142
else if (src[src_ndx] == 0x1b) // escape
144
dst[dst_ndx++]= 0x5C; dst[dst_ndx++]= (unsigned char) 'e';
146
else if (src[src_ndx] == 0x22) // quotation mark
148
dst[dst_ndx++]= 0x5C; dst[dst_ndx++]= 0x22;
150
else if (src[src_ndx] == 0x2C) // comma
152
dst[dst_ndx++]= 0x5C; dst[dst_ndx++]= 0x2C;
154
else if (src[src_ndx] == 0x5C) // backslash
156
dst[dst_ndx++]= 0x5C; dst[dst_ndx++]= 0x5C;
158
else if ((src[src_ndx] < 0x20) || (src[src_ndx] == 0x7F)) // other unprintable ASCII
160
dst[dst_ndx++]= 0x5C;
161
dst[dst_ndx++]= (unsigned char) 'x';
162
dst[dst_ndx++]= hexit[(src[src_ndx] >> 4) & 0x0f];
163
dst[dst_ndx++]= hexit[src[src_ndx] & 0x0f];
96
if (static_cast<unsigned char>(*src_iter) > 0x7f)
98
dst.push_back(*src_iter);
100
else if (*src_iter == 0x00) // null
102
dst.push_back(ESCAPE_CHAR); dst.push_back('0');
104
else if (*src_iter == 0x07) // bell
106
dst.push_back(ESCAPE_CHAR); dst.push_back('a');
108
else if (*src_iter == 0x08) // backspace
110
dst.push_back(ESCAPE_CHAR); dst.push_back('b');
112
else if (*src_iter == 0x09) // horiz tab
114
dst.push_back(ESCAPE_CHAR); dst.push_back('t');
116
else if (*src_iter == 0x0a) // line feed
118
dst.push_back(ESCAPE_CHAR); dst.push_back('n');
120
else if (*src_iter == 0x0b) // vert tab
122
dst.push_back(ESCAPE_CHAR); dst.push_back('v');
124
else if (*src_iter == 0x0c) // formfeed
126
dst.push_back(ESCAPE_CHAR); dst.push_back('f');
128
else if (*src_iter == 0x0d) // carrage return
130
dst.push_back(ESCAPE_CHAR); dst.push_back('r');
132
else if (*src_iter == 0x1b) // escape
134
dst.push_back(ESCAPE_CHAR); dst.push_back('e');
136
else if (*src_iter == 0x22) // quotation mark
138
dst.push_back(ESCAPE_CHAR); dst.push_back(0x22);
140
else if (*src_iter == SEPARATOR_CHAR)
142
dst.push_back(ESCAPE_CHAR); dst.push_back(SEPARATOR_CHAR);
144
else if (*src_iter == ESCAPE_CHAR)
146
dst.push_back(ESCAPE_CHAR); dst.push_back(ESCAPE_CHAR);
148
else if ((*src_iter < 0x20) || (*src_iter == 0x7F)) // other unprintable ASCII
150
dst.push_back(ESCAPE_CHAR);
152
dst.push_back(hexit[(*src_iter >> 4) & 0x0f]);
153
dst.push_back(hexit[*src_iter & 0x0f]);
165
155
else // everything else
167
dst[dst_ndx++]= src[src_ndx];
157
dst.push_back(*src_iter);
278
262
int this_pcre_rc;
279
this_pcre_rc = pcre_exec(re, pe, session->query.c_str(), session->query.length(), 0, 0, NULL, 0);
263
this_pcre_rc= pcre_exec(re, pe, session->query.c_str(), session->query.length(), 0, 0, NULL, 0);
280
264
if (this_pcre_rc < 0)
284
268
// buffer to quotify the query
285
unsigned char qs[255];
271
// Since quotify() builds the quoted string incrementally, we can
272
// avoid some reallocating if we reserve some space up front.
273
qs.reserve(session->getQueryLength());
275
quotify(session->getQueryString(), qs);
287
277
// to avoid trying to printf %s something that is potentially NULL
288
278
const char *dbs= session->db.empty() ? "" : session->db.c_str();
291
snprintf(msgbuf, MAX_MSG_LEN,
292
"%"PRIu64",%"PRIu64",%"PRIu64",\"%.*s\",\"%s\",\"%.*s\","
293
"%"PRIu64",%"PRIu64",%"PRIu64",%"PRIu64",%"PRIu64","
294
"%"PRIu32",%"PRIu32",%"PRIu32",\"%s\"\n",
297
session->getQueryId(),
298
// dont need to quote the db name, always CSV safe
299
(int)session->db.length(), dbs,
300
// do need to quote the query
301
quotify((unsigned char *)session->getQueryString().c_str(),
302
session->getQueryLength(), qs, sizeof(qs)),
303
// command_name is defined in drizzled/sql_parse.cc
304
// dont need to quote the command name, always CSV safe
305
(int)command_name[session->command].length,
306
command_name[session->command].str,
307
// counters are at end, to make it easier to add more
308
(t_mark - session->getConnectMicroseconds()),
309
(t_mark - session->start_utime),
310
(t_mark - session->utime_after_lock),
311
session->sent_row_count,
312
session->examined_row_count,
314
session->total_warn_count,
315
session->getServerId(),
282
% session->getQueryId()
285
% command_name[session->command].str
286
% (t_mark - session->getConnectMicroseconds())
287
% (t_mark - session->start_utime)
288
% (t_mark - session->utime_after_lock)
289
% session->sent_row_count
290
% session->examined_row_count
292
% session->total_warn_count
293
% session->getServerId()
296
string msgbuf= formatter.str();
319
298
// a single write has a kernel thread lock, thus no need mutex guard this
320
wrv= write(fd, msgbuf, msgbuf_len);
321
assert(wrv == msgbuf_len);
299
wrv= write(fd, msgbuf.c_str(), msgbuf.length());
300
assert(wrv == msgbuf.length());
327
306
static Logging_query *handler= NULL;
329
static int logging_query_plugin_init(drizzled::plugin::Context &context)
308
static int logging_query_plugin_init(drizzled::module::Context &context)
311
const module::option_map &vm= context.getOptions();
312
if (vm.count("threshold-slow"))
314
if (sysvar_logging_query_threshold_slow > UINT32_MAX)
316
errmsg_printf(ERRMSG_LVL_ERROR, _("Invalid value for threshold-slow"));
321
if (vm.count("threshold-big-resultset"))
323
if (sysvar_logging_query_threshold_big_resultset > UINT32_MAX)
325
errmsg_printf(ERRMSG_LVL_ERROR, _("Invalid value for threshold-big-resultset"));
330
if (vm.count("threshold-big-examined"))
332
if (sysvar_logging_query_threshold_big_examined > UINT32_MAX)
334
errmsg_printf(ERRMSG_LVL_ERROR, _("Invalid value for threshold-big-examined"));
331
338
handler= new Logging_query();
332
339
context.add(handler);
344
static void init_options(drizzled::module::option_context &context)
347
po::value<bool>(&sysvar_logging_query_enable)->default_value(false)->zero_tokens(),
348
N_("Enable logging to CSV file"));
349
context("threshold-slow",
350
po::value<unsigned long>(&sysvar_logging_query_threshold_slow)->default_value(0),
351
N_("Threshold for logging slow queries, in microseconds"));
352
context("threshold-big-resultset",
353
po::value<unsigned long>(&sysvar_logging_query_threshold_big_resultset)->default_value(0),
354
N_("Threshold for logging big queries, for rows returned"));
355
context("threshold-big-examined",
356
po::value<unsigned long>(&sysvar_logging_query_threshold_big_examined)->default_value(0),
357
N_("Threshold for logging big queries, for rows examined"));
337
360
static DRIZZLE_SYSVAR_BOOL(
339
362
sysvar_logging_query_enable,