~linuxjedi/drizzle/trunk-bug-667053

« back to all changes in this revision

Viewing changes to sql/sql_load.cc

  • Committer: brian
  • Date: 2008-06-25 05:29:13 UTC
  • Revision ID: brian@localhost.localdomain-20080625052913-6upwo0jsrl4lnapl
clean slate

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Copyright (C) 2000-2006 MySQL AB
 
2
 
 
3
   This program is free software; you can redistribute it and/or modify
 
4
   it under the terms of the GNU General Public License as published by
 
5
   the Free Software Foundation; version 2 of the License.
 
6
 
 
7
   This program is distributed in the hope that it will be useful,
 
8
   but WITHOUT ANY WARRANTY; without even the implied warranty of
 
9
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
10
   GNU General Public License for more details.
 
11
 
 
12
   You should have received a copy of the GNU General Public License
 
13
   along with this program; if not, write to the Free Software
 
14
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
 
15
 
 
16
 
 
17
/* Copy data from a textfile to table */
 
18
/* 2006-12 Erik Wetterberg : LOAD XML added */
 
19
 
 
20
#include "mysql_priv.h"
 
21
#include <my_dir.h>
 
22
#include <m_ctype.h>
 
23
#include "sql_repl.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
}
 
40
 
 
41
 
 
42
class READ_INFO {
 
43
  File  file;
 
44
  uchar *buffer,                        /* Buffer for read text */
 
45
        *end_of_buff;                   /* Data in bufferts ends here */
 
46
  uint  buff_length,                    /* Length of buffert */
 
47
        max_length;                     /* Max length of row */
 
48
  char  *field_term_ptr,*line_term_ptr,*line_start_ptr,*line_start_end;
 
49
  uint  field_term_length,line_term_length,enclosed_length;
 
50
  int   field_term_char,line_term_char,enclosed_char,escape_char;
 
51
  int   *stack,*stack_pos;
 
52
  bool  found_end_of_line,start_of_line,eof;
 
53
  bool  need_end_io_cache;
 
54
  IO_CACHE cache;
 
55
  NET *io_net;
 
56
  int level; /* for load xml */
 
57
 
 
58
public:
 
59
  bool error,line_cuted,found_null,enclosed;
 
60
  uchar *row_start,                     /* Found row starts here */
 
61
        *row_end;                       /* Found row ends here */
 
62
  CHARSET_INFO *read_charset;
 
63
 
 
64
  READ_INFO(File file,uint tot_length,CHARSET_INFO *cs,
 
65
            String &field_term,String &line_start,String &line_term,
 
66
            String &enclosed,int escape,bool get_it_from_net, bool is_fifo);
 
67
  ~READ_INFO();
 
68
  int read_field();
 
69
  int read_fixed_length(void);
 
70
  int next_line(void);
 
71
  char unescape(char chr);
 
72
  int terminator(char *ptr,uint length);
 
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);
 
79
 
 
80
  /*
 
81
    We need to force cache close before destructor is invoked to log
 
82
    the last read block
 
83
  */
 
84
  void end_io_cache()
 
85
  {
 
86
    ::end_io_cache(&cache);
 
87
    need_end_io_cache = 0;
 
88
  }
 
89
 
 
90
  /*
 
91
    Either this method, or we need to make cache public
 
92
    Arg must be set from mysql_load() since constructor does not see
 
93
    either the table or THD value
 
94
  */
 
95
  void set_io_cache_arg(void* arg) { cache.arg = arg; }
 
96
};
 
97
 
 
98
static int read_fixed_length(THD *thd, COPY_INFO &info, TABLE_LIST *table_list,
 
99
                             List<Item> &fields_vars, List<Item> &set_fields,
 
100
                             List<Item> &set_values, READ_INFO &read_info,
 
101
                             ulong skip_lines,
 
102
                             bool ignore_check_option_errors);
 
103
static int read_sep_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list,
 
104
                          List<Item> &fields_vars, List<Item> &set_fields,
 
105
                          List<Item> &set_values, READ_INFO &read_info,
 
106
                          String &enclosed, ulong skip_lines,
 
107
                          bool ignore_check_option_errors);
 
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
 
 
115
static bool write_execute_load_query_log_event(THD *thd,
 
116
                                               bool duplicates, bool ignore,
 
117
                                               bool transactional_table,
 
118
                                               THD::killed_state killed_status);
 
119
 
 
120
/*
 
121
  Execute LOAD DATA query
 
122
 
 
123
  SYNOPSYS
 
124
    mysql_load()
 
125
      thd - current thread
 
126
      ex  - sql_exchange object representing source file and its parsing rules
 
127
      table_list  - list of tables to which we are loading data
 
128
      fields_vars - list of fields and variables to which we read
 
129
                    data from file
 
130
      set_fields  - list of fields mentioned in set clause
 
131
      set_values  - expressions to assign to fields in previous list
 
132
      handle_duplicates - indicates whenever we should emit error or
 
133
                          replace row if we will meet duplicates.
 
134
      ignore -          - indicates whenever we should ignore duplicates
 
135
      read_file_from_client - is this LOAD DATA LOCAL ?
 
136
 
 
137
  RETURN VALUES
 
138
    TRUE - error / FALSE - success
 
139
*/
 
140
 
 
141
int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
 
142
                List<Item> &fields_vars, List<Item> &set_fields,
 
143
                List<Item> &set_values,
 
144
                enum enum_duplicates handle_duplicates, bool ignore,
 
145
                bool read_file_from_client)
 
146
{
 
147
  char name[FN_REFLEN];
 
148
  File file;
 
149
  TABLE *table= NULL;
 
150
  int error;
 
151
  String *field_term=ex->field_term,*escaped=ex->escaped;
 
152
  String *enclosed=ex->enclosed;
 
153
  bool is_fifo=0;
 
154
  LOAD_FILE_INFO lf_info;
 
155
  char *db = table_list->db;                    // This is never null
 
156
  /*
 
157
    If path for file is not defined, we will use the current database.
 
158
    If this is not set, we will use the directory where the table to be
 
159
    loaded is located
 
160
  */
 
161
  char *tdb= thd->db ? thd->db : db;            // Result is never null
 
162
  ulong skip_lines= ex->skip_lines;
 
163
  bool transactional_table;
 
164
  THD::killed_state killed_status= THD::NOT_KILLED;
 
165
  DBUG_ENTER("mysql_load");
 
166
 
 
167
  if (escaped->length() > 1 || enclosed->length() > 1)
 
168
  {
 
169
    my_message(ER_WRONG_FIELD_TERMINATORS,ER(ER_WRONG_FIELD_TERMINATORS),
 
170
               MYF(0));
 
171
    DBUG_RETURN(TRUE);
 
172
  }
 
173
  if (open_and_lock_tables(thd, table_list))
 
174
    DBUG_RETURN(TRUE);
 
175
  if (setup_tables_and_check_access(thd, &thd->lex->select_lex.context,
 
176
                                    &thd->lex->select_lex.top_join_list,
 
177
                                    table_list,
 
178
                                    &thd->lex->select_lex.leaf_tables, true))
 
179
     DBUG_RETURN(-1);
 
180
 
 
181
  /*
 
182
    Let us emit an error if we are loading data to table which is used
 
183
    in subselect in SET clause like we do it for INSERT.
 
184
 
 
185
    The main thing to fix to remove this restriction is to ensure that the
 
186
    table is marked to be 'used for insert' in which case we should never
 
187
    mark this table as 'const table' (ie, one that has only one row).
 
188
  */
 
189
  if (unique_table(thd, table_list, table_list->next_global, 0))
 
190
  {
 
191
    my_error(ER_UPDATE_TABLE_USED, MYF(0), table_list->table_name);
 
192
    DBUG_RETURN(TRUE);
 
193
  }
 
194
 
 
195
  table= table_list->table;
 
196
  transactional_table= table->file->has_transactions();
 
197
 
 
198
  if (!fields_vars.elements)
 
199
  {
 
200
    Field **field;
 
201
    for (field=table->field; *field ; field++)
 
202
      fields_vars.push_back(new Item_field(*field));
 
203
    bitmap_set_all(table->write_set);
 
204
    table->timestamp_field_type= TIMESTAMP_NO_AUTO_SET;
 
205
    /*
 
206
      Let us also prepare SET clause, altough it is probably empty
 
207
      in this case.
 
208
    */
 
209
    if (setup_fields(thd, 0, set_fields, MARK_COLUMNS_WRITE, 0, 0) ||
 
210
        setup_fields(thd, 0, set_values, MARK_COLUMNS_READ, 0, 0))
 
211
      DBUG_RETURN(TRUE);
 
212
  }
 
213
  else
 
214
  {                                             // Part field list
 
215
    /* TODO: use this conds for 'WITH CHECK OPTIONS' */
 
216
    if (setup_fields(thd, 0, fields_vars, MARK_COLUMNS_WRITE, 0, 0) ||
 
217
        setup_fields(thd, 0, set_fields, MARK_COLUMNS_WRITE, 0, 0) ||
 
218
        check_that_all_fields_are_given_values(thd, table, table_list))
 
219
      DBUG_RETURN(TRUE);
 
220
    /*
 
221
      Check whenever TIMESTAMP field with auto-set feature specified
 
222
      explicitly.
 
223
    */
 
224
    if (table->timestamp_field)
 
225
    {
 
226
      if (bitmap_is_set(table->write_set,
 
227
                        table->timestamp_field->field_index))
 
228
        table->timestamp_field_type= TIMESTAMP_NO_AUTO_SET;
 
229
      else
 
230
      {
 
231
        bitmap_set_bit(table->write_set,
 
232
                       table->timestamp_field->field_index);
 
233
      }
 
234
    }
 
235
    /* Fix the expressions in SET clause */
 
236
    if (setup_fields(thd, 0, set_values, MARK_COLUMNS_READ, 0, 0))
 
237
      DBUG_RETURN(TRUE);
 
238
  }
 
239
 
 
240
  table->mark_columns_needed_for_insert();
 
241
 
 
242
  uint tot_length=0;
 
243
  bool use_blobs= 0, use_vars= 0;
 
244
  List_iterator_fast<Item> it(fields_vars);
 
245
  Item *item;
 
246
 
 
247
  while ((item= it++))
 
248
  {
 
249
    Item *real_item= item->real_item();
 
250
 
 
251
    if (real_item->type() == Item::FIELD_ITEM)
 
252
    {
 
253
      Field *field= ((Item_field*)real_item)->field;
 
254
      if (field->flags & BLOB_FLAG)
 
255
      {
 
256
        use_blobs= 1;
 
257
        tot_length+= 256;                       // Will be extended if needed
 
258
      }
 
259
      else
 
260
        tot_length+= field->field_length;
 
261
    }
 
262
    else if (item->type() == Item::STRING_ITEM)
 
263
      use_vars= 1;
 
264
  }
 
265
  if (use_blobs && !ex->line_term->length() && !field_term->length())
 
266
  {
 
267
    my_message(ER_BLOBS_AND_NO_TERMINATED,ER(ER_BLOBS_AND_NO_TERMINATED),
 
268
               MYF(0));
 
269
    DBUG_RETURN(TRUE);
 
270
  }
 
271
  if (use_vars && !field_term->length() && !enclosed->length())
 
272
  {
 
273
    my_error(ER_LOAD_FROM_FIXED_SIZE_ROWS_TO_VAR, MYF(0));
 
274
    DBUG_RETURN(TRUE);
 
275
  }
 
276
 
 
277
  /* We can't give an error in the middle when using LOCAL files */
 
278
  if (read_file_from_client && handle_duplicates == DUP_ERROR)
 
279
    ignore= 1;
 
280
 
 
281
  if (read_file_from_client)
 
282
  {
 
283
    (void)net_request_file(&thd->net,ex->file_name);
 
284
    file = -1;
 
285
  }
 
286
  else
 
287
  {
 
288
#ifdef DONT_ALLOW_FULL_LOAD_DATA_PATHS
 
289
    ex->file_name+=dirname_length(ex->file_name);
 
290
#endif
 
291
    if (!dirname_length(ex->file_name))
 
292
    {
 
293
      strxnmov(name, FN_REFLEN-1, mysql_real_data_home, tdb, NullS);
 
294
      (void) fn_format(name, ex->file_name, name, "",
 
295
                       MY_RELATIVE_PATH | MY_UNPACK_FILENAME);
 
296
    }
 
297
    else
 
298
    {
 
299
      (void) fn_format(name, ex->file_name, mysql_real_data_home, "",
 
300
                       MY_RELATIVE_PATH | MY_UNPACK_FILENAME);
 
301
 
 
302
      if (opt_secure_file_priv &&
 
303
          strncmp(opt_secure_file_priv, name, strlen(opt_secure_file_priv)))
 
304
      {
 
305
        /* Read only allowed from within dir specified by secure_file_priv */
 
306
        my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--secure-file-priv");
 
307
        DBUG_RETURN(TRUE);
 
308
      }
 
309
 
 
310
      MY_STAT stat_info;
 
311
      if (!my_stat(name,&stat_info,MYF(MY_WME)))
 
312
        DBUG_RETURN(TRUE);
 
313
 
 
314
      // if we are not in slave thread, the file must be:
 
315
      if (!thd->slave_thread &&
 
316
          !((stat_info.st_mode & S_IROTH) == S_IROTH &&  // readable by others
 
317
            (stat_info.st_mode & S_IFLNK) != S_IFLNK && // and not a symlink
 
318
            ((stat_info.st_mode & S_IFREG) == S_IFREG ||
 
319
             (stat_info.st_mode & S_IFIFO) == S_IFIFO)))
 
320
      {
 
321
        my_error(ER_TEXTFILE_NOT_READABLE, MYF(0), name);
 
322
        DBUG_RETURN(TRUE);
 
323
      }
 
324
      if ((stat_info.st_mode & S_IFIFO) == S_IFIFO)
 
325
        is_fifo = 1;
 
326
    }
 
327
    if ((file=my_open(name,O_RDONLY,MYF(MY_WME))) < 0)
 
328
      DBUG_RETURN(TRUE);
 
329
  }
 
330
 
 
331
  COPY_INFO info;
 
332
  bzero((char*) &info,sizeof(info));
 
333
  info.ignore= ignore;
 
334
  info.handle_duplicates=handle_duplicates;
 
335
  info.escape_char=escaped->length() ? (*escaped)[0] : INT_MAX;
 
336
 
 
337
  READ_INFO read_info(file,tot_length,
 
338
                      ex->cs ? ex->cs : thd->variables.collation_database,
 
339
                      *field_term,*ex->line_start, *ex->line_term, *enclosed,
 
340
                      info.escape_char, read_file_from_client, is_fifo);
 
341
  if (read_info.error)
 
342
  {
 
343
    if  (file >= 0)
 
344
      my_close(file,MYF(0));                    // no files in net reading
 
345
    DBUG_RETURN(TRUE);                          // Can't allocate buffers
 
346
  }
 
347
 
 
348
  if (mysql_bin_log.is_open())
 
349
  {
 
350
    lf_info.thd = thd;
 
351
    lf_info.wrote_create_file = 0;
 
352
    lf_info.last_pos_in_file = HA_POS_ERROR;
 
353
    lf_info.log_delayed= transactional_table;
 
354
    read_info.set_io_cache_arg((void*) &lf_info);
 
355
  }
 
356
 
 
357
  thd->count_cuted_fields= CHECK_FIELD_WARN;            /* calc cuted fields */
 
358
  thd->cuted_fields=0L;
 
359
  /* Skip lines if there is a line terminator */
 
360
  if (ex->line_term->length() && ex->filetype != FILETYPE_XML)
 
361
  {
 
362
    /* ex->skip_lines needs to be preserved for logging */
 
363
    while (skip_lines > 0)
 
364
    {
 
365
      skip_lines--;
 
366
      if (read_info.next_line())
 
367
        break;
 
368
    }
 
369
  }
 
370
 
 
371
  if (!(error=test(read_info.error)))
 
372
  {
 
373
 
 
374
    table->next_number_field=table->found_next_number_field;
 
375
    if (ignore ||
 
376
        handle_duplicates == DUP_REPLACE)
 
377
      table->file->extra(HA_EXTRA_IGNORE_DUP_KEY);
 
378
    if (handle_duplicates == DUP_REPLACE)
 
379
        table->file->extra(HA_EXTRA_WRITE_CAN_REPLACE);
 
380
    table->file->ha_start_bulk_insert((ha_rows) 0);
 
381
    table->copy_blobs=1;
 
382
 
 
383
    thd->abort_on_warning= (!ignore &&
 
384
                            (thd->variables.sql_mode &
 
385
                             (MODE_STRICT_TRANS_TABLES |
 
386
                              MODE_STRICT_ALL_TABLES)));
 
387
 
 
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())
 
393
      error= read_fixed_length(thd, info, table_list, fields_vars,
 
394
                               set_fields, set_values, read_info,
 
395
                               skip_lines, ignore);
 
396
    else
 
397
      error= read_sep_field(thd, info, table_list, fields_vars,
 
398
                            set_fields, set_values, read_info,
 
399
                            *enclosed, skip_lines, ignore);
 
400
    if (table->file->ha_end_bulk_insert() && !error)
 
401
    {
 
402
      table->file->print_error(my_errno, MYF(0));
 
403
      error= 1;
 
404
    }
 
405
    table->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY);
 
406
    table->file->extra(HA_EXTRA_WRITE_CANNOT_REPLACE);
 
407
    table->next_number_field=0;
 
408
  }
 
409
  if (file >= 0)
 
410
    my_close(file,MYF(0));
 
411
  free_blobs(table);                            /* if pack_blob was used */
 
412
  table->copy_blobs=0;
 
413
  thd->count_cuted_fields= CHECK_FIELD_IGNORE;
 
414
  /* 
 
415
     simulated killing in the middle of per-row loop
 
416
     must be effective for binlogging
 
417
  */
 
418
  DBUG_EXECUTE_IF("simulate_kill_bug27571",
 
419
                  {
 
420
                    error=1;
 
421
                    thd->killed= THD::KILL_QUERY;
 
422
                  };);
 
423
  killed_status= (error == 0)? THD::NOT_KILLED : thd->killed;
 
424
  if (error)
 
425
  {
 
426
    if (read_file_from_client)
 
427
      while (!read_info.next_line())
 
428
        ;
 
429
 
 
430
    if (mysql_bin_log.is_open())
 
431
    {
 
432
      {
 
433
        /*
 
434
          Make sure last block (the one which caused the error) gets
 
435
          logged.  This is needed because otherwise after write of (to
 
436
          the binlog, not to read_info (which is a cache))
 
437
          Delete_file_log_event the bad block will remain in read_info
 
438
          (because pre_read is not called at the end of the last
 
439
          block; remember pre_read is called whenever a new block is
 
440
          read from disk).  At the end of mysql_load(), the destructor
 
441
          of read_info will call end_io_cache() which will flush
 
442
          read_info, so we will finally have this in the binlog:
 
443
 
 
444
          Append_block # The last successfull block
 
445
          Delete_file
 
446
          Append_block # The failing block
 
447
          which is nonsense.
 
448
          Or could also be (for a small file)
 
449
          Create_file  # The failing block
 
450
          which is nonsense (Delete_file is not written in this case, because:
 
451
          Create_file has not been written, so Delete_file is not written, then
 
452
          when read_info is destroyed end_io_cache() is called which writes
 
453
          Create_file.
 
454
        */
 
455
        read_info.end_io_cache();
 
456
        /* If the file was not empty, wrote_create_file is true */
 
457
        if (lf_info.wrote_create_file)
 
458
        {
 
459
          if (thd->transaction.stmt.modified_non_trans_table)
 
460
            write_execute_load_query_log_event(thd, handle_duplicates,
 
461
                                               ignore, transactional_table,
 
462
                                               killed_status);
 
463
          else
 
464
          {
 
465
            Delete_file_log_event d(thd, db, transactional_table);
 
466
            d.flags|= LOG_EVENT_UPDATE_TABLE_MAP_VERSION_F;
 
467
            mysql_bin_log.write(&d);
 
468
          }
 
469
        }
 
470
      }
 
471
    }
 
472
    error= -1;                          // Error on read
 
473
    goto err;
 
474
  }
 
475
  sprintf(name, ER(ER_LOAD_INFO), (ulong) info.records, (ulong) info.deleted,
 
476
          (ulong) (info.records - info.copied), (ulong) thd->cuted_fields);
 
477
 
 
478
  if (thd->transaction.stmt.modified_non_trans_table)
 
479
    thd->transaction.all.modified_non_trans_table= TRUE;
 
480
 
 
481
  if (mysql_bin_log.is_open())
 
482
  {
 
483
    /*
 
484
      We need to do the job that is normally done inside
 
485
      binlog_query() here, which is to ensure that the pending event
 
486
      is written before tables are unlocked and before any other
 
487
      events are written.  We also need to update the table map
 
488
      version for the binary log to mark that table maps are invalid
 
489
      after this point.
 
490
     */
 
491
    if (thd->current_stmt_binlog_row_based)
 
492
      thd->binlog_flush_pending_rows_event(true);
 
493
    else
 
494
    {
 
495
      /*
 
496
        As already explained above, we need to call end_io_cache() or the last
 
497
        block will be logged only after Execute_load_query_log_event (which is
 
498
        wrong), when read_info is destroyed.
 
499
      */
 
500
      read_info.end_io_cache();
 
501
      if (lf_info.wrote_create_file)
 
502
      {
 
503
        write_execute_load_query_log_event(thd, handle_duplicates, ignore,
 
504
                                           transactional_table,killed_status);
 
505
      }
 
506
    }
 
507
  }
 
508
 
 
509
  /* ok to client sent only after binlog write and engine commit */
 
510
  my_ok(thd, info.copied + info.deleted, 0L, name);
 
511
err:
 
512
  DBUG_ASSERT(transactional_table || !(info.copied || info.deleted) ||
 
513
              thd->transaction.stmt.modified_non_trans_table);
 
514
  table->file->ha_release_auto_increment();
 
515
  table->auto_increment_field_not_null= FALSE;
 
516
  thd->abort_on_warning= 0;
 
517
  DBUG_RETURN(error);
 
518
}
 
519
 
 
520
 
 
521
/* Not a very useful function; just to avoid duplication of code */
 
522
static bool write_execute_load_query_log_event(THD *thd,
 
523
                                               bool duplicates, bool ignore,
 
524
                                               bool transactional_table,
 
525
                                               THD::killed_state killed_err_arg)
 
526
{
 
527
  Execute_load_query_log_event
 
528
    e(thd, thd->query, thd->query_length,
 
529
      (char*)thd->lex->fname_start - (char*)thd->query,
 
530
      (char*)thd->lex->fname_end - (char*)thd->query,
 
531
      (duplicates == DUP_REPLACE) ? LOAD_DUP_REPLACE :
 
532
      (ignore ? LOAD_DUP_IGNORE : LOAD_DUP_ERROR),
 
533
      transactional_table, FALSE, killed_err_arg);
 
534
  e.flags|= LOG_EVENT_UPDATE_TABLE_MAP_VERSION_F;
 
535
  return mysql_bin_log.write(&e);
 
536
}
 
537
 
 
538
 
 
539
/****************************************************************************
 
540
** Read of rows of fixed size + optional garage + optonal newline
 
541
****************************************************************************/
 
542
 
 
543
static int
 
544
read_fixed_length(THD *thd, COPY_INFO &info, TABLE_LIST *table_list,
 
545
                  List<Item> &fields_vars, List<Item> &set_fields,
 
546
                  List<Item> &set_values, READ_INFO &read_info,
 
547
                  ulong skip_lines, bool ignore_check_option_errors)
 
548
{
 
549
  List_iterator_fast<Item> it(fields_vars);
 
550
  Item_field *sql_field;
 
551
  TABLE *table= table_list->table;
 
552
  ulonglong id;
 
553
  bool err;
 
554
  DBUG_ENTER("read_fixed_length");
 
555
 
 
556
  id= 0;
 
557
 
 
558
  while (!read_info.read_fixed_length())
 
559
  {
 
560
    if (thd->killed)
 
561
    {
 
562
      thd->send_kill_message();
 
563
      DBUG_RETURN(1);
 
564
    }
 
565
    if (skip_lines)
 
566
    {
 
567
      /*
 
568
        We could implement this with a simple seek if:
 
569
        - We are not using DATA INFILE LOCAL
 
570
        - escape character is  ""
 
571
        - line starting prefix is ""
 
572
      */
 
573
      skip_lines--;
 
574
      continue;
 
575
    }
 
576
    it.rewind();
 
577
    uchar *pos=read_info.row_start;
 
578
#ifdef HAVE_purify
 
579
    read_info.row_end[0]=0;
 
580
#endif
 
581
 
 
582
    restore_record(table, s->default_values);
 
583
    /*
 
584
      There is no variables in fields_vars list in this format so
 
585
      this conversion is safe.
 
586
    */
 
587
    while ((sql_field= (Item_field*) it++))
 
588
    {
 
589
      Field *field= sql_field->field;                  
 
590
      if (field == table->next_number_field)
 
591
        table->auto_increment_field_not_null= TRUE;
 
592
      /*
 
593
        No fields specified in fields_vars list can be null in this format.
 
594
        Mark field as not null, we should do this for each row because of
 
595
        restore_record...
 
596
      */
 
597
      field->set_notnull();
 
598
 
 
599
      if (pos == read_info.row_end)
 
600
      {
 
601
        thd->cuted_fields++;                    /* Not enough fields */
 
602
        push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, 
 
603
                            ER_WARN_TOO_FEW_RECORDS, 
 
604
                            ER(ER_WARN_TOO_FEW_RECORDS), thd->row_count);
 
605
        if (!field->maybe_null() && field->type() == FIELD_TYPE_TIMESTAMP)
 
606
            ((Field_timestamp*) field)->set_time();
 
607
      }
 
608
      else
 
609
      {
 
610
        uint length;
 
611
        uchar save_chr;
 
612
        if ((length=(uint) (read_info.row_end-pos)) >
 
613
            field->field_length)
 
614
          length=field->field_length;
 
615
        save_chr=pos[length]; pos[length]='\0'; // Safeguard aganst malloc
 
616
        field->store((char*) pos,length,read_info.read_charset);
 
617
        pos[length]=save_chr;
 
618
        if ((pos+=length) > read_info.row_end)
 
619
          pos= read_info.row_end;       /* Fills rest with space */
 
620
      }
 
621
    }
 
622
    if (pos != read_info.row_end)
 
623
    {
 
624
      thd->cuted_fields++;                      /* To long row */
 
625
      push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, 
 
626
                          ER_WARN_TOO_MANY_RECORDS, 
 
627
                          ER(ER_WARN_TOO_MANY_RECORDS), thd->row_count); 
 
628
    }
 
629
 
 
630
    if (thd->killed ||
 
631
        fill_record(thd, set_fields, set_values,
 
632
                    ignore_check_option_errors))
 
633
      DBUG_RETURN(1);
 
634
 
 
635
    err= write_record(thd, table, &info);
 
636
    table->auto_increment_field_not_null= FALSE;
 
637
    if (err)
 
638
      DBUG_RETURN(1);
 
639
   
 
640
    /*
 
641
      We don't need to reset auto-increment field since we are restoring
 
642
      its default value at the beginning of each loop iteration.
 
643
    */
 
644
    if (read_info.next_line())                  // Skip to next line
 
645
      break;
 
646
    if (read_info.line_cuted)
 
647
    {
 
648
      thd->cuted_fields++;                      /* To long row */
 
649
      push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, 
 
650
                          ER_WARN_TOO_MANY_RECORDS, 
 
651
                          ER(ER_WARN_TOO_MANY_RECORDS), thd->row_count); 
 
652
    }
 
653
    thd->row_count++;
 
654
  }
 
655
  DBUG_RETURN(test(read_info.error));
 
656
}
 
657
 
 
658
 
 
659
 
 
660
static int
 
661
read_sep_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list,
 
662
               List<Item> &fields_vars, List<Item> &set_fields,
 
663
               List<Item> &set_values, READ_INFO &read_info,
 
664
               String &enclosed, ulong skip_lines,
 
665
               bool ignore_check_option_errors)
 
666
{
 
667
  List_iterator_fast<Item> it(fields_vars);
 
668
  Item *item;
 
669
  TABLE *table= table_list->table;
 
670
  uint enclosed_length;
 
671
  ulonglong id;
 
672
  bool err;
 
673
  DBUG_ENTER("read_sep_field");
 
674
 
 
675
  enclosed_length=enclosed.length();
 
676
  id= 0;
 
677
 
 
678
  for (;;it.rewind())
 
679
  {
 
680
    if (thd->killed)
 
681
    {
 
682
      thd->send_kill_message();
 
683
      DBUG_RETURN(1);
 
684
    }
 
685
 
 
686
    restore_record(table, s->default_values);
 
687
 
 
688
    while ((item= it++))
 
689
    {
 
690
      uint length;
 
691
      uchar *pos;
 
692
      Item *real_item;
 
693
 
 
694
      if (read_info.read_field())
 
695
        break;
 
696
 
 
697
      /* If this line is to be skipped we don't want to fill field or var */
 
698
      if (skip_lines)
 
699
        continue;
 
700
 
 
701
      pos=read_info.row_start;
 
702
      length=(uint) (read_info.row_end-pos);
 
703
 
 
704
      real_item= item->real_item();
 
705
 
 
706
      if ((!read_info.enclosed && (enclosed_length && length == 4 && !memcmp(pos, STRING_WITH_LEN("NULL")))) ||
 
707
          (length == 1 && read_info.found_null))
 
708
      {
 
709
 
 
710
        if (real_item->type() == Item::FIELD_ITEM)
 
711
        {
 
712
          Field *field= ((Item_field *)real_item)->field;
 
713
          if (field->reset())
 
714
          {
 
715
            my_error(ER_WARN_NULL_TO_NOTNULL, MYF(0), field->field_name,
 
716
                     thd->row_count);
 
717
            DBUG_RETURN(1);
 
718
          }
 
719
          field->set_null();
 
720
          if (!field->maybe_null())
 
721
          {
 
722
            if (field->type() == MYSQL_TYPE_TIMESTAMP)
 
723
              ((Field_timestamp*) field)->set_time();
 
724
            else if (field != table->next_number_field)
 
725
              field->set_warning(MYSQL_ERROR::WARN_LEVEL_WARN,
 
726
                                 ER_WARN_NULL_TO_NOTNULL, 1);
 
727
          }
 
728
        }
 
729
        else if (item->type() == Item::STRING_ITEM)
 
730
        {
 
731
          ((Item_user_var_as_out_param *)item)->set_null_value(
 
732
                                                  read_info.read_charset);
 
733
        }
 
734
        else
 
735
        {
 
736
          my_error(ER_LOAD_DATA_INVALID_COLUMN, MYF(0), item->full_name());
 
737
          DBUG_RETURN(1);
 
738
        }
 
739
 
 
740
        continue;
 
741
      }
 
742
 
 
743
      if (real_item->type() == Item::FIELD_ITEM)
 
744
      {
 
745
        Field *field= ((Item_field *)real_item)->field;
 
746
        field->set_notnull();
 
747
        read_info.row_end[0]=0;                 // Safe to change end marker
 
748
        if (field == table->next_number_field)
 
749
          table->auto_increment_field_not_null= TRUE;
 
750
        field->store((char*) pos, length, read_info.read_charset);
 
751
      }
 
752
      else if (item->type() == Item::STRING_ITEM)
 
753
      {
 
754
        ((Item_user_var_as_out_param *)item)->set_value((char*) pos, length,
 
755
                                                        read_info.read_charset);
 
756
      }
 
757
      else
 
758
      {
 
759
        my_error(ER_LOAD_DATA_INVALID_COLUMN, MYF(0), item->full_name());
 
760
        DBUG_RETURN(1);
 
761
      }
 
762
    }
 
763
    if (read_info.error)
 
764
      break;
 
765
    if (skip_lines)
 
766
    {
 
767
      skip_lines--;
 
768
      continue;
 
769
    }
 
770
    if (item)
 
771
    {
 
772
      /* Have not read any field, thus input file is simply ended */
 
773
      if (item == fields_vars.head())
 
774
        break;
 
775
      for (; item ; item= it++)
 
776
      {
 
777
        Item *real_item= item->real_item();
 
778
        if (real_item->type() == Item::FIELD_ITEM)
 
779
        {
 
780
          Field *field= ((Item_field *)real_item)->field;
 
781
          if (field->reset())
 
782
          {
 
783
            my_error(ER_WARN_NULL_TO_NOTNULL, MYF(0),field->field_name,
 
784
                     thd->row_count);
 
785
            DBUG_RETURN(1);
 
786
          }
 
787
          if (!field->maybe_null() && field->type() == FIELD_TYPE_TIMESTAMP)
 
788
              ((Field_timestamp*) field)->set_time();
 
789
          /*
 
790
            QQ: We probably should not throw warning for each field.
 
791
            But how about intention to always have the same number
 
792
            of warnings in THD::cuted_fields (and get rid of cuted_fields
 
793
            in the end ?)
 
794
          */
 
795
          thd->cuted_fields++;
 
796
          push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
 
797
                              ER_WARN_TOO_FEW_RECORDS,
 
798
                              ER(ER_WARN_TOO_FEW_RECORDS), thd->row_count);
 
799
        }
 
800
        else if (item->type() == Item::STRING_ITEM)
 
801
        {
 
802
          ((Item_user_var_as_out_param *)item)->set_null_value(
 
803
                                                  read_info.read_charset);
 
804
        }
 
805
        else
 
806
        {
 
807
          my_error(ER_LOAD_DATA_INVALID_COLUMN, MYF(0), item->full_name());
 
808
          DBUG_RETURN(1);
 
809
        }
 
810
      }
 
811
    }
 
812
 
 
813
    if (thd->killed ||
 
814
        fill_record(thd, set_fields, set_values,
 
815
                    ignore_check_option_errors))
 
816
      DBUG_RETURN(1);
 
817
 
 
818
    err= write_record(thd, table, &info);
 
819
    table->auto_increment_field_not_null= FALSE;
 
820
    if (err)
 
821
      DBUG_RETURN(1);
 
822
    /*
 
823
      We don't need to reset auto-increment field since we are restoring
 
824
      its default value at the beginning of each loop iteration.
 
825
    */
 
826
    if (read_info.next_line())                  // Skip to next line
 
827
      break;
 
828
    if (read_info.line_cuted)
 
829
    {
 
830
      thd->cuted_fields++;                      /* To long row */
 
831
      push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, 
 
832
                          ER_WARN_TOO_MANY_RECORDS, ER(ER_WARN_TOO_MANY_RECORDS), 
 
833
                          thd->row_count);   
 
834
      if (thd->killed)
 
835
        DBUG_RETURN(1);
 
836
    }
 
837
    thd->row_count++;
 
838
  }
 
839
  DBUG_RETURN(test(read_info.error));
 
840
}
 
841
 
 
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
 
 
994
/* Unescape all escape characters, mark \N as null */
 
995
 
 
996
char
 
997
READ_INFO::unescape(char chr)
 
998
{
 
999
  /* keep this switch synchornous with the ESCAPE_CHARS macro */
 
1000
  switch(chr) {
 
1001
  case 'n': return '\n';
 
1002
  case 't': return '\t';
 
1003
  case 'r': return '\r';
 
1004
  case 'b': return '\b';
 
1005
  case '0': return 0;                           // Ascii null
 
1006
  case 'Z': return '\032';                      // Win32 end of file
 
1007
  case 'N': found_null=1;
 
1008
 
 
1009
    /* fall through */
 
1010
  default:  return chr;
 
1011
  }
 
1012
}
 
1013
 
 
1014
 
 
1015
/*
 
1016
  Read a line using buffering
 
1017
  If last line is empty (in line mode) then it isn't outputed
 
1018
*/
 
1019
 
 
1020
 
 
1021
READ_INFO::READ_INFO(File file_par, uint tot_length, CHARSET_INFO *cs,
 
1022
                     String &field_term, String &line_start, String &line_term,
 
1023
                     String &enclosed_par, int escape, bool get_it_from_net,
 
1024
                     bool is_fifo)
 
1025
  :file(file_par),escape_char(escape)
 
1026
{
 
1027
  read_charset= cs;
 
1028
  field_term_ptr=(char*) field_term.ptr();
 
1029
  field_term_length= field_term.length();
 
1030
  line_term_ptr=(char*) line_term.ptr();
 
1031
  line_term_length= line_term.length();
 
1032
  level= 0; /* for load xml */
 
1033
  if (line_start.length() == 0)
 
1034
  {
 
1035
    line_start_ptr=0;
 
1036
    start_of_line= 0;
 
1037
  }
 
1038
  else
 
1039
  {
 
1040
    line_start_ptr=(char*) line_start.ptr();
 
1041
    line_start_end=line_start_ptr+line_start.length();
 
1042
    start_of_line= 1;
 
1043
  }
 
1044
  /* If field_terminator == line_terminator, don't use line_terminator */
 
1045
  if (field_term_length == line_term_length &&
 
1046
      !memcmp(field_term_ptr,line_term_ptr,field_term_length))
 
1047
  {
 
1048
    line_term_length=0;
 
1049
    line_term_ptr=(char*) "";
 
1050
  }
 
1051
  enclosed_char= (enclosed_length=enclosed_par.length()) ?
 
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;
 
1055
  error=eof=found_end_of_line=found_null=line_cuted=0;
 
1056
  buff_length=tot_length;
 
1057
 
 
1058
 
 
1059
  /* Set of a stack for unget if long terminators */
 
1060
  uint length=max(field_term_length,line_term_length)+1;
 
1061
  set_if_bigger(length,line_start.length());
 
1062
  stack=stack_pos=(int*) sql_alloc(sizeof(int)*length);
 
1063
 
 
1064
  if (!(buffer=(uchar*) my_malloc(buff_length+1,MYF(0))))
 
1065
    error=1; /* purecov: inspected */
 
1066
  else
 
1067
  {
 
1068
    end_of_buff=buffer+buff_length;
 
1069
    if (init_io_cache(&cache,(get_it_from_net) ? -1 : file, 0,
 
1070
                      (get_it_from_net) ? READ_NET :
 
1071
                      (is_fifo ? READ_FIFO : READ_CACHE),0L,1,
 
1072
                      MYF(MY_WME)))
 
1073
    {
 
1074
      my_free((uchar*) buffer,MYF(0)); /* purecov: inspected */
 
1075
      error=1;
 
1076
    }
 
1077
    else
 
1078
    {
 
1079
      /*
 
1080
        init_io_cache() will not initialize read_function member
 
1081
        if the cache is READ_NET. So we work around the problem with a
 
1082
        manual assignment
 
1083
      */
 
1084
      need_end_io_cache = 1;
 
1085
 
 
1086
      if (get_it_from_net)
 
1087
        cache.read_function = _my_b_net_read;
 
1088
 
 
1089
      if (mysql_bin_log.is_open())
 
1090
        cache.pre_read = cache.pre_close =
 
1091
          (IO_CACHE_CALLBACK) log_loaded_block;
 
1092
    }
 
1093
  }
 
1094
}
 
1095
 
 
1096
 
 
1097
READ_INFO::~READ_INFO()
 
1098
{
 
1099
  if (!error)
 
1100
  {
 
1101
    if (need_end_io_cache)
 
1102
      ::end_io_cache(&cache);
 
1103
    my_free((uchar*) buffer,MYF(0));
 
1104
    error=1;
 
1105
  }
 
1106
  List_iterator<XML_TAG> xmlit(taglist);
 
1107
  XML_TAG *t;
 
1108
  while ((t= xmlit++))
 
1109
    delete(t);
 
1110
}
 
1111
 
 
1112
 
 
1113
#define GET (stack_pos != stack ? *--stack_pos : my_b_get(&cache))
 
1114
#define PUSH(A) *(stack_pos++)=(A)
 
1115
 
 
1116
 
 
1117
inline int READ_INFO::terminator(char *ptr,uint length)
 
1118
{
 
1119
  int chr=0;                                    // Keep gcc happy
 
1120
  uint i;
 
1121
  for (i=1 ; i < length ; i++)
 
1122
  {
 
1123
    if ((chr=GET) != *++ptr)
 
1124
    {
 
1125
      break;
 
1126
    }
 
1127
  }
 
1128
  if (i == length)
 
1129
    return 1;
 
1130
  PUSH(chr);
 
1131
  while (i-- > 1)
 
1132
    PUSH((uchar) *--ptr);
 
1133
  return 0;
 
1134
}
 
1135
 
 
1136
 
 
1137
int READ_INFO::read_field()
 
1138
{
 
1139
  int chr,found_enclosed_char;
 
1140
  uchar *to,*new_buffer;
 
1141
 
 
1142
  found_null=0;
 
1143
  if (found_end_of_line)
 
1144
    return 1;                                   // One have to call next_line
 
1145
 
 
1146
  /* Skip until we find 'line_start' */
 
1147
 
 
1148
  if (start_of_line)
 
1149
  {                                             // Skip until line_start
 
1150
    start_of_line=0;
 
1151
    if (find_start_of_fields())
 
1152
      return 1;
 
1153
  }
 
1154
  if ((chr=GET) == my_b_EOF)
 
1155
  {
 
1156
    found_end_of_line=eof=1;
 
1157
    return 1;
 
1158
  }
 
1159
  to=buffer;
 
1160
  if (chr == enclosed_char)
 
1161
  {
 
1162
    found_enclosed_char=enclosed_char;
 
1163
    *to++=(uchar) chr;                          // If error
 
1164
  }
 
1165
  else
 
1166
  {
 
1167
    found_enclosed_char= INT_MAX;
 
1168
    PUSH(chr);
 
1169
  }
 
1170
 
 
1171
  for (;;)
 
1172
  {
 
1173
    while ( to < end_of_buff)
 
1174
    {
 
1175
      chr = GET;
 
1176
#ifdef USE_MB
 
1177
      if ((my_mbcharlen(read_charset, chr) > 1) &&
 
1178
          to+my_mbcharlen(read_charset, chr) <= end_of_buff)
 
1179
      {
 
1180
          uchar* p = (uchar*)to;
 
1181
          *to++ = chr;
 
1182
          int ml = my_mbcharlen(read_charset, chr);
 
1183
          int i;
 
1184
          for (i=1; i<ml; i++) {
 
1185
              chr = GET;
 
1186
              if (chr == my_b_EOF)
 
1187
                  goto found_eof;
 
1188
              *to++ = chr;
 
1189
          }
 
1190
          if (my_ismbchar(read_charset,
 
1191
                          (const char *)p,
 
1192
                          (const char *)to))
 
1193
            continue;
 
1194
          for (i=0; i<ml; i++)
 
1195
            PUSH((uchar) *--to);
 
1196
          chr = GET;
 
1197
      }
 
1198
#endif
 
1199
      if (chr == my_b_EOF)
 
1200
        goto found_eof;
 
1201
      if (chr == escape_char)
 
1202
      {
 
1203
        if ((chr=GET) == my_b_EOF)
 
1204
        {
 
1205
          *to++= (uchar) escape_char;
 
1206
          goto found_eof;
 
1207
        }
 
1208
        /*
 
1209
          When escape_char == enclosed_char, we treat it like we do for
 
1210
          handling quotes in SQL parsing -- you can double-up the
 
1211
          escape_char to include it literally, but it doesn't do escapes
 
1212
          like \n. This allows: LOAD DATA ... ENCLOSED BY '"' ESCAPED BY '"'
 
1213
          with data like: "fie""ld1", "field2"
 
1214
         */
 
1215
        if (escape_char != enclosed_char || chr == escape_char)
 
1216
        {
 
1217
          *to++ = (uchar) unescape((char) chr);
 
1218
          continue;
 
1219
        }
 
1220
        PUSH(chr);
 
1221
        chr= escape_char;
 
1222
      }
 
1223
#ifdef ALLOW_LINESEPARATOR_IN_STRINGS
 
1224
      if (chr == line_term_char)
 
1225
#else
 
1226
      if (chr == line_term_char && found_enclosed_char == INT_MAX)
 
1227
#endif
 
1228
      {
 
1229
        if (terminator(line_term_ptr,line_term_length))
 
1230
        {                                       // Maybe unexpected linefeed
 
1231
          enclosed=0;
 
1232
          found_end_of_line=1;
 
1233
          row_start=buffer;
 
1234
          row_end=  to;
 
1235
          return 0;
 
1236
        }
 
1237
      }
 
1238
      if (chr == found_enclosed_char)
 
1239
      {
 
1240
        if ((chr=GET) == found_enclosed_char)
 
1241
        {                                       // Remove dupplicated
 
1242
          *to++ = (uchar) chr;
 
1243
          continue;
 
1244
        }
 
1245
        // End of enclosed field if followed by field_term or line_term
 
1246
        if (chr == my_b_EOF ||
 
1247
            (chr == line_term_char && terminator(line_term_ptr, line_term_length)))
 
1248
        {                                       // Maybe unexpected linefeed
 
1249
          enclosed=1;
 
1250
          found_end_of_line=1;
 
1251
          row_start=buffer+1;
 
1252
          row_end=  to;
 
1253
          return 0;
 
1254
        }
 
1255
        if (chr == field_term_char &&
 
1256
            terminator(field_term_ptr,field_term_length))
 
1257
        {
 
1258
          enclosed=1;
 
1259
          row_start=buffer+1;
 
1260
          row_end=  to;
 
1261
          return 0;
 
1262
        }
 
1263
        /*
 
1264
          The string didn't terminate yet.
 
1265
          Store back next character for the loop
 
1266
        */
 
1267
        PUSH(chr);
 
1268
        /* copy the found term character to 'to' */
 
1269
        chr= found_enclosed_char;
 
1270
      }
 
1271
      else if (chr == field_term_char && found_enclosed_char == INT_MAX)
 
1272
      {
 
1273
        if (terminator(field_term_ptr,field_term_length))
 
1274
        {
 
1275
          enclosed=0;
 
1276
          row_start=buffer;
 
1277
          row_end=  to;
 
1278
          return 0;
 
1279
        }
 
1280
      }
 
1281
      *to++ = (uchar) chr;
 
1282
    }
 
1283
    /*
 
1284
    ** We come here if buffer is too small. Enlarge it and continue
 
1285
    */
 
1286
    if (!(new_buffer=(uchar*) my_realloc((char*) buffer,buff_length+1+IO_SIZE,
 
1287
                                        MYF(MY_WME))))
 
1288
      return (error=1);
 
1289
    to=new_buffer + (to-buffer);
 
1290
    buffer=new_buffer;
 
1291
    buff_length+=IO_SIZE;
 
1292
    end_of_buff=buffer+buff_length;
 
1293
  }
 
1294
 
 
1295
found_eof:
 
1296
  enclosed=0;
 
1297
  found_end_of_line=eof=1;
 
1298
  row_start=buffer;
 
1299
  row_end=to;
 
1300
  return 0;
 
1301
}
 
1302
 
 
1303
/*
 
1304
  Read a row with fixed length.
 
1305
 
 
1306
  NOTES
 
1307
    The row may not be fixed size on disk if there are escape
 
1308
    characters in the file.
 
1309
 
 
1310
  IMPLEMENTATION NOTE
 
1311
    One can't use fixed length with multi-byte charset **
 
1312
 
 
1313
  RETURN
 
1314
    0  ok
 
1315
    1  error
 
1316
*/
 
1317
 
 
1318
int READ_INFO::read_fixed_length()
 
1319
{
 
1320
  int chr;
 
1321
  uchar *to;
 
1322
  if (found_end_of_line)
 
1323
    return 1;                                   // One have to call next_line
 
1324
 
 
1325
  if (start_of_line)
 
1326
  {                                             // Skip until line_start
 
1327
    start_of_line=0;
 
1328
    if (find_start_of_fields())
 
1329
      return 1;
 
1330
  }
 
1331
 
 
1332
  to=row_start=buffer;
 
1333
  while (to < end_of_buff)
 
1334
  {
 
1335
    if ((chr=GET) == my_b_EOF)
 
1336
      goto found_eof;
 
1337
    if (chr == escape_char)
 
1338
    {
 
1339
      if ((chr=GET) == my_b_EOF)
 
1340
      {
 
1341
        *to++= (uchar) escape_char;
 
1342
        goto found_eof;
 
1343
      }
 
1344
      *to++ =(uchar) unescape((char) chr);
 
1345
      continue;
 
1346
    }
 
1347
    if (chr == line_term_char)
 
1348
    {
 
1349
      if (terminator(line_term_ptr,line_term_length))
 
1350
      {                                         // Maybe unexpected linefeed
 
1351
        found_end_of_line=1;
 
1352
        row_end=  to;
 
1353
        return 0;
 
1354
      }
 
1355
    }
 
1356
    *to++ = (uchar) chr;
 
1357
  }
 
1358
  row_end=to;                                   // Found full line
 
1359
  return 0;
 
1360
 
 
1361
found_eof:
 
1362
  found_end_of_line=eof=1;
 
1363
  row_start=buffer;
 
1364
  row_end=to;
 
1365
  return to == buffer ? 1 : 0;
 
1366
}
 
1367
 
 
1368
 
 
1369
int READ_INFO::next_line()
 
1370
{
 
1371
  line_cuted=0;
 
1372
  start_of_line= line_start_ptr != 0;
 
1373
  if (found_end_of_line || eof)
 
1374
  {
 
1375
    found_end_of_line=0;
 
1376
    return eof;
 
1377
  }
 
1378
  found_end_of_line=0;
 
1379
  if (!line_term_length)
 
1380
    return 0;                                   // No lines
 
1381
  for (;;)
 
1382
  {
 
1383
    int chr = GET;
 
1384
#ifdef USE_MB
 
1385
   if (my_mbcharlen(read_charset, chr) > 1)
 
1386
   {
 
1387
       for (uint i=1;
 
1388
            chr != my_b_EOF && i<my_mbcharlen(read_charset, chr);
 
1389
            i++)
 
1390
           chr = GET;
 
1391
       if (chr == escape_char)
 
1392
           continue;
 
1393
   }
 
1394
#endif
 
1395
   if (chr == my_b_EOF)
 
1396
   {
 
1397
      eof=1;
 
1398
      return 1;
 
1399
    }
 
1400
    if (chr == escape_char)
 
1401
    {
 
1402
      line_cuted=1;
 
1403
      if (GET == my_b_EOF)
 
1404
        return 1;
 
1405
      continue;
 
1406
    }
 
1407
    if (chr == line_term_char && terminator(line_term_ptr,line_term_length))
 
1408
      return 0;
 
1409
    line_cuted=1;
 
1410
  }
 
1411
}
 
1412
 
 
1413
 
 
1414
bool READ_INFO::find_start_of_fields()
 
1415
{
 
1416
  int chr;
 
1417
 try_again:
 
1418
  do
 
1419
  {
 
1420
    if ((chr=GET) == my_b_EOF)
 
1421
    {
 
1422
      found_end_of_line=eof=1;
 
1423
      return 1;
 
1424
    }
 
1425
  } while ((char) chr != line_start_ptr[0]);
 
1426
  for (char *ptr=line_start_ptr+1 ; ptr != line_start_end ; ptr++)
 
1427
  {
 
1428
    chr=GET;                                    // Eof will be checked later
 
1429
    if ((char) chr != *ptr)
 
1430
    {                                           // Can't be line_start
 
1431
      PUSH(chr);
 
1432
      while (--ptr != line_start_ptr)
 
1433
      {                                         // Restart with next char
 
1434
        PUSH((uchar) *ptr);
 
1435
      }
 
1436
      goto try_again;
 
1437
    }
 
1438
  }
 
1439
  return 0;
 
1440
}
 
1441
 
 
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
}