2
#define WIN32_LEAN_AND_MEAN
9
#include "myx_sql_tree_item.h"
10
#include "myx_lex_helpers.h"
16
#define strcasecmp _stricmp
17
#define strncasecmp strnicmp
21
namespace mysql_parser
24
const char* find_cstr_in_array_ci(const char *arr[], size_t arr_size, const char* str)
26
for (size_t n= 0; n < arr_size; ++n)
27
if (are_cstrings_eq_ci(arr[n], str))
31
const char* find_str_in_array_ci(const char *arr[], size_t arr_size, const std::string &str)
33
return find_cstr_in_array_ci(arr, arr_size, str.c_str());
37
bool are_cstrings_eq(const char *str1, const char *str2, bool case_sensitive)
40
return ((str1 == str2) ||
42
((NULL != str1) && (NULL != str2)) &&
43
(strlen(str1) == strlen(str2)) &&
44
(0 == strcmp(str1, str2))
47
return are_cstrings_eq_ci(str1, str2);
49
bool are_strings_eq(const std::string &str1, const std::string &str2, bool case_sensitive)
51
return are_cstrings_eq(str1.c_str(), str2.c_str(), case_sensitive);
55
bool are_cstrings_eq_ci(const char *str1, const char *str2)
57
return ((str1 == str2) ||
59
((NULL != str1) && (NULL != str2)) &&
60
(toupper(str1[0]) == toupper(str2[0])) &&
61
(strlen(str1) == strlen(str2)) &&
62
(0 == strncasecmp(str1, str2, strlen(str1)))
65
bool are_strings_eq_ci(const std::string &str1, const std::string &str2)
67
return are_cstrings_eq_ci(str1.c_str(), str2.c_str());
71
SqlAstNode::SubItemList SqlAstTerminalNode::_empty_list;
74
MYX_PUBLIC_FUNC std::ostream& operator << (std::ostream& os, const SqlAstNode& item)
76
if (item.value()[0] != '\0')
78
sql::symbol item_name= item.name();
79
std::string item_value= item.value();
80
os << "<elem name='" << (item_name ? sql::symbol_names[item_name] : "") << "' value='" << item_value.c_str() << "'>";
83
os << "<elem name='" << item.name() << "'>";
86
SqlAstNode::SubItemList *subitems= item.subitems();
88
for (SqlAstNode::SubItemList::const_iterator i= subitems->begin(), i_end= subitems->end(); i != i_end; ++i)
98
std::list<SqlAstNode *> SqlAstStatics::_ast_nodes;
99
const SqlAstNode * SqlAstStatics::_tree= NULL;
100
const char * SqlAstStatics::_sql_statement= NULL;
101
bool SqlAstStatics::is_ast_generation_enabled= true;
102
SqlAstTerminalNode SqlAstStatics::last_terminal_node(NULL, 0, -1, -1, -1);
103
SqlAstTerminalNode SqlAstStatics::first_terminal_node(NULL, 0, -1, -1, -1);
106
void SqlAstStatics::tree(const SqlAstNode *tree)
109
mysql_parser::tree= _tree;
113
void SqlAstStatics::cleanup_ast_nodes()
115
for (std::list<SqlAstNode*>::iterator i= _ast_nodes.begin(), i_end= _ast_nodes.end(); i != i_end; ++i)
119
//_sql_statement= NULL;
123
SqlAstNode::SqlAstNode(sql::symbol name, const char *value, int value_length, int stmt_lineno, int stmt_boffset, int stmt_eoffset, SubItemList *items)
126
_value((value) ? new std::string(value) : NULL),
127
_value_length(value_length),
128
_stmt_lineno(stmt_lineno),
129
_stmt_boffset(stmt_boffset),
130
_stmt_eoffset(stmt_eoffset),
133
if (-1 != _stmt_eoffset && (_stmt_boffset + _value_length) > _stmt_eoffset)
134
_stmt_eoffset= _stmt_boffset + _value_length;
138
SqlAstNode::~SqlAstNode()
143
std::string SqlAstNode::value() const
147
else if (_value_length)
148
return std::string(SqlAstStatics::sql_statement() + _stmt_boffset, _value_length);
154
const SqlAstNode * SqlAstNode::left_most_subitem() const
156
return (_subitems) ? (*_subitems->begin())->left_most_subitem() : this;
160
const SqlAstNode * SqlAstNode::right_most_subitem() const
162
return (_subitems) ? (*_subitems->rend())->right_most_subitem() : this;
166
int SqlAstNode::stmt_lineno() const
168
if ((-1 == _stmt_lineno) && _subitems)
169
return (*_subitems->begin())->stmt_lineno();
174
int SqlAstNode::stmt_boffset() const
176
if ((-1 == _stmt_boffset) && _subitems)
177
return (*_subitems->begin())->stmt_boffset();
178
return _stmt_boffset;
182
int SqlAstNode::stmt_eoffset() const
184
if ((-1 == _stmt_eoffset) && _subitems)
185
return (*_subitems->rbegin())->stmt_eoffset();
186
return _stmt_eoffset;
191
Tries to find sequence of items begining from subitem (if specified, otherwise from 1st subitem).
192
Returns last item from found sequence.
194
const SqlAstNode * SqlAstNode::subseq__(const SqlAstNode *subitem, sql::symbol name, va_list args) const
196
SqlAstNode::SubItemList::iterator i= _subitems->begin();
197
SqlAstNode::SubItemList::iterator i_end= _subitems->end();
199
// skip some elements if start subitem is specified
201
i= std::find(i, i_end, subitem);
203
for (; i != i_end; ++i)
206
if (!subitem->name_equals(name))
209
name= (sql::symbol)va_arg(args, int);
211
name= va_arg(args, sql::symbol);
214
return subitem; // return last item from found sequence
221
const SqlAstNode * SqlAstNode::subseq_(sql::symbol name, ...) const
224
va_start(args, name);
225
const SqlAstNode * subitem= subseq__(NULL, name, args);
231
const SqlAstNode * SqlAstNode::subseq_(const SqlAstNode *subitem, sql::symbol name, ...) const
234
va_start(args, name);
235
subitem= subseq__(subitem, name, args);
242
Tries to find sequence within whole range of children items starting from 'subitem' (if specified, otherwise from 1st subitem).
243
Returns last item from found sequence.
245
const SqlAstNode * SqlAstNode::find_subseq__(const SqlAstNode *subitem, sql::symbol name, va_list args) const
247
SqlAstNode::SubItemList::iterator i= _subitems->begin();
248
SqlAstNode::SubItemList::iterator i_end= _subitems->end();
250
// skip some elements if start subitem is specified
252
i= std::find(i, i_end, subitem);
254
for (; i != i_end; ++i)
257
if (subitem->name_equals(name) && (subitem= subseq__(subitem, name, args)))
258
return subitem; // return last item from found sequence
265
const SqlAstNode * SqlAstNode::find_subseq_(sql::symbol name, ...) const
268
va_start(args, name);
269
const SqlAstNode * subitem= find_subseq__(NULL, name, args);
275
const SqlAstNode * SqlAstNode::find_subseq_(const SqlAstNode *subitem, sql::symbol name, ...) const
278
va_start(args, name);
279
subitem= find_subseq__(subitem, name, args);
286
Tries to find sequence of items begining from subitem (if specified, otherwise from 1st subitem).
287
Returns last item from found sequence.
289
const SqlAstNode * SqlAstNode::check_words(sql::symbol words[], size_t words_count, const SqlAstNode *start_item) const
291
const SqlAstNode *result= NULL;
293
if (NULL != _subitems)
295
SqlAstNode::SubItemList::iterator i= _subitems->begin();
296
SqlAstNode::SubItemList::iterator i_end= _subitems->end();
298
// skip some elements if needed
299
if (NULL != start_item)
300
for (; (*i != start_item) && (i != i_end); ++i);
302
// now check given sequence
304
for (; n != words_count && i != i_end; ++i, ++n)
307
if (!result->name_equals(words[n]))
319
Tries to find sequence within whole range of children items starting from 'subitem' (if specified, otherwise from 1st subitem).
320
Returns last item from found sequence.
322
const SqlAstNode * SqlAstNode::find_words(sql::symbol words[], size_t words_count, const SqlAstNode *start_item) const
324
SqlAstNode::SubItemList::iterator i= _subitems->begin();
325
SqlAstNode::SubItemList::iterator i_end= _subitems->end();
327
// skip some elements if needed
328
if (NULL != start_item)
329
for (; (*i != start_item) && (i != i_end); ++i);
331
// now try to find given sequence
332
const SqlAstNode *item= NULL;
334
for (; i != i_end; ++i)
337
if (item->name_equals(words[n]))
339
if (words_count == ++n)
346
return (words_count == n) ? item : NULL;
350
const SqlAstNode * SqlAstNode::search_by_names(sql::symbol names[], size_t path_count) const
352
const SqlAstNode *result= NULL;
353
for (size_t n= 0; n < path_count; ++n)
354
if ((result= subitem_by_name(names[n])))
360
const SqlAstNode * SqlAstNode::search_by_paths(sql::symbol * paths[], size_t path_count) const
362
const SqlAstNode *result= NULL;
363
for (size_t n= 0; n < path_count; ++n)
364
if ((result= subitem_by_path(paths[n])))
370
std::string SqlAstNode::restore_sql_text(const std::string &sql_statement, const SqlAstNode *first_subitem, const SqlAstNode *last_subitem) const
372
int boffset= first_subitem ? first_subitem->_stmt_boffset : -1;
373
int eoffset= last_subitem ? last_subitem->_stmt_eoffset : -1;
375
restore_sql_text(boffset, eoffset, first_subitem, last_subitem);
377
if (-1 != boffset && -1 != eoffset)
379
std::string sql_text;
380
sql_text.reserve(eoffset - boffset);
381
std::copy(sql_statement.begin()+boffset, sql_statement.begin()+eoffset, std::back_inserter(sql_text));
385
return std::string();
389
void SqlAstNode::restore_sql_text(int &boffset, int &eoffset, const SqlAstNode *first_subitem, const SqlAstNode *last_subitem) const
391
if (-1 == boffset || (boffset > _stmt_boffset && -1 != _stmt_boffset))
392
boffset= _stmt_boffset;
393
if (-1 == eoffset || (eoffset < _stmt_eoffset && -1 != _stmt_eoffset))
394
eoffset= _stmt_eoffset;
395
if (NULL != _subitems)
397
SqlAstNode::SubItemList::const_iterator i= _subitems->begin();
398
const SqlAstNode::SubItemList::const_iterator i_end= _subitems->end();
400
for (; (i_end != i) && (*i != first_subitem); ++i);
401
for (; (i != i_end) && (*i != last_subitem); ++i)
402
(*i)->restore_sql_text(boffset, eoffset, NULL, NULL);
407
// warning this sql has incorrect syntax
408
void SqlAstNode::build_sql(std::string &sql_text) const
412
sql_text.append(value());
414
const char *nl_keywords[]= {"begin", "end", ";"};
415
std::string item_value= value();
416
if (find_cstr_in_array_ci(nl_keywords, ARR_CAPACITY(nl_keywords), item_value.c_str()))
417
sql_text.append("\n");
419
sql_text.append(" ");
422
if (NULL != _subitems)
423
for (SqlAstNode::SubItemList::const_iterator i= _subitems->begin(), i_end= _subitems->end(); i != i_end; ++i)
424
(*i)->build_sql(sql_text);
428
const SqlAstNode * SqlAstNode::subitem_(sql::symbol name, ...) const
431
va_start(args, name);
432
const SqlAstNode *item= subitem__(name, args);
438
const SqlAstNode *SqlAstNode::subitem__(sql::symbol name, va_list args) const
440
const SqlAstNode *item= this;
444
item= item->subitem_by_name(name);
445
assert(sizeof(int) == sizeof(sql::symbol));
447
name= (sql::symbol)va_arg(args, int);
449
name= va_arg(args, sql::symbol);
457
const SqlAstNode * SqlAstNode::subitem_(int position, ...) const
459
SqlAstNode::SubItemList::const_iterator i= _subitems->begin();
460
if ((0 <= position) && (_subitems->size() > (size_t)position))
462
SqlAstNode::SubItemList::const_iterator i= _subitems->begin();
463
for (; 0 < position; --position) ++i;
470
const SqlAstNode *SqlAstNode::subitem_by_name(sql::symbol name, const SqlAstNode *start_item) const
475
SqlAstNode::SubItemList::const_iterator i= _subitems->begin();
476
SqlAstNode::SubItemList::const_iterator i_end= _subitems->end();
479
i= find(i, i_end, start_item);
481
for (; i != i_end; ++i)
482
if ((*i)->name_equals(name))
489
const SqlAstNode * SqlAstNode::subitem_by_name(sql::symbol name, size_t position) const
494
if (_subitems->size() > position)
496
SqlAstNode::SubItemList::const_iterator i= _subitems->begin();
497
SqlAstNode::SubItemList::const_iterator i_end= _subitems->end();
499
for (; 0 < position; --position)
502
for (; i != i_end; ++i)
503
if ((*i)->name_equals(name))
511
const SqlAstNode *SqlAstNode::rsubitem_by_name(sql::symbol name, size_t position) const
513
if (_subitems->size() > position)
515
SqlAstNode::SubItemList::const_reverse_iterator i= _subitems->rbegin();
516
SqlAstNode::SubItemList::const_reverse_iterator i_end= _subitems->rend();
518
for (; 0 < position; --position)
521
for (; i != i_end; ++i)
522
if ((*i)->name_equals(name))
530
const SqlAstNode * SqlAstNode::subitem_by_path(sql::symbol path[]) const
532
const SqlAstNode *item= this;
533
sql::symbol *name= path;
535
while ((item) && *name)
536
item= item->subitem_by_name(*name++);
541
char * SqlAstNode::subitems_as_string(const char *delim) const
547
const char *current_delim= "";
548
for (SqlAstNode::SubItemList::const_iterator i= _subitems->begin(), i_end= _subitems->end(); i != i_end; ++i)
550
SqlAstNode *subitem= *i;
551
if (subitem->subitems()->size() > 0)
553
char *s= subitem->subitems_as_string(delim);
555
current_delim= delim;
562
current_delim= delim;
563
to += subitem->value();
568
return strcpy(new char[to.length()+1], to.c_str());
572
SqlAstNonTerminalNode::~SqlAstNonTerminalNode()
574
// no need in this code after flat list of all allocated ast nodes was introduced, see SqlAstStatics::_ast_nodes
575
//for (SubItemList::iterator i= _subitems.begin(), end= _subitems.end(); i != end; ++i)
583
extern void * new_ast_node(sql::symbol name)
585
SqlAstNode *node= SqlAstStatics::add_ast_node(new SqlAstNonTerminalNode(name));
589
extern void * reuse_ast_node(void *node_, sql::symbol name)
591
return (node_) ? set_ast_node_name(node_, name) : new_ast_node(name);
594
extern void * set_ast_node_name(void *node_, sql::symbol name)
598
static_cast<SqlAstNode *>(node_)->set_name(name);
602
extern void add_ast_child_node(void *parent_node_, void *child_node_)
604
if (!parent_node_ || !child_node_)
606
SqlAstNode *child_node= static_cast<SqlAstNode *>(child_node_);
607
SqlAstNode *parent_node= static_cast<SqlAstNode *>(parent_node_);
608
parent_node->subitems()->push_back(child_node);
611
extern void merge_ast_child_nodes(void *dest_node_, void *src_node_)
613
if (!dest_node_ || !src_node_)
615
SqlAstNode::SubItemList *dest_list= static_cast<SqlAstNode *>(dest_node_)->subitems();
616
SqlAstNode::SubItemList *src_list= static_cast<SqlAstNode *>(src_node_)->subitems();
617
dest_list->splice(dest_list->end(), *src_list);
620
extern void tree_item_dump_xml_to_file(const void *tree_item, const char *filename)
622
const SqlAstNode* item= static_cast<const SqlAstNode *>(tree_item);
623
std::ofstream os(filename);
629
} // namespace mysql_parser