~ubuntu-branches/ubuntu/quantal/mysql-workbench/quantal

« back to all changes in this revision

Viewing changes to library/sql-parser/source/myx_sql_tree_item.cpp

  • Committer: Package Import Robot
  • Author(s): Dmitry Smirnov
  • Date: 2012-03-01 21:57:30 UTC
  • Revision ID: package-import@ubuntu.com-20120301215730-o7y8av8y38n162ro
Tags: upstream-5.2.38+dfsg
ImportĀ upstreamĀ versionĀ 5.2.38+dfsg

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#ifdef _WIN32
 
2
#define WIN32_LEAN_AND_MEAN
 
3
#include <windows.h>
 
4
#include <iterator>
 
5
#else
 
6
#include <stdarg.h>
 
7
#endif
 
8
#include <algorithm>
 
9
#include "myx_sql_tree_item.h"
 
10
#include "myx_lex_helpers.h"
 
11
#include <functional>
 
12
#include <assert.h>
 
13
 
 
14
#ifdef _WIN32
 
15
  #ifndef strcasecmp
 
16
    #define strcasecmp _stricmp
 
17
    #define strncasecmp strnicmp
 
18
  #endif
 
19
#endif
 
20
 
 
21
namespace mysql_parser
 
22
{
 
23
 
 
24
const char* find_cstr_in_array_ci(const char *arr[], size_t arr_size, const char* str)
 
25
{
 
26
  for (size_t n= 0; n < arr_size; ++n)
 
27
    if (are_cstrings_eq_ci(arr[n], str))
 
28
      return arr[n];
 
29
  return NULL;
 
30
}
 
31
const char* find_str_in_array_ci(const char *arr[], size_t arr_size, const std::string &str)
 
32
{
 
33
  return find_cstr_in_array_ci(arr, arr_size, str.c_str());
 
34
}
 
35
 
 
36
 
 
37
bool are_cstrings_eq(const char *str1, const char *str2, bool case_sensitive)
 
38
{
 
39
  if (case_sensitive)
 
40
    return ((str1 == str2) ||
 
41
      (
 
42
        ((NULL != str1) && (NULL != str2)) &&
 
43
        (strlen(str1) == strlen(str2)) &&
 
44
        (0 == strcmp(str1, str2))
 
45
      ));
 
46
  else
 
47
    return are_cstrings_eq_ci(str1, str2);
 
48
}
 
49
bool are_strings_eq(const std::string &str1, const std::string &str2, bool case_sensitive)
 
50
{
 
51
  return are_cstrings_eq(str1.c_str(), str2.c_str(), case_sensitive);
 
52
}
 
53
 
 
54
 
 
55
bool are_cstrings_eq_ci(const char *str1, const char *str2)
 
56
{
 
57
  return ((str1 == str2) ||
 
58
    (
 
59
      ((NULL != str1) && (NULL != str2)) &&
 
60
      (toupper(str1[0]) == toupper(str2[0])) &&
 
61
      (strlen(str1) == strlen(str2)) &&
 
62
      (0 == strncasecmp(str1, str2, strlen(str1)))
 
63
    ));
 
64
}
 
65
bool are_strings_eq_ci(const std::string &str1, const std::string &str2)
 
66
{
 
67
  return are_cstrings_eq_ci(str1.c_str(), str2.c_str());
 
68
}
 
69
 
 
70
 
 
71
SqlAstNode::SubItemList SqlAstTerminalNode::_empty_list;
 
72
 
 
73
 
 
74
MYX_PUBLIC_FUNC std::ostream& operator << (std::ostream& os, const SqlAstNode& item)
 
75
{
 
76
  if (item.value()[0] != '\0')
 
77
  {
 
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() << "'>";
 
81
  }
 
82
  else
 
83
    os << "<elem name='" << item.name() << "'>";
 
84
 
 
85
  {
 
86
    SqlAstNode::SubItemList *subitems= item.subitems();
 
87
    if (subitems)
 
88
      for (SqlAstNode::SubItemList::const_iterator i= subitems->begin(), i_end= subitems->end(); i != i_end; ++i)
 
89
        os << *i;
 
90
  }
 
91
 
 
92
  os << "</elem>";
 
93
 
 
94
  return os;
 
95
}
 
96
 
 
97
 
 
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);
 
104
 
 
105
 
 
106
void SqlAstStatics::tree(const SqlAstNode *tree)
 
107
{
 
108
  _tree= tree;
 
109
  mysql_parser::tree= _tree;
 
110
}
 
111
 
 
112
 
 
113
void SqlAstStatics::cleanup_ast_nodes()
 
114
{
 
115
  for (std::list<SqlAstNode*>::iterator i= _ast_nodes.begin(), i_end= _ast_nodes.end(); i != i_end; ++i)
 
116
    delete *i;
 
117
  _ast_nodes.clear();
 
118
  _tree= NULL;
 
119
  //_sql_statement= NULL;
 
120
}
 
121
 
 
122
 
 
123
SqlAstNode::SqlAstNode(sql::symbol name, const char *value, int value_length, int stmt_lineno, int stmt_boffset, int stmt_eoffset, SubItemList *items)
 
124
  :
 
125
_name(name),
 
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),
 
131
_subitems(items)
 
132
{
 
133
  if (-1 != _stmt_eoffset && (_stmt_boffset + _value_length) > _stmt_eoffset)
 
134
    _stmt_eoffset= _stmt_boffset + _value_length;
 
135
}
 
136
 
 
137
 
 
138
SqlAstNode::~SqlAstNode()
 
139
{
 
140
}
 
141
 
 
142
 
 
143
std::string SqlAstNode::value() const
 
144
{
 
145
  if (_value.get())
 
146
    return *_value;
 
147
  else if (_value_length)
 
148
    return std::string(SqlAstStatics::sql_statement() + _stmt_boffset, _value_length);
 
149
  else
 
150
    return "";
 
151
}
 
152
 
 
153
 
 
154
const SqlAstNode * SqlAstNode::left_most_subitem() const
 
155
{
 
156
  return (_subitems) ? (*_subitems->begin())->left_most_subitem() : this;
 
157
}
 
158
 
 
159
 
 
160
const SqlAstNode * SqlAstNode::right_most_subitem() const
 
161
{
 
162
  return (_subitems) ? (*_subitems->rend())->right_most_subitem() : this;
 
163
}
 
164
 
 
165
 
 
166
int SqlAstNode::stmt_lineno() const
 
167
{
 
168
  if ((-1 == _stmt_lineno) && _subitems)
 
169
    return (*_subitems->begin())->stmt_lineno();
 
170
  return _stmt_lineno;
 
171
}
 
172
 
 
173
 
 
174
int SqlAstNode::stmt_boffset() const
 
175
{
 
176
  if ((-1 == _stmt_boffset) && _subitems)
 
177
    return (*_subitems->begin())->stmt_boffset();
 
178
  return _stmt_boffset;
 
179
}
 
180
 
 
181
 
 
182
int SqlAstNode::stmt_eoffset() const
 
183
{
 
184
  if ((-1 == _stmt_eoffset) && _subitems)
 
185
    return (*_subitems->rbegin())->stmt_eoffset();
 
186
  return _stmt_eoffset;
 
187
}
 
188
 
 
189
 
 
190
/*
 
191
Tries to find sequence of items begining from subitem (if specified, otherwise from 1st subitem).
 
192
Returns last item from found sequence.
 
193
*/
 
194
const SqlAstNode * SqlAstNode::subseq__(const SqlAstNode *subitem, sql::symbol name, va_list args) const
 
195
{
 
196
  SqlAstNode::SubItemList::iterator i= _subitems->begin();
 
197
  SqlAstNode::SubItemList::iterator i_end= _subitems->end();
 
198
 
 
199
  // skip some elements if start subitem is specified
 
200
  if (subitem)
 
201
    i= std::find(i, i_end, subitem);
 
202
 
 
203
  for (; i != i_end; ++i)
 
204
  {
 
205
    subitem= *i;
 
206
    if (!subitem->name_equals(name))
 
207
      return NULL;
 
208
#ifdef __GNUC__
 
209
    name= (sql::symbol)va_arg(args, int);
 
210
#else
 
211
    name= va_arg(args, sql::symbol);
 
212
#endif
 
213
    if (!name)
 
214
      return subitem; // return last item from found sequence
 
215
  }
 
216
 
 
217
  return NULL;
 
218
}
 
219
 
 
220
 
 
221
const SqlAstNode * SqlAstNode::subseq_(sql::symbol name, ...) const
 
222
{
 
223
  va_list args;
 
224
  va_start(args, name);
 
225
  const SqlAstNode * subitem= subseq__(NULL, name, args);
 
226
  va_end(args);
 
227
  return subitem;
 
228
}
 
229
 
 
230
 
 
231
const SqlAstNode * SqlAstNode::subseq_(const SqlAstNode *subitem, sql::symbol name, ...) const
 
232
{
 
233
  va_list args;
 
234
  va_start(args, name);
 
235
  subitem= subseq__(subitem, name, args);
 
236
  va_end(args);
 
237
  return subitem;
 
238
}
 
239
 
 
240
 
 
241
/*
 
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.
 
244
*/
 
245
const SqlAstNode * SqlAstNode::find_subseq__(const SqlAstNode *subitem, sql::symbol name, va_list args) const
 
246
{
 
247
  SqlAstNode::SubItemList::iterator i= _subitems->begin();
 
248
  SqlAstNode::SubItemList::iterator i_end= _subitems->end();
 
249
 
 
250
  // skip some elements if start subitem is specified
 
251
  if (subitem)
 
252
    i= std::find(i, i_end, subitem);
 
253
 
 
254
  for (; i != i_end; ++i)
 
255
  {
 
256
    subitem= *i;
 
257
    if (subitem->name_equals(name) && (subitem= subseq__(subitem, name, args)))
 
258
      return subitem; // return last item from found sequence
 
259
  }
 
260
 
 
261
  return NULL;
 
262
}
 
263
 
 
264
 
 
265
const SqlAstNode * SqlAstNode::find_subseq_(sql::symbol name, ...) const
 
266
{
 
267
  va_list args;
 
268
  va_start(args, name);
 
269
  const SqlAstNode * subitem= find_subseq__(NULL, name, args);
 
270
  va_end(args);
 
271
  return subitem;
 
272
}
 
273
 
 
274
 
 
275
const SqlAstNode * SqlAstNode::find_subseq_(const SqlAstNode *subitem, sql::symbol name, ...) const
 
276
{
 
277
  va_list args;
 
278
  va_start(args, name);
 
279
  subitem= find_subseq__(subitem, name, args);
 
280
  va_end(args);
 
281
  return subitem;
 
282
}
 
283
 
 
284
 
 
285
/*
 
286
Tries to find sequence of items begining from subitem (if specified, otherwise from 1st subitem).
 
287
Returns last item from found sequence.
 
288
*/
 
289
const SqlAstNode * SqlAstNode::check_words(sql::symbol words[], size_t words_count, const SqlAstNode *start_item) const
 
290
{
 
291
  const SqlAstNode *result= NULL;
 
292
 
 
293
  if (NULL != _subitems)
 
294
  {
 
295
    SqlAstNode::SubItemList::iterator i= _subitems->begin();
 
296
    SqlAstNode::SubItemList::iterator i_end= _subitems->end();
 
297
 
 
298
    // skip some elements if needed
 
299
    if (NULL != start_item)
 
300
      for (; (*i != start_item) && (i != i_end); ++i);
 
301
 
 
302
    // now check given sequence
 
303
    size_t n= 0;
 
304
    for (; n != words_count && i != i_end; ++i, ++n)
 
305
    {
 
306
      result= *i;
 
307
      if (!result->name_equals(words[n]))
 
308
        return NULL;
 
309
    }
 
310
    if (n < words_count)
 
311
      return NULL;
 
312
  }
 
313
 
 
314
  return result;
 
315
}
 
316
 
 
317
 
 
318
/*
 
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.
 
321
*/
 
322
const SqlAstNode * SqlAstNode::find_words(sql::symbol words[], size_t words_count, const SqlAstNode *start_item) const
 
323
{
 
324
  SqlAstNode::SubItemList::iterator i= _subitems->begin();
 
325
  SqlAstNode::SubItemList::iterator i_end= _subitems->end();
 
326
 
 
327
  // skip some elements if needed
 
328
  if (NULL != start_item)
 
329
    for (; (*i != start_item) && (i != i_end); ++i);
 
330
 
 
331
  // now try to find given sequence
 
332
  const SqlAstNode *item= NULL;
 
333
  size_t n= 0;
 
334
  for (; i != i_end; ++i)
 
335
  {
 
336
    item= *i;
 
337
    if (item->name_equals(words[n]))
 
338
    {
 
339
      if (words_count == ++n)
 
340
        break;
 
341
    }
 
342
    else
 
343
      n= 0;
 
344
  }
 
345
 
 
346
  return (words_count == n) ? item : NULL;
 
347
}
 
348
 
 
349
 
 
350
const SqlAstNode * SqlAstNode::search_by_names(sql::symbol names[], size_t path_count) const
 
351
{
 
352
  const SqlAstNode *result= NULL;
 
353
  for (size_t n= 0; n < path_count; ++n)
 
354
    if ((result= subitem_by_name(names[n])))
 
355
      break;
 
356
  return result;
 
357
}
 
358
 
 
359
 
 
360
const SqlAstNode * SqlAstNode::search_by_paths(sql::symbol * paths[], size_t path_count) const
 
361
{
 
362
  const SqlAstNode *result= NULL;
 
363
  for (size_t n= 0; n < path_count; ++n)
 
364
    if ((result= subitem_by_path(paths[n])))
 
365
      break;
 
366
  return result;
 
367
}
 
368
 
 
369
 
 
370
std::string SqlAstNode::restore_sql_text(const std::string &sql_statement, const SqlAstNode *first_subitem, const SqlAstNode *last_subitem) const
 
371
{
 
372
  int boffset= first_subitem ? first_subitem->_stmt_boffset : -1;
 
373
  int eoffset= last_subitem ? last_subitem->_stmt_eoffset : -1;
 
374
 
 
375
  restore_sql_text(boffset, eoffset, first_subitem, last_subitem);
 
376
 
 
377
  if (-1 != boffset && -1 != eoffset)
 
378
  {
 
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));
 
382
    return sql_text;
 
383
  }
 
384
 
 
385
  return std::string();
 
386
}
 
387
 
 
388
 
 
389
void SqlAstNode::restore_sql_text(int &boffset, int &eoffset, const SqlAstNode *first_subitem, const SqlAstNode *last_subitem) const
 
390
{
 
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)
 
396
  {
 
397
    SqlAstNode::SubItemList::const_iterator i= _subitems->begin();
 
398
    const SqlAstNode::SubItemList::const_iterator i_end= _subitems->end();
 
399
    if (first_subitem)
 
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);
 
403
  }
 
404
}
 
405
 
 
406
 
 
407
// warning this sql has incorrect syntax
 
408
void SqlAstNode::build_sql(std::string &sql_text) const
 
409
{
 
410
  if (_value_length)
 
411
  {
 
412
    sql_text.append(value());
 
413
 
 
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");
 
418
    else
 
419
      sql_text.append(" ");
 
420
  }
 
421
 
 
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);
 
425
}
 
426
 
 
427
 
 
428
const SqlAstNode * SqlAstNode::subitem_(sql::symbol name, ...) const
 
429
{
 
430
  va_list args;
 
431
  va_start(args, name);
 
432
  const SqlAstNode *item= subitem__(name, args);
 
433
  va_end(args);
 
434
  return item;
 
435
}
 
436
 
 
437
 
 
438
const SqlAstNode *SqlAstNode::subitem__(sql::symbol name, va_list args) const
 
439
{
 
440
  const SqlAstNode *item= this;
 
441
 
 
442
  while (name && item)
 
443
  {
 
444
    item= item->subitem_by_name(name);
 
445
    assert(sizeof(int) == sizeof(sql::symbol));
 
446
#ifdef __GNUC__
 
447
    name= (sql::symbol)va_arg(args, int);
 
448
#else
 
449
    name= va_arg(args, sql::symbol);
 
450
#endif
 
451
  }
 
452
 
 
453
  return item;
 
454
}
 
455
 
 
456
 
 
457
const SqlAstNode * SqlAstNode::subitem_(int position, ...) const
 
458
{
 
459
  SqlAstNode::SubItemList::const_iterator i= _subitems->begin();
 
460
  if ((0 <= position) && (_subitems->size() > (size_t)position))
 
461
  {
 
462
    SqlAstNode::SubItemList::const_iterator i= _subitems->begin();
 
463
    for (; 0 < position; --position) ++i;
 
464
    return *i;
 
465
  }
 
466
  return NULL;
 
467
}
 
468
 
 
469
 
 
470
const SqlAstNode *SqlAstNode::subitem_by_name(sql::symbol name, const SqlAstNode *start_item) const
 
471
{
 
472
  if (!(_subitems))
 
473
    return NULL;
 
474
 
 
475
  SqlAstNode::SubItemList::const_iterator i= _subitems->begin();
 
476
  SqlAstNode::SubItemList::const_iterator i_end= _subitems->end();
 
477
 
 
478
  if (start_item)
 
479
    i= find(i, i_end, start_item);
 
480
 
 
481
  for (; i != i_end; ++i)
 
482
    if ((*i)->name_equals(name))
 
483
      return *i;
 
484
 
 
485
  return NULL;
 
486
}
 
487
 
 
488
 
 
489
const SqlAstNode * SqlAstNode::subitem_by_name(sql::symbol name, size_t position) const
 
490
{
 
491
  if (!(_subitems))
 
492
    return NULL;
 
493
 
 
494
  if (_subitems->size() > position)
 
495
  {
 
496
    SqlAstNode::SubItemList::const_iterator i= _subitems->begin();
 
497
    SqlAstNode::SubItemList::const_iterator i_end= _subitems->end();
 
498
 
 
499
    for (; 0 < position; --position)
 
500
      ++i;
 
501
 
 
502
    for (; i != i_end; ++i)
 
503
      if ((*i)->name_equals(name))
 
504
        return *i;
 
505
  }
 
506
 
 
507
  return NULL;
 
508
}
 
509
 
 
510
 
 
511
const SqlAstNode *SqlAstNode::rsubitem_by_name(sql::symbol name, size_t position) const
 
512
{
 
513
  if (_subitems->size() > position)
 
514
  {
 
515
    SqlAstNode::SubItemList::const_reverse_iterator i= _subitems->rbegin();
 
516
    SqlAstNode::SubItemList::const_reverse_iterator i_end= _subitems->rend();
 
517
 
 
518
    for (; 0 < position; --position)
 
519
      ++i;
 
520
 
 
521
    for (; i != i_end; ++i)
 
522
      if ((*i)->name_equals(name))
 
523
        return *i;
 
524
  }
 
525
 
 
526
  return NULL;
 
527
}
 
528
 
 
529
 
 
530
const SqlAstNode * SqlAstNode::subitem_by_path(sql::symbol path[]) const
 
531
{
 
532
  const SqlAstNode *item= this;
 
533
  sql::symbol *name= path;
 
534
 
 
535
  while ((item) && *name)
 
536
    item= item->subitem_by_name(*name++);
 
537
  return item;
 
538
}
 
539
 
 
540
 
 
541
char * SqlAstNode::subitems_as_string(const char *delim) const
 
542
{
 
543
  std::string to;
 
544
 
 
545
  if (_subitems)
 
546
  {
 
547
    const char *current_delim= "";
 
548
    for (SqlAstNode::SubItemList::const_iterator i= _subitems->begin(), i_end= _subitems->end(); i != i_end; ++i) 
 
549
    {
 
550
      SqlAstNode *subitem= *i;
 
551
      if (subitem->subitems()->size() > 0)
 
552
      {
 
553
        char *s= subitem->subitems_as_string(delim);
 
554
        to += current_delim;
 
555
        current_delim= delim;
 
556
        to += s;
 
557
        delete[] s;
 
558
      }
 
559
      else
 
560
      {
 
561
        to += current_delim;
 
562
        current_delim= delim;
 
563
        to += subitem->value();
 
564
      }
 
565
    }
 
566
  }
 
567
 
 
568
  return strcpy(new char[to.length()+1], to.c_str());
 
569
}
 
570
 
 
571
 
 
572
SqlAstNonTerminalNode::~SqlAstNonTerminalNode()
 
573
{
 
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)
 
576
  //  delete *i;
 
577
}
 
578
 
 
579
 
 
580
//extern "C"
 
581
//{
 
582
 
 
583
  extern void * new_ast_node(sql::symbol name)
 
584
  {
 
585
    SqlAstNode *node= SqlAstStatics::add_ast_node(new SqlAstNonTerminalNode(name));
 
586
    return node;
 
587
  }
 
588
 
 
589
  extern void * reuse_ast_node(void *node_, sql::symbol name)
 
590
  {
 
591
    return (node_) ? set_ast_node_name(node_, name) : new_ast_node(name);
 
592
  }
 
593
 
 
594
  extern void * set_ast_node_name(void *node_, sql::symbol name)
 
595
  {
 
596
    if (!node_)
 
597
      return node_;
 
598
    static_cast<SqlAstNode *>(node_)->set_name(name);
 
599
    return node_;
 
600
  }
 
601
 
 
602
  extern void add_ast_child_node(void *parent_node_, void *child_node_)
 
603
  {
 
604
    if (!parent_node_ || !child_node_)
 
605
      return;
 
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);
 
609
  }
 
610
 
 
611
  extern void merge_ast_child_nodes(void *dest_node_, void *src_node_)
 
612
  {
 
613
    if (!dest_node_ || !src_node_)
 
614
      return;
 
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);
 
618
  }
 
619
 
 
620
  extern void tree_item_dump_xml_to_file(const void *tree_item, const char *filename)
 
621
  {
 
622
    const SqlAstNode* item= static_cast<const SqlAstNode *>(tree_item);
 
623
    std::ofstream os(filename);
 
624
    os << *item;
 
625
  }
 
626
 
 
627
//} // extern "C"
 
628
 
 
629
} // namespace mysql_parser