~drizzle-trunk/drizzle/development

1 by brian
clean slate
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
243.1.17 by Jay Pipes
FINAL PHASE removal of mysql_priv.h (Bye, bye my friend.)
19
#include <drizzled/server_includes.h>
1 by brian
clean slate
20
#include "sql_repl.h"
202.3.6 by Monty Taylor
First pass at gettexizing the error messages.
21
#include <drizzled/drizzled_error_messages.h>
1 by brian
clean slate
22
23
24
class READ_INFO {
25
  File	file;
26
  uchar	*buffer,			/* Buffer for read text */
27
	*end_of_buff;			/* Data in bufferts ends here */
28
  uint	buff_length,			/* Length of buffert */
29
	max_length;			/* Max length of row */
30
  char	*field_term_ptr,*line_term_ptr,*line_start_ptr,*line_start_end;
31
  uint	field_term_length,line_term_length,enclosed_length;
32
  int	field_term_char,line_term_char,enclosed_char,escape_char;
33
  int	*stack,*stack_pos;
34
  bool	found_end_of_line,start_of_line,eof;
35
  bool  need_end_io_cache;
36
  IO_CACHE cache;
37
  NET *io_net;
38
39
public:
40
  bool error,line_cuted,found_null,enclosed;
41
  uchar	*row_start,			/* Found row starts here */
42
	*row_end;			/* Found row ends here */
264.2.6 by Andrey Hristov
Constify the usage of CHARSET_INFO almost to the last place in the code.
43
  const CHARSET_INFO *read_charset;
1 by brian
clean slate
44
264.2.6 by Andrey Hristov
Constify the usage of CHARSET_INFO almost to the last place in the code.
45
  READ_INFO(File file,uint tot_length, const CHARSET_INFO * const cs,
1 by brian
clean slate
46
	    String &field_term,String &line_start,String &line_term,
47
	    String &enclosed,int escape,bool get_it_from_net, bool is_fifo);
48
  ~READ_INFO();
49
  int read_field();
50
  int read_fixed_length(void);
51
  int next_line(void);
52
  char unescape(char chr);
53
  int terminator(char *ptr,uint length);
54
  bool find_start_of_fields();
55
56
  /*
57
    We need to force cache close before destructor is invoked to log
58
    the last read block
59
  */
60
  void end_io_cache()
61
  {
62
    ::end_io_cache(&cache);
63
    need_end_io_cache = 0;
64
  }
65
66
  /*
67
    Either this method, or we need to make cache public
68
    Arg must be set from mysql_load() since constructor does not see
69
    either the table or THD value
70
  */
71
  void set_io_cache_arg(void* arg) { cache.arg = arg; }
72
};
73
74
static int read_fixed_length(THD *thd, COPY_INFO &info, TABLE_LIST *table_list,
75
                             List<Item> &fields_vars, List<Item> &set_fields,
76
                             List<Item> &set_values, READ_INFO &read_info,
77
			     ulong skip_lines,
78
			     bool ignore_check_option_errors);
79
static int read_sep_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list,
80
                          List<Item> &fields_vars, List<Item> &set_fields,
81
                          List<Item> &set_values, READ_INFO &read_info,
82
			  String &enclosed, ulong skip_lines,
83
			  bool ignore_check_option_errors);
84
85
static bool write_execute_load_query_log_event(THD *thd,
86
					       bool duplicates, bool ignore,
87
					       bool transactional_table,
88
                                               THD::killed_state killed_status);
89
90
/*
91
  Execute LOAD DATA query
92
93
  SYNOPSYS
94
    mysql_load()
95
      thd - current thread
96
      ex  - sql_exchange object representing source file and its parsing rules
97
      table_list  - list of tables to which we are loading data
98
      fields_vars - list of fields and variables to which we read
99
                    data from file
100
      set_fields  - list of fields mentioned in set clause
101
      set_values  - expressions to assign to fields in previous list
102
      handle_duplicates - indicates whenever we should emit error or
103
                          replace row if we will meet duplicates.
104
      ignore -          - indicates whenever we should ignore duplicates
105
      read_file_from_client - is this LOAD DATA LOCAL ?
106
107
  RETURN VALUES
51.1.53 by Jay Pipes
Removed/replaced DBUG symbols and standardized TRUE/FALSE
108
    true - error / false - success
1 by brian
clean slate
109
*/
110
111
int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
112
	        List<Item> &fields_vars, List<Item> &set_fields,
113
                List<Item> &set_values,
114
                enum enum_duplicates handle_duplicates, bool ignore,
115
                bool read_file_from_client)
116
{
117
  char name[FN_REFLEN];
118
  File file;
119
  TABLE *table= NULL;
120
  int error;
121
  String *field_term=ex->field_term,*escaped=ex->escaped;
122
  String *enclosed=ex->enclosed;
123
  bool is_fifo=0;
124
  LOAD_FILE_INFO lf_info;
125
  char *db = table_list->db;			// This is never null
126
  /*
127
    If path for file is not defined, we will use the current database.
128
    If this is not set, we will use the directory where the table to be
129
    loaded is located
130
  */
131
  char *tdb= thd->db ? thd->db : db;		// Result is never null
132
  ulong skip_lines= ex->skip_lines;
133
  bool transactional_table;
134
  THD::killed_state killed_status= THD::NOT_KILLED;
135
136
  if (escaped->length() > 1 || enclosed->length() > 1)
137
  {
138
    my_message(ER_WRONG_FIELD_TERMINATORS,ER(ER_WRONG_FIELD_TERMINATORS),
139
	       MYF(0));
51.1.53 by Jay Pipes
Removed/replaced DBUG symbols and standardized TRUE/FALSE
140
    return(true);
1 by brian
clean slate
141
  }
142
  if (open_and_lock_tables(thd, table_list))
51.1.53 by Jay Pipes
Removed/replaced DBUG symbols and standardized TRUE/FALSE
143
    return(true);
1 by brian
clean slate
144
  if (setup_tables_and_check_access(thd, &thd->lex->select_lex.context,
145
                                    &thd->lex->select_lex.top_join_list,
146
                                    table_list,
147
                                    &thd->lex->select_lex.leaf_tables, true))
51.1.1 by Jay Pipes
Merged PatG's removal of various DBUG stuff with still keeping DBUG_ASSERT calls since they seem to be breaking test runs
148
     return(-1);
1 by brian
clean slate
149
150
  /*
151
    Let us emit an error if we are loading data to table which is used
152
    in subselect in SET clause like we do it for INSERT.
153
154
    The main thing to fix to remove this restriction is to ensure that the
155
    table is marked to be 'used for insert' in which case we should never
156
    mark this table as 'const table' (ie, one that has only one row).
157
  */
158
  if (unique_table(thd, table_list, table_list->next_global, 0))
159
  {
160
    my_error(ER_UPDATE_TABLE_USED, MYF(0), table_list->table_name);
51.1.53 by Jay Pipes
Removed/replaced DBUG symbols and standardized TRUE/FALSE
161
    return(true);
1 by brian
clean slate
162
  }
163
164
  table= table_list->table;
165
  transactional_table= table->file->has_transactions();
166
167
  if (!fields_vars.elements)
168
  {
169
    Field **field;
170
    for (field=table->field; *field ; field++)
171
      fields_vars.push_back(new Item_field(*field));
172
    bitmap_set_all(table->write_set);
173
    table->timestamp_field_type= TIMESTAMP_NO_AUTO_SET;
174
    /*
175
      Let us also prepare SET clause, altough it is probably empty
176
      in this case.
177
    */
178
    if (setup_fields(thd, 0, set_fields, MARK_COLUMNS_WRITE, 0, 0) ||
179
        setup_fields(thd, 0, set_values, MARK_COLUMNS_READ, 0, 0))
51.1.53 by Jay Pipes
Removed/replaced DBUG symbols and standardized TRUE/FALSE
180
      return(true);
1 by brian
clean slate
181
  }
182
  else
183
  {						// Part field list
184
    /* TODO: use this conds for 'WITH CHECK OPTIONS' */
185
    if (setup_fields(thd, 0, fields_vars, MARK_COLUMNS_WRITE, 0, 0) ||
186
        setup_fields(thd, 0, set_fields, MARK_COLUMNS_WRITE, 0, 0) ||
187
        check_that_all_fields_are_given_values(thd, table, table_list))
51.1.53 by Jay Pipes
Removed/replaced DBUG symbols and standardized TRUE/FALSE
188
      return(true);
1 by brian
clean slate
189
    /*
190
      Check whenever TIMESTAMP field with auto-set feature specified
191
      explicitly.
192
    */
193
    if (table->timestamp_field)
194
    {
195
      if (bitmap_is_set(table->write_set,
196
                        table->timestamp_field->field_index))
197
        table->timestamp_field_type= TIMESTAMP_NO_AUTO_SET;
198
      else
199
      {
200
        bitmap_set_bit(table->write_set,
201
                       table->timestamp_field->field_index);
202
      }
203
    }
204
    /* Fix the expressions in SET clause */
205
    if (setup_fields(thd, 0, set_values, MARK_COLUMNS_READ, 0, 0))
51.1.53 by Jay Pipes
Removed/replaced DBUG symbols and standardized TRUE/FALSE
206
      return(true);
1 by brian
clean slate
207
  }
208
209
  table->mark_columns_needed_for_insert();
210
211
  uint tot_length=0;
212
  bool use_blobs= 0, use_vars= 0;
213
  List_iterator_fast<Item> it(fields_vars);
214
  Item *item;
215
216
  while ((item= it++))
217
  {
218
    Item *real_item= item->real_item();
219
220
    if (real_item->type() == Item::FIELD_ITEM)
221
    {
222
      Field *field= ((Item_field*)real_item)->field;
223
      if (field->flags & BLOB_FLAG)
224
      {
225
        use_blobs= 1;
226
        tot_length+= 256;			// Will be extended if needed
227
      }
228
      else
229
        tot_length+= field->field_length;
230
    }
231
    else if (item->type() == Item::STRING_ITEM)
232
      use_vars= 1;
233
  }
234
  if (use_blobs && !ex->line_term->length() && !field_term->length())
235
  {
236
    my_message(ER_BLOBS_AND_NO_TERMINATED,ER(ER_BLOBS_AND_NO_TERMINATED),
237
	       MYF(0));
51.1.53 by Jay Pipes
Removed/replaced DBUG symbols and standardized TRUE/FALSE
238
    return(true);
1 by brian
clean slate
239
  }
240
  if (use_vars && !field_term->length() && !enclosed->length())
241
  {
242
    my_error(ER_LOAD_FROM_FIXED_SIZE_ROWS_TO_VAR, MYF(0));
51.1.53 by Jay Pipes
Removed/replaced DBUG symbols and standardized TRUE/FALSE
243
    return(true);
1 by brian
clean slate
244
  }
245
246
  /* We can't give an error in the middle when using LOCAL files */
247
  if (read_file_from_client && handle_duplicates == DUP_ERROR)
248
    ignore= 1;
249
250
  if (read_file_from_client)
251
  {
252
    (void)net_request_file(&thd->net,ex->file_name);
253
    file = -1;
254
  }
255
  else
256
  {
257
#ifdef DONT_ALLOW_FULL_LOAD_DATA_PATHS
258
    ex->file_name+=dirname_length(ex->file_name);
259
#endif
260
    if (!dirname_length(ex->file_name))
261
    {
262
      strxnmov(name, FN_REFLEN-1, mysql_real_data_home, tdb, NullS);
263
      (void) fn_format(name, ex->file_name, name, "",
264
		       MY_RELATIVE_PATH | MY_UNPACK_FILENAME);
265
    }
266
    else
267
    {
268
      (void) fn_format(name, ex->file_name, mysql_real_data_home, "",
269
		       MY_RELATIVE_PATH | MY_UNPACK_FILENAME);
270
271
      if (opt_secure_file_priv &&
272
          strncmp(opt_secure_file_priv, name, strlen(opt_secure_file_priv)))
273
      {
274
        /* Read only allowed from within dir specified by secure_file_priv */
275
        my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--secure-file-priv");
51.1.53 by Jay Pipes
Removed/replaced DBUG symbols and standardized TRUE/FALSE
276
        return(true);
1 by brian
clean slate
277
      }
278
15 by brian
Fix for stat, NETWARE removal
279
      struct stat stat_info;
280
      if (stat(name,&stat_info))
51.1.53 by Jay Pipes
Removed/replaced DBUG symbols and standardized TRUE/FALSE
281
	return(true);
1 by brian
clean slate
282
283
      // if we are not in slave thread, the file must be:
284
      if (!thd->slave_thread &&
285
	  !((stat_info.st_mode & S_IROTH) == S_IROTH &&  // readable by others
286
	    (stat_info.st_mode & S_IFLNK) != S_IFLNK && // and not a symlink
287
	    ((stat_info.st_mode & S_IFREG) == S_IFREG ||
288
	     (stat_info.st_mode & S_IFIFO) == S_IFIFO)))
289
      {
290
	my_error(ER_TEXTFILE_NOT_READABLE, MYF(0), name);
51.1.53 by Jay Pipes
Removed/replaced DBUG symbols and standardized TRUE/FALSE
291
	return(true);
1 by brian
clean slate
292
      }
293
      if ((stat_info.st_mode & S_IFIFO) == S_IFIFO)
294
	is_fifo = 1;
295
    }
296
    if ((file=my_open(name,O_RDONLY,MYF(MY_WME))) < 0)
51.1.53 by Jay Pipes
Removed/replaced DBUG symbols and standardized TRUE/FALSE
297
      return(true);
1 by brian
clean slate
298
  }
299
300
  COPY_INFO info;
212.6.6 by Mats Kindahl
Removing redundant use of casts in drizzled/ for memcmp(), memcpy(), memset(), and memmove().
301
  memset(&info, 0, sizeof(info));
1 by brian
clean slate
302
  info.ignore= ignore;
303
  info.handle_duplicates=handle_duplicates;
304
  info.escape_char=escaped->length() ? (*escaped)[0] : INT_MAX;
305
306
  READ_INFO read_info(file,tot_length,
307
                      ex->cs ? ex->cs : thd->variables.collation_database,
308
		      *field_term,*ex->line_start, *ex->line_term, *enclosed,
309
		      info.escape_char, read_file_from_client, is_fifo);
310
  if (read_info.error)
311
  {
312
    if	(file >= 0)
313
      my_close(file,MYF(0));			// no files in net reading
51.1.53 by Jay Pipes
Removed/replaced DBUG symbols and standardized TRUE/FALSE
314
    return(true);				// Can't allocate buffers
1 by brian
clean slate
315
  }
316
317
  if (mysql_bin_log.is_open())
318
  {
319
    lf_info.thd = thd;
320
    lf_info.wrote_create_file = 0;
321
    lf_info.last_pos_in_file = HA_POS_ERROR;
322
    lf_info.log_delayed= transactional_table;
323
    read_info.set_io_cache_arg((void*) &lf_info);
324
  }
325
326
  thd->count_cuted_fields= CHECK_FIELD_WARN;		/* calc cuted fields */
327
  thd->cuted_fields=0L;
328
  /* Skip lines if there is a line terminator */
266.1.23 by Monty Taylor
Removed load xml infile. Hope nobody liked it. Now the only thing we need xml.c
329
  if (ex->line_term->length())
1 by brian
clean slate
330
  {
331
    /* ex->skip_lines needs to be preserved for logging */
332
    while (skip_lines > 0)
333
    {
334
      skip_lines--;
335
      if (read_info.next_line())
336
	break;
337
    }
338
  }
339
340
  if (!(error=test(read_info.error)))
341
  {
342
343
    table->next_number_field=table->found_next_number_field;
344
    if (ignore ||
345
	handle_duplicates == DUP_REPLACE)
346
      table->file->extra(HA_EXTRA_IGNORE_DUP_KEY);
347
    if (handle_duplicates == DUP_REPLACE)
348
        table->file->extra(HA_EXTRA_WRITE_CAN_REPLACE);
349
    table->file->ha_start_bulk_insert((ha_rows) 0);
350
    table->copy_blobs=1;
351
352
    thd->abort_on_warning= (!ignore &&
353
                            (thd->variables.sql_mode &
354
                             (MODE_STRICT_TRANS_TABLES |
355
                              MODE_STRICT_ALL_TABLES)));
356
266.1.23 by Monty Taylor
Removed load xml infile. Hope nobody liked it. Now the only thing we need xml.c
357
    if (!field_term->length() && !enclosed->length())
1 by brian
clean slate
358
      error= read_fixed_length(thd, info, table_list, fields_vars,
359
                               set_fields, set_values, read_info,
360
			       skip_lines, ignore);
361
    else
362
      error= read_sep_field(thd, info, table_list, fields_vars,
363
                            set_fields, set_values, read_info,
364
			    *enclosed, skip_lines, ignore);
365
    if (table->file->ha_end_bulk_insert() && !error)
366
    {
367
      table->file->print_error(my_errno, MYF(0));
368
      error= 1;
369
    }
370
    table->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY);
371
    table->file->extra(HA_EXTRA_WRITE_CANNOT_REPLACE);
372
    table->next_number_field=0;
373
  }
374
  if (file >= 0)
375
    my_close(file,MYF(0));
376
  free_blobs(table);				/* if pack_blob was used */
377
  table->copy_blobs=0;
378
  thd->count_cuted_fields= CHECK_FIELD_IGNORE;
379
  /* 
380
     simulated killing in the middle of per-row loop
381
     must be effective for binlogging
382
  */
383
  killed_status= (error == 0)? THD::NOT_KILLED : thd->killed;
384
  if (error)
385
  {
386
    if (read_file_from_client)
387
      while (!read_info.next_line())
388
	;
389
390
    if (mysql_bin_log.is_open())
391
    {
392
      {
393
	/*
394
	  Make sure last block (the one which caused the error) gets
395
	  logged.  This is needed because otherwise after write of (to
396
	  the binlog, not to read_info (which is a cache))
397
	  Delete_file_log_event the bad block will remain in read_info
398
	  (because pre_read is not called at the end of the last
399
	  block; remember pre_read is called whenever a new block is
400
	  read from disk).  At the end of mysql_load(), the destructor
401
	  of read_info will call end_io_cache() which will flush
402
	  read_info, so we will finally have this in the binlog:
403
404
	  Append_block # The last successfull block
405
	  Delete_file
406
	  Append_block # The failing block
407
	  which is nonsense.
408
	  Or could also be (for a small file)
409
	  Create_file  # The failing block
410
	  which is nonsense (Delete_file is not written in this case, because:
411
	  Create_file has not been written, so Delete_file is not written, then
412
	  when read_info is destroyed end_io_cache() is called which writes
413
	  Create_file.
414
	*/
415
	read_info.end_io_cache();
416
	/* If the file was not empty, wrote_create_file is true */
417
	if (lf_info.wrote_create_file)
418
	{
419
	  if (thd->transaction.stmt.modified_non_trans_table)
420
	    write_execute_load_query_log_event(thd, handle_duplicates,
421
					       ignore, transactional_table,
422
                                               killed_status);
423
	  else
424
	  {
425
	    Delete_file_log_event d(thd, db, transactional_table);
426
            d.flags|= LOG_EVENT_UPDATE_TABLE_MAP_VERSION_F;
427
	    mysql_bin_log.write(&d);
428
	  }
429
	}
430
      }
431
    }
432
    error= -1;				// Error on read
433
    goto err;
434
  }
435
  sprintf(name, ER(ER_LOAD_INFO), (ulong) info.records, (ulong) info.deleted,
436
	  (ulong) (info.records - info.copied), (ulong) thd->cuted_fields);
437
438
  if (thd->transaction.stmt.modified_non_trans_table)
51.1.53 by Jay Pipes
Removed/replaced DBUG symbols and standardized TRUE/FALSE
439
    thd->transaction.all.modified_non_trans_table= true;
1 by brian
clean slate
440
441
  if (mysql_bin_log.is_open())
442
  {
443
    /*
444
      We need to do the job that is normally done inside
445
      binlog_query() here, which is to ensure that the pending event
446
      is written before tables are unlocked and before any other
447
      events are written.  We also need to update the table map
448
      version for the binary log to mark that table maps are invalid
449
      after this point.
450
     */
451
    if (thd->current_stmt_binlog_row_based)
452
      thd->binlog_flush_pending_rows_event(true);
453
    else
454
    {
455
      /*
456
        As already explained above, we need to call end_io_cache() or the last
457
        block will be logged only after Execute_load_query_log_event (which is
458
        wrong), when read_info is destroyed.
459
      */
460
      read_info.end_io_cache();
461
      if (lf_info.wrote_create_file)
462
      {
463
        write_execute_load_query_log_event(thd, handle_duplicates, ignore,
464
                                           transactional_table,killed_status);
465
      }
466
    }
467
  }
468
469
  /* ok to client sent only after binlog write and engine commit */
470
  my_ok(thd, info.copied + info.deleted, 0L, name);
471
err:
51.1.53 by Jay Pipes
Removed/replaced DBUG symbols and standardized TRUE/FALSE
472
  assert(transactional_table || !(info.copied || info.deleted) ||
1 by brian
clean slate
473
              thd->transaction.stmt.modified_non_trans_table);
474
  table->file->ha_release_auto_increment();
51.1.53 by Jay Pipes
Removed/replaced DBUG symbols and standardized TRUE/FALSE
475
  table->auto_increment_field_not_null= false;
1 by brian
clean slate
476
  thd->abort_on_warning= 0;
51.1.1 by Jay Pipes
Merged PatG's removal of various DBUG stuff with still keeping DBUG_ASSERT calls since they seem to be breaking test runs
477
  return(error);
1 by brian
clean slate
478
}
479
480
481
/* Not a very useful function; just to avoid duplication of code */
482
static bool write_execute_load_query_log_event(THD *thd,
483
					       bool duplicates, bool ignore,
484
					       bool transactional_table,
485
                                               THD::killed_state killed_err_arg)
486
{
487
  Execute_load_query_log_event
488
    e(thd, thd->query, thd->query_length,
489
      (char*)thd->lex->fname_start - (char*)thd->query,
490
      (char*)thd->lex->fname_end - (char*)thd->query,
491
      (duplicates == DUP_REPLACE) ? LOAD_DUP_REPLACE :
492
      (ignore ? LOAD_DUP_IGNORE : LOAD_DUP_ERROR),
51.1.53 by Jay Pipes
Removed/replaced DBUG symbols and standardized TRUE/FALSE
493
      transactional_table, false, killed_err_arg);
1 by brian
clean slate
494
  e.flags|= LOG_EVENT_UPDATE_TABLE_MAP_VERSION_F;
495
  return mysql_bin_log.write(&e);
496
}
497
498
499
/****************************************************************************
500
** Read of rows of fixed size + optional garage + optonal newline
501
****************************************************************************/
502
503
static int
504
read_fixed_length(THD *thd, COPY_INFO &info, TABLE_LIST *table_list,
505
                  List<Item> &fields_vars, List<Item> &set_fields,
506
                  List<Item> &set_values, READ_INFO &read_info,
507
                  ulong skip_lines, bool ignore_check_option_errors)
508
{
509
  List_iterator_fast<Item> it(fields_vars);
510
  Item_field *sql_field;
511
  TABLE *table= table_list->table;
151 by Brian Aker
Ulonglong to uint64_t
512
  uint64_t id;
1 by brian
clean slate
513
  bool err;
514
515
  id= 0;
516
 
517
  while (!read_info.read_fixed_length())
518
  {
519
    if (thd->killed)
520
    {
521
      thd->send_kill_message();
51.1.1 by Jay Pipes
Merged PatG's removal of various DBUG stuff with still keeping DBUG_ASSERT calls since they seem to be breaking test runs
522
      return(1);
1 by brian
clean slate
523
    }
524
    if (skip_lines)
525
    {
526
      /*
527
	We could implement this with a simple seek if:
528
	- We are not using DATA INFILE LOCAL
529
	- escape character is  ""
530
	- line starting prefix is ""
531
      */
532
      skip_lines--;
533
      continue;
534
    }
535
    it.rewind();
536
    uchar *pos=read_info.row_start;
537
#ifdef HAVE_purify
538
    read_info.row_end[0]=0;
539
#endif
540
541
    restore_record(table, s->default_values);
542
    /*
543
      There is no variables in fields_vars list in this format so
544
      this conversion is safe.
545
    */
546
    while ((sql_field= (Item_field*) it++))
547
    {
548
      Field *field= sql_field->field;                  
549
      if (field == table->next_number_field)
51.1.53 by Jay Pipes
Removed/replaced DBUG symbols and standardized TRUE/FALSE
550
        table->auto_increment_field_not_null= true;
1 by brian
clean slate
551
      /*
552
        No fields specified in fields_vars list can be null in this format.
553
        Mark field as not null, we should do this for each row because of
554
        restore_record...
555
      */
556
      field->set_notnull();
557
558
      if (pos == read_info.row_end)
559
      {
560
        thd->cuted_fields++;			/* Not enough fields */
261.4.1 by Felipe
- Renamed MYSQL_ERROR to DRIZZLE_ERROR.
561
        push_warning_printf(thd, DRIZZLE_ERROR::WARN_LEVEL_WARN, 
1 by brian
clean slate
562
                            ER_WARN_TOO_FEW_RECORDS, 
563
                            ER(ER_WARN_TOO_FEW_RECORDS), thd->row_count);
212.2.2 by Patrick Galbraith
Renamed FIELD_TYPE to DRIZZLE_TYPE
564
        if (!field->maybe_null() && field->type() == DRIZZLE_TYPE_TIMESTAMP)
1 by brian
clean slate
565
            ((Field_timestamp*) field)->set_time();
566
      }
567
      else
568
      {
569
	uint length;
570
	uchar save_chr;
571
	if ((length=(uint) (read_info.row_end-pos)) >
572
	    field->field_length)
573
	  length=field->field_length;
574
	save_chr=pos[length]; pos[length]='\0'; // Safeguard aganst malloc
575
        field->store((char*) pos,length,read_info.read_charset);
576
	pos[length]=save_chr;
577
	if ((pos+=length) > read_info.row_end)
578
	  pos= read_info.row_end;	/* Fills rest with space */
579
      }
580
    }
581
    if (pos != read_info.row_end)
582
    {
583
      thd->cuted_fields++;			/* To long row */
261.4.1 by Felipe
- Renamed MYSQL_ERROR to DRIZZLE_ERROR.
584
      push_warning_printf(thd, DRIZZLE_ERROR::WARN_LEVEL_WARN, 
1 by brian
clean slate
585
                          ER_WARN_TOO_MANY_RECORDS, 
586
                          ER(ER_WARN_TOO_MANY_RECORDS), thd->row_count); 
587
    }
588
589
    if (thd->killed ||
590
        fill_record(thd, set_fields, set_values,
591
                    ignore_check_option_errors))
51.1.1 by Jay Pipes
Merged PatG's removal of various DBUG stuff with still keeping DBUG_ASSERT calls since they seem to be breaking test runs
592
      return(1);
1 by brian
clean slate
593
594
    err= write_record(thd, table, &info);
51.1.53 by Jay Pipes
Removed/replaced DBUG symbols and standardized TRUE/FALSE
595
    table->auto_increment_field_not_null= false;
1 by brian
clean slate
596
    if (err)
51.1.1 by Jay Pipes
Merged PatG's removal of various DBUG stuff with still keeping DBUG_ASSERT calls since they seem to be breaking test runs
597
      return(1);
1 by brian
clean slate
598
   
599
    /*
600
      We don't need to reset auto-increment field since we are restoring
601
      its default value at the beginning of each loop iteration.
602
    */
603
    if (read_info.next_line())			// Skip to next line
604
      break;
605
    if (read_info.line_cuted)
606
    {
607
      thd->cuted_fields++;			/* To long row */
261.4.1 by Felipe
- Renamed MYSQL_ERROR to DRIZZLE_ERROR.
608
      push_warning_printf(thd, DRIZZLE_ERROR::WARN_LEVEL_WARN, 
1 by brian
clean slate
609
                          ER_WARN_TOO_MANY_RECORDS, 
610
                          ER(ER_WARN_TOO_MANY_RECORDS), thd->row_count); 
611
    }
612
    thd->row_count++;
613
  }
51.1.1 by Jay Pipes
Merged PatG's removal of various DBUG stuff with still keeping DBUG_ASSERT calls since they seem to be breaking test runs
614
  return(test(read_info.error));
1 by brian
clean slate
615
}
616
617
618
619
static int
620
read_sep_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list,
621
               List<Item> &fields_vars, List<Item> &set_fields,
622
               List<Item> &set_values, READ_INFO &read_info,
623
	       String &enclosed, ulong skip_lines,
624
	       bool ignore_check_option_errors)
625
{
626
  List_iterator_fast<Item> it(fields_vars);
627
  Item *item;
628
  TABLE *table= table_list->table;
629
  uint enclosed_length;
151 by Brian Aker
Ulonglong to uint64_t
630
  uint64_t id;
1 by brian
clean slate
631
  bool err;
632
633
  enclosed_length=enclosed.length();
634
  id= 0;
635
636
  for (;;it.rewind())
637
  {
638
    if (thd->killed)
639
    {
640
      thd->send_kill_message();
51.1.1 by Jay Pipes
Merged PatG's removal of various DBUG stuff with still keeping DBUG_ASSERT calls since they seem to be breaking test runs
641
      return(1);
1 by brian
clean slate
642
    }
643
644
    restore_record(table, s->default_values);
645
646
    while ((item= it++))
647
    {
648
      uint length;
649
      uchar *pos;
650
      Item *real_item;
651
652
      if (read_info.read_field())
653
	break;
654
655
      /* If this line is to be skipped we don't want to fill field or var */
656
      if (skip_lines)
657
        continue;
658
659
      pos=read_info.row_start;
660
      length=(uint) (read_info.row_end-pos);
661
662
      real_item= item->real_item();
663
664
      if ((!read_info.enclosed && (enclosed_length && length == 4 && !memcmp(pos, STRING_WITH_LEN("NULL")))) ||
665
	  (length == 1 && read_info.found_null))
666
      {
667
668
        if (real_item->type() == Item::FIELD_ITEM)
669
        {
670
          Field *field= ((Item_field *)real_item)->field;
671
          if (field->reset())
672
          {
673
            my_error(ER_WARN_NULL_TO_NOTNULL, MYF(0), field->field_name,
674
                     thd->row_count);
51.1.1 by Jay Pipes
Merged PatG's removal of various DBUG stuff with still keeping DBUG_ASSERT calls since they seem to be breaking test runs
675
            return(1);
1 by brian
clean slate
676
          }
677
          field->set_null();
678
          if (!field->maybe_null())
679
          {
212.2.2 by Patrick Galbraith
Renamed FIELD_TYPE to DRIZZLE_TYPE
680
            if (field->type() == DRIZZLE_TYPE_TIMESTAMP)
1 by brian
clean slate
681
              ((Field_timestamp*) field)->set_time();
682
            else if (field != table->next_number_field)
261.4.1 by Felipe
- Renamed MYSQL_ERROR to DRIZZLE_ERROR.
683
              field->set_warning(DRIZZLE_ERROR::WARN_LEVEL_WARN,
1 by brian
clean slate
684
                                 ER_WARN_NULL_TO_NOTNULL, 1);
685
          }
686
	}
687
        else if (item->type() == Item::STRING_ITEM)
688
        {
689
          ((Item_user_var_as_out_param *)item)->set_null_value(
690
                                                  read_info.read_charset);
691
        }
692
        else
693
        {
694
          my_error(ER_LOAD_DATA_INVALID_COLUMN, MYF(0), item->full_name());
51.1.1 by Jay Pipes
Merged PatG's removal of various DBUG stuff with still keeping DBUG_ASSERT calls since they seem to be breaking test runs
695
          return(1);
1 by brian
clean slate
696
        }
697
698
	continue;
699
      }
700
701
      if (real_item->type() == Item::FIELD_ITEM)
702
      {
703
        Field *field= ((Item_field *)real_item)->field;
704
        field->set_notnull();
705
        read_info.row_end[0]=0;			// Safe to change end marker
706
        if (field == table->next_number_field)
51.1.53 by Jay Pipes
Removed/replaced DBUG symbols and standardized TRUE/FALSE
707
          table->auto_increment_field_not_null= true;
1 by brian
clean slate
708
        field->store((char*) pos, length, read_info.read_charset);
709
      }
710
      else if (item->type() == Item::STRING_ITEM)
711
      {
712
        ((Item_user_var_as_out_param *)item)->set_value((char*) pos, length,
713
                                                        read_info.read_charset);
714
      }
715
      else
716
      {
717
        my_error(ER_LOAD_DATA_INVALID_COLUMN, MYF(0), item->full_name());
51.1.1 by Jay Pipes
Merged PatG's removal of various DBUG stuff with still keeping DBUG_ASSERT calls since they seem to be breaking test runs
718
        return(1);
1 by brian
clean slate
719
      }
720
    }
721
    if (read_info.error)
722
      break;
723
    if (skip_lines)
724
    {
725
      skip_lines--;
726
      continue;
727
    }
728
    if (item)
729
    {
730
      /* Have not read any field, thus input file is simply ended */
731
      if (item == fields_vars.head())
732
	break;
733
      for (; item ; item= it++)
734
      {
735
        Item *real_item= item->real_item();
736
        if (real_item->type() == Item::FIELD_ITEM)
737
        {
738
          Field *field= ((Item_field *)real_item)->field;
739
          if (field->reset())
740
          {
741
            my_error(ER_WARN_NULL_TO_NOTNULL, MYF(0),field->field_name,
742
                     thd->row_count);
51.1.1 by Jay Pipes
Merged PatG's removal of various DBUG stuff with still keeping DBUG_ASSERT calls since they seem to be breaking test runs
743
            return(1);
1 by brian
clean slate
744
          }
212.2.2 by Patrick Galbraith
Renamed FIELD_TYPE to DRIZZLE_TYPE
745
          if (!field->maybe_null() && field->type() == DRIZZLE_TYPE_TIMESTAMP)
1 by brian
clean slate
746
              ((Field_timestamp*) field)->set_time();
747
          /*
748
            QQ: We probably should not throw warning for each field.
749
            But how about intention to always have the same number
750
            of warnings in THD::cuted_fields (and get rid of cuted_fields
751
            in the end ?)
752
          */
753
          thd->cuted_fields++;
261.4.1 by Felipe
- Renamed MYSQL_ERROR to DRIZZLE_ERROR.
754
          push_warning_printf(thd, DRIZZLE_ERROR::WARN_LEVEL_WARN,
1 by brian
clean slate
755
                              ER_WARN_TOO_FEW_RECORDS,
756
                              ER(ER_WARN_TOO_FEW_RECORDS), thd->row_count);
757
        }
758
        else if (item->type() == Item::STRING_ITEM)
759
        {
760
          ((Item_user_var_as_out_param *)item)->set_null_value(
761
                                                  read_info.read_charset);
762
        }
763
        else
764
        {
765
          my_error(ER_LOAD_DATA_INVALID_COLUMN, MYF(0), item->full_name());
51.1.1 by Jay Pipes
Merged PatG's removal of various DBUG stuff with still keeping DBUG_ASSERT calls since they seem to be breaking test runs
766
          return(1);
1 by brian
clean slate
767
        }
768
      }
769
    }
770
771
    if (thd->killed ||
772
        fill_record(thd, set_fields, set_values,
773
                    ignore_check_option_errors))
51.1.1 by Jay Pipes
Merged PatG's removal of various DBUG stuff with still keeping DBUG_ASSERT calls since they seem to be breaking test runs
774
      return(1);
1 by brian
clean slate
775
776
    err= write_record(thd, table, &info);
51.1.53 by Jay Pipes
Removed/replaced DBUG symbols and standardized TRUE/FALSE
777
    table->auto_increment_field_not_null= false;
1 by brian
clean slate
778
    if (err)
51.1.1 by Jay Pipes
Merged PatG's removal of various DBUG stuff with still keeping DBUG_ASSERT calls since they seem to be breaking test runs
779
      return(1);
1 by brian
clean slate
780
    /*
781
      We don't need to reset auto-increment field since we are restoring
782
      its default value at the beginning of each loop iteration.
783
    */
784
    if (read_info.next_line())			// Skip to next line
785
      break;
786
    if (read_info.line_cuted)
787
    {
788
      thd->cuted_fields++;			/* To long row */
261.4.1 by Felipe
- Renamed MYSQL_ERROR to DRIZZLE_ERROR.
789
      push_warning_printf(thd, DRIZZLE_ERROR::WARN_LEVEL_WARN, 
1 by brian
clean slate
790
                          ER_WARN_TOO_MANY_RECORDS, ER(ER_WARN_TOO_MANY_RECORDS), 
791
                          thd->row_count);   
792
      if (thd->killed)
51.1.1 by Jay Pipes
Merged PatG's removal of various DBUG stuff with still keeping DBUG_ASSERT calls since they seem to be breaking test runs
793
        return(1);
1 by brian
clean slate
794
    }
795
    thd->row_count++;
796
  }
51.1.1 by Jay Pipes
Merged PatG's removal of various DBUG stuff with still keeping DBUG_ASSERT calls since they seem to be breaking test runs
797
  return(test(read_info.error));
1 by brian
clean slate
798
}
799
800
801
/* Unescape all escape characters, mark \N as null */
802
803
char
804
READ_INFO::unescape(char chr)
805
{
806
  /* keep this switch synchornous with the ESCAPE_CHARS macro */
807
  switch(chr) {
808
  case 'n': return '\n';
809
  case 't': return '\t';
810
  case 'r': return '\r';
811
  case 'b': return '\b';
812
  case '0': return 0;				// Ascii null
813
  case 'Z': return '\032';			// Win32 end of file
814
  case 'N': found_null=1;
815
816
    /* fall through */
817
  default:  return chr;
818
  }
819
}
820
821
822
/*
823
  Read a line using buffering
824
  If last line is empty (in line mode) then it isn't outputed
825
*/
826
827
264.2.6 by Andrey Hristov
Constify the usage of CHARSET_INFO almost to the last place in the code.
828
READ_INFO::READ_INFO(File file_par, uint tot_length, const CHARSET_INFO * const cs,
1 by brian
clean slate
829
		     String &field_term, String &line_start, String &line_term,
830
		     String &enclosed_par, int escape, bool get_it_from_net,
831
		     bool is_fifo)
832
  :file(file_par),escape_char(escape)
833
{
834
  read_charset= cs;
835
  field_term_ptr=(char*) field_term.ptr();
836
  field_term_length= field_term.length();
837
  line_term_ptr=(char*) line_term.ptr();
838
  line_term_length= line_term.length();
839
  if (line_start.length() == 0)
840
  {
841
    line_start_ptr=0;
842
    start_of_line= 0;
843
  }
844
  else
845
  {
846
    line_start_ptr=(char*) line_start.ptr();
847
    line_start_end=line_start_ptr+line_start.length();
848
    start_of_line= 1;
849
  }
850
  /* If field_terminator == line_terminator, don't use line_terminator */
851
  if (field_term_length == line_term_length &&
852
      !memcmp(field_term_ptr,line_term_ptr,field_term_length))
853
  {
854
    line_term_length=0;
855
    line_term_ptr=(char*) "";
856
  }
857
  enclosed_char= (enclosed_length=enclosed_par.length()) ?
858
    (uchar) enclosed_par[0] : INT_MAX;
859
  field_term_char= field_term_length ? (uchar) field_term_ptr[0] : INT_MAX;
860
  line_term_char= line_term_length ? (uchar) line_term_ptr[0] : INT_MAX;
861
  error=eof=found_end_of_line=found_null=line_cuted=0;
862
  buff_length=tot_length;
863
864
865
  /* Set of a stack for unget if long terminators */
866
  uint length=max(field_term_length,line_term_length)+1;
867
  set_if_bigger(length,line_start.length());
868
  stack=stack_pos=(int*) sql_alloc(sizeof(int)*length);
869
870
  if (!(buffer=(uchar*) my_malloc(buff_length+1,MYF(0))))
871
    error=1; /* purecov: inspected */
872
  else
873
  {
874
    end_of_buff=buffer+buff_length;
875
    if (init_io_cache(&cache,(get_it_from_net) ? -1 : file, 0,
876
		      (get_it_from_net) ? READ_NET :
877
		      (is_fifo ? READ_FIFO : READ_CACHE),0L,1,
878
		      MYF(MY_WME)))
879
    {
880
      my_free((uchar*) buffer,MYF(0)); /* purecov: inspected */
881
      error=1;
882
    }
883
    else
884
    {
885
      /*
886
	init_io_cache() will not initialize read_function member
887
	if the cache is READ_NET. So we work around the problem with a
888
	manual assignment
889
      */
890
      need_end_io_cache = 1;
891
892
      if (get_it_from_net)
893
	cache.read_function = _my_b_net_read;
894
895
      if (mysql_bin_log.is_open())
896
	cache.pre_read = cache.pre_close =
897
	  (IO_CACHE_CALLBACK) log_loaded_block;
898
    }
899
  }
900
}
901
902
903
READ_INFO::~READ_INFO()
904
{
905
  if (!error)
906
  {
907
    if (need_end_io_cache)
908
      ::end_io_cache(&cache);
909
    my_free((uchar*) buffer,MYF(0));
910
    error=1;
911
  }
912
}
913
914
915
#define GET (stack_pos != stack ? *--stack_pos : my_b_get(&cache))
916
#define PUSH(A) *(stack_pos++)=(A)
917
918
919
inline int READ_INFO::terminator(char *ptr,uint length)
920
{
921
  int chr=0;					// Keep gcc happy
922
  uint i;
923
  for (i=1 ; i < length ; i++)
924
  {
925
    if ((chr=GET) != *++ptr)
926
    {
927
      break;
928
    }
929
  }
930
  if (i == length)
931
    return 1;
932
  PUSH(chr);
933
  while (i-- > 1)
934
    PUSH((uchar) *--ptr);
935
  return 0;
936
}
937
938
939
int READ_INFO::read_field()
940
{
941
  int chr,found_enclosed_char;
942
  uchar *to,*new_buffer;
943
944
  found_null=0;
945
  if (found_end_of_line)
946
    return 1;					// One have to call next_line
947
948
  /* Skip until we find 'line_start' */
949
950
  if (start_of_line)
951
  {						// Skip until line_start
952
    start_of_line=0;
953
    if (find_start_of_fields())
954
      return 1;
955
  }
956
  if ((chr=GET) == my_b_EOF)
957
  {
958
    found_end_of_line=eof=1;
959
    return 1;
960
  }
961
  to=buffer;
962
  if (chr == enclosed_char)
963
  {
964
    found_enclosed_char=enclosed_char;
965
    *to++=(uchar) chr;				// If error
966
  }
967
  else
968
  {
969
    found_enclosed_char= INT_MAX;
970
    PUSH(chr);
971
  }
972
973
  for (;;)
974
  {
975
    while ( to < end_of_buff)
976
    {
977
      chr = GET;
978
#ifdef USE_MB
979
      if ((my_mbcharlen(read_charset, chr) > 1) &&
980
          to+my_mbcharlen(read_charset, chr) <= end_of_buff)
981
      {
982
	  uchar* p = (uchar*)to;
983
	  *to++ = chr;
984
	  int ml = my_mbcharlen(read_charset, chr);
985
	  int i;
986
	  for (i=1; i<ml; i++) {
987
	      chr = GET;
988
	      if (chr == my_b_EOF)
989
		  goto found_eof;
990
	      *to++ = chr;
991
	  }
992
	  if (my_ismbchar(read_charset,
993
                          (const char *)p,
994
                          (const char *)to))
995
	    continue;
996
	  for (i=0; i<ml; i++)
997
	    PUSH((uchar) *--to);
998
	  chr = GET;
999
      }
1000
#endif
1001
      if (chr == my_b_EOF)
1002
	goto found_eof;
1003
      if (chr == escape_char)
1004
      {
1005
	if ((chr=GET) == my_b_EOF)
1006
	{
1007
	  *to++= (uchar) escape_char;
1008
	  goto found_eof;
1009
	}
1010
        /*
1011
          When escape_char == enclosed_char, we treat it like we do for
1012
          handling quotes in SQL parsing -- you can double-up the
1013
          escape_char to include it literally, but it doesn't do escapes
1014
          like \n. This allows: LOAD DATA ... ENCLOSED BY '"' ESCAPED BY '"'
1015
          with data like: "fie""ld1", "field2"
1016
         */
1017
        if (escape_char != enclosed_char || chr == escape_char)
1018
        {
1019
          *to++ = (uchar) unescape((char) chr);
1020
          continue;
1021
        }
1022
        PUSH(chr);
1023
        chr= escape_char;
1024
      }
1025
#ifdef ALLOW_LINESEPARATOR_IN_STRINGS
1026
      if (chr == line_term_char)
1027
#else
1028
      if (chr == line_term_char && found_enclosed_char == INT_MAX)
1029
#endif
1030
      {
1031
	if (terminator(line_term_ptr,line_term_length))
1032
	{					// Maybe unexpected linefeed
1033
	  enclosed=0;
1034
	  found_end_of_line=1;
1035
	  row_start=buffer;
1036
	  row_end=  to;
1037
	  return 0;
1038
	}
1039
      }
1040
      if (chr == found_enclosed_char)
1041
      {
1042
	if ((chr=GET) == found_enclosed_char)
1043
	{					// Remove dupplicated
1044
	  *to++ = (uchar) chr;
1045
	  continue;
1046
	}
1047
	// End of enclosed field if followed by field_term or line_term
1048
	if (chr == my_b_EOF ||
1049
	    (chr == line_term_char && terminator(line_term_ptr, line_term_length)))
1050
	{					// Maybe unexpected linefeed
1051
	  enclosed=1;
1052
	  found_end_of_line=1;
1053
	  row_start=buffer+1;
1054
	  row_end=  to;
1055
	  return 0;
1056
	}
1057
	if (chr == field_term_char &&
1058
	    terminator(field_term_ptr,field_term_length))
1059
	{
1060
	  enclosed=1;
1061
	  row_start=buffer+1;
1062
	  row_end=  to;
1063
	  return 0;
1064
	}
1065
	/*
1066
	  The string didn't terminate yet.
1067
	  Store back next character for the loop
1068
	*/
1069
	PUSH(chr);
1070
	/* copy the found term character to 'to' */
1071
	chr= found_enclosed_char;
1072
      }
1073
      else if (chr == field_term_char && found_enclosed_char == INT_MAX)
1074
      {
1075
	if (terminator(field_term_ptr,field_term_length))
1076
	{
1077
	  enclosed=0;
1078
	  row_start=buffer;
1079
	  row_end=  to;
1080
	  return 0;
1081
	}
1082
      }
1083
      *to++ = (uchar) chr;
1084
    }
1085
    /*
1086
    ** We come here if buffer is too small. Enlarge it and continue
1087
    */
1088
    if (!(new_buffer=(uchar*) my_realloc((char*) buffer,buff_length+1+IO_SIZE,
1089
					MYF(MY_WME))))
1090
      return (error=1);
1091
    to=new_buffer + (to-buffer);
1092
    buffer=new_buffer;
1093
    buff_length+=IO_SIZE;
1094
    end_of_buff=buffer+buff_length;
1095
  }
1096
1097
found_eof:
1098
  enclosed=0;
1099
  found_end_of_line=eof=1;
1100
  row_start=buffer;
1101
  row_end=to;
1102
  return 0;
1103
}
1104
1105
/*
1106
  Read a row with fixed length.
1107
1108
  NOTES
1109
    The row may not be fixed size on disk if there are escape
1110
    characters in the file.
1111
1112
  IMPLEMENTATION NOTE
1113
    One can't use fixed length with multi-byte charset **
1114
1115
  RETURN
1116
    0  ok
1117
    1  error
1118
*/
1119
1120
int READ_INFO::read_fixed_length()
1121
{
1122
  int chr;
1123
  uchar *to;
1124
  if (found_end_of_line)
1125
    return 1;					// One have to call next_line
1126
1127
  if (start_of_line)
1128
  {						// Skip until line_start
1129
    start_of_line=0;
1130
    if (find_start_of_fields())
1131
      return 1;
1132
  }
1133
1134
  to=row_start=buffer;
1135
  while (to < end_of_buff)
1136
  {
1137
    if ((chr=GET) == my_b_EOF)
1138
      goto found_eof;
1139
    if (chr == escape_char)
1140
    {
1141
      if ((chr=GET) == my_b_EOF)
1142
      {
1143
	*to++= (uchar) escape_char;
1144
	goto found_eof;
1145
      }
1146
      *to++ =(uchar) unescape((char) chr);
1147
      continue;
1148
    }
1149
    if (chr == line_term_char)
1150
    {
1151
      if (terminator(line_term_ptr,line_term_length))
1152
      {						// Maybe unexpected linefeed
1153
	found_end_of_line=1;
1154
	row_end=  to;
1155
	return 0;
1156
      }
1157
    }
1158
    *to++ = (uchar) chr;
1159
  }
1160
  row_end=to;					// Found full line
1161
  return 0;
1162
1163
found_eof:
1164
  found_end_of_line=eof=1;
1165
  row_start=buffer;
1166
  row_end=to;
1167
  return to == buffer ? 1 : 0;
1168
}
1169
1170
1171
int READ_INFO::next_line()
1172
{
1173
  line_cuted=0;
1174
  start_of_line= line_start_ptr != 0;
1175
  if (found_end_of_line || eof)
1176
  {
1177
    found_end_of_line=0;
1178
    return eof;
1179
  }
1180
  found_end_of_line=0;
1181
  if (!line_term_length)
1182
    return 0;					// No lines
1183
  for (;;)
1184
  {
1185
    int chr = GET;
1186
#ifdef USE_MB
1187
   if (my_mbcharlen(read_charset, chr) > 1)
1188
   {
1189
       for (uint i=1;
1190
            chr != my_b_EOF && i<my_mbcharlen(read_charset, chr);
1191
            i++)
1192
	   chr = GET;
1193
       if (chr == escape_char)
1194
	   continue;
1195
   }
1196
#endif
1197
   if (chr == my_b_EOF)
1198
   {
1199
      eof=1;
1200
      return 1;
1201
    }
1202
    if (chr == escape_char)
1203
    {
1204
      line_cuted=1;
1205
      if (GET == my_b_EOF)
1206
	return 1;
1207
      continue;
1208
    }
1209
    if (chr == line_term_char && terminator(line_term_ptr,line_term_length))
1210
      return 0;
1211
    line_cuted=1;
1212
  }
1213
}
1214
1215
1216
bool READ_INFO::find_start_of_fields()
1217
{
1218
  int chr;
1219
 try_again:
1220
  do
1221
  {
1222
    if ((chr=GET) == my_b_EOF)
1223
    {
1224
      found_end_of_line=eof=1;
1225
      return 1;
1226
    }
1227
  } while ((char) chr != line_start_ptr[0]);
1228
  for (char *ptr=line_start_ptr+1 ; ptr != line_start_end ; ptr++)
1229
  {
1230
    chr=GET;					// Eof will be checked later
1231
    if ((char) chr != *ptr)
1232
    {						// Can't be line_start
1233
      PUSH(chr);
1234
      while (--ptr != line_start_ptr)
1235
      {						// Restart with next char
1236
	PUSH((uchar) *ptr);
1237
      }
1238
      goto try_again;
1239
    }
1240
  }
1241
  return 0;
1242
}
1243
1244