~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to sql/sql_load.cc

Deleted files from strings that are not used. 

Show diffs side-by-side

added added

removed removed

Lines of Context:
15
15
 
16
16
 
17
17
/* Copy data from a textfile to table */
 
18
/* 2006-12 Erik Wetterberg : LOAD XML added */
18
19
 
19
 
#include <drizzled/server_includes.h>
 
20
#include "mysql_priv.h"
 
21
#include <my_dir.h>
 
22
#include <m_ctype.h>
20
23
#include "sql_repl.h"
21
 
#include <drizzled/drizzled_error_messages.h>
 
24
 
 
25
class XML_TAG {
 
26
public:
 
27
  int level;
 
28
  String field;
 
29
  String value;
 
30
  XML_TAG(int l, String f, String v);
 
31
};
 
32
 
 
33
 
 
34
XML_TAG::XML_TAG(int l, String f, String v)
 
35
{
 
36
  level= l;
 
37
  field.append(f);
 
38
  value.append(v);
 
39
}
22
40
 
23
41
 
24
42
class READ_INFO {
25
43
  File  file;
26
 
  unsigned char *buffer,                        /* Buffer for read text */
 
44
  uchar *buffer,                        /* Buffer for read text */
27
45
        *end_of_buff;                   /* Data in bufferts ends here */
28
46
  uint  buff_length,                    /* Length of buffert */
29
47
        max_length;                     /* Max length of row */
35
53
  bool  need_end_io_cache;
36
54
  IO_CACHE cache;
37
55
  NET *io_net;
 
56
  int level; /* for load xml */
38
57
 
39
58
public:
40
59
  bool error,line_cuted,found_null,enclosed;
41
 
  unsigned char *row_start,                     /* Found row starts here */
 
60
  uchar *row_start,                     /* Found row starts here */
42
61
        *row_end;                       /* Found row ends here */
43
 
  const CHARSET_INFO *read_charset;
 
62
  CHARSET_INFO *read_charset;
44
63
 
45
 
  READ_INFO(File file,uint32_t tot_length, const CHARSET_INFO * const cs,
 
64
  READ_INFO(File file,uint tot_length,CHARSET_INFO *cs,
46
65
            String &field_term,String &line_start,String &line_term,
47
66
            String &enclosed,int escape,bool get_it_from_net, bool is_fifo);
48
67
  ~READ_INFO();
50
69
  int read_fixed_length(void);
51
70
  int next_line(void);
52
71
  char unescape(char chr);
53
 
  int terminator(char *ptr,uint32_t length);
 
72
  int terminator(char *ptr,uint length);
54
73
  bool find_start_of_fields();
 
74
  /* load xml */
 
75
  List<XML_TAG> taglist;
 
76
  int read_value(int delim, String *val);
 
77
  int read_xml();
 
78
  int clear_level(int level);
55
79
 
56
80
  /*
57
81
    We need to force cache close before destructor is invoked to log
71
95
  void set_io_cache_arg(void* arg) { cache.arg = arg; }
72
96
};
73
97
 
74
 
static int read_fixed_length(THD *thd, COPY_INFO &info, TableList *table_list,
 
98
static int read_fixed_length(THD *thd, COPY_INFO &info, TABLE_LIST *table_list,
75
99
                             List<Item> &fields_vars, List<Item> &set_fields,
76
100
                             List<Item> &set_values, READ_INFO &read_info,
77
 
                             uint32_t skip_lines,
 
101
                             ulong skip_lines,
78
102
                             bool ignore_check_option_errors);
79
 
static int read_sep_field(THD *thd, COPY_INFO &info, TableList *table_list,
 
103
static int read_sep_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list,
80
104
                          List<Item> &fields_vars, List<Item> &set_fields,
81
105
                          List<Item> &set_values, READ_INFO &read_info,
82
 
                          String &enclosed, uint32_t skip_lines,
 
106
                          String &enclosed, ulong skip_lines,
83
107
                          bool ignore_check_option_errors);
84
108
 
 
109
static int read_xml_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list,
 
110
                          List<Item> &fields_vars, List<Item> &set_fields,
 
111
                          List<Item> &set_values, READ_INFO &read_info,
 
112
                          String &enclosed, ulong skip_lines,
 
113
                          bool ignore_check_option_errors);
 
114
 
85
115
static bool write_execute_load_query_log_event(THD *thd,
86
116
                                               bool duplicates, bool ignore,
87
117
                                               bool transactional_table,
105
135
      read_file_from_client - is this LOAD DATA LOCAL ?
106
136
 
107
137
  RETURN VALUES
108
 
    true - error / false - success
 
138
    TRUE - error / FALSE - success
109
139
*/
110
140
 
111
 
int mysql_load(THD *thd,sql_exchange *ex,TableList *table_list,
 
141
int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
112
142
                List<Item> &fields_vars, List<Item> &set_fields,
113
143
                List<Item> &set_values,
114
144
                enum enum_duplicates handle_duplicates, bool ignore,
116
146
{
117
147
  char name[FN_REFLEN];
118
148
  File file;
119
 
  Table *table= NULL;
 
149
  TABLE *table= NULL;
120
150
  int error;
121
151
  String *field_term=ex->field_term,*escaped=ex->escaped;
122
152
  String *enclosed=ex->enclosed;
129
159
    loaded is located
130
160
  */
131
161
  char *tdb= thd->db ? thd->db : db;            // Result is never null
132
 
  uint32_t skip_lines= ex->skip_lines;
 
162
  ulong skip_lines= ex->skip_lines;
133
163
  bool transactional_table;
134
164
  THD::killed_state killed_status= THD::NOT_KILLED;
 
165
  DBUG_ENTER("mysql_load");
135
166
 
136
167
  if (escaped->length() > 1 || enclosed->length() > 1)
137
168
  {
138
169
    my_message(ER_WRONG_FIELD_TERMINATORS,ER(ER_WRONG_FIELD_TERMINATORS),
139
170
               MYF(0));
140
 
    return(true);
 
171
    DBUG_RETURN(TRUE);
141
172
  }
142
173
  if (open_and_lock_tables(thd, table_list))
143
 
    return(true);
 
174
    DBUG_RETURN(TRUE);
144
175
  if (setup_tables_and_check_access(thd, &thd->lex->select_lex.context,
145
176
                                    &thd->lex->select_lex.top_join_list,
146
177
                                    table_list,
147
178
                                    &thd->lex->select_lex.leaf_tables, true))
148
 
     return(-1);
 
179
     DBUG_RETURN(-1);
149
180
 
150
181
  /*
151
182
    Let us emit an error if we are loading data to table which is used
158
189
  if (unique_table(thd, table_list, table_list->next_global, 0))
159
190
  {
160
191
    my_error(ER_UPDATE_TABLE_USED, MYF(0), table_list->table_name);
161
 
    return(true);
 
192
    DBUG_RETURN(TRUE);
162
193
  }
163
194
 
164
195
  table= table_list->table;
177
208
    */
178
209
    if (setup_fields(thd, 0, set_fields, MARK_COLUMNS_WRITE, 0, 0) ||
179
210
        setup_fields(thd, 0, set_values, MARK_COLUMNS_READ, 0, 0))
180
 
      return(true);
 
211
      DBUG_RETURN(TRUE);
181
212
  }
182
213
  else
183
214
  {                                             // Part field list
185
216
    if (setup_fields(thd, 0, fields_vars, MARK_COLUMNS_WRITE, 0, 0) ||
186
217
        setup_fields(thd, 0, set_fields, MARK_COLUMNS_WRITE, 0, 0) ||
187
218
        check_that_all_fields_are_given_values(thd, table, table_list))
188
 
      return(true);
 
219
      DBUG_RETURN(TRUE);
189
220
    /*
190
221
      Check whenever TIMESTAMP field with auto-set feature specified
191
222
      explicitly.
203
234
    }
204
235
    /* Fix the expressions in SET clause */
205
236
    if (setup_fields(thd, 0, set_values, MARK_COLUMNS_READ, 0, 0))
206
 
      return(true);
 
237
      DBUG_RETURN(TRUE);
207
238
  }
208
239
 
209
240
  table->mark_columns_needed_for_insert();
210
241
 
211
 
  uint32_t tot_length=0;
 
242
  uint tot_length=0;
212
243
  bool use_blobs= 0, use_vars= 0;
213
244
  List_iterator_fast<Item> it(fields_vars);
214
245
  Item *item;
235
266
  {
236
267
    my_message(ER_BLOBS_AND_NO_TERMINATED,ER(ER_BLOBS_AND_NO_TERMINATED),
237
268
               MYF(0));
238
 
    return(true);
 
269
    DBUG_RETURN(TRUE);
239
270
  }
240
271
  if (use_vars && !field_term->length() && !enclosed->length())
241
272
  {
242
273
    my_error(ER_LOAD_FROM_FIXED_SIZE_ROWS_TO_VAR, MYF(0));
243
 
    return(true);
 
274
    DBUG_RETURN(TRUE);
244
275
  }
245
276
 
246
277
  /* We can't give an error in the middle when using LOCAL files */
259
290
#endif
260
291
    if (!dirname_length(ex->file_name))
261
292
    {
262
 
      strxnmov(name, FN_REFLEN-1, mysql_real_data_home, tdb, NULL);
 
293
      strxnmov(name, FN_REFLEN-1, mysql_real_data_home, tdb, NullS);
263
294
      (void) fn_format(name, ex->file_name, name, "",
264
295
                       MY_RELATIVE_PATH | MY_UNPACK_FILENAME);
265
296
    }
273
304
      {
274
305
        /* Read only allowed from within dir specified by secure_file_priv */
275
306
        my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--secure-file-priv");
276
 
        return(true);
 
307
        DBUG_RETURN(TRUE);
277
308
      }
278
309
 
279
310
      struct stat stat_info;
280
311
      if (stat(name,&stat_info))
281
 
        return(true);
 
312
        DBUG_RETURN(TRUE);
282
313
 
283
314
      // if we are not in slave thread, the file must be:
284
315
      if (!thd->slave_thread &&
288
319
             (stat_info.st_mode & S_IFIFO) == S_IFIFO)))
289
320
      {
290
321
        my_error(ER_TEXTFILE_NOT_READABLE, MYF(0), name);
291
 
        return(true);
 
322
        DBUG_RETURN(TRUE);
292
323
      }
293
324
      if ((stat_info.st_mode & S_IFIFO) == S_IFIFO)
294
325
        is_fifo = 1;
295
326
    }
296
327
    if ((file=my_open(name,O_RDONLY,MYF(MY_WME))) < 0)
297
 
      return(true);
 
328
      DBUG_RETURN(TRUE);
298
329
  }
299
330
 
300
331
  COPY_INFO info;
301
 
  memset(&info, 0, sizeof(info));
 
332
  bzero((char*) &info,sizeof(info));
302
333
  info.ignore= ignore;
303
334
  info.handle_duplicates=handle_duplicates;
304
335
  info.escape_char=escaped->length() ? (*escaped)[0] : INT_MAX;
311
342
  {
312
343
    if  (file >= 0)
313
344
      my_close(file,MYF(0));                    // no files in net reading
314
 
    return(true);                               // Can't allocate buffers
 
345
    DBUG_RETURN(TRUE);                          // Can't allocate buffers
315
346
  }
316
347
 
317
348
  if (mysql_bin_log.is_open())
326
357
  thd->count_cuted_fields= CHECK_FIELD_WARN;            /* calc cuted fields */
327
358
  thd->cuted_fields=0L;
328
359
  /* Skip lines if there is a line terminator */
329
 
  if (ex->line_term->length())
 
360
  if (ex->line_term->length() && ex->filetype != FILETYPE_XML)
330
361
  {
331
362
    /* ex->skip_lines needs to be preserved for logging */
332
363
    while (skip_lines > 0)
349
380
    table->file->ha_start_bulk_insert((ha_rows) 0);
350
381
    table->copy_blobs=1;
351
382
 
352
 
    thd->abort_on_warning= true;
 
383
    thd->abort_on_warning= (!ignore &&
 
384
                            (thd->variables.sql_mode &
 
385
                             (MODE_STRICT_TRANS_TABLES |
 
386
                              MODE_STRICT_ALL_TABLES)));
353
387
 
354
 
    if (!field_term->length() && !enclosed->length())
 
388
    if (ex->filetype == FILETYPE_XML) /* load xml */
 
389
      error= read_xml_field(thd, info, table_list, fields_vars,
 
390
                            set_fields, set_values, read_info,
 
391
                            *(ex->line_term), skip_lines, ignore);
 
392
    else if (!field_term->length() && !enclosed->length())
355
393
      error= read_fixed_length(thd, info, table_list, fields_vars,
356
394
                               set_fields, set_values, read_info,
357
395
                               skip_lines, ignore);
377
415
     simulated killing in the middle of per-row loop
378
416
     must be effective for binlogging
379
417
  */
 
418
  DBUG_EXECUTE_IF("simulate_kill_bug27571",
 
419
                  {
 
420
                    error=1;
 
421
                    thd->killed= THD::KILL_QUERY;
 
422
                  };);
380
423
  killed_status= (error == 0)? THD::NOT_KILLED : thd->killed;
381
424
  if (error)
382
425
  {
429
472
    error= -1;                          // Error on read
430
473
    goto err;
431
474
  }
432
 
  sprintf(name, ER(ER_LOAD_INFO), (uint32_t) info.records, (uint32_t) info.deleted,
433
 
          (uint32_t) (info.records - info.copied), (uint32_t) thd->cuted_fields);
 
475
  sprintf(name, ER(ER_LOAD_INFO), (ulong) info.records, (ulong) info.deleted,
 
476
          (ulong) (info.records - info.copied), (ulong) thd->cuted_fields);
434
477
 
435
478
  if (thd->transaction.stmt.modified_non_trans_table)
436
 
    thd->transaction.all.modified_non_trans_table= true;
 
479
    thd->transaction.all.modified_non_trans_table= TRUE;
437
480
 
438
481
  if (mysql_bin_log.is_open())
439
482
  {
466
509
  /* ok to client sent only after binlog write and engine commit */
467
510
  my_ok(thd, info.copied + info.deleted, 0L, name);
468
511
err:
469
 
  assert(transactional_table || !(info.copied || info.deleted) ||
 
512
  DBUG_ASSERT(transactional_table || !(info.copied || info.deleted) ||
470
513
              thd->transaction.stmt.modified_non_trans_table);
471
514
  table->file->ha_release_auto_increment();
472
 
  table->auto_increment_field_not_null= false;
 
515
  table->auto_increment_field_not_null= FALSE;
473
516
  thd->abort_on_warning= 0;
474
 
  return(error);
 
517
  DBUG_RETURN(error);
475
518
}
476
519
 
477
520
 
487
530
      (char*)thd->lex->fname_end - (char*)thd->query,
488
531
      (duplicates == DUP_REPLACE) ? LOAD_DUP_REPLACE :
489
532
      (ignore ? LOAD_DUP_IGNORE : LOAD_DUP_ERROR),
490
 
      transactional_table, false, killed_err_arg);
 
533
      transactional_table, FALSE, killed_err_arg);
491
534
  e.flags|= LOG_EVENT_UPDATE_TABLE_MAP_VERSION_F;
492
535
  return mysql_bin_log.write(&e);
493
536
}
498
541
****************************************************************************/
499
542
 
500
543
static int
501
 
read_fixed_length(THD *thd, COPY_INFO &info, TableList *table_list,
 
544
read_fixed_length(THD *thd, COPY_INFO &info, TABLE_LIST *table_list,
502
545
                  List<Item> &fields_vars, List<Item> &set_fields,
503
546
                  List<Item> &set_values, READ_INFO &read_info,
504
 
                  uint32_t skip_lines, bool ignore_check_option_errors)
 
547
                  ulong skip_lines, bool ignore_check_option_errors)
505
548
{
506
549
  List_iterator_fast<Item> it(fields_vars);
507
550
  Item_field *sql_field;
508
 
  Table *table= table_list->table;
509
 
  uint64_t id;
 
551
  TABLE *table= table_list->table;
 
552
  ulonglong id;
510
553
  bool err;
 
554
  DBUG_ENTER("read_fixed_length");
511
555
 
512
556
  id= 0;
513
557
 
516
560
    if (thd->killed)
517
561
    {
518
562
      thd->send_kill_message();
519
 
      return(1);
 
563
      DBUG_RETURN(1);
520
564
    }
521
565
    if (skip_lines)
522
566
    {
530
574
      continue;
531
575
    }
532
576
    it.rewind();
533
 
    unsigned char *pos=read_info.row_start;
 
577
    uchar *pos=read_info.row_start;
534
578
#ifdef HAVE_purify
535
579
    read_info.row_end[0]=0;
536
580
#endif
544
588
    {
545
589
      Field *field= sql_field->field;                  
546
590
      if (field == table->next_number_field)
547
 
        table->auto_increment_field_not_null= true;
 
591
        table->auto_increment_field_not_null= TRUE;
548
592
      /*
549
593
        No fields specified in fields_vars list can be null in this format.
550
594
        Mark field as not null, we should do this for each row because of
555
599
      if (pos == read_info.row_end)
556
600
      {
557
601
        thd->cuted_fields++;                    /* Not enough fields */
558
 
        push_warning_printf(thd, DRIZZLE_ERROR::WARN_LEVEL_WARN, 
 
602
        push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, 
559
603
                            ER_WARN_TOO_FEW_RECORDS, 
560
604
                            ER(ER_WARN_TOO_FEW_RECORDS), thd->row_count);
561
 
        if (!field->maybe_null() && field->type() == DRIZZLE_TYPE_TIMESTAMP)
 
605
        if (!field->maybe_null() && field->type() == FIELD_TYPE_TIMESTAMP)
562
606
            ((Field_timestamp*) field)->set_time();
563
607
      }
564
608
      else
565
609
      {
566
 
        uint32_t length;
567
 
        unsigned char save_chr;
 
610
        uint length;
 
611
        uchar save_chr;
568
612
        if ((length=(uint) (read_info.row_end-pos)) >
569
613
            field->field_length)
570
614
          length=field->field_length;
578
622
    if (pos != read_info.row_end)
579
623
    {
580
624
      thd->cuted_fields++;                      /* To long row */
581
 
      push_warning_printf(thd, DRIZZLE_ERROR::WARN_LEVEL_WARN, 
 
625
      push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, 
582
626
                          ER_WARN_TOO_MANY_RECORDS, 
583
627
                          ER(ER_WARN_TOO_MANY_RECORDS), thd->row_count); 
584
628
    }
586
630
    if (thd->killed ||
587
631
        fill_record(thd, set_fields, set_values,
588
632
                    ignore_check_option_errors))
589
 
      return(1);
 
633
      DBUG_RETURN(1);
590
634
 
591
635
    err= write_record(thd, table, &info);
592
 
    table->auto_increment_field_not_null= false;
 
636
    table->auto_increment_field_not_null= FALSE;
593
637
    if (err)
594
 
      return(1);
 
638
      DBUG_RETURN(1);
595
639
   
596
640
    /*
597
641
      We don't need to reset auto-increment field since we are restoring
602
646
    if (read_info.line_cuted)
603
647
    {
604
648
      thd->cuted_fields++;                      /* To long row */
605
 
      push_warning_printf(thd, DRIZZLE_ERROR::WARN_LEVEL_WARN, 
 
649
      push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, 
606
650
                          ER_WARN_TOO_MANY_RECORDS, 
607
651
                          ER(ER_WARN_TOO_MANY_RECORDS), thd->row_count); 
608
652
    }
609
653
    thd->row_count++;
610
654
  }
611
 
  return(test(read_info.error));
 
655
  DBUG_RETURN(test(read_info.error));
612
656
}
613
657
 
614
658
 
615
659
 
616
660
static int
617
 
read_sep_field(THD *thd, COPY_INFO &info, TableList *table_list,
 
661
read_sep_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list,
618
662
               List<Item> &fields_vars, List<Item> &set_fields,
619
663
               List<Item> &set_values, READ_INFO &read_info,
620
 
               String &enclosed, uint32_t skip_lines,
 
664
               String &enclosed, ulong skip_lines,
621
665
               bool ignore_check_option_errors)
622
666
{
623
667
  List_iterator_fast<Item> it(fields_vars);
624
668
  Item *item;
625
 
  Table *table= table_list->table;
626
 
  uint32_t enclosed_length;
627
 
  uint64_t id;
 
669
  TABLE *table= table_list->table;
 
670
  uint enclosed_length;
 
671
  ulonglong id;
628
672
  bool err;
 
673
  DBUG_ENTER("read_sep_field");
629
674
 
630
675
  enclosed_length=enclosed.length();
631
676
  id= 0;
635
680
    if (thd->killed)
636
681
    {
637
682
      thd->send_kill_message();
638
 
      return(1);
 
683
      DBUG_RETURN(1);
639
684
    }
640
685
 
641
686
    restore_record(table, s->default_values);
642
687
 
643
688
    while ((item= it++))
644
689
    {
645
 
      uint32_t length;
646
 
      unsigned char *pos;
 
690
      uint length;
 
691
      uchar *pos;
647
692
      Item *real_item;
648
693
 
649
694
      if (read_info.read_field())
669
714
          {
670
715
            my_error(ER_WARN_NULL_TO_NOTNULL, MYF(0), field->field_name,
671
716
                     thd->row_count);
672
 
            return(1);
 
717
            DBUG_RETURN(1);
673
718
          }
674
719
          field->set_null();
675
720
          if (!field->maybe_null())
676
721
          {
677
 
            if (field->type() == DRIZZLE_TYPE_TIMESTAMP)
 
722
            if (field->type() == MYSQL_TYPE_TIMESTAMP)
678
723
              ((Field_timestamp*) field)->set_time();
679
724
            else if (field != table->next_number_field)
680
 
              field->set_warning(DRIZZLE_ERROR::WARN_LEVEL_WARN,
 
725
              field->set_warning(MYSQL_ERROR::WARN_LEVEL_WARN,
681
726
                                 ER_WARN_NULL_TO_NOTNULL, 1);
682
727
          }
683
728
        }
689
734
        else
690
735
        {
691
736
          my_error(ER_LOAD_DATA_INVALID_COLUMN, MYF(0), item->full_name());
692
 
          return(1);
 
737
          DBUG_RETURN(1);
693
738
        }
694
739
 
695
740
        continue;
701
746
        field->set_notnull();
702
747
        read_info.row_end[0]=0;                 // Safe to change end marker
703
748
        if (field == table->next_number_field)
704
 
          table->auto_increment_field_not_null= true;
 
749
          table->auto_increment_field_not_null= TRUE;
705
750
        field->store((char*) pos, length, read_info.read_charset);
706
751
      }
707
752
      else if (item->type() == Item::STRING_ITEM)
712
757
      else
713
758
      {
714
759
        my_error(ER_LOAD_DATA_INVALID_COLUMN, MYF(0), item->full_name());
715
 
        return(1);
 
760
        DBUG_RETURN(1);
716
761
      }
717
762
    }
718
763
    if (read_info.error)
737
782
          {
738
783
            my_error(ER_WARN_NULL_TO_NOTNULL, MYF(0),field->field_name,
739
784
                     thd->row_count);
740
 
            return(1);
 
785
            DBUG_RETURN(1);
741
786
          }
742
 
          if (!field->maybe_null() && field->type() == DRIZZLE_TYPE_TIMESTAMP)
 
787
          if (!field->maybe_null() && field->type() == FIELD_TYPE_TIMESTAMP)
743
788
              ((Field_timestamp*) field)->set_time();
744
789
          /*
745
790
            QQ: We probably should not throw warning for each field.
748
793
            in the end ?)
749
794
          */
750
795
          thd->cuted_fields++;
751
 
          push_warning_printf(thd, DRIZZLE_ERROR::WARN_LEVEL_WARN,
 
796
          push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
752
797
                              ER_WARN_TOO_FEW_RECORDS,
753
798
                              ER(ER_WARN_TOO_FEW_RECORDS), thd->row_count);
754
799
        }
760
805
        else
761
806
        {
762
807
          my_error(ER_LOAD_DATA_INVALID_COLUMN, MYF(0), item->full_name());
763
 
          return(1);
 
808
          DBUG_RETURN(1);
764
809
        }
765
810
      }
766
811
    }
768
813
    if (thd->killed ||
769
814
        fill_record(thd, set_fields, set_values,
770
815
                    ignore_check_option_errors))
771
 
      return(1);
 
816
      DBUG_RETURN(1);
772
817
 
773
818
    err= write_record(thd, table, &info);
774
 
    table->auto_increment_field_not_null= false;
 
819
    table->auto_increment_field_not_null= FALSE;
775
820
    if (err)
776
 
      return(1);
 
821
      DBUG_RETURN(1);
777
822
    /*
778
823
      We don't need to reset auto-increment field since we are restoring
779
824
      its default value at the beginning of each loop iteration.
783
828
    if (read_info.line_cuted)
784
829
    {
785
830
      thd->cuted_fields++;                      /* To long row */
786
 
      push_warning_printf(thd, DRIZZLE_ERROR::WARN_LEVEL_WARN, 
 
831
      push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, 
787
832
                          ER_WARN_TOO_MANY_RECORDS, ER(ER_WARN_TOO_MANY_RECORDS), 
788
833
                          thd->row_count);   
789
834
      if (thd->killed)
790
 
        return(1);
 
835
        DBUG_RETURN(1);
791
836
    }
792
837
    thd->row_count++;
793
838
  }
794
 
  return(test(read_info.error));
 
839
  DBUG_RETURN(test(read_info.error));
795
840
}
796
841
 
797
842
 
 
843
/****************************************************************************
 
844
** Read rows in xml format
 
845
****************************************************************************/
 
846
static int
 
847
read_xml_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list,
 
848
               List<Item> &fields_vars, List<Item> &set_fields,
 
849
               List<Item> &set_values, READ_INFO &read_info,
 
850
               String &row_tag, ulong skip_lines,
 
851
               bool ignore_check_option_errors)
 
852
{
 
853
  List_iterator_fast<Item> it(fields_vars);
 
854
  Item *item;
 
855
  TABLE *table= table_list->table;
 
856
  bool no_trans_update_stmt;
 
857
  CHARSET_INFO *cs= read_info.read_charset;
 
858
  DBUG_ENTER("read_xml_field");
 
859
  
 
860
  no_trans_update_stmt= !table->file->has_transactions();
 
861
  
 
862
  for ( ; ; it.rewind())
 
863
  {
 
864
    if (thd->killed)
 
865
    {
 
866
      thd->send_kill_message();
 
867
      DBUG_RETURN(1);
 
868
    }
 
869
    
 
870
    // read row tag and save values into tag list
 
871
    if (read_info.read_xml())
 
872
      break;
 
873
    
 
874
    List_iterator_fast<XML_TAG> xmlit(read_info.taglist);
 
875
    xmlit.rewind();
 
876
    XML_TAG *tag= NULL;
 
877
    
 
878
#ifndef DBUG_OFF
 
879
    DBUG_PRINT("read_xml_field", ("skip_lines=%d", (int) skip_lines));
 
880
    while ((tag= xmlit++))
 
881
    {
 
882
      DBUG_PRINT("read_xml_field", ("got tag:%i '%s' '%s'",
 
883
                                    tag->level, tag->field.c_ptr(),
 
884
                                    tag->value.c_ptr()));
 
885
    }
 
886
#endif
 
887
    
 
888
    restore_record(table, s->default_values);
 
889
    
 
890
    while ((item= it++))
 
891
    {
 
892
      /* If this line is to be skipped we don't want to fill field or var */
 
893
      if (skip_lines)
 
894
        continue;
 
895
      
 
896
      /* find field in tag list */
 
897
      xmlit.rewind();
 
898
      tag= xmlit++;
 
899
      
 
900
      while(tag && strcmp(tag->field.c_ptr(), item->name) != 0)
 
901
        tag= xmlit++;
 
902
      
 
903
      if (!tag) // found null
 
904
      {
 
905
        if (item->type() == Item::FIELD_ITEM)
 
906
        {
 
907
          Field *field= ((Item_field *) item)->field;
 
908
          field->reset();
 
909
          field->set_null();
 
910
          if (field == table->next_number_field)
 
911
            table->auto_increment_field_not_null= TRUE;
 
912
          if (!field->maybe_null())
 
913
          {
 
914
            if (field->type() == FIELD_TYPE_TIMESTAMP)
 
915
              ((Field_timestamp *) field)->set_time();
 
916
            else if (field != table->next_number_field)
 
917
              field->set_warning(MYSQL_ERROR::WARN_LEVEL_WARN,
 
918
                                 ER_WARN_NULL_TO_NOTNULL, 1);
 
919
          }
 
920
        }
 
921
        else
 
922
          ((Item_user_var_as_out_param *) item)->set_null_value(cs);
 
923
        continue;
 
924
      }
 
925
 
 
926
      if (item->type() == Item::FIELD_ITEM)
 
927
      {
 
928
 
 
929
        Field *field= ((Item_field *)item)->field;
 
930
        field->set_notnull();
 
931
        if (field == table->next_number_field)
 
932
          table->auto_increment_field_not_null= TRUE;
 
933
        field->store((char *) tag->value.ptr(), tag->value.length(), cs);
 
934
      }
 
935
      else
 
936
        ((Item_user_var_as_out_param *) item)->set_value(
 
937
                                                 (char *) tag->value.ptr(), 
 
938
                                                 tag->value.length(), cs);
 
939
    }
 
940
    
 
941
    if (read_info.error)
 
942
      break;
 
943
    
 
944
    if (skip_lines)
 
945
    {
 
946
      skip_lines--;
 
947
      continue;
 
948
    }
 
949
    
 
950
    if (item)
 
951
    {
 
952
      /* Have not read any field, thus input file is simply ended */
 
953
      if (item == fields_vars.head())
 
954
        break;
 
955
      
 
956
      for ( ; item; item= it++)
 
957
      {
 
958
        if (item->type() == Item::FIELD_ITEM)
 
959
        {
 
960
          /*
 
961
            QQ: We probably should not throw warning for each field.
 
962
            But how about intention to always have the same number
 
963
            of warnings in THD::cuted_fields (and get rid of cuted_fields
 
964
            in the end ?)
 
965
          */
 
966
          thd->cuted_fields++;
 
967
          push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
 
968
                              ER_WARN_TOO_FEW_RECORDS,
 
969
                              ER(ER_WARN_TOO_FEW_RECORDS), thd->row_count);
 
970
        }
 
971
        else
 
972
          ((Item_user_var_as_out_param *)item)->set_null_value(cs);
 
973
      }
 
974
    }
 
975
 
 
976
    if (thd->killed || fill_record(thd, set_fields, set_values,
 
977
                    ignore_check_option_errors))
 
978
      DBUG_RETURN(1);
 
979
 
 
980
    if (write_record(thd, table, &info))
 
981
      DBUG_RETURN(1);
 
982
    
 
983
    /*
 
984
      We don't need to reset auto-increment field since we are restoring
 
985
      its default value at the beginning of each loop iteration.
 
986
    */
 
987
    thd->transaction.stmt.modified_non_trans_table= no_trans_update_stmt;
 
988
    thd->row_count++;
 
989
  }
 
990
  DBUG_RETURN(test(read_info.error));
 
991
} /* load xml end */
 
992
 
 
993
 
798
994
/* Unescape all escape characters, mark \N as null */
799
995
 
800
996
char
822
1018
*/
823
1019
 
824
1020
 
825
 
READ_INFO::READ_INFO(File file_par, uint32_t tot_length, const CHARSET_INFO * const cs,
 
1021
READ_INFO::READ_INFO(File file_par, uint tot_length, CHARSET_INFO *cs,
826
1022
                     String &field_term, String &line_start, String &line_term,
827
1023
                     String &enclosed_par, int escape, bool get_it_from_net,
828
1024
                     bool is_fifo)
833
1029
  field_term_length= field_term.length();
834
1030
  line_term_ptr=(char*) line_term.ptr();
835
1031
  line_term_length= line_term.length();
 
1032
  level= 0; /* for load xml */
836
1033
  if (line_start.length() == 0)
837
1034
  {
838
1035
    line_start_ptr=0;
852
1049
    line_term_ptr=(char*) "";
853
1050
  }
854
1051
  enclosed_char= (enclosed_length=enclosed_par.length()) ?
855
 
    (unsigned char) enclosed_par[0] : INT_MAX;
856
 
  field_term_char= field_term_length ? (unsigned char) field_term_ptr[0] : INT_MAX;
857
 
  line_term_char= line_term_length ? (unsigned char) line_term_ptr[0] : INT_MAX;
 
1052
    (uchar) enclosed_par[0] : INT_MAX;
 
1053
  field_term_char= field_term_length ? (uchar) field_term_ptr[0] : INT_MAX;
 
1054
  line_term_char= line_term_length ? (uchar) line_term_ptr[0] : INT_MAX;
858
1055
  error=eof=found_end_of_line=found_null=line_cuted=0;
859
1056
  buff_length=tot_length;
860
1057
 
861
1058
 
862
1059
  /* Set of a stack for unget if long terminators */
863
 
  uint32_t length=cmax(field_term_length,line_term_length)+1;
 
1060
  uint length=max(field_term_length,line_term_length)+1;
864
1061
  set_if_bigger(length,line_start.length());
865
1062
  stack=stack_pos=(int*) sql_alloc(sizeof(int)*length);
866
1063
 
867
 
  if (!(buffer=(unsigned char*) my_malloc(buff_length+1,MYF(0))))
 
1064
  if (!(buffer=(uchar*) my_malloc(buff_length+1,MYF(0))))
868
1065
    error=1; /* purecov: inspected */
869
1066
  else
870
1067
  {
874
1071
                      (is_fifo ? READ_FIFO : READ_CACHE),0L,1,
875
1072
                      MYF(MY_WME)))
876
1073
    {
877
 
      free((unsigned char*) buffer); /* purecov: inspected */
 
1074
      my_free((uchar*) buffer,MYF(0)); /* purecov: inspected */
878
1075
      error=1;
879
1076
    }
880
1077
    else
903
1100
  {
904
1101
    if (need_end_io_cache)
905
1102
      ::end_io_cache(&cache);
906
 
    free((unsigned char*) buffer);
 
1103
    my_free((uchar*) buffer,MYF(0));
907
1104
    error=1;
908
1105
  }
 
1106
  List_iterator<XML_TAG> xmlit(taglist);
 
1107
  XML_TAG *t;
 
1108
  while ((t= xmlit++))
 
1109
    delete(t);
909
1110
}
910
1111
 
911
1112
 
913
1114
#define PUSH(A) *(stack_pos++)=(A)
914
1115
 
915
1116
 
916
 
inline int READ_INFO::terminator(char *ptr,uint32_t length)
 
1117
inline int READ_INFO::terminator(char *ptr,uint length)
917
1118
{
918
1119
  int chr=0;                                    // Keep gcc happy
919
 
  uint32_t i;
 
1120
  uint i;
920
1121
  for (i=1 ; i < length ; i++)
921
1122
  {
922
1123
    if ((chr=GET) != *++ptr)
928
1129
    return 1;
929
1130
  PUSH(chr);
930
1131
  while (i-- > 1)
931
 
    PUSH((unsigned char) *--ptr);
 
1132
    PUSH((uchar) *--ptr);
932
1133
  return 0;
933
1134
}
934
1135
 
936
1137
int READ_INFO::read_field()
937
1138
{
938
1139
  int chr,found_enclosed_char;
939
 
  unsigned char *to,*new_buffer;
 
1140
  uchar *to,*new_buffer;
940
1141
 
941
1142
  found_null=0;
942
1143
  if (found_end_of_line)
959
1160
  if (chr == enclosed_char)
960
1161
  {
961
1162
    found_enclosed_char=enclosed_char;
962
 
    *to++=(unsigned char) chr;                          // If error
 
1163
    *to++=(uchar) chr;                          // If error
963
1164
  }
964
1165
  else
965
1166
  {
976
1177
      if ((my_mbcharlen(read_charset, chr) > 1) &&
977
1178
          to+my_mbcharlen(read_charset, chr) <= end_of_buff)
978
1179
      {
979
 
          unsigned char* p = (unsigned char*)to;
 
1180
          uchar* p = (uchar*)to;
980
1181
          *to++ = chr;
981
1182
          int ml = my_mbcharlen(read_charset, chr);
982
1183
          int i;
991
1192
                          (const char *)to))
992
1193
            continue;
993
1194
          for (i=0; i<ml; i++)
994
 
            PUSH((unsigned char) *--to);
 
1195
            PUSH((uchar) *--to);
995
1196
          chr = GET;
996
1197
      }
997
1198
#endif
1001
1202
      {
1002
1203
        if ((chr=GET) == my_b_EOF)
1003
1204
        {
1004
 
          *to++= (unsigned char) escape_char;
 
1205
          *to++= (uchar) escape_char;
1005
1206
          goto found_eof;
1006
1207
        }
1007
1208
        /*
1013
1214
         */
1014
1215
        if (escape_char != enclosed_char || chr == escape_char)
1015
1216
        {
1016
 
          *to++ = (unsigned char) unescape((char) chr);
 
1217
          *to++ = (uchar) unescape((char) chr);
1017
1218
          continue;
1018
1219
        }
1019
1220
        PUSH(chr);
1038
1239
      {
1039
1240
        if ((chr=GET) == found_enclosed_char)
1040
1241
        {                                       // Remove dupplicated
1041
 
          *to++ = (unsigned char) chr;
 
1242
          *to++ = (uchar) chr;
1042
1243
          continue;
1043
1244
        }
1044
1245
        // End of enclosed field if followed by field_term or line_term
1077
1278
          return 0;
1078
1279
        }
1079
1280
      }
1080
 
      *to++ = (unsigned char) chr;
 
1281
      *to++ = (uchar) chr;
1081
1282
    }
1082
1283
    /*
1083
1284
    ** We come here if buffer is too small. Enlarge it and continue
1084
1285
    */
1085
 
    if (!(new_buffer=(unsigned char*) my_realloc((char*) buffer,buff_length+1+IO_SIZE,
 
1286
    if (!(new_buffer=(uchar*) my_realloc((char*) buffer,buff_length+1+IO_SIZE,
1086
1287
                                        MYF(MY_WME))))
1087
1288
      return (error=1);
1088
1289
    to=new_buffer + (to-buffer);
1117
1318
int READ_INFO::read_fixed_length()
1118
1319
{
1119
1320
  int chr;
1120
 
  unsigned char *to;
 
1321
  uchar *to;
1121
1322
  if (found_end_of_line)
1122
1323
    return 1;                                   // One have to call next_line
1123
1324
 
1137
1338
    {
1138
1339
      if ((chr=GET) == my_b_EOF)
1139
1340
      {
1140
 
        *to++= (unsigned char) escape_char;
 
1341
        *to++= (uchar) escape_char;
1141
1342
        goto found_eof;
1142
1343
      }
1143
 
      *to++ =(unsigned char) unescape((char) chr);
 
1344
      *to++ =(uchar) unescape((char) chr);
1144
1345
      continue;
1145
1346
    }
1146
1347
    if (chr == line_term_char)
1152
1353
        return 0;
1153
1354
      }
1154
1355
    }
1155
 
    *to++ = (unsigned char) chr;
 
1356
    *to++ = (uchar) chr;
1156
1357
  }
1157
1358
  row_end=to;                                   // Found full line
1158
1359
  return 0;
1183
1384
#ifdef USE_MB
1184
1385
   if (my_mbcharlen(read_charset, chr) > 1)
1185
1386
   {
1186
 
       for (uint32_t i=1;
 
1387
       for (uint i=1;
1187
1388
            chr != my_b_EOF && i<my_mbcharlen(read_charset, chr);
1188
1389
            i++)
1189
1390
           chr = GET;
1230
1431
      PUSH(chr);
1231
1432
      while (--ptr != line_start_ptr)
1232
1433
      {                                         // Restart with next char
1233
 
        PUSH((unsigned char) *ptr);
 
1434
        PUSH((uchar) *ptr);
1234
1435
      }
1235
1436
      goto try_again;
1236
1437
    }
1239
1440
}
1240
1441
 
1241
1442
 
 
1443
/*
 
1444
  Clear taglist from tags with a specified level
 
1445
*/
 
1446
int READ_INFO::clear_level(int level)
 
1447
{
 
1448
  DBUG_ENTER("READ_INFO::read_xml clear_level");
 
1449
  List_iterator<XML_TAG> xmlit(taglist);
 
1450
  xmlit.rewind();
 
1451
  XML_TAG *tag;
 
1452
  
 
1453
  while ((tag= xmlit++))
 
1454
  {
 
1455
     if(tag->level >= level)
 
1456
     {
 
1457
       xmlit.remove();
 
1458
       delete tag;
 
1459
     }
 
1460
  }
 
1461
  DBUG_RETURN(0);
 
1462
}
 
1463
 
 
1464
 
 
1465
/*
 
1466
  Convert an XML entity to Unicode value.
 
1467
  Return -1 on error;
 
1468
*/
 
1469
static int
 
1470
my_xml_entity_to_char(const char *name, uint length)
 
1471
{
 
1472
  if (length == 2)
 
1473
  {
 
1474
    if (!memcmp(name, "gt", length))
 
1475
      return '>';
 
1476
    if (!memcmp(name, "lt", length))
 
1477
      return '<';
 
1478
  }
 
1479
  else if (length == 3)
 
1480
  {
 
1481
    if (!memcmp(name, "amp", length))
 
1482
      return '&';
 
1483
  }
 
1484
  else if (length == 4)
 
1485
  {
 
1486
    if (!memcmp(name, "quot", length))
 
1487
      return '"';
 
1488
    if (!memcmp(name, "apos", length))
 
1489
      return '\'';
 
1490
  }
 
1491
  return -1;
 
1492
}
 
1493
 
 
1494
 
 
1495
/**
 
1496
  @brief Convert newline, linefeed, tab to space
 
1497
  
 
1498
  @param chr    character
 
1499
  
 
1500
  @details According to the "XML 1.0" standard,
 
1501
           only space (#x20) characters, carriage returns,
 
1502
           line feeds or tabs are considered as spaces.
 
1503
           Convert all of them to space (#x20) for parsing simplicity.
 
1504
*/
 
1505
static int
 
1506
my_tospace(int chr)
 
1507
{
 
1508
  return (chr == '\t' || chr == '\r' || chr == '\n') ? ' ' : chr;
 
1509
}
 
1510
 
 
1511
 
 
1512
/*
 
1513
  Read an xml value: handle multibyte and xml escape
 
1514
*/
 
1515
int READ_INFO::read_value(int delim, String *val)
 
1516
{
 
1517
  int chr;
 
1518
  String tmp;
 
1519
 
 
1520
  for (chr= my_tospace(GET); chr != delim && chr != my_b_EOF; )
 
1521
  {
 
1522
#ifdef USE_MB
 
1523
    if (my_mbcharlen(read_charset, chr) > 1)
 
1524
    {
 
1525
      DBUG_PRINT("read_xml",("multi byte"));
 
1526
      int i, ml= my_mbcharlen(read_charset, chr);
 
1527
      for (i= 1; i < ml; i++) 
 
1528
      {
 
1529
        val->append(chr);
 
1530
        /*
 
1531
          Don't use my_tospace() in the middle of a multi-byte character
 
1532
          TODO: check that the multi-byte sequence is valid.
 
1533
        */
 
1534
        chr= GET; 
 
1535
        if (chr == my_b_EOF)
 
1536
          return chr;
 
1537
      }
 
1538
    }
 
1539
#endif
 
1540
    if(chr == '&')
 
1541
    {
 
1542
      tmp.length(0);
 
1543
      for (chr= my_tospace(GET) ; chr != ';' ; chr= my_tospace(GET))
 
1544
      {
 
1545
        if (chr == my_b_EOF)
 
1546
          return chr;
 
1547
        tmp.append(chr);
 
1548
      }
 
1549
      if ((chr= my_xml_entity_to_char(tmp.ptr(), tmp.length())) >= 0)
 
1550
        val->append(chr);
 
1551
      else
 
1552
      {
 
1553
        val->append('&');
 
1554
        val->append(tmp);
 
1555
        val->append(';'); 
 
1556
      }
 
1557
    }
 
1558
    else
 
1559
      val->append(chr);
 
1560
    chr= my_tospace(GET);
 
1561
  }            
 
1562
  return chr;
 
1563
}
 
1564
 
 
1565
 
 
1566
/*
 
1567
  Read a record in xml format
 
1568
  tags and attributes are stored in taglist
 
1569
  when tag set in ROWS IDENTIFIED BY is closed, we are ready and return
 
1570
*/
 
1571
int READ_INFO::read_xml()
 
1572
{
 
1573
  DBUG_ENTER("READ_INFO::read_xml");
 
1574
  int chr, chr2, chr3;
 
1575
  int delim= 0;
 
1576
  String tag, attribute, value;
 
1577
  bool in_tag= false;
 
1578
  
 
1579
  tag.length(0);
 
1580
  attribute.length(0);
 
1581
  value.length(0);
 
1582
  
 
1583
  for (chr= my_tospace(GET); chr != my_b_EOF ; )
 
1584
  {
 
1585
    switch(chr){
 
1586
    case '<':  /* read tag */
 
1587
        /* TODO: check if this is a comment <!-- comment -->  */
 
1588
      chr= my_tospace(GET);
 
1589
      if(chr == '!')
 
1590
      {
 
1591
        chr2= GET;
 
1592
        chr3= GET;
 
1593
        
 
1594
        if(chr2 == '-' && chr3 == '-')
 
1595
        {
 
1596
          chr2= 0;
 
1597
          chr3= 0;
 
1598
          chr= my_tospace(GET);
 
1599
          
 
1600
          while(chr != '>' || chr2 != '-' || chr3 != '-')
 
1601
          {
 
1602
            if(chr == '-')
 
1603
            {
 
1604
              chr3= chr2;
 
1605
              chr2= chr;
 
1606
            }
 
1607
            else if (chr2 == '-')
 
1608
            {
 
1609
              chr2= 0;
 
1610
              chr3= 0;
 
1611
            }
 
1612
            chr= my_tospace(GET);
 
1613
            if (chr == my_b_EOF)
 
1614
              goto found_eof;
 
1615
          }
 
1616
          break;
 
1617
        }
 
1618
      }
 
1619
      
 
1620
      tag.length(0);
 
1621
      while(chr != '>' && chr != ' ' && chr != '/' && chr != my_b_EOF)
 
1622
      {
 
1623
        if(chr != delim) /* fix for the '<field name =' format */
 
1624
          tag.append(chr);
 
1625
        chr= my_tospace(GET);
 
1626
      }
 
1627
      
 
1628
      // row tag should be in ROWS IDENTIFIED BY '<row>' - stored in line_term 
 
1629
      if((tag.length() == line_term_length -2) &&
 
1630
         (strncmp(tag.c_ptr_safe(), line_term_ptr + 1, tag.length()) == 0))
 
1631
      {
 
1632
        DBUG_PRINT("read_xml", ("start-of-row: %i %s %s", 
 
1633
                                level,tag.c_ptr_safe(), line_term_ptr));
 
1634
      }
 
1635
      
 
1636
      if(chr == ' ' || chr == '>')
 
1637
      {
 
1638
        level++;
 
1639
        clear_level(level + 1);
 
1640
      }
 
1641
      
 
1642
      if (chr == ' ')
 
1643
        in_tag= true;
 
1644
      else 
 
1645
        in_tag= false;
 
1646
      break;
 
1647
      
 
1648
    case ' ': /* read attribute */
 
1649
      while(chr == ' ')  /* skip blanks */
 
1650
        chr= my_tospace(GET);
 
1651
      
 
1652
      if(!in_tag)
 
1653
        break;
 
1654
      
 
1655
      while(chr != '=' && chr != '/' && chr != '>' && chr != my_b_EOF)
 
1656
      {
 
1657
        attribute.append(chr);
 
1658
        chr= my_tospace(GET);
 
1659
      }
 
1660
      break;
 
1661
      
 
1662
    case '>': /* end tag - read tag value */
 
1663
      in_tag= false;
 
1664
      chr= read_value('<', &value);
 
1665
      if(chr == my_b_EOF)
 
1666
        goto found_eof;
 
1667
      
 
1668
      /* save value to list */
 
1669
      if(tag.length() > 0 && value.length() > 0)
 
1670
      {
 
1671
        DBUG_PRINT("read_xml", ("lev:%i tag:%s val:%s",
 
1672
                                level,tag.c_ptr_safe(), value.c_ptr_safe()));
 
1673
        taglist.push_front( new XML_TAG(level, tag, value));
 
1674
      }
 
1675
      tag.length(0);
 
1676
      value.length(0);
 
1677
      attribute.length(0);
 
1678
      break;
 
1679
      
 
1680
    case '/': /* close tag */
 
1681
      level--;
 
1682
      chr= my_tospace(GET);
 
1683
      if(chr != '>')   /* if this is an empty tag <tag   /> */
 
1684
        tag.length(0); /* we should keep tag value          */
 
1685
      while(chr != '>' && chr != my_b_EOF)
 
1686
      {
 
1687
        tag.append(chr);
 
1688
        chr= my_tospace(GET);
 
1689
      }
 
1690
      
 
1691
      if((tag.length() == line_term_length -2) &&
 
1692
         (strncmp(tag.c_ptr_safe(), line_term_ptr + 1, tag.length()) == 0))
 
1693
      {
 
1694
         DBUG_PRINT("read_xml", ("found end-of-row %i %s", 
 
1695
                                 level, tag.c_ptr_safe()));
 
1696
         DBUG_RETURN(0); //normal return
 
1697
      }
 
1698
      chr= my_tospace(GET);
 
1699
      break;   
 
1700
      
 
1701
    case '=': /* attribute name end - read the value */
 
1702
      //check for tag field and attribute name
 
1703
      if(!memcmp(tag.c_ptr_safe(), STRING_WITH_LEN("field")) &&
 
1704
         !memcmp(attribute.c_ptr_safe(), STRING_WITH_LEN("name")))
 
1705
      {
 
1706
        /*
 
1707
          this is format <field name="xx">xx</field>
 
1708
          where actual fieldname is in attribute
 
1709
        */
 
1710
        delim= my_tospace(GET);
 
1711
        tag.length(0);
 
1712
        attribute.length(0);
 
1713
        chr= '<'; /* we pretend that it is a tag */
 
1714
        level--;
 
1715
        break;
 
1716
      }
 
1717
      
 
1718
      //check for " or '
 
1719
      chr= GET;
 
1720
      if (chr == my_b_EOF)
 
1721
        goto found_eof;
 
1722
      if(chr == '"' || chr == '\'')
 
1723
      {
 
1724
        delim= chr;
 
1725
      }
 
1726
      else
 
1727
      {
 
1728
        delim= ' '; /* no delimiter, use space */
 
1729
        PUSH(chr);
 
1730
      }
 
1731
      
 
1732
      chr= read_value(delim, &value);
 
1733
      if(attribute.length() > 0 && value.length() > 0)
 
1734
      {
 
1735
        DBUG_PRINT("read_xml", ("lev:%i att:%s val:%s\n",
 
1736
                                level + 1,
 
1737
                                attribute.c_ptr_safe(),
 
1738
                                value.c_ptr_safe()));
 
1739
        taglist.push_front(new XML_TAG(level + 1, attribute, value));
 
1740
      }
 
1741
      attribute.length(0);
 
1742
      value.length(0);
 
1743
      if (chr != ' ')
 
1744
        chr= my_tospace(GET);
 
1745
      break;
 
1746
    
 
1747
    default:
 
1748
      chr= my_tospace(GET);
 
1749
    } /* end switch */
 
1750
  } /* end while */
 
1751
  
 
1752
found_eof:
 
1753
  DBUG_PRINT("read_xml",("Found eof"));
 
1754
  eof= 1;
 
1755
  DBUG_RETURN(1);
 
1756
}