~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to server/sql_load.cc

Merged.

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,
108
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;
135
165
 
208
238
 
209
239
  table->mark_columns_needed_for_insert();
210
240
 
211
 
  uint32_t tot_length=0;
 
241
  uint tot_length=0;
212
242
  bool use_blobs= 0, use_vars= 0;
213
243
  List_iterator_fast<Item> it(fields_vars);
214
244
  Item *item;
259
289
#endif
260
290
    if (!dirname_length(ex->file_name))
261
291
    {
262
 
      strxnmov(name, FN_REFLEN-1, mysql_real_data_home, tdb, NULL);
 
292
      strxnmov(name, FN_REFLEN-1, mysql_real_data_home, tdb, NullS);
263
293
      (void) fn_format(name, ex->file_name, name, "",
264
294
                       MY_RELATIVE_PATH | MY_UNPACK_FILENAME);
265
295
    }
298
328
  }
299
329
 
300
330
  COPY_INFO info;
301
 
  memset(&info, 0, sizeof(info));
 
331
  bzero((char*) &info,sizeof(info));
302
332
  info.ignore= ignore;
303
333
  info.handle_duplicates=handle_duplicates;
304
334
  info.escape_char=escaped->length() ? (*escaped)[0] : INT_MAX;
326
356
  thd->count_cuted_fields= CHECK_FIELD_WARN;            /* calc cuted fields */
327
357
  thd->cuted_fields=0L;
328
358
  /* Skip lines if there is a line terminator */
329
 
  if (ex->line_term->length())
 
359
  if (ex->line_term->length() && ex->filetype != FILETYPE_XML)
330
360
  {
331
361
    /* ex->skip_lines needs to be preserved for logging */
332
362
    while (skip_lines > 0)
349
379
    table->file->ha_start_bulk_insert((ha_rows) 0);
350
380
    table->copy_blobs=1;
351
381
 
352
 
    thd->abort_on_warning= true;
 
382
    thd->abort_on_warning= (!ignore &&
 
383
                            (thd->variables.sql_mode &
 
384
                             (MODE_STRICT_TRANS_TABLES |
 
385
                              MODE_STRICT_ALL_TABLES)));
353
386
 
354
 
    if (!field_term->length() && !enclosed->length())
 
387
    if (ex->filetype == FILETYPE_XML) /* load xml */
 
388
      error= read_xml_field(thd, info, table_list, fields_vars,
 
389
                            set_fields, set_values, read_info,
 
390
                            *(ex->line_term), skip_lines, ignore);
 
391
    else if (!field_term->length() && !enclosed->length())
355
392
      error= read_fixed_length(thd, info, table_list, fields_vars,
356
393
                               set_fields, set_values, read_info,
357
394
                               skip_lines, ignore);
429
466
    error= -1;                          // Error on read
430
467
    goto err;
431
468
  }
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);
 
469
  sprintf(name, ER(ER_LOAD_INFO), (ulong) info.records, (ulong) info.deleted,
 
470
          (ulong) (info.records - info.copied), (ulong) thd->cuted_fields);
434
471
 
435
472
  if (thd->transaction.stmt.modified_non_trans_table)
436
473
    thd->transaction.all.modified_non_trans_table= true;
498
535
****************************************************************************/
499
536
 
500
537
static int
501
 
read_fixed_length(THD *thd, COPY_INFO &info, TableList *table_list,
 
538
read_fixed_length(THD *thd, COPY_INFO &info, TABLE_LIST *table_list,
502
539
                  List<Item> &fields_vars, List<Item> &set_fields,
503
540
                  List<Item> &set_values, READ_INFO &read_info,
504
 
                  uint32_t skip_lines, bool ignore_check_option_errors)
 
541
                  ulong skip_lines, bool ignore_check_option_errors)
505
542
{
506
543
  List_iterator_fast<Item> it(fields_vars);
507
544
  Item_field *sql_field;
508
 
  Table *table= table_list->table;
 
545
  TABLE *table= table_list->table;
509
546
  uint64_t id;
510
547
  bool err;
511
548
 
530
567
      continue;
531
568
    }
532
569
    it.rewind();
533
 
    unsigned char *pos=read_info.row_start;
 
570
    uchar *pos=read_info.row_start;
534
571
#ifdef HAVE_purify
535
572
    read_info.row_end[0]=0;
536
573
#endif
555
592
      if (pos == read_info.row_end)
556
593
      {
557
594
        thd->cuted_fields++;                    /* Not enough fields */
558
 
        push_warning_printf(thd, DRIZZLE_ERROR::WARN_LEVEL_WARN, 
 
595
        push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, 
559
596
                            ER_WARN_TOO_FEW_RECORDS, 
560
597
                            ER(ER_WARN_TOO_FEW_RECORDS), thd->row_count);
561
 
        if (!field->maybe_null() && field->type() == DRIZZLE_TYPE_TIMESTAMP)
 
598
        if (!field->maybe_null() && field->type() == FIELD_TYPE_TIMESTAMP)
562
599
            ((Field_timestamp*) field)->set_time();
563
600
      }
564
601
      else
565
602
      {
566
 
        uint32_t length;
567
 
        unsigned char save_chr;
 
603
        uint length;
 
604
        uchar save_chr;
568
605
        if ((length=(uint) (read_info.row_end-pos)) >
569
606
            field->field_length)
570
607
          length=field->field_length;
578
615
    if (pos != read_info.row_end)
579
616
    {
580
617
      thd->cuted_fields++;                      /* To long row */
581
 
      push_warning_printf(thd, DRIZZLE_ERROR::WARN_LEVEL_WARN, 
 
618
      push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, 
582
619
                          ER_WARN_TOO_MANY_RECORDS, 
583
620
                          ER(ER_WARN_TOO_MANY_RECORDS), thd->row_count); 
584
621
    }
602
639
    if (read_info.line_cuted)
603
640
    {
604
641
      thd->cuted_fields++;                      /* To long row */
605
 
      push_warning_printf(thd, DRIZZLE_ERROR::WARN_LEVEL_WARN, 
 
642
      push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, 
606
643
                          ER_WARN_TOO_MANY_RECORDS, 
607
644
                          ER(ER_WARN_TOO_MANY_RECORDS), thd->row_count); 
608
645
    }
614
651
 
615
652
 
616
653
static int
617
 
read_sep_field(THD *thd, COPY_INFO &info, TableList *table_list,
 
654
read_sep_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list,
618
655
               List<Item> &fields_vars, List<Item> &set_fields,
619
656
               List<Item> &set_values, READ_INFO &read_info,
620
 
               String &enclosed, uint32_t skip_lines,
 
657
               String &enclosed, ulong skip_lines,
621
658
               bool ignore_check_option_errors)
622
659
{
623
660
  List_iterator_fast<Item> it(fields_vars);
624
661
  Item *item;
625
 
  Table *table= table_list->table;
626
 
  uint32_t enclosed_length;
 
662
  TABLE *table= table_list->table;
 
663
  uint enclosed_length;
627
664
  uint64_t id;
628
665
  bool err;
629
666
 
642
679
 
643
680
    while ((item= it++))
644
681
    {
645
 
      uint32_t length;
646
 
      unsigned char *pos;
 
682
      uint length;
 
683
      uchar *pos;
647
684
      Item *real_item;
648
685
 
649
686
      if (read_info.read_field())
674
711
          field->set_null();
675
712
          if (!field->maybe_null())
676
713
          {
677
 
            if (field->type() == DRIZZLE_TYPE_TIMESTAMP)
 
714
            if (field->type() == MYSQL_TYPE_TIMESTAMP)
678
715
              ((Field_timestamp*) field)->set_time();
679
716
            else if (field != table->next_number_field)
680
 
              field->set_warning(DRIZZLE_ERROR::WARN_LEVEL_WARN,
 
717
              field->set_warning(MYSQL_ERROR::WARN_LEVEL_WARN,
681
718
                                 ER_WARN_NULL_TO_NOTNULL, 1);
682
719
          }
683
720
        }
739
776
                     thd->row_count);
740
777
            return(1);
741
778
          }
742
 
          if (!field->maybe_null() && field->type() == DRIZZLE_TYPE_TIMESTAMP)
 
779
          if (!field->maybe_null() && field->type() == FIELD_TYPE_TIMESTAMP)
743
780
              ((Field_timestamp*) field)->set_time();
744
781
          /*
745
782
            QQ: We probably should not throw warning for each field.
748
785
            in the end ?)
749
786
          */
750
787
          thd->cuted_fields++;
751
 
          push_warning_printf(thd, DRIZZLE_ERROR::WARN_LEVEL_WARN,
 
788
          push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
752
789
                              ER_WARN_TOO_FEW_RECORDS,
753
790
                              ER(ER_WARN_TOO_FEW_RECORDS), thd->row_count);
754
791
        }
783
820
    if (read_info.line_cuted)
784
821
    {
785
822
      thd->cuted_fields++;                      /* To long row */
786
 
      push_warning_printf(thd, DRIZZLE_ERROR::WARN_LEVEL_WARN, 
 
823
      push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, 
787
824
                          ER_WARN_TOO_MANY_RECORDS, ER(ER_WARN_TOO_MANY_RECORDS), 
788
825
                          thd->row_count);   
789
826
      if (thd->killed)
795
832
}
796
833
 
797
834
 
 
835
/****************************************************************************
 
836
** Read rows in xml format
 
837
****************************************************************************/
 
838
static int
 
839
read_xml_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list,
 
840
               List<Item> &fields_vars, List<Item> &set_fields,
 
841
               List<Item> &set_values, READ_INFO &read_info,
 
842
               String &row_tag __attribute__((__unused__)),
 
843
               ulong skip_lines,
 
844
               bool ignore_check_option_errors)
 
845
{
 
846
  List_iterator_fast<Item> it(fields_vars);
 
847
  Item *item;
 
848
  TABLE *table= table_list->table;
 
849
  bool no_trans_update_stmt;
 
850
  CHARSET_INFO *cs= read_info.read_charset;
 
851
 
 
852
  no_trans_update_stmt= !table->file->has_transactions();
 
853
 
 
854
  for ( ; ; it.rewind())
 
855
  {
 
856
    if (thd->killed)
 
857
    {
 
858
      thd->send_kill_message();
 
859
      return(1);
 
860
    }
 
861
    
 
862
    // read row tag and save values into tag list
 
863
    if (read_info.read_xml())
 
864
      break;
 
865
    
 
866
    List_iterator_fast<XML_TAG> xmlit(read_info.taglist);
 
867
    xmlit.rewind();
 
868
    XML_TAG *tag= NULL;
 
869
    
 
870
    
 
871
    restore_record(table, s->default_values);
 
872
    
 
873
    while ((item= it++))
 
874
    {
 
875
      /* If this line is to be skipped we don't want to fill field or var */
 
876
      if (skip_lines)
 
877
        continue;
 
878
      
 
879
      /* find field in tag list */
 
880
      xmlit.rewind();
 
881
      tag= xmlit++;
 
882
      
 
883
      while(tag && strcmp(tag->field.c_ptr(), item->name) != 0)
 
884
        tag= xmlit++;
 
885
      
 
886
      if (!tag) // found null
 
887
      {
 
888
        if (item->type() == Item::FIELD_ITEM)
 
889
        {
 
890
          Field *field= ((Item_field *) item)->field;
 
891
          field->reset();
 
892
          field->set_null();
 
893
          if (field == table->next_number_field)
 
894
            table->auto_increment_field_not_null= true;
 
895
          if (!field->maybe_null())
 
896
          {
 
897
            if (field->type() == FIELD_TYPE_TIMESTAMP)
 
898
              ((Field_timestamp *) field)->set_time();
 
899
            else if (field != table->next_number_field)
 
900
              field->set_warning(MYSQL_ERROR::WARN_LEVEL_WARN,
 
901
                                 ER_WARN_NULL_TO_NOTNULL, 1);
 
902
          }
 
903
        }
 
904
        else
 
905
          ((Item_user_var_as_out_param *) item)->set_null_value(cs);
 
906
        continue;
 
907
      }
 
908
 
 
909
      if (item->type() == Item::FIELD_ITEM)
 
910
      {
 
911
 
 
912
        Field *field= ((Item_field *)item)->field;
 
913
        field->set_notnull();
 
914
        if (field == table->next_number_field)
 
915
          table->auto_increment_field_not_null= true;
 
916
        field->store((char *) tag->value.ptr(), tag->value.length(), cs);
 
917
      }
 
918
      else
 
919
        ((Item_user_var_as_out_param *) item)->set_value(
 
920
                                                 (char *) tag->value.ptr(), 
 
921
                                                 tag->value.length(), cs);
 
922
    }
 
923
    
 
924
    if (read_info.error)
 
925
      break;
 
926
    
 
927
    if (skip_lines)
 
928
    {
 
929
      skip_lines--;
 
930
      continue;
 
931
    }
 
932
    
 
933
    if (item)
 
934
    {
 
935
      /* Have not read any field, thus input file is simply ended */
 
936
      if (item == fields_vars.head())
 
937
        break;
 
938
      
 
939
      for ( ; item; item= it++)
 
940
      {
 
941
        if (item->type() == Item::FIELD_ITEM)
 
942
        {
 
943
          /*
 
944
            QQ: We probably should not throw warning for each field.
 
945
            But how about intention to always have the same number
 
946
            of warnings in THD::cuted_fields (and get rid of cuted_fields
 
947
            in the end ?)
 
948
          */
 
949
          thd->cuted_fields++;
 
950
          push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
 
951
                              ER_WARN_TOO_FEW_RECORDS,
 
952
                              ER(ER_WARN_TOO_FEW_RECORDS), thd->row_count);
 
953
        }
 
954
        else
 
955
          ((Item_user_var_as_out_param *)item)->set_null_value(cs);
 
956
      }
 
957
    }
 
958
 
 
959
    if (thd->killed || fill_record(thd, set_fields, set_values,
 
960
                    ignore_check_option_errors))
 
961
      return(1);
 
962
 
 
963
    if (write_record(thd, table, &info))
 
964
      return(1);
 
965
    
 
966
    /*
 
967
      We don't need to reset auto-increment field since we are restoring
 
968
      its default value at the beginning of each loop iteration.
 
969
    */
 
970
    thd->transaction.stmt.modified_non_trans_table= no_trans_update_stmt;
 
971
    thd->row_count++;
 
972
  }
 
973
  return(test(read_info.error));
 
974
} /* load xml end */
 
975
 
 
976
 
798
977
/* Unescape all escape characters, mark \N as null */
799
978
 
800
979
char
822
1001
*/
823
1002
 
824
1003
 
825
 
READ_INFO::READ_INFO(File file_par, uint32_t tot_length, const CHARSET_INFO * const cs,
 
1004
READ_INFO::READ_INFO(File file_par, uint tot_length, CHARSET_INFO *cs,
826
1005
                     String &field_term, String &line_start, String &line_term,
827
1006
                     String &enclosed_par, int escape, bool get_it_from_net,
828
1007
                     bool is_fifo)
833
1012
  field_term_length= field_term.length();
834
1013
  line_term_ptr=(char*) line_term.ptr();
835
1014
  line_term_length= line_term.length();
 
1015
  level= 0; /* for load xml */
836
1016
  if (line_start.length() == 0)
837
1017
  {
838
1018
    line_start_ptr=0;
852
1032
    line_term_ptr=(char*) "";
853
1033
  }
854
1034
  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;
 
1035
    (uchar) enclosed_par[0] : INT_MAX;
 
1036
  field_term_char= field_term_length ? (uchar) field_term_ptr[0] : INT_MAX;
 
1037
  line_term_char= line_term_length ? (uchar) line_term_ptr[0] : INT_MAX;
858
1038
  error=eof=found_end_of_line=found_null=line_cuted=0;
859
1039
  buff_length=tot_length;
860
1040
 
861
1041
 
862
1042
  /* Set of a stack for unget if long terminators */
863
 
  uint32_t length=cmax(field_term_length,line_term_length)+1;
 
1043
  uint length=max(field_term_length,line_term_length)+1;
864
1044
  set_if_bigger(length,line_start.length());
865
1045
  stack=stack_pos=(int*) sql_alloc(sizeof(int)*length);
866
1046
 
867
 
  if (!(buffer=(unsigned char*) my_malloc(buff_length+1,MYF(0))))
 
1047
  if (!(buffer=(uchar*) my_malloc(buff_length+1,MYF(0))))
868
1048
    error=1; /* purecov: inspected */
869
1049
  else
870
1050
  {
874
1054
                      (is_fifo ? READ_FIFO : READ_CACHE),0L,1,
875
1055
                      MYF(MY_WME)))
876
1056
    {
877
 
      free((unsigned char*) buffer); /* purecov: inspected */
 
1057
      my_free((uchar*) buffer,MYF(0)); /* purecov: inspected */
878
1058
      error=1;
879
1059
    }
880
1060
    else
903
1083
  {
904
1084
    if (need_end_io_cache)
905
1085
      ::end_io_cache(&cache);
906
 
    free((unsigned char*) buffer);
 
1086
    my_free((uchar*) buffer,MYF(0));
907
1087
    error=1;
908
1088
  }
 
1089
  List_iterator<XML_TAG> xmlit(taglist);
 
1090
  XML_TAG *t;
 
1091
  while ((t= xmlit++))
 
1092
    delete(t);
909
1093
}
910
1094
 
911
1095
 
913
1097
#define PUSH(A) *(stack_pos++)=(A)
914
1098
 
915
1099
 
916
 
inline int READ_INFO::terminator(char *ptr,uint32_t length)
 
1100
inline int READ_INFO::terminator(char *ptr,uint length)
917
1101
{
918
1102
  int chr=0;                                    // Keep gcc happy
919
 
  uint32_t i;
 
1103
  uint i;
920
1104
  for (i=1 ; i < length ; i++)
921
1105
  {
922
1106
    if ((chr=GET) != *++ptr)
928
1112
    return 1;
929
1113
  PUSH(chr);
930
1114
  while (i-- > 1)
931
 
    PUSH((unsigned char) *--ptr);
 
1115
    PUSH((uchar) *--ptr);
932
1116
  return 0;
933
1117
}
934
1118
 
936
1120
int READ_INFO::read_field()
937
1121
{
938
1122
  int chr,found_enclosed_char;
939
 
  unsigned char *to,*new_buffer;
 
1123
  uchar *to,*new_buffer;
940
1124
 
941
1125
  found_null=0;
942
1126
  if (found_end_of_line)
959
1143
  if (chr == enclosed_char)
960
1144
  {
961
1145
    found_enclosed_char=enclosed_char;
962
 
    *to++=(unsigned char) chr;                          // If error
 
1146
    *to++=(uchar) chr;                          // If error
963
1147
  }
964
1148
  else
965
1149
  {
976
1160
      if ((my_mbcharlen(read_charset, chr) > 1) &&
977
1161
          to+my_mbcharlen(read_charset, chr) <= end_of_buff)
978
1162
      {
979
 
          unsigned char* p = (unsigned char*)to;
 
1163
          uchar* p = (uchar*)to;
980
1164
          *to++ = chr;
981
1165
          int ml = my_mbcharlen(read_charset, chr);
982
1166
          int i;
991
1175
                          (const char *)to))
992
1176
            continue;
993
1177
          for (i=0; i<ml; i++)
994
 
            PUSH((unsigned char) *--to);
 
1178
            PUSH((uchar) *--to);
995
1179
          chr = GET;
996
1180
      }
997
1181
#endif
1001
1185
      {
1002
1186
        if ((chr=GET) == my_b_EOF)
1003
1187
        {
1004
 
          *to++= (unsigned char) escape_char;
 
1188
          *to++= (uchar) escape_char;
1005
1189
          goto found_eof;
1006
1190
        }
1007
1191
        /*
1013
1197
         */
1014
1198
        if (escape_char != enclosed_char || chr == escape_char)
1015
1199
        {
1016
 
          *to++ = (unsigned char) unescape((char) chr);
 
1200
          *to++ = (uchar) unescape((char) chr);
1017
1201
          continue;
1018
1202
        }
1019
1203
        PUSH(chr);
1038
1222
      {
1039
1223
        if ((chr=GET) == found_enclosed_char)
1040
1224
        {                                       // Remove dupplicated
1041
 
          *to++ = (unsigned char) chr;
 
1225
          *to++ = (uchar) chr;
1042
1226
          continue;
1043
1227
        }
1044
1228
        // End of enclosed field if followed by field_term or line_term
1077
1261
          return 0;
1078
1262
        }
1079
1263
      }
1080
 
      *to++ = (unsigned char) chr;
 
1264
      *to++ = (uchar) chr;
1081
1265
    }
1082
1266
    /*
1083
1267
    ** We come here if buffer is too small. Enlarge it and continue
1084
1268
    */
1085
 
    if (!(new_buffer=(unsigned char*) my_realloc((char*) buffer,buff_length+1+IO_SIZE,
 
1269
    if (!(new_buffer=(uchar*) my_realloc((char*) buffer,buff_length+1+IO_SIZE,
1086
1270
                                        MYF(MY_WME))))
1087
1271
      return (error=1);
1088
1272
    to=new_buffer + (to-buffer);
1117
1301
int READ_INFO::read_fixed_length()
1118
1302
{
1119
1303
  int chr;
1120
 
  unsigned char *to;
 
1304
  uchar *to;
1121
1305
  if (found_end_of_line)
1122
1306
    return 1;                                   // One have to call next_line
1123
1307
 
1137
1321
    {
1138
1322
      if ((chr=GET) == my_b_EOF)
1139
1323
      {
1140
 
        *to++= (unsigned char) escape_char;
 
1324
        *to++= (uchar) escape_char;
1141
1325
        goto found_eof;
1142
1326
      }
1143
 
      *to++ =(unsigned char) unescape((char) chr);
 
1327
      *to++ =(uchar) unescape((char) chr);
1144
1328
      continue;
1145
1329
    }
1146
1330
    if (chr == line_term_char)
1152
1336
        return 0;
1153
1337
      }
1154
1338
    }
1155
 
    *to++ = (unsigned char) chr;
 
1339
    *to++ = (uchar) chr;
1156
1340
  }
1157
1341
  row_end=to;                                   // Found full line
1158
1342
  return 0;
1183
1367
#ifdef USE_MB
1184
1368
   if (my_mbcharlen(read_charset, chr) > 1)
1185
1369
   {
1186
 
       for (uint32_t i=1;
 
1370
       for (uint i=1;
1187
1371
            chr != my_b_EOF && i<my_mbcharlen(read_charset, chr);
1188
1372
            i++)
1189
1373
           chr = GET;
1230
1414
      PUSH(chr);
1231
1415
      while (--ptr != line_start_ptr)
1232
1416
      {                                         // Restart with next char
1233
 
        PUSH((unsigned char) *ptr);
 
1417
        PUSH((uchar) *ptr);
1234
1418
      }
1235
1419
      goto try_again;
1236
1420
    }
1239
1423
}
1240
1424
 
1241
1425
 
 
1426
/*
 
1427
  Clear taglist from tags with a specified level
 
1428
*/
 
1429
int READ_INFO::clear_level(int level)
 
1430
{
 
1431
  List_iterator<XML_TAG> xmlit(taglist);
 
1432
  xmlit.rewind();
 
1433
  XML_TAG *tag;
 
1434
  
 
1435
  while ((tag= xmlit++))
 
1436
  {
 
1437
     if(tag->level >= level)
 
1438
     {
 
1439
       xmlit.remove();
 
1440
       delete tag;
 
1441
     }
 
1442
  }
 
1443
  return(0);
 
1444
}
 
1445
 
 
1446
 
 
1447
/*
 
1448
  Convert an XML entity to Unicode value.
 
1449
  Return -1 on error;
 
1450
*/
 
1451
static int
 
1452
my_xml_entity_to_char(const char *name, uint length)
 
1453
{
 
1454
  if (length == 2)
 
1455
  {
 
1456
    if (!memcmp(name, "gt", length))
 
1457
      return '>';
 
1458
    if (!memcmp(name, "lt", length))
 
1459
      return '<';
 
1460
  }
 
1461
  else if (length == 3)
 
1462
  {
 
1463
    if (!memcmp(name, "amp", length))
 
1464
      return '&';
 
1465
  }
 
1466
  else if (length == 4)
 
1467
  {
 
1468
    if (!memcmp(name, "quot", length))
 
1469
      return '"';
 
1470
    if (!memcmp(name, "apos", length))
 
1471
      return '\'';
 
1472
  }
 
1473
  return -1;
 
1474
}
 
1475
 
 
1476
 
 
1477
/**
 
1478
  @brief Convert newline, linefeed, tab to space
 
1479
  
 
1480
  @param chr    character
 
1481
  
 
1482
  @details According to the "XML 1.0" standard,
 
1483
           only space (#x20) characters, carriage returns,
 
1484
           line feeds or tabs are considered as spaces.
 
1485
           Convert all of them to space (#x20) for parsing simplicity.
 
1486
*/
 
1487
static int
 
1488
my_tospace(int chr)
 
1489
{
 
1490
  return (chr == '\t' || chr == '\r' || chr == '\n') ? ' ' : chr;
 
1491
}
 
1492
 
 
1493
 
 
1494
/*
 
1495
  Read an xml value: handle multibyte and xml escape
 
1496
*/
 
1497
int READ_INFO::read_value(int delim, String *val)
 
1498
{
 
1499
  int chr;
 
1500
  String tmp;
 
1501
 
 
1502
  for (chr= my_tospace(GET); chr != delim && chr != my_b_EOF; )
 
1503
  {
 
1504
#ifdef USE_MB
 
1505
    if (my_mbcharlen(read_charset, chr) > 1)
 
1506
    {
 
1507
      int i, ml= my_mbcharlen(read_charset, chr);
 
1508
      for (i= 1; i < ml; i++) 
 
1509
      {
 
1510
        val->append(chr);
 
1511
        /*
 
1512
          Don't use my_tospace() in the middle of a multi-byte character
 
1513
          TODO: check that the multi-byte sequence is valid.
 
1514
        */
 
1515
        chr= GET; 
 
1516
        if (chr == my_b_EOF)
 
1517
          return chr;
 
1518
      }
 
1519
    }
 
1520
#endif
 
1521
    if(chr == '&')
 
1522
    {
 
1523
      tmp.length(0);
 
1524
      for (chr= my_tospace(GET) ; chr != ';' ; chr= my_tospace(GET))
 
1525
      {
 
1526
        if (chr == my_b_EOF)
 
1527
          return chr;
 
1528
        tmp.append(chr);
 
1529
      }
 
1530
      if ((chr= my_xml_entity_to_char(tmp.ptr(), tmp.length())) >= 0)
 
1531
        val->append(chr);
 
1532
      else
 
1533
      {
 
1534
        val->append('&');
 
1535
        val->append(tmp);
 
1536
        val->append(';'); 
 
1537
      }
 
1538
    }
 
1539
    else
 
1540
      val->append(chr);
 
1541
    chr= my_tospace(GET);
 
1542
  }            
 
1543
  return chr;
 
1544
}
 
1545
 
 
1546
 
 
1547
/*
 
1548
  Read a record in xml format
 
1549
  tags and attributes are stored in taglist
 
1550
  when tag set in ROWS IDENTIFIED BY is closed, we are ready and return
 
1551
*/
 
1552
int READ_INFO::read_xml()
 
1553
{
 
1554
  int chr, chr2, chr3;
 
1555
  int delim= 0;
 
1556
  String tag, attribute, value;
 
1557
  bool in_tag= false;
 
1558
  
 
1559
  tag.length(0);
 
1560
  attribute.length(0);
 
1561
  value.length(0);
 
1562
  
 
1563
  for (chr= my_tospace(GET); chr != my_b_EOF ; )
 
1564
  {
 
1565
    switch(chr){
 
1566
    case '<':  /* read tag */
 
1567
        /* TODO: check if this is a comment <!-- comment -->  */
 
1568
      chr= my_tospace(GET);
 
1569
      if(chr == '!')
 
1570
      {
 
1571
        chr2= GET;
 
1572
        chr3= GET;
 
1573
        
 
1574
        if(chr2 == '-' && chr3 == '-')
 
1575
        {
 
1576
          chr2= 0;
 
1577
          chr3= 0;
 
1578
          chr= my_tospace(GET);
 
1579
          
 
1580
          while(chr != '>' || chr2 != '-' || chr3 != '-')
 
1581
          {
 
1582
            if(chr == '-')
 
1583
            {
 
1584
              chr3= chr2;
 
1585
              chr2= chr;
 
1586
            }
 
1587
            else if (chr2 == '-')
 
1588
            {
 
1589
              chr2= 0;
 
1590
              chr3= 0;
 
1591
            }
 
1592
            chr= my_tospace(GET);
 
1593
            if (chr == my_b_EOF)
 
1594
              goto found_eof;
 
1595
          }
 
1596
          break;
 
1597
        }
 
1598
      }
 
1599
      
 
1600
      tag.length(0);
 
1601
      while(chr != '>' && chr != ' ' && chr != '/' && chr != my_b_EOF)
 
1602
      {
 
1603
        if(chr != delim) /* fix for the '<field name =' format */
 
1604
          tag.append(chr);
 
1605
        chr= my_tospace(GET);
 
1606
      }
 
1607
      
 
1608
      if(chr == ' ' || chr == '>')
 
1609
      {
 
1610
        level++;
 
1611
        clear_level(level + 1);
 
1612
      }
 
1613
      
 
1614
      if (chr == ' ')
 
1615
        in_tag= true;
 
1616
      else 
 
1617
        in_tag= false;
 
1618
      break;
 
1619
      
 
1620
    case ' ': /* read attribute */
 
1621
      while(chr == ' ')  /* skip blanks */
 
1622
        chr= my_tospace(GET);
 
1623
      
 
1624
      if(!in_tag)
 
1625
        break;
 
1626
      
 
1627
      while(chr != '=' && chr != '/' && chr != '>' && chr != my_b_EOF)
 
1628
      {
 
1629
        attribute.append(chr);
 
1630
        chr= my_tospace(GET);
 
1631
      }
 
1632
      break;
 
1633
      
 
1634
    case '>': /* end tag - read tag value */
 
1635
      in_tag= false;
 
1636
      chr= read_value('<', &value);
 
1637
      if(chr == my_b_EOF)
 
1638
        goto found_eof;
 
1639
      
 
1640
      /* save value to list */
 
1641
      if(tag.length() > 0 && value.length() > 0)
 
1642
        taglist.push_front( new XML_TAG(level, tag, value));
 
1643
 
 
1644
      tag.length(0);
 
1645
      value.length(0);
 
1646
      attribute.length(0);
 
1647
      break;
 
1648
      
 
1649
    case '/': /* close tag */
 
1650
      level--;
 
1651
      chr= my_tospace(GET);
 
1652
      if(chr != '>')   /* if this is an empty tag <tag   /> */
 
1653
        tag.length(0); /* we should keep tag value          */
 
1654
      while(chr != '>' && chr != my_b_EOF)
 
1655
      {
 
1656
        tag.append(chr);
 
1657
        chr= my_tospace(GET);
 
1658
      }
 
1659
      
 
1660
      if((tag.length() == line_term_length -2) &&
 
1661
         (strncmp(tag.c_ptr_safe(), line_term_ptr + 1, tag.length()) == 0))
 
1662
         return(0); //normal return
 
1663
 
 
1664
      chr= my_tospace(GET);
 
1665
      break;   
 
1666
      
 
1667
    case '=': /* attribute name end - read the value */
 
1668
      //check for tag field and attribute name
 
1669
      if(!memcmp(tag.c_ptr_safe(), STRING_WITH_LEN("field")) &&
 
1670
         !memcmp(attribute.c_ptr_safe(), STRING_WITH_LEN("name")))
 
1671
      {
 
1672
        /*
 
1673
          this is format <field name="xx">xx</field>
 
1674
          where actual fieldname is in attribute
 
1675
        */
 
1676
        delim= my_tospace(GET);
 
1677
        tag.length(0);
 
1678
        attribute.length(0);
 
1679
        chr= '<'; /* we pretend that it is a tag */
 
1680
        level--;
 
1681
        break;
 
1682
      }
 
1683
      
 
1684
      //check for " or '
 
1685
      chr= GET;
 
1686
      if (chr == my_b_EOF)
 
1687
        goto found_eof;
 
1688
      if(chr == '"' || chr == '\'')
 
1689
      {
 
1690
        delim= chr;
 
1691
      }
 
1692
      else
 
1693
      {
 
1694
        delim= ' '; /* no delimiter, use space */
 
1695
        PUSH(chr);
 
1696
      }
 
1697
      
 
1698
      chr= read_value(delim, &value);
 
1699
      if(attribute.length() > 0 && value.length() > 0)
 
1700
        taglist.push_front(new XML_TAG(level + 1, attribute, value));
 
1701
 
 
1702
      attribute.length(0);
 
1703
      value.length(0);
 
1704
      if (chr != ' ')
 
1705
        chr= my_tospace(GET);
 
1706
      break;
 
1707
    
 
1708
    default:
 
1709
      chr= my_tospace(GET);
 
1710
    } /* end switch */
 
1711
  } /* end while */
 
1712
  
 
1713
found_eof:
 
1714
  eof= 1;
 
1715
  return(1);
 
1716
}