8
#include "myx_statement_parser.h"
10
#include "mysql_version.h"
11
#include "my_global.h"
13
#include "sql_string.h"
22
namespace mysql_parser
25
MyxStatementParser::MyxStatementParser(CHARSET_INFO *charset)
26
: cs(charset), eof_hit(false)
29
char_buffer= new char[CHAR_BUFFER_SIZE];
30
char_buffer_e= char_buffer_b= char_buffer + CHAR_BUFFER_SIZE;
33
MyxStatementParser::~MyxStatementParser()
38
static void replace_string(std::string &text, const std::string &from, const std::string &to)
40
std::string::size_type from_len= from.length();
41
std::string::size_type p= text.find(from);
42
while (p != std::string::npos)
44
text.replace(p, from_len, to);
45
p= text.find(from, p);
49
static bool is_empty_statement(const std::string& str)
59
int MyxStatementParser::fill_buffer(std::istream& is)
61
char *input_start= std::copy(char_buffer_b, char_buffer_e, char_buffer);
62
int len= (input_start - char_buffer);
63
is.read(input_start, CHAR_BUFFER_SIZE - len);
64
int gc= (int) is.gcount();
65
char_buffer_b= char_buffer;
66
char_buffer_e= char_buffer + len + gc;
70
int MyxStatementParser::buffer_eof(std::istream& is)
75
int MyxStatementParser::get_next_char(std::istream& is, int *len, int count_lines)
77
if(char_buffer_e - char_buffer_b < 4)
80
if(char_buffer_e == char_buffer_b)
90
if (my_mbcharlen(cs, *char_buffer_b) > 1)
92
static unsigned int mask[3]= { 0x0000FFFF, 0x00FFFFFF, 0xFFFFFFFF };
94
*len= my_ismbchar(cs, char_buffer_b, char_buffer_e);
95
c= *(unsigned int *)char_buffer_b;
96
char_buffer_b += *len;
111
if ('\n' == peek_next_char(is, &len))
116
_symbols_since_newline= 0;
119
_symbols_since_newline += *len;
127
int MyxStatementParser::peek_next_char(std::istream& is, int *len)
129
int c= get_next_char(is, len, 0);
130
char_buffer_b -= *len;
134
void MyxStatementParser::add_char_to_buffer(std::string& buffer, int c, int len) const
136
unsigned uc= (unsigned)c;
138
switch(len) // all cases fall through
141
buffer += (char)((uc & 0xFF000000) >> 24);
143
buffer += (char)((uc & 0x00FF0000) >> 16);
145
buffer += (char)((uc & 0x0000FF00) >> 8);
147
buffer += (char)((uc & 0x000000FF) >> 0);
151
void MyxStatementParser::process(std::istream& is, process_sql_statement_callback cb, void *arg, int mode)
153
static const char *kwd= "DELIMITER";
156
ParserState state= start, prevState;
157
std::string stmt_buffer;
158
std::string delim_buffer;
161
_stmt_first_line_first_symbol_pos= 0;
162
_symbols_since_newline= 0;
169
while(!buffer_eof(is) && !parser_is_stopped) {
176
c= get_next_char(is, &len);
177
while(my_isspace(cs, c) || (c == '\n') || (c == '\r')) {
178
add_char_to_buffer(stmt_buffer, c, len);
179
c= get_next_char(is, &len);
181
add_char_to_buffer(stmt_buffer, c, len);
182
if(kwd[0] == my_toupper(cs, c)) {
184
} else if(c == '`') {
187
} else if(c == '\'') {
190
} else if(c == '"') {
193
} else if((c == '/') && (peek_next_char(is, &len) == '*')) {
196
} else if((c == '-') && (peek_next_char(is, &len) == '-')) {
199
} else if(c == '#') {
202
} else if(c == delim[0]) {
211
for (int i= 1; kwd[i] != '\0'; i++) {
212
c= peek_next_char(is, &len);
213
if(my_toupper(cs, c) != kwd[i]) {
219
c= get_next_char(is, &len);
220
add_char_to_buffer(stmt_buffer, c, len);
228
c= get_next_char(is, &len);
229
add_char_to_buffer(stmt_buffer, c, len);
230
if(!my_isspace(cs, c)) {
234
c= peek_next_char(is, &len);
235
while(my_isspace(cs, c)) {
236
c= get_next_char(is, &len);
237
add_char_to_buffer(stmt_buffer, c, len);
238
c= peek_next_char(is, &len);
240
if((c == '\r') || (c == '\n')) {
241
add_char_to_buffer(stmt_buffer, c, len);
245
delim_buffer.clear();
246
_stmt_boffset+= stmt_buffer.size();
247
while((c != '\r') && (c != '\n') /*&& !my_isspace(cs, c)*/ && !buffer_eof(is))
249
c= get_next_char(is, &len);
252
c= peek_next_char(is, &len);
254
//if(delim_buffer.length() > delim.length())
256
// if(delim_buffer.compare(delim_buffer.length() - delim.length(), delim.length(), delim) == 0)
258
// delim_buffer.erase(delim_buffer.length() - delim.length());
263
if(!delim_buffer.empty())
266
for (size_t n= 0, count= delim_buffer.size(); n < count; ++n)
268
if (my_isspace(cs, delim_buffer[n]))
270
delim_buffer.resize(n);
277
c= peek_next_char(is, &len);
278
if((c != '\r') && (c != '\n'))
280
c= get_next_char(is, &len);
283
_stmt_first_line_first_symbol_pos= _symbols_since_newline;
290
c= get_next_char(is, &len);
291
while((c != strchar) && !buffer_eof(is))
293
add_char_to_buffer(stmt_buffer, c, len);
296
c= get_next_char(is, &len);
297
add_char_to_buffer(stmt_buffer, c, len);
299
c= get_next_char(is, &len);
301
add_char_to_buffer(stmt_buffer, c, len);
309
c= get_next_char(is, &len);
310
add_char_to_buffer(stmt_buffer, c, len);
317
while(!buffer_eof(is)) {
318
c= get_next_char(is, &len);
319
add_char_to_buffer(stmt_buffer, c, len);
320
if((c == '/') && (p == '*')) {
333
c= get_next_char(is, &len);
334
while((c != '\r') && (c != '\n') && !buffer_eof(is)) {
335
add_char_to_buffer(stmt_buffer, c, len);
336
c= get_next_char(is, &len);
338
add_char_to_buffer(stmt_buffer, c, len);
341
c= peek_next_char(is, &len);
342
while((c == '\r') || (c == '\n'))
344
c= get_next_char(is, &len);
345
add_char_to_buffer(stmt_buffer, c, len);
346
c= peek_next_char(is, &len);
352
c= get_next_char(is, &len);
354
add_char_to_buffer(stmt_buffer, c, len);
358
while((c != '\r') && (c != '\n') && !buffer_eof(is)) {
359
add_char_to_buffer(stmt_buffer, c, len);
360
c= get_next_char(is, &len);
362
add_char_to_buffer(stmt_buffer, c, len);
365
c= peek_next_char(is, &len);
366
while((c == '\r') || (c == '\n'))
368
c= get_next_char(is, &len);
369
add_char_to_buffer(stmt_buffer, c, len);
370
c= peek_next_char(is, &len);
376
for(size_t i= 1; i < delim.size(); i++) {
377
c= get_next_char(is, &len);
378
add_char_to_buffer(stmt_buffer, c, len);
379
if(my_toupper(cs, c) != delim[i]) {
388
// new statement is read
389
stmt_buffer.erase(stmt_buffer.length() - delim.length());
391
int stmt_boffset_inc= stmt_buffer.size() + delim.size();
392
if(!is_empty_statement(stmt_buffer))
393
cb(this, stmt_buffer.c_str(), arg);
394
_stmt_boffset+= stmt_boffset_inc;
397
_stmt_first_line_first_symbol_pos= _symbols_since_newline;
406
while(!buffer_eof(is)) {
407
c= get_next_char(is, &len);
408
add_char_to_buffer(stmt_buffer, c, len);
409
if(can_be_kwd && (kwd[0] == my_toupper(cs, c))) {
413
} else if(c == '`') {
418
} else if(c == '\'') {
423
} else if(c == '"') {
428
} else if((c == '/') && (peek_next_char(is, &len) == '*')) {
432
} else if((c == '-') && (peek_next_char(is, &len) == '-')) {
436
} else if(c == '#') {
440
} else if(c == delim[0]) {
452
if (parser_is_stopped)
454
else if(!(mode & MYX_SPM_DELIMS_REQUIRED)
455
&& (stmt_buffer.length() > 0)
456
&& !is_empty_statement(stmt_buffer))
458
int stmt_boffset_inc= stmt_buffer.size();
459
cb(this, stmt_buffer.c_str(), arg);
460
_stmt_boffset+= stmt_boffset_inc;
465
int myx_process_sql_statements(const char *sql, CHARSET_INFO *cs, process_sql_statement_callback cb, void *user_data, int mode)
467
MyxStatementParser p(cs);
468
std::istringstream tmp(sql, std::ios::in | std::ios::binary);
469
p.process(tmp, cb, user_data, mode);
474
int myx_process_sql_statements_from_file(const char *filename, CHARSET_INFO *cs, process_sql_statement_callback cb, void *user_data, int mode)
478
#if defined(__WIN__) || defined(_WIN32) || defined(_WIN64)
479
std::ios_base::open_mode om= std::ios::in | std::ios::binary;
481
wchar_t filename_[MAX_PATH+1]= {0};
482
MultiByteToWideChar(CP_UTF8, 0, filename, -1, filename_, MAX_PATH);
483
is.open(filename_, std::ios::in | std::ios::binary);
486
is.open(filename, std::ios::in | std::ios::binary);
489
// Find out size of the file and return if it doesn't contain anything.
490
is.seekg (0, std::ios::end);
491
std::streamoff length = is.tellg();
492
is.seekg (0, std::ios::beg);
493
if (length < 3) // 3 bytes to allow checking for a UTF-8 BOM.
496
// Check if the file contains a BOM (byte-order-mark). 3 characters for the UTF-8 encoded BOM
497
// +1 for the terminating 0 added by get().
500
if (((unsigned char)buffer[0] != 0xEF) || ((unsigned char)buffer[1] != 0xBB) || ((unsigned char)buffer[2] != 0xBF))
502
// Not a BOM, so reset the input pointer.
503
is.seekg (0, std::ios::beg);
506
MyxStatementParser p(cs);
507
p.process(is, cb, user_data, mode);
511
} // namespace mysql_parser