~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
327.2.4 by Brian Aker
Refactoring table.h
74
static int read_fixed_length(THD *thd, COPY_INFO &info, TableList *table_list,
1 by brian
clean slate
75
                             List<Item> &fields_vars, List<Item> &set_fields,
76
                             List<Item> &set_values, READ_INFO &read_info,
307 by Brian Aker
Minor cleanups around ulong in kernel.
77
			     uint32_t skip_lines,
1 by brian
clean slate
78
			     bool ignore_check_option_errors);
327.2.4 by Brian Aker
Refactoring table.h
79
static int read_sep_field(THD *thd, COPY_INFO &info, TableList *table_list,
1 by brian
clean slate
80
                          List<Item> &fields_vars, List<Item> &set_fields,
81
                          List<Item> &set_values, READ_INFO &read_info,
307 by Brian Aker
Minor cleanups around ulong in kernel.
82
			  String &enclosed, uint32_t skip_lines,
1 by brian
clean slate
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
327.2.4 by Brian Aker
Refactoring table.h
111
int mysql_load(THD *thd,sql_exchange *ex,TableList *table_list,
1 by brian
clean slate
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;
327.1.5 by Brian Aker
Refactor around classes. TABLE_LIST has been factored out of table.h
119
  Table *table= NULL;
1 by brian
clean slate
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
307 by Brian Aker
Minor cleanups around ulong in kernel.
132
  uint32_t skip_lines= ex->skip_lines;
1 by brian
clean slate
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
360 by Brian Aker
More MODE removal.
352
    thd->abort_on_warning= true;
1 by brian
clean slate
353
266.1.23 by Monty Taylor
Removed load xml infile. Hope nobody liked it. Now the only thing we need xml.c
354
    if (!field_term->length() && !enclosed->length())
1 by brian
clean slate
355
      error= read_fixed_length(thd, info, table_list, fields_vars,
356
                               set_fields, set_values, read_info,
357
			       skip_lines, ignore);
358
    else
359
      error= read_sep_field(thd, info, table_list, fields_vars,
360
                            set_fields, set_values, read_info,
361
			    *enclosed, skip_lines, ignore);
362
    if (table->file->ha_end_bulk_insert() && !error)
363
    {
364
      table->file->print_error(my_errno, MYF(0));
365
      error= 1;
366
    }
367
    table->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY);
368
    table->file->extra(HA_EXTRA_WRITE_CANNOT_REPLACE);
369
    table->next_number_field=0;
370
  }
371
  if (file >= 0)
372
    my_close(file,MYF(0));
373
  free_blobs(table);				/* if pack_blob was used */
374
  table->copy_blobs=0;
375
  thd->count_cuted_fields= CHECK_FIELD_IGNORE;
376
  /* 
377
     simulated killing in the middle of per-row loop
378
     must be effective for binlogging
379
  */
380
  killed_status= (error == 0)? THD::NOT_KILLED : thd->killed;
381
  if (error)
382
  {
383
    if (read_file_from_client)
384
      while (!read_info.next_line())
385
	;
386
387
    if (mysql_bin_log.is_open())
388
    {
389
      {
390
	/*
391
	  Make sure last block (the one which caused the error) gets
392
	  logged.  This is needed because otherwise after write of (to
393
	  the binlog, not to read_info (which is a cache))
394
	  Delete_file_log_event the bad block will remain in read_info
395
	  (because pre_read is not called at the end of the last
396
	  block; remember pre_read is called whenever a new block is
397
	  read from disk).  At the end of mysql_load(), the destructor
398
	  of read_info will call end_io_cache() which will flush
399
	  read_info, so we will finally have this in the binlog:
400
401
	  Append_block # The last successfull block
402
	  Delete_file
403
	  Append_block # The failing block
404
	  which is nonsense.
405
	  Or could also be (for a small file)
406
	  Create_file  # The failing block
407
	  which is nonsense (Delete_file is not written in this case, because:
408
	  Create_file has not been written, so Delete_file is not written, then
409
	  when read_info is destroyed end_io_cache() is called which writes
410
	  Create_file.
411
	*/
412
	read_info.end_io_cache();
413
	/* If the file was not empty, wrote_create_file is true */
414
	if (lf_info.wrote_create_file)
415
	{
416
	  if (thd->transaction.stmt.modified_non_trans_table)
417
	    write_execute_load_query_log_event(thd, handle_duplicates,
418
					       ignore, transactional_table,
419
                                               killed_status);
420
	  else
421
	  {
422
	    Delete_file_log_event d(thd, db, transactional_table);
423
            d.flags|= LOG_EVENT_UPDATE_TABLE_MAP_VERSION_F;
424
	    mysql_bin_log.write(&d);
425
	  }
426
	}
427
      }
428
    }
429
    error= -1;				// Error on read
430
    goto err;
431
  }
307 by Brian Aker
Minor cleanups around ulong in kernel.
432
  sprintf(name, ER(ER_LOAD_INFO), (uint32_t) info.records, (uint32_t) info.deleted,
433
	  (uint32_t) (info.records - info.copied), (uint32_t) thd->cuted_fields);
1 by brian
clean slate
434
435
  if (thd->transaction.stmt.modified_non_trans_table)
51.1.53 by Jay Pipes
Removed/replaced DBUG symbols and standardized TRUE/FALSE
436
    thd->transaction.all.modified_non_trans_table= true;
1 by brian
clean slate
437
438
  if (mysql_bin_log.is_open())
439
  {
440
    /*
441
      We need to do the job that is normally done inside
442
      binlog_query() here, which is to ensure that the pending event
443
      is written before tables are unlocked and before any other
444
      events are written.  We also need to update the table map
445
      version for the binary log to mark that table maps are invalid
446
      after this point.
447
     */
448
    if (thd->current_stmt_binlog_row_based)
449
      thd->binlog_flush_pending_rows_event(true);
450
    else
451
    {
452
      /*
453
        As already explained above, we need to call end_io_cache() or the last
454
        block will be logged only after Execute_load_query_log_event (which is
455
        wrong), when read_info is destroyed.
456
      */
457
      read_info.end_io_cache();
458
      if (lf_info.wrote_create_file)
459
      {
460
        write_execute_load_query_log_event(thd, handle_duplicates, ignore,
461
                                           transactional_table,killed_status);
462
      }
463
    }
464
  }
465
466
  /* ok to client sent only after binlog write and engine commit */
467
  my_ok(thd, info.copied + info.deleted, 0L, name);
468
err:
51.1.53 by Jay Pipes
Removed/replaced DBUG symbols and standardized TRUE/FALSE
469
  assert(transactional_table || !(info.copied || info.deleted) ||
1 by brian
clean slate
470
              thd->transaction.stmt.modified_non_trans_table);
471
  table->file->ha_release_auto_increment();
51.1.53 by Jay Pipes
Removed/replaced DBUG symbols and standardized TRUE/FALSE
472
  table->auto_increment_field_not_null= false;
1 by brian
clean slate
473
  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
474
  return(error);
1 by brian
clean slate
475
}
476
477
478
/* Not a very useful function; just to avoid duplication of code */
479
static bool write_execute_load_query_log_event(THD *thd,
480
					       bool duplicates, bool ignore,
481
					       bool transactional_table,
482
                                               THD::killed_state killed_err_arg)
483
{
484
  Execute_load_query_log_event
485
    e(thd, thd->query, thd->query_length,
486
      (char*)thd->lex->fname_start - (char*)thd->query,
487
      (char*)thd->lex->fname_end - (char*)thd->query,
488
      (duplicates == DUP_REPLACE) ? LOAD_DUP_REPLACE :
489
      (ignore ? LOAD_DUP_IGNORE : LOAD_DUP_ERROR),
51.1.53 by Jay Pipes
Removed/replaced DBUG symbols and standardized TRUE/FALSE
490
      transactional_table, false, killed_err_arg);
1 by brian
clean slate
491
  e.flags|= LOG_EVENT_UPDATE_TABLE_MAP_VERSION_F;
492
  return mysql_bin_log.write(&e);
493
}
494
495
496
/****************************************************************************
497
** Read of rows of fixed size + optional garage + optonal newline
498
****************************************************************************/
499
500
static int
327.2.4 by Brian Aker
Refactoring table.h
501
read_fixed_length(THD *thd, COPY_INFO &info, TableList *table_list,
1 by brian
clean slate
502
                  List<Item> &fields_vars, List<Item> &set_fields,
503
                  List<Item> &set_values, READ_INFO &read_info,
307 by Brian Aker
Minor cleanups around ulong in kernel.
504
                  uint32_t skip_lines, bool ignore_check_option_errors)
1 by brian
clean slate
505
{
506
  List_iterator_fast<Item> it(fields_vars);
507
  Item_field *sql_field;
327.1.5 by Brian Aker
Refactor around classes. TABLE_LIST has been factored out of table.h
508
  Table *table= table_list->table;
151 by Brian Aker
Ulonglong to uint64_t
509
  uint64_t id;
1 by brian
clean slate
510
  bool err;
511
512
  id= 0;
513
 
514
  while (!read_info.read_fixed_length())
515
  {
516
    if (thd->killed)
517
    {
518
      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
519
      return(1);
1 by brian
clean slate
520
    }
521
    if (skip_lines)
522
    {
523
      /*
524
	We could implement this with a simple seek if:
525
	- We are not using DATA INFILE LOCAL
526
	- escape character is  ""
527
	- line starting prefix is ""
528
      */
529
      skip_lines--;
530
      continue;
531
    }
532
    it.rewind();
533
    uchar *pos=read_info.row_start;
534
#ifdef HAVE_purify
535
    read_info.row_end[0]=0;
536
#endif
537
538
    restore_record(table, s->default_values);
539
    /*
540
      There is no variables in fields_vars list in this format so
541
      this conversion is safe.
542
    */
543
    while ((sql_field= (Item_field*) it++))
544
    {
545
      Field *field= sql_field->field;                  
546
      if (field == table->next_number_field)
51.1.53 by Jay Pipes
Removed/replaced DBUG symbols and standardized TRUE/FALSE
547
        table->auto_increment_field_not_null= true;
1 by brian
clean slate
548
      /*
549
        No fields specified in fields_vars list can be null in this format.
550
        Mark field as not null, we should do this for each row because of
551
        restore_record...
552
      */
553
      field->set_notnull();
554
555
      if (pos == read_info.row_end)
556
      {
557
        thd->cuted_fields++;			/* Not enough fields */
261.4.1 by Felipe
- Renamed MYSQL_ERROR to DRIZZLE_ERROR.
558
        push_warning_printf(thd, DRIZZLE_ERROR::WARN_LEVEL_WARN, 
1 by brian
clean slate
559
                            ER_WARN_TOO_FEW_RECORDS, 
560
                            ER(ER_WARN_TOO_FEW_RECORDS), thd->row_count);
212.2.2 by Patrick Galbraith
Renamed FIELD_TYPE to DRIZZLE_TYPE
561
        if (!field->maybe_null() && field->type() == DRIZZLE_TYPE_TIMESTAMP)
1 by brian
clean slate
562
            ((Field_timestamp*) field)->set_time();
563
      }
564
      else
565
      {
566
	uint length;
567
	uchar save_chr;
568
	if ((length=(uint) (read_info.row_end-pos)) >
569
	    field->field_length)
570
	  length=field->field_length;
571
	save_chr=pos[length]; pos[length]='\0'; // Safeguard aganst malloc
572
        field->store((char*) pos,length,read_info.read_charset);
573
	pos[length]=save_chr;
574
	if ((pos+=length) > read_info.row_end)
575
	  pos= read_info.row_end;	/* Fills rest with space */
576
      }
577
    }
578
    if (pos != read_info.row_end)
579
    {
580
      thd->cuted_fields++;			/* To long row */
261.4.1 by Felipe
- Renamed MYSQL_ERROR to DRIZZLE_ERROR.
581
      push_warning_printf(thd, DRIZZLE_ERROR::WARN_LEVEL_WARN, 
1 by brian
clean slate
582
                          ER_WARN_TOO_MANY_RECORDS, 
583
                          ER(ER_WARN_TOO_MANY_RECORDS), thd->row_count); 
584
    }
585
586
    if (thd->killed ||
587
        fill_record(thd, set_fields, set_values,
588
                    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
589
      return(1);
1 by brian
clean slate
590
591
    err= write_record(thd, table, &info);
51.1.53 by Jay Pipes
Removed/replaced DBUG symbols and standardized TRUE/FALSE
592
    table->auto_increment_field_not_null= false;
1 by brian
clean slate
593
    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
594
      return(1);
1 by brian
clean slate
595
   
596
    /*
597
      We don't need to reset auto-increment field since we are restoring
598
      its default value at the beginning of each loop iteration.
599
    */
600
    if (read_info.next_line())			// Skip to next line
601
      break;
602
    if (read_info.line_cuted)
603
    {
604
      thd->cuted_fields++;			/* To long row */
261.4.1 by Felipe
- Renamed MYSQL_ERROR to DRIZZLE_ERROR.
605
      push_warning_printf(thd, DRIZZLE_ERROR::WARN_LEVEL_WARN, 
1 by brian
clean slate
606
                          ER_WARN_TOO_MANY_RECORDS, 
607
                          ER(ER_WARN_TOO_MANY_RECORDS), thd->row_count); 
608
    }
609
    thd->row_count++;
610
  }
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
611
  return(test(read_info.error));
1 by brian
clean slate
612
}
613
614
615
616
static int
327.2.4 by Brian Aker
Refactoring table.h
617
read_sep_field(THD *thd, COPY_INFO &info, TableList *table_list,
1 by brian
clean slate
618
               List<Item> &fields_vars, List<Item> &set_fields,
619
               List<Item> &set_values, READ_INFO &read_info,
307 by Brian Aker
Minor cleanups around ulong in kernel.
620
	       String &enclosed, uint32_t skip_lines,
1 by brian
clean slate
621
	       bool ignore_check_option_errors)
622
{
623
  List_iterator_fast<Item> it(fields_vars);
624
  Item *item;
327.1.5 by Brian Aker
Refactor around classes. TABLE_LIST has been factored out of table.h
625
  Table *table= table_list->table;
1 by brian
clean slate
626
  uint enclosed_length;
151 by Brian Aker
Ulonglong to uint64_t
627
  uint64_t id;
1 by brian
clean slate
628
  bool err;
629
630
  enclosed_length=enclosed.length();
631
  id= 0;
632
633
  for (;;it.rewind())
634
  {
635
    if (thd->killed)
636
    {
637
      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
638
      return(1);
1 by brian
clean slate
639
    }
640
641
    restore_record(table, s->default_values);
642
643
    while ((item= it++))
644
    {
645
      uint length;
646
      uchar *pos;
647
      Item *real_item;
648
649
      if (read_info.read_field())
650
	break;
651
652
      /* If this line is to be skipped we don't want to fill field or var */
653
      if (skip_lines)
654
        continue;
655
656
      pos=read_info.row_start;
657
      length=(uint) (read_info.row_end-pos);
658
659
      real_item= item->real_item();
660
661
      if ((!read_info.enclosed && (enclosed_length && length == 4 && !memcmp(pos, STRING_WITH_LEN("NULL")))) ||
662
	  (length == 1 && read_info.found_null))
663
      {
664
665
        if (real_item->type() == Item::FIELD_ITEM)
666
        {
667
          Field *field= ((Item_field *)real_item)->field;
668
          if (field->reset())
669
          {
670
            my_error(ER_WARN_NULL_TO_NOTNULL, MYF(0), field->field_name,
671
                     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
672
            return(1);
1 by brian
clean slate
673
          }
674
          field->set_null();
675
          if (!field->maybe_null())
676
          {
212.2.2 by Patrick Galbraith
Renamed FIELD_TYPE to DRIZZLE_TYPE
677
            if (field->type() == DRIZZLE_TYPE_TIMESTAMP)
1 by brian
clean slate
678
              ((Field_timestamp*) field)->set_time();
679
            else if (field != table->next_number_field)
261.4.1 by Felipe
- Renamed MYSQL_ERROR to DRIZZLE_ERROR.
680
              field->set_warning(DRIZZLE_ERROR::WARN_LEVEL_WARN,
1 by brian
clean slate
681
                                 ER_WARN_NULL_TO_NOTNULL, 1);
682
          }
683
	}
684
        else if (item->type() == Item::STRING_ITEM)
685
        {
686
          ((Item_user_var_as_out_param *)item)->set_null_value(
687
                                                  read_info.read_charset);
688
        }
689
        else
690
        {
691
          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
692
          return(1);
1 by brian
clean slate
693
        }
694
695
	continue;
696
      }
697
698
      if (real_item->type() == Item::FIELD_ITEM)
699
      {
700
        Field *field= ((Item_field *)real_item)->field;
701
        field->set_notnull();
702
        read_info.row_end[0]=0;			// Safe to change end marker
703
        if (field == table->next_number_field)
51.1.53 by Jay Pipes
Removed/replaced DBUG symbols and standardized TRUE/FALSE
704
          table->auto_increment_field_not_null= true;
1 by brian
clean slate
705
        field->store((char*) pos, length, read_info.read_charset);
706
      }
707
      else if (item->type() == Item::STRING_ITEM)
708
      {
709
        ((Item_user_var_as_out_param *)item)->set_value((char*) pos, length,
710
                                                        read_info.read_charset);
711
      }
712
      else
713
      {
714
        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
715
        return(1);
1 by brian
clean slate
716
      }
717
    }
718
    if (read_info.error)
719
      break;
720
    if (skip_lines)
721
    {
722
      skip_lines--;
723
      continue;
724
    }
725
    if (item)
726
    {
727
      /* Have not read any field, thus input file is simply ended */
728
      if (item == fields_vars.head())
729
	break;
730
      for (; item ; item= it++)
731
      {
732
        Item *real_item= item->real_item();
733
        if (real_item->type() == Item::FIELD_ITEM)
734
        {
735
          Field *field= ((Item_field *)real_item)->field;
736
          if (field->reset())
737
          {
738
            my_error(ER_WARN_NULL_TO_NOTNULL, MYF(0),field->field_name,
739
                     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
740
            return(1);
1 by brian
clean slate
741
          }
212.2.2 by Patrick Galbraith
Renamed FIELD_TYPE to DRIZZLE_TYPE
742
          if (!field->maybe_null() && field->type() == DRIZZLE_TYPE_TIMESTAMP)
1 by brian
clean slate
743
              ((Field_timestamp*) field)->set_time();
744
          /*
745
            QQ: We probably should not throw warning for each field.
746
            But how about intention to always have the same number
747
            of warnings in THD::cuted_fields (and get rid of cuted_fields
748
            in the end ?)
749
          */
750
          thd->cuted_fields++;
261.4.1 by Felipe
- Renamed MYSQL_ERROR to DRIZZLE_ERROR.
751
          push_warning_printf(thd, DRIZZLE_ERROR::WARN_LEVEL_WARN,
1 by brian
clean slate
752
                              ER_WARN_TOO_FEW_RECORDS,
753
                              ER(ER_WARN_TOO_FEW_RECORDS), thd->row_count);
754
        }
755
        else if (item->type() == Item::STRING_ITEM)
756
        {
757
          ((Item_user_var_as_out_param *)item)->set_null_value(
758
                                                  read_info.read_charset);
759
        }
760
        else
761
        {
762
          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
763
          return(1);
1 by brian
clean slate
764
        }
765
      }
766
    }
767
768
    if (thd->killed ||
769
        fill_record(thd, set_fields, set_values,
770
                    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
771
      return(1);
1 by brian
clean slate
772
773
    err= write_record(thd, table, &info);
51.1.53 by Jay Pipes
Removed/replaced DBUG symbols and standardized TRUE/FALSE
774
    table->auto_increment_field_not_null= false;
1 by brian
clean slate
775
    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
776
      return(1);
1 by brian
clean slate
777
    /*
778
      We don't need to reset auto-increment field since we are restoring
779
      its default value at the beginning of each loop iteration.
780
    */
781
    if (read_info.next_line())			// Skip to next line
782
      break;
783
    if (read_info.line_cuted)
784
    {
785
      thd->cuted_fields++;			/* To long row */
261.4.1 by Felipe
- Renamed MYSQL_ERROR to DRIZZLE_ERROR.
786
      push_warning_printf(thd, DRIZZLE_ERROR::WARN_LEVEL_WARN, 
1 by brian
clean slate
787
                          ER_WARN_TOO_MANY_RECORDS, ER(ER_WARN_TOO_MANY_RECORDS), 
788
                          thd->row_count);   
789
      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
790
        return(1);
1 by brian
clean slate
791
    }
792
    thd->row_count++;
793
  }
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
794
  return(test(read_info.error));
1 by brian
clean slate
795
}
796
797
798
/* Unescape all escape characters, mark \N as null */
799
800
char
801
READ_INFO::unescape(char chr)
802
{
803
  /* keep this switch synchornous with the ESCAPE_CHARS macro */
804
  switch(chr) {
805
  case 'n': return '\n';
806
  case 't': return '\t';
807
  case 'r': return '\r';
808
  case 'b': return '\b';
809
  case '0': return 0;				// Ascii null
810
  case 'Z': return '\032';			// Win32 end of file
811
  case 'N': found_null=1;
812
813
    /* fall through */
814
  default:  return chr;
815
  }
816
}
817
818
819
/*
820
  Read a line using buffering
821
  If last line is empty (in line mode) then it isn't outputed
822
*/
823
824
264.2.6 by Andrey Hristov
Constify the usage of CHARSET_INFO almost to the last place in the code.
825
READ_INFO::READ_INFO(File file_par, uint tot_length, const CHARSET_INFO * const cs,
1 by brian
clean slate
826
		     String &field_term, String &line_start, String &line_term,
827
		     String &enclosed_par, int escape, bool get_it_from_net,
828
		     bool is_fifo)
829
  :file(file_par),escape_char(escape)
830
{
831
  read_charset= cs;
832
  field_term_ptr=(char*) field_term.ptr();
833
  field_term_length= field_term.length();
834
  line_term_ptr=(char*) line_term.ptr();
835
  line_term_length= line_term.length();
836
  if (line_start.length() == 0)
837
  {
838
    line_start_ptr=0;
839
    start_of_line= 0;
840
  }
841
  else
842
  {
843
    line_start_ptr=(char*) line_start.ptr();
844
    line_start_end=line_start_ptr+line_start.length();
845
    start_of_line= 1;
846
  }
847
  /* If field_terminator == line_terminator, don't use line_terminator */
848
  if (field_term_length == line_term_length &&
849
      !memcmp(field_term_ptr,line_term_ptr,field_term_length))
850
  {
851
    line_term_length=0;
852
    line_term_ptr=(char*) "";
853
  }
854
  enclosed_char= (enclosed_length=enclosed_par.length()) ?
855
    (uchar) enclosed_par[0] : INT_MAX;
856
  field_term_char= field_term_length ? (uchar) field_term_ptr[0] : INT_MAX;
857
  line_term_char= line_term_length ? (uchar) line_term_ptr[0] : INT_MAX;
858
  error=eof=found_end_of_line=found_null=line_cuted=0;
859
  buff_length=tot_length;
860
861
862
  /* Set of a stack for unget if long terminators */
398.1.4 by Monty Taylor
Renamed max/min.
863
  uint length=cmax(field_term_length,line_term_length)+1;
1 by brian
clean slate
864
  set_if_bigger(length,line_start.length());
865
  stack=stack_pos=(int*) sql_alloc(sizeof(int)*length);
866
867
  if (!(buffer=(uchar*) my_malloc(buff_length+1,MYF(0))))
868
    error=1; /* purecov: inspected */
869
  else
870
  {
871
    end_of_buff=buffer+buff_length;
872
    if (init_io_cache(&cache,(get_it_from_net) ? -1 : file, 0,
873
		      (get_it_from_net) ? READ_NET :
874
		      (is_fifo ? READ_FIFO : READ_CACHE),0L,1,
875
		      MYF(MY_WME)))
876
    {
877
      my_free((uchar*) buffer,MYF(0)); /* purecov: inspected */
878
      error=1;
879
    }
880
    else
881
    {
882
      /*
883
	init_io_cache() will not initialize read_function member
884
	if the cache is READ_NET. So we work around the problem with a
885
	manual assignment
886
      */
887
      need_end_io_cache = 1;
888
889
      if (get_it_from_net)
890
	cache.read_function = _my_b_net_read;
891
892
      if (mysql_bin_log.is_open())
893
	cache.pre_read = cache.pre_close =
894
	  (IO_CACHE_CALLBACK) log_loaded_block;
895
    }
896
  }
897
}
898
899
900
READ_INFO::~READ_INFO()
901
{
902
  if (!error)
903
  {
904
    if (need_end_io_cache)
905
      ::end_io_cache(&cache);
906
    my_free((uchar*) buffer,MYF(0));
907
    error=1;
908
  }
909
}
910
911
912
#define GET (stack_pos != stack ? *--stack_pos : my_b_get(&cache))
913
#define PUSH(A) *(stack_pos++)=(A)
914
915
916
inline int READ_INFO::terminator(char *ptr,uint length)
917
{
918
  int chr=0;					// Keep gcc happy
919
  uint i;
920
  for (i=1 ; i < length ; i++)
921
  {
922
    if ((chr=GET) != *++ptr)
923
    {
924
      break;
925
    }
926
  }
927
  if (i == length)
928
    return 1;
929
  PUSH(chr);
930
  while (i-- > 1)
931
    PUSH((uchar) *--ptr);
932
  return 0;
933
}
934
935
936
int READ_INFO::read_field()
937
{
938
  int chr,found_enclosed_char;
939
  uchar *to,*new_buffer;
940
941
  found_null=0;
942
  if (found_end_of_line)
943
    return 1;					// One have to call next_line
944
945
  /* Skip until we find 'line_start' */
946
947
  if (start_of_line)
948
  {						// Skip until line_start
949
    start_of_line=0;
950
    if (find_start_of_fields())
951
      return 1;
952
  }
953
  if ((chr=GET) == my_b_EOF)
954
  {
955
    found_end_of_line=eof=1;
956
    return 1;
957
  }
958
  to=buffer;
959
  if (chr == enclosed_char)
960
  {
961
    found_enclosed_char=enclosed_char;
962
    *to++=(uchar) chr;				// If error
963
  }
964
  else
965
  {
966
    found_enclosed_char= INT_MAX;
967
    PUSH(chr);
968
  }
969
970
  for (;;)
971
  {
972
    while ( to < end_of_buff)
973
    {
974
      chr = GET;
975
#ifdef USE_MB
976
      if ((my_mbcharlen(read_charset, chr) > 1) &&
977
          to+my_mbcharlen(read_charset, chr) <= end_of_buff)
978
      {
979
	  uchar* p = (uchar*)to;
980
	  *to++ = chr;
981
	  int ml = my_mbcharlen(read_charset, chr);
982
	  int i;
983
	  for (i=1; i<ml; i++) {
984
	      chr = GET;
985
	      if (chr == my_b_EOF)
986
		  goto found_eof;
987
	      *to++ = chr;
988
	  }
989
	  if (my_ismbchar(read_charset,
990
                          (const char *)p,
991
                          (const char *)to))
992
	    continue;
993
	  for (i=0; i<ml; i++)
994
	    PUSH((uchar) *--to);
995
	  chr = GET;
996
      }
997
#endif
998
      if (chr == my_b_EOF)
999
	goto found_eof;
1000
      if (chr == escape_char)
1001
      {
1002
	if ((chr=GET) == my_b_EOF)
1003
	{
1004
	  *to++= (uchar) escape_char;
1005
	  goto found_eof;
1006
	}
1007
        /*
1008
          When escape_char == enclosed_char, we treat it like we do for
1009
          handling quotes in SQL parsing -- you can double-up the
1010
          escape_char to include it literally, but it doesn't do escapes
1011
          like \n. This allows: LOAD DATA ... ENCLOSED BY '"' ESCAPED BY '"'
1012
          with data like: "fie""ld1", "field2"
1013
         */
1014
        if (escape_char != enclosed_char || chr == escape_char)
1015
        {
1016
          *to++ = (uchar) unescape((char) chr);
1017
          continue;
1018
        }
1019
        PUSH(chr);
1020
        chr= escape_char;
1021
      }
1022
#ifdef ALLOW_LINESEPARATOR_IN_STRINGS
1023
      if (chr == line_term_char)
1024
#else
1025
      if (chr == line_term_char && found_enclosed_char == INT_MAX)
1026
#endif
1027
      {
1028
	if (terminator(line_term_ptr,line_term_length))
1029
	{					// Maybe unexpected linefeed
1030
	  enclosed=0;
1031
	  found_end_of_line=1;
1032
	  row_start=buffer;
1033
	  row_end=  to;
1034
	  return 0;
1035
	}
1036
      }
1037
      if (chr == found_enclosed_char)
1038
      {
1039
	if ((chr=GET) == found_enclosed_char)
1040
	{					// Remove dupplicated
1041
	  *to++ = (uchar) chr;
1042
	  continue;
1043
	}
1044
	// End of enclosed field if followed by field_term or line_term
1045
	if (chr == my_b_EOF ||
1046
	    (chr == line_term_char && terminator(line_term_ptr, line_term_length)))
1047
	{					// Maybe unexpected linefeed
1048
	  enclosed=1;
1049
	  found_end_of_line=1;
1050
	  row_start=buffer+1;
1051
	  row_end=  to;
1052
	  return 0;
1053
	}
1054
	if (chr == field_term_char &&
1055
	    terminator(field_term_ptr,field_term_length))
1056
	{
1057
	  enclosed=1;
1058
	  row_start=buffer+1;
1059
	  row_end=  to;
1060
	  return 0;
1061
	}
1062
	/*
1063
	  The string didn't terminate yet.
1064
	  Store back next character for the loop
1065
	*/
1066
	PUSH(chr);
1067
	/* copy the found term character to 'to' */
1068
	chr= found_enclosed_char;
1069
      }
1070
      else if (chr == field_term_char && found_enclosed_char == INT_MAX)
1071
      {
1072
	if (terminator(field_term_ptr,field_term_length))
1073
	{
1074
	  enclosed=0;
1075
	  row_start=buffer;
1076
	  row_end=  to;
1077
	  return 0;
1078
	}
1079
      }
1080
      *to++ = (uchar) chr;
1081
    }
1082
    /*
1083
    ** We come here if buffer is too small. Enlarge it and continue
1084
    */
1085
    if (!(new_buffer=(uchar*) my_realloc((char*) buffer,buff_length+1+IO_SIZE,
1086
					MYF(MY_WME))))
1087
      return (error=1);
1088
    to=new_buffer + (to-buffer);
1089
    buffer=new_buffer;
1090
    buff_length+=IO_SIZE;
1091
    end_of_buff=buffer+buff_length;
1092
  }
1093
1094
found_eof:
1095
  enclosed=0;
1096
  found_end_of_line=eof=1;
1097
  row_start=buffer;
1098
  row_end=to;
1099
  return 0;
1100
}
1101
1102
/*
1103
  Read a row with fixed length.
1104
1105
  NOTES
1106
    The row may not be fixed size on disk if there are escape
1107
    characters in the file.
1108
1109
  IMPLEMENTATION NOTE
1110
    One can't use fixed length with multi-byte charset **
1111
1112
  RETURN
1113
    0  ok
1114
    1  error
1115
*/
1116
1117
int READ_INFO::read_fixed_length()
1118
{
1119
  int chr;
1120
  uchar *to;
1121
  if (found_end_of_line)
1122
    return 1;					// One have to call next_line
1123
1124
  if (start_of_line)
1125
  {						// Skip until line_start
1126
    start_of_line=0;
1127
    if (find_start_of_fields())
1128
      return 1;
1129
  }
1130
1131
  to=row_start=buffer;
1132
  while (to < end_of_buff)
1133
  {
1134
    if ((chr=GET) == my_b_EOF)
1135
      goto found_eof;
1136
    if (chr == escape_char)
1137
    {
1138
      if ((chr=GET) == my_b_EOF)
1139
      {
1140
	*to++= (uchar) escape_char;
1141
	goto found_eof;
1142
      }
1143
      *to++ =(uchar) unescape((char) chr);
1144
      continue;
1145
    }
1146
    if (chr == line_term_char)
1147
    {
1148
      if (terminator(line_term_ptr,line_term_length))
1149
      {						// Maybe unexpected linefeed
1150
	found_end_of_line=1;
1151
	row_end=  to;
1152
	return 0;
1153
      }
1154
    }
1155
    *to++ = (uchar) chr;
1156
  }
1157
  row_end=to;					// Found full line
1158
  return 0;
1159
1160
found_eof:
1161
  found_end_of_line=eof=1;
1162
  row_start=buffer;
1163
  row_end=to;
1164
  return to == buffer ? 1 : 0;
1165
}
1166
1167
1168
int READ_INFO::next_line()
1169
{
1170
  line_cuted=0;
1171
  start_of_line= line_start_ptr != 0;
1172
  if (found_end_of_line || eof)
1173
  {
1174
    found_end_of_line=0;
1175
    return eof;
1176
  }
1177
  found_end_of_line=0;
1178
  if (!line_term_length)
1179
    return 0;					// No lines
1180
  for (;;)
1181
  {
1182
    int chr = GET;
1183
#ifdef USE_MB
1184
   if (my_mbcharlen(read_charset, chr) > 1)
1185
   {
1186
       for (uint i=1;
1187
            chr != my_b_EOF && i<my_mbcharlen(read_charset, chr);
1188
            i++)
1189
	   chr = GET;
1190
       if (chr == escape_char)
1191
	   continue;
1192
   }
1193
#endif
1194
   if (chr == my_b_EOF)
1195
   {
1196
      eof=1;
1197
      return 1;
1198
    }
1199
    if (chr == escape_char)
1200
    {
1201
      line_cuted=1;
1202
      if (GET == my_b_EOF)
1203
	return 1;
1204
      continue;
1205
    }
1206
    if (chr == line_term_char && terminator(line_term_ptr,line_term_length))
1207
      return 0;
1208
    line_cuted=1;
1209
  }
1210
}
1211
1212
1213
bool READ_INFO::find_start_of_fields()
1214
{
1215
  int chr;
1216
 try_again:
1217
  do
1218
  {
1219
    if ((chr=GET) == my_b_EOF)
1220
    {
1221
      found_end_of_line=eof=1;
1222
      return 1;
1223
    }
1224
  } while ((char) chr != line_start_ptr[0]);
1225
  for (char *ptr=line_start_ptr+1 ; ptr != line_start_end ; ptr++)
1226
  {
1227
    chr=GET;					// Eof will be checked later
1228
    if ((char) chr != *ptr)
1229
    {						// Can't be line_start
1230
      PUSH(chr);
1231
      while (--ptr != line_start_ptr)
1232
      {						// Restart with next char
1233
	PUSH((uchar) *ptr);
1234
      }
1235
      goto try_again;
1236
    }
1237
  }
1238
  return 0;
1239
}
1240
1241