~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>
584.1.15 by Monty Taylor
The mega-patch from hell. Renamed sql_class to session (since that's what it is) and removed it and field and table from common_includes.
20
#include <drizzled/sql_load.h>
549 by Monty Taylor
Took gettext.h out of header files.
21
#include <drizzled/error.h>
520.6.7 by Monty Taylor
Moved a bunch of crap out of common_includes.
22
#include <drizzled/data_home.h>
584.1.15 by Monty Taylor
The mega-patch from hell. Renamed sql_class to session (since that's what it is) and removed it and field and table from common_includes.
23
#include <drizzled/session.h>
24
#include <drizzled/sql_base.h>
584.5.1 by Monty Taylor
Removed field includes from field.h.
25
#include <drizzled/field/timestamp.h>
1 by brian
clean slate
26
27
class READ_INFO {
28
  File	file;
481 by Brian Aker
Remove all of uchar.
29
  unsigned char	*buffer,			/* Buffer for read text */
1 by brian
clean slate
30
	*end_of_buff;			/* Data in bufferts ends here */
31
  uint	buff_length,			/* Length of buffert */
32
	max_length;			/* Max length of row */
33
  char	*field_term_ptr,*line_term_ptr,*line_start_ptr,*line_start_end;
34
  uint	field_term_length,line_term_length,enclosed_length;
35
  int	field_term_char,line_term_char,enclosed_char,escape_char;
36
  int	*stack,*stack_pos;
37
  bool	found_end_of_line,start_of_line,eof;
38
  bool  need_end_io_cache;
39
  IO_CACHE cache;
40
  NET *io_net;
41
42
public:
43
  bool error,line_cuted,found_null,enclosed;
481 by Brian Aker
Remove all of uchar.
44
  unsigned char	*row_start,			/* Found row starts here */
1 by brian
clean slate
45
	*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.
46
  const CHARSET_INFO *read_charset;
1 by brian
clean slate
47
482 by Brian Aker
Remove uint.
48
  READ_INFO(File file,uint32_t tot_length, const CHARSET_INFO * const cs,
1 by brian
clean slate
49
	    String &field_term,String &line_start,String &line_term,
50
	    String &enclosed,int escape,bool get_it_from_net, bool is_fifo);
51
  ~READ_INFO();
52
  int read_field();
53
  int read_fixed_length(void);
54
  int next_line(void);
55
  char unescape(char chr);
482 by Brian Aker
Remove uint.
56
  int terminator(char *ptr,uint32_t length);
1 by brian
clean slate
57
  bool find_start_of_fields();
58
59
  /*
60
    We need to force cache close before destructor is invoked to log
61
    the last read block
62
  */
63
  void end_io_cache()
64
  {
65
    ::end_io_cache(&cache);
66
    need_end_io_cache = 0;
67
  }
68
69
  /*
70
    Either this method, or we need to make cache public
71
    Arg must be set from mysql_load() since constructor does not see
520.1.21 by Brian Aker
THD -> Session rename
72
    either the table or Session value
1 by brian
clean slate
73
  */
74
  void set_io_cache_arg(void* arg) { cache.arg = arg; }
75
};
76
520.1.22 by Brian Aker
Second pass of thd cleanup
77
static int read_fixed_length(Session *session, COPY_INFO &info, TableList *table_list,
1 by brian
clean slate
78
                             List<Item> &fields_vars, List<Item> &set_fields,
79
                             List<Item> &set_values, READ_INFO &read_info,
307 by Brian Aker
Minor cleanups around ulong in kernel.
80
			     uint32_t skip_lines,
1 by brian
clean slate
81
			     bool ignore_check_option_errors);
520.1.22 by Brian Aker
Second pass of thd cleanup
82
static int read_sep_field(Session *session, COPY_INFO &info, TableList *table_list,
1 by brian
clean slate
83
                          List<Item> &fields_vars, List<Item> &set_fields,
84
                          List<Item> &set_values, READ_INFO &read_info,
307 by Brian Aker
Minor cleanups around ulong in kernel.
85
			  String &enclosed, uint32_t skip_lines,
1 by brian
clean slate
86
			  bool ignore_check_option_errors);
87
88
89
/*
90
  Execute LOAD DATA query
91
92
  SYNOPSYS
93
    mysql_load()
520.1.22 by Brian Aker
Second pass of thd cleanup
94
      session - current thread
831.1.2 by Brian Aker
Rename class file_exchange
95
      ex  - file_exchange object representing source file and its parsing rules
1 by brian
clean slate
96
      table_list  - list of tables to which we are loading data
97
      fields_vars - list of fields and variables to which we read
98
                    data from file
99
      set_fields  - list of fields mentioned in set clause
100
      set_values  - expressions to assign to fields in previous list
101
      handle_duplicates - indicates whenever we should emit error or
102
                          replace row if we will meet duplicates.
103
      ignore -          - indicates whenever we should ignore duplicates
104
      read_file_from_client - is this LOAD DATA LOCAL ?
105
106
  RETURN VALUES
51.1.53 by Jay Pipes
Removed/replaced DBUG symbols and standardized TRUE/FALSE
107
    true - error / false - success
1 by brian
clean slate
108
*/
109
831.1.2 by Brian Aker
Rename class file_exchange
110
int mysql_load(Session *session,file_exchange *ex,TableList *table_list,
1 by brian
clean slate
111
	        List<Item> &fields_vars, List<Item> &set_fields,
112
                List<Item> &set_values,
113
                enum enum_duplicates handle_duplicates, bool ignore,
114
                bool read_file_from_client)
115
{
116
  char name[FN_REFLEN];
117
  File file;
327.1.5 by Brian Aker
Refactor around classes. TABLE_LIST has been factored out of table.h
118
  Table *table= NULL;
1 by brian
clean slate
119
  int error;
120
  String *field_term=ex->field_term,*escaped=ex->escaped;
121
  String *enclosed=ex->enclosed;
122
  bool is_fifo=0;
630 by Brian Aker
Removing old STMT logic from load data infile (still need to clean up the
123
  char *db= table_list->db;			// This is never null
124
  assert(db);
1 by brian
clean slate
125
  /*
126
    If path for file is not defined, we will use the current database.
127
    If this is not set, we will use the directory where the table to be
128
    loaded is located
129
  */
520.1.22 by Brian Aker
Second pass of thd cleanup
130
  char *tdb= session->db ? session->db : db;		// Result is never null
630 by Brian Aker
Removing old STMT logic from load data infile (still need to clean up the
131
  assert(tdb);
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;
520.1.21 by Brian Aker
THD -> Session rename
134
  Session::killed_state killed_status= Session::NOT_KILLED;
1 by brian
clean slate
135
685.4.6 by Jay Pipes
Fix for Bug#308457. Gave UTF8 enclosure and escape character on LOAD DATA INFILE and changed the error message to be more descriptive
136
  /* Escape and enclosed character may be a utf8 4-byte character */
137
  if (escaped->length() > 4 || enclosed->length() > 4)
1 by brian
clean slate
138
  {
685.4.6 by Jay Pipes
Fix for Bug#308457. Gave UTF8 enclosure and escape character on LOAD DATA INFILE and changed the error message to be more descriptive
139
    my_error(ER_WRONG_FIELD_TERMINATORS,MYF(0),enclosed->c_ptr(), enclosed->length());
51.1.53 by Jay Pipes
Removed/replaced DBUG symbols and standardized TRUE/FALSE
140
    return(true);
1 by brian
clean slate
141
  }
520.1.22 by Brian Aker
Second pass of thd cleanup
142
  if (open_and_lock_tables(session, table_list))
51.1.53 by Jay Pipes
Removed/replaced DBUG symbols and standardized TRUE/FALSE
143
    return(true);
520.1.22 by Brian Aker
Second pass of thd cleanup
144
  if (setup_tables_and_check_access(session, &session->lex->select_lex.context,
145
                                    &session->lex->select_lex.top_join_list,
1 by brian
clean slate
146
                                    table_list,
520.1.22 by Brian Aker
Second pass of thd cleanup
147
                                    &session->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
  */
520.1.22 by Brian Aker
Second pass of thd cleanup
158
  if (unique_table(session, table_list, table_list->next_global, 0))
1 by brian
clean slate
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
    */
520.1.22 by Brian Aker
Second pass of thd cleanup
178
    if (setup_fields(session, 0, set_fields, MARK_COLUMNS_WRITE, 0, 0) ||
179
        setup_fields(session, 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' */
520.1.22 by Brian Aker
Second pass of thd cleanup
185
    if (setup_fields(session, 0, fields_vars, MARK_COLUMNS_WRITE, 0, 0) ||
186
        setup_fields(session, 0, set_fields, MARK_COLUMNS_WRITE, 0, 0) ||
187
        check_that_all_fields_are_given_values(session, 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 */
520.1.22 by Brian Aker
Second pass of thd cleanup
205
    if (setup_fields(session, 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
482 by Brian Aker
Remove uint.
211
  uint32_t tot_length=0;
1 by brian
clean slate
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
  {
798.2.28 by Brian Aker
More pulling of code... master_pos function code removed.
252
    assert(0);
1 by brian
clean slate
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
    {
575.4.1 by ysano
Rename mysql to drizzle.
262
      strcpy(name, drizzle_real_data_home);
263
      strncat(name, tdb, FN_REFLEN-strlen(drizzle_real_data_home)-1);
1 by brian
clean slate
264
      (void) fn_format(name, ex->file_name, name, "",
265
		       MY_RELATIVE_PATH | MY_UNPACK_FILENAME);
266
    }
267
    else
268
    {
575.4.1 by ysano
Rename mysql to drizzle.
269
      (void) fn_format(name, ex->file_name, drizzle_real_data_home, "",
1 by brian
clean slate
270
		       MY_RELATIVE_PATH | MY_UNPACK_FILENAME);
271
272
      if (opt_secure_file_priv &&
273
          strncmp(opt_secure_file_priv, name, strlen(opt_secure_file_priv)))
274
      {
275
        /* Read only allowed from within dir specified by secure_file_priv */
276
        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
277
        return(true);
1 by brian
clean slate
278
      }
279
15 by brian
Fix for stat, NETWARE removal
280
      struct stat stat_info;
281
      if (stat(name,&stat_info))
673.3.8 by Stewart Smith
fix outfile_loaddata test for drizzle.
282
      {
283
        my_error(ER_FILE_NOT_FOUND, MYF(0), name, errno);
51.1.53 by Jay Pipes
Removed/replaced DBUG symbols and standardized TRUE/FALSE
284
	return(true);
673.3.8 by Stewart Smith
fix outfile_loaddata test for drizzle.
285
      }
1 by brian
clean slate
286
287
      // if we are not in slave thread, the file must be:
808 by Brian Aker
Move number of threads to use for pool of threads to module. Removed slave
288
      if (!((stat_info.st_mode & S_IROTH) == S_IROTH &&  // readable by others
289
            (stat_info.st_mode & S_IFLNK) != S_IFLNK && // and not a symlink
290
            ((stat_info.st_mode & S_IFREG) == S_IFREG ||
291
             (stat_info.st_mode & S_IFIFO) == S_IFIFO)))
1 by brian
clean slate
292
      {
293
	my_error(ER_TEXTFILE_NOT_READABLE, MYF(0), name);
51.1.53 by Jay Pipes
Removed/replaced DBUG symbols and standardized TRUE/FALSE
294
	return(true);
1 by brian
clean slate
295
      }
296
      if ((stat_info.st_mode & S_IFIFO) == S_IFIFO)
297
	is_fifo = 1;
298
    }
299
    if ((file=my_open(name,O_RDONLY,MYF(MY_WME))) < 0)
673.3.8 by Stewart Smith
fix outfile_loaddata test for drizzle.
300
    {
301
      my_error(ER_CANT_OPEN_FILE, MYF(0), my_errno);
51.1.53 by Jay Pipes
Removed/replaced DBUG symbols and standardized TRUE/FALSE
302
      return(true);
673.3.8 by Stewart Smith
fix outfile_loaddata test for drizzle.
303
    }
1 by brian
clean slate
304
  }
305
306
  COPY_INFO info;
212.6.6 by Mats Kindahl
Removing redundant use of casts in drizzled/ for memcmp(), memcpy(), memset(), and memmove().
307
  memset(&info, 0, sizeof(info));
1 by brian
clean slate
308
  info.ignore= ignore;
309
  info.handle_duplicates=handle_duplicates;
310
  info.escape_char=escaped->length() ? (*escaped)[0] : INT_MAX;
311
312
  READ_INFO read_info(file,tot_length,
520.1.22 by Brian Aker
Second pass of thd cleanup
313
                      ex->cs ? ex->cs : session->variables.collation_database,
1 by brian
clean slate
314
		      *field_term,*ex->line_start, *ex->line_term, *enclosed,
315
		      info.escape_char, read_file_from_client, is_fifo);
316
  if (read_info.error)
317
  {
318
    if	(file >= 0)
319
      my_close(file,MYF(0));			// no files in net reading
51.1.53 by Jay Pipes
Removed/replaced DBUG symbols and standardized TRUE/FALSE
320
    return(true);				// Can't allocate buffers
1 by brian
clean slate
321
  }
322
685.4.1 by Jay Pipes
Enabled the null.test.
323
  /*
324
   * Per the SQL standard, inserting NULL into a NOT NULL
325
   * field requires an error to be thrown.
326
   *
327
   * @NOTE
328
   *
329
   * NULL check and handling occurs in field_conv.cc
330
   */
331
  session->count_cuted_fields= CHECK_FIELD_ERROR_FOR_NULL;
520.1.22 by Brian Aker
Second pass of thd cleanup
332
  session->cuted_fields=0L;
1 by brian
clean slate
333
  /* 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
334
  if (ex->line_term->length())
1 by brian
clean slate
335
  {
336
    /* ex->skip_lines needs to be preserved for logging */
337
    while (skip_lines > 0)
338
    {
339
      skip_lines--;
340
      if (read_info.next_line())
341
	break;
342
    }
343
  }
344
345
  if (!(error=test(read_info.error)))
346
  {
347
348
    table->next_number_field=table->found_next_number_field;
349
    if (ignore ||
350
	handle_duplicates == DUP_REPLACE)
351
      table->file->extra(HA_EXTRA_IGNORE_DUP_KEY);
352
    if (handle_duplicates == DUP_REPLACE)
353
        table->file->extra(HA_EXTRA_WRITE_CAN_REPLACE);
354
    table->file->ha_start_bulk_insert((ha_rows) 0);
355
    table->copy_blobs=1;
356
520.1.22 by Brian Aker
Second pass of thd cleanup
357
    session->abort_on_warning= true;
1 by brian
clean slate
358
266.1.23 by Monty Taylor
Removed load xml infile. Hope nobody liked it. Now the only thing we need xml.c
359
    if (!field_term->length() && !enclosed->length())
520.1.22 by Brian Aker
Second pass of thd cleanup
360
      error= read_fixed_length(session, info, table_list, fields_vars,
1 by brian
clean slate
361
                               set_fields, set_values, read_info,
362
			       skip_lines, ignore);
363
    else
520.1.22 by Brian Aker
Second pass of thd cleanup
364
      error= read_sep_field(session, info, table_list, fields_vars,
1 by brian
clean slate
365
                            set_fields, set_values, read_info,
366
			    *enclosed, skip_lines, ignore);
367
    if (table->file->ha_end_bulk_insert() && !error)
368
    {
369
      table->file->print_error(my_errno, MYF(0));
370
      error= 1;
371
    }
372
    table->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY);
373
    table->file->extra(HA_EXTRA_WRITE_CANNOT_REPLACE);
374
    table->next_number_field=0;
375
  }
376
  if (file >= 0)
377
    my_close(file,MYF(0));
378
  free_blobs(table);				/* if pack_blob was used */
379
  table->copy_blobs=0;
520.1.22 by Brian Aker
Second pass of thd cleanup
380
  session->count_cuted_fields= CHECK_FIELD_IGNORE;
660.1.3 by Eric Herman
removed trailing whitespace with simple script:
381
  /*
1 by brian
clean slate
382
     simulated killing in the middle of per-row loop
383
     must be effective for binlogging
384
  */
520.1.22 by Brian Aker
Second pass of thd cleanup
385
  killed_status= (error == 0)? Session::NOT_KILLED : session->killed;
1 by brian
clean slate
386
  if (error)
387
  {
388
    if (read_file_from_client)
389
      while (!read_info.next_line())
390
	;
391
392
    error= -1;				// Error on read
393
    goto err;
394
  }
307 by Brian Aker
Minor cleanups around ulong in kernel.
395
  sprintf(name, ER(ER_LOAD_INFO), (uint32_t) info.records, (uint32_t) info.deleted,
520.1.22 by Brian Aker
Second pass of thd cleanup
396
	  (uint32_t) (info.records - info.copied), (uint32_t) session->cuted_fields);
1 by brian
clean slate
397
520.1.22 by Brian Aker
Second pass of thd cleanup
398
  if (session->transaction.stmt.modified_non_trans_table)
399
    session->transaction.all.modified_non_trans_table= true;
1 by brian
clean slate
400
401
  /* ok to client sent only after binlog write and engine commit */
836 by Brian Aker
Fixed session call from function to method.
402
  session->my_ok(info.copied + info.deleted, 0L, name);
1 by brian
clean slate
403
err:
51.1.53 by Jay Pipes
Removed/replaced DBUG symbols and standardized TRUE/FALSE
404
  assert(transactional_table || !(info.copied || info.deleted) ||
520.1.22 by Brian Aker
Second pass of thd cleanup
405
              session->transaction.stmt.modified_non_trans_table);
1 by brian
clean slate
406
  table->file->ha_release_auto_increment();
51.1.53 by Jay Pipes
Removed/replaced DBUG symbols and standardized TRUE/FALSE
407
  table->auto_increment_field_not_null= false;
520.1.22 by Brian Aker
Second pass of thd cleanup
408
  session->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
409
  return(error);
1 by brian
clean slate
410
}
411
412
413
/****************************************************************************
414
** Read of rows of fixed size + optional garage + optonal newline
415
****************************************************************************/
416
417
static int
520.1.22 by Brian Aker
Second pass of thd cleanup
418
read_fixed_length(Session *session, COPY_INFO &info, TableList *table_list,
1 by brian
clean slate
419
                  List<Item> &fields_vars, List<Item> &set_fields,
420
                  List<Item> &set_values, READ_INFO &read_info,
307 by Brian Aker
Minor cleanups around ulong in kernel.
421
                  uint32_t skip_lines, bool ignore_check_option_errors)
1 by brian
clean slate
422
{
423
  List_iterator_fast<Item> it(fields_vars);
424
  Item_field *sql_field;
327.1.5 by Brian Aker
Refactor around classes. TABLE_LIST has been factored out of table.h
425
  Table *table= table_list->table;
151 by Brian Aker
Ulonglong to uint64_t
426
  uint64_t id;
1 by brian
clean slate
427
  bool err;
428
429
  id= 0;
660.1.3 by Eric Herman
removed trailing whitespace with simple script:
430
1 by brian
clean slate
431
  while (!read_info.read_fixed_length())
432
  {
520.1.22 by Brian Aker
Second pass of thd cleanup
433
    if (session->killed)
1 by brian
clean slate
434
    {
520.1.22 by Brian Aker
Second pass of thd cleanup
435
      session->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
436
      return(1);
1 by brian
clean slate
437
    }
438
    if (skip_lines)
439
    {
440
      /*
441
	We could implement this with a simple seek if:
442
	- We are not using DATA INFILE LOCAL
443
	- escape character is  ""
444
	- line starting prefix is ""
445
      */
446
      skip_lines--;
447
      continue;
448
    }
449
    it.rewind();
481 by Brian Aker
Remove all of uchar.
450
    unsigned char *pos=read_info.row_start;
1 by brian
clean slate
451
#ifdef HAVE_purify
452
    read_info.row_end[0]=0;
453
#endif
454
455
    restore_record(table, s->default_values);
456
    /*
457
      There is no variables in fields_vars list in this format so
458
      this conversion is safe.
459
    */
460
    while ((sql_field= (Item_field*) it++))
461
    {
660.1.3 by Eric Herman
removed trailing whitespace with simple script:
462
      Field *field= sql_field->field;
1 by brian
clean slate
463
      if (field == table->next_number_field)
51.1.53 by Jay Pipes
Removed/replaced DBUG symbols and standardized TRUE/FALSE
464
        table->auto_increment_field_not_null= true;
1 by brian
clean slate
465
      /*
466
        No fields specified in fields_vars list can be null in this format.
467
        Mark field as not null, we should do this for each row because of
468
        restore_record...
469
      */
470
      field->set_notnull();
471
472
      if (pos == read_info.row_end)
473
      {
520.1.22 by Brian Aker
Second pass of thd cleanup
474
        session->cuted_fields++;			/* Not enough fields */
660.1.3 by Eric Herman
removed trailing whitespace with simple script:
475
        push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_WARN,
476
                            ER_WARN_TOO_FEW_RECORDS,
520.1.22 by Brian Aker
Second pass of thd cleanup
477
                            ER(ER_WARN_TOO_FEW_RECORDS), session->row_count);
212.2.2 by Patrick Galbraith
Renamed FIELD_TYPE to DRIZZLE_TYPE
478
        if (!field->maybe_null() && field->type() == DRIZZLE_TYPE_TIMESTAMP)
1 by brian
clean slate
479
            ((Field_timestamp*) field)->set_time();
480
      }
481
      else
482
      {
482 by Brian Aker
Remove uint.
483
	uint32_t length;
481 by Brian Aker
Remove all of uchar.
484
	unsigned char save_chr;
1 by brian
clean slate
485
	if ((length=(uint) (read_info.row_end-pos)) >
486
	    field->field_length)
487
	  length=field->field_length;
488
	save_chr=pos[length]; pos[length]='\0'; // Safeguard aganst malloc
489
        field->store((char*) pos,length,read_info.read_charset);
490
	pos[length]=save_chr;
491
	if ((pos+=length) > read_info.row_end)
492
	  pos= read_info.row_end;	/* Fills rest with space */
493
      }
494
    }
495
    if (pos != read_info.row_end)
496
    {
520.1.22 by Brian Aker
Second pass of thd cleanup
497
      session->cuted_fields++;			/* To long row */
660.1.3 by Eric Herman
removed trailing whitespace with simple script:
498
      push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_WARN,
499
                          ER_WARN_TOO_MANY_RECORDS,
500
                          ER(ER_WARN_TOO_MANY_RECORDS), session->row_count);
1 by brian
clean slate
501
    }
502
520.1.22 by Brian Aker
Second pass of thd cleanup
503
    if (session->killed ||
504
        fill_record(session, set_fields, set_values,
1 by brian
clean slate
505
                    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
506
      return(1);
1 by brian
clean slate
507
520.1.22 by Brian Aker
Second pass of thd cleanup
508
    err= write_record(session, table, &info);
51.1.53 by Jay Pipes
Removed/replaced DBUG symbols and standardized TRUE/FALSE
509
    table->auto_increment_field_not_null= false;
1 by brian
clean slate
510
    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
511
      return(1);
660.1.3 by Eric Herman
removed trailing whitespace with simple script:
512
1 by brian
clean slate
513
    /*
514
      We don't need to reset auto-increment field since we are restoring
515
      its default value at the beginning of each loop iteration.
516
    */
517
    if (read_info.next_line())			// Skip to next line
518
      break;
519
    if (read_info.line_cuted)
520
    {
520.1.22 by Brian Aker
Second pass of thd cleanup
521
      session->cuted_fields++;			/* To long row */
660.1.3 by Eric Herman
removed trailing whitespace with simple script:
522
      push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_WARN,
523
                          ER_WARN_TOO_MANY_RECORDS,
524
                          ER(ER_WARN_TOO_MANY_RECORDS), session->row_count);
1 by brian
clean slate
525
    }
520.1.22 by Brian Aker
Second pass of thd cleanup
526
    session->row_count++;
1 by brian
clean slate
527
  }
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
528
  return(test(read_info.error));
1 by brian
clean slate
529
}
530
531
532
533
static int
520.1.22 by Brian Aker
Second pass of thd cleanup
534
read_sep_field(Session *session, COPY_INFO &info, TableList *table_list,
1 by brian
clean slate
535
               List<Item> &fields_vars, List<Item> &set_fields,
536
               List<Item> &set_values, READ_INFO &read_info,
307 by Brian Aker
Minor cleanups around ulong in kernel.
537
	       String &enclosed, uint32_t skip_lines,
1 by brian
clean slate
538
	       bool ignore_check_option_errors)
539
{
540
  List_iterator_fast<Item> it(fields_vars);
541
  Item *item;
327.1.5 by Brian Aker
Refactor around classes. TABLE_LIST has been factored out of table.h
542
  Table *table= table_list->table;
482 by Brian Aker
Remove uint.
543
  uint32_t enclosed_length;
151 by Brian Aker
Ulonglong to uint64_t
544
  uint64_t id;
1 by brian
clean slate
545
  bool err;
546
547
  enclosed_length=enclosed.length();
548
  id= 0;
549
550
  for (;;it.rewind())
551
  {
520.1.22 by Brian Aker
Second pass of thd cleanup
552
    if (session->killed)
1 by brian
clean slate
553
    {
520.1.22 by Brian Aker
Second pass of thd cleanup
554
      session->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
555
      return(1);
1 by brian
clean slate
556
    }
557
558
    restore_record(table, s->default_values);
559
560
    while ((item= it++))
561
    {
482 by Brian Aker
Remove uint.
562
      uint32_t length;
481 by Brian Aker
Remove all of uchar.
563
      unsigned char *pos;
1 by brian
clean slate
564
      Item *real_item;
565
566
      if (read_info.read_field())
567
	break;
568
569
      /* If this line is to be skipped we don't want to fill field or var */
570
      if (skip_lines)
571
        continue;
572
573
      pos=read_info.row_start;
574
      length=(uint) (read_info.row_end-pos);
575
576
      real_item= item->real_item();
577
578
      if ((!read_info.enclosed && (enclosed_length && length == 4 && !memcmp(pos, STRING_WITH_LEN("NULL")))) ||
579
	  (length == 1 && read_info.found_null))
580
      {
581
582
        if (real_item->type() == Item::FIELD_ITEM)
583
        {
584
          Field *field= ((Item_field *)real_item)->field;
585
          if (field->reset())
586
          {
587
            my_error(ER_WARN_NULL_TO_NOTNULL, MYF(0), field->field_name,
520.1.22 by Brian Aker
Second pass of thd cleanup
588
                     session->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
589
            return(1);
1 by brian
clean slate
590
          }
591
          field->set_null();
592
          if (!field->maybe_null())
593
          {
212.2.2 by Patrick Galbraith
Renamed FIELD_TYPE to DRIZZLE_TYPE
594
            if (field->type() == DRIZZLE_TYPE_TIMESTAMP)
1 by brian
clean slate
595
              ((Field_timestamp*) field)->set_time();
596
            else if (field != table->next_number_field)
261.4.1 by Felipe
- Renamed MYSQL_ERROR to DRIZZLE_ERROR.
597
              field->set_warning(DRIZZLE_ERROR::WARN_LEVEL_WARN,
1 by brian
clean slate
598
                                 ER_WARN_NULL_TO_NOTNULL, 1);
599
          }
600
	}
601
        else if (item->type() == Item::STRING_ITEM)
602
        {
603
          ((Item_user_var_as_out_param *)item)->set_null_value(
604
                                                  read_info.read_charset);
605
        }
606
        else
607
        {
608
          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
609
          return(1);
1 by brian
clean slate
610
        }
611
612
	continue;
613
      }
614
615
      if (real_item->type() == Item::FIELD_ITEM)
616
      {
617
        Field *field= ((Item_field *)real_item)->field;
618
        field->set_notnull();
619
        read_info.row_end[0]=0;			// Safe to change end marker
620
        if (field == table->next_number_field)
51.1.53 by Jay Pipes
Removed/replaced DBUG symbols and standardized TRUE/FALSE
621
          table->auto_increment_field_not_null= true;
1 by brian
clean slate
622
        field->store((char*) pos, length, read_info.read_charset);
623
      }
624
      else if (item->type() == Item::STRING_ITEM)
625
      {
626
        ((Item_user_var_as_out_param *)item)->set_value((char*) pos, length,
627
                                                        read_info.read_charset);
628
      }
629
      else
630
      {
631
        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
632
        return(1);
1 by brian
clean slate
633
      }
634
    }
635
    if (read_info.error)
636
      break;
637
    if (skip_lines)
638
    {
639
      skip_lines--;
640
      continue;
641
    }
642
    if (item)
643
    {
644
      /* Have not read any field, thus input file is simply ended */
645
      if (item == fields_vars.head())
646
	break;
647
      for (; item ; item= it++)
648
      {
649
        Item *real_item= item->real_item();
650
        if (real_item->type() == Item::FIELD_ITEM)
651
        {
652
          Field *field= ((Item_field *)real_item)->field;
653
          if (field->reset())
654
          {
655
            my_error(ER_WARN_NULL_TO_NOTNULL, MYF(0),field->field_name,
520.1.22 by Brian Aker
Second pass of thd cleanup
656
                     session->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
657
            return(1);
1 by brian
clean slate
658
          }
212.2.2 by Patrick Galbraith
Renamed FIELD_TYPE to DRIZZLE_TYPE
659
          if (!field->maybe_null() && field->type() == DRIZZLE_TYPE_TIMESTAMP)
1 by brian
clean slate
660
              ((Field_timestamp*) field)->set_time();
661
          /*
662
            QQ: We probably should not throw warning for each field.
663
            But how about intention to always have the same number
520.1.21 by Brian Aker
THD -> Session rename
664
            of warnings in Session::cuted_fields (and get rid of cuted_fields
1 by brian
clean slate
665
            in the end ?)
666
          */
520.1.22 by Brian Aker
Second pass of thd cleanup
667
          session->cuted_fields++;
668
          push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_WARN,
1 by brian
clean slate
669
                              ER_WARN_TOO_FEW_RECORDS,
520.1.22 by Brian Aker
Second pass of thd cleanup
670
                              ER(ER_WARN_TOO_FEW_RECORDS), session->row_count);
1 by brian
clean slate
671
        }
672
        else if (item->type() == Item::STRING_ITEM)
673
        {
674
          ((Item_user_var_as_out_param *)item)->set_null_value(
675
                                                  read_info.read_charset);
676
        }
677
        else
678
        {
679
          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
680
          return(1);
1 by brian
clean slate
681
        }
682
      }
683
    }
684
520.1.22 by Brian Aker
Second pass of thd cleanup
685
    if (session->killed ||
686
        fill_record(session, set_fields, set_values,
1 by brian
clean slate
687
                    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
688
      return(1);
1 by brian
clean slate
689
520.1.22 by Brian Aker
Second pass of thd cleanup
690
    err= write_record(session, table, &info);
51.1.53 by Jay Pipes
Removed/replaced DBUG symbols and standardized TRUE/FALSE
691
    table->auto_increment_field_not_null= false;
1 by brian
clean slate
692
    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
693
      return(1);
1 by brian
clean slate
694
    /*
695
      We don't need to reset auto-increment field since we are restoring
696
      its default value at the beginning of each loop iteration.
697
    */
698
    if (read_info.next_line())			// Skip to next line
699
      break;
700
    if (read_info.line_cuted)
701
    {
520.1.22 by Brian Aker
Second pass of thd cleanup
702
      session->cuted_fields++;			/* To long row */
660.1.3 by Eric Herman
removed trailing whitespace with simple script:
703
      push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_WARN,
704
                          ER_WARN_TOO_MANY_RECORDS, ER(ER_WARN_TOO_MANY_RECORDS),
705
                          session->row_count);
520.1.22 by Brian Aker
Second pass of thd cleanup
706
      if (session->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
707
        return(1);
1 by brian
clean slate
708
    }
520.1.22 by Brian Aker
Second pass of thd cleanup
709
    session->row_count++;
1 by brian
clean slate
710
  }
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
711
  return(test(read_info.error));
1 by brian
clean slate
712
}
713
714
715
/* Unescape all escape characters, mark \N as null */
716
717
char
718
READ_INFO::unescape(char chr)
719
{
720
  /* keep this switch synchornous with the ESCAPE_CHARS macro */
721
  switch(chr) {
722
  case 'n': return '\n';
723
  case 't': return '\t';
724
  case 'r': return '\r';
725
  case 'b': return '\b';
726
  case '0': return 0;				// Ascii null
727
  case 'Z': return '\032';			// Win32 end of file
728
  case 'N': found_null=1;
729
730
    /* fall through */
731
  default:  return chr;
732
  }
733
}
734
735
736
/*
737
  Read a line using buffering
738
  If last line is empty (in line mode) then it isn't outputed
739
*/
740
741
482 by Brian Aker
Remove uint.
742
READ_INFO::READ_INFO(File file_par, uint32_t tot_length, const CHARSET_INFO * const cs,
1 by brian
clean slate
743
		     String &field_term, String &line_start, String &line_term,
744
		     String &enclosed_par, int escape, bool get_it_from_net,
745
		     bool is_fifo)
746
  :file(file_par),escape_char(escape)
747
{
748
  read_charset= cs;
749
  field_term_ptr=(char*) field_term.ptr();
750
  field_term_length= field_term.length();
751
  line_term_ptr=(char*) line_term.ptr();
752
  line_term_length= line_term.length();
753
  if (line_start.length() == 0)
754
  {
755
    line_start_ptr=0;
756
    start_of_line= 0;
757
  }
758
  else
759
  {
760
    line_start_ptr=(char*) line_start.ptr();
761
    line_start_end=line_start_ptr+line_start.length();
762
    start_of_line= 1;
763
  }
764
  /* If field_terminator == line_terminator, don't use line_terminator */
765
  if (field_term_length == line_term_length &&
766
      !memcmp(field_term_ptr,line_term_ptr,field_term_length))
767
  {
768
    line_term_length=0;
769
    line_term_ptr=(char*) "";
770
  }
771
  enclosed_char= (enclosed_length=enclosed_par.length()) ?
481 by Brian Aker
Remove all of uchar.
772
    (unsigned char) enclosed_par[0] : INT_MAX;
773
  field_term_char= field_term_length ? (unsigned char) field_term_ptr[0] : INT_MAX;
774
  line_term_char= line_term_length ? (unsigned char) line_term_ptr[0] : INT_MAX;
1 by brian
clean slate
775
  error=eof=found_end_of_line=found_null=line_cuted=0;
776
  buff_length=tot_length;
777
778
779
  /* Set of a stack for unget if long terminators */
482 by Brian Aker
Remove uint.
780
  uint32_t length=cmax(field_term_length,line_term_length)+1;
1 by brian
clean slate
781
  set_if_bigger(length,line_start.length());
782
  stack=stack_pos=(int*) sql_alloc(sizeof(int)*length);
783
641.3.8 by Monty Taylor
Removed my_malloc from drizzled.
784
  if (!(buffer=(unsigned char*) malloc(buff_length+1)))
1 by brian
clean slate
785
    error=1; /* purecov: inspected */
786
  else
787
  {
788
    end_of_buff=buffer+buff_length;
789
    if (init_io_cache(&cache,(get_it_from_net) ? -1 : file, 0,
790
		      (get_it_from_net) ? READ_NET :
791
		      (is_fifo ? READ_FIFO : READ_CACHE),0L,1,
792
		      MYF(MY_WME)))
793
    {
481 by Brian Aker
Remove all of uchar.
794
      free((unsigned char*) buffer); /* purecov: inspected */
1 by brian
clean slate
795
      error=1;
796
    }
797
    else
798
    {
799
      /*
800
	init_io_cache() will not initialize read_function member
801
	if the cache is READ_NET. So we work around the problem with a
802
	manual assignment
803
      */
804
      need_end_io_cache = 1;
805
806
      if (get_it_from_net)
807
	cache.read_function = _my_b_net_read;
808
    }
809
  }
810
}
811
812
813
READ_INFO::~READ_INFO()
814
{
815
  if (!error)
816
  {
817
    if (need_end_io_cache)
818
      ::end_io_cache(&cache);
481 by Brian Aker
Remove all of uchar.
819
    free((unsigned char*) buffer);
1 by brian
clean slate
820
    error=1;
821
  }
822
}
823
824
825
#define GET (stack_pos != stack ? *--stack_pos : my_b_get(&cache))
826
#define PUSH(A) *(stack_pos++)=(A)
827
828
482 by Brian Aker
Remove uint.
829
inline int READ_INFO::terminator(char *ptr,uint32_t length)
1 by brian
clean slate
830
{
831
  int chr=0;					// Keep gcc happy
482 by Brian Aker
Remove uint.
832
  uint32_t i;
1 by brian
clean slate
833
  for (i=1 ; i < length ; i++)
834
  {
835
    if ((chr=GET) != *++ptr)
836
    {
837
      break;
838
    }
839
  }
840
  if (i == length)
841
    return 1;
842
  PUSH(chr);
843
  while (i-- > 1)
481 by Brian Aker
Remove all of uchar.
844
    PUSH((unsigned char) *--ptr);
1 by brian
clean slate
845
  return 0;
846
}
847
848
849
int READ_INFO::read_field()
850
{
851
  int chr,found_enclosed_char;
481 by Brian Aker
Remove all of uchar.
852
  unsigned char *to,*new_buffer;
1 by brian
clean slate
853
854
  found_null=0;
855
  if (found_end_of_line)
856
    return 1;					// One have to call next_line
857
858
  /* Skip until we find 'line_start' */
859
860
  if (start_of_line)
861
  {						// Skip until line_start
862
    start_of_line=0;
863
    if (find_start_of_fields())
864
      return 1;
865
  }
866
  if ((chr=GET) == my_b_EOF)
867
  {
868
    found_end_of_line=eof=1;
869
    return 1;
870
  }
871
  to=buffer;
872
  if (chr == enclosed_char)
873
  {
874
    found_enclosed_char=enclosed_char;
481 by Brian Aker
Remove all of uchar.
875
    *to++=(unsigned char) chr;				// If error
1 by brian
clean slate
876
  }
877
  else
878
  {
879
    found_enclosed_char= INT_MAX;
880
    PUSH(chr);
881
  }
882
883
  for (;;)
884
  {
885
    while ( to < end_of_buff)
886
    {
887
      chr = GET;
888
#ifdef USE_MB
889
      if ((my_mbcharlen(read_charset, chr) > 1) &&
890
          to+my_mbcharlen(read_charset, chr) <= end_of_buff)
891
      {
481 by Brian Aker
Remove all of uchar.
892
	  unsigned char* p = (unsigned char*)to;
1 by brian
clean slate
893
	  *to++ = chr;
894
	  int ml = my_mbcharlen(read_charset, chr);
895
	  int i;
896
	  for (i=1; i<ml; i++) {
897
	      chr = GET;
898
	      if (chr == my_b_EOF)
899
		  goto found_eof;
900
	      *to++ = chr;
901
	  }
902
	  if (my_ismbchar(read_charset,
903
                          (const char *)p,
904
                          (const char *)to))
905
	    continue;
906
	  for (i=0; i<ml; i++)
481 by Brian Aker
Remove all of uchar.
907
	    PUSH((unsigned char) *--to);
1 by brian
clean slate
908
	  chr = GET;
909
      }
910
#endif
911
      if (chr == my_b_EOF)
912
	goto found_eof;
913
      if (chr == escape_char)
914
      {
915
	if ((chr=GET) == my_b_EOF)
916
	{
481 by Brian Aker
Remove all of uchar.
917
	  *to++= (unsigned char) escape_char;
1 by brian
clean slate
918
	  goto found_eof;
919
	}
920
        /*
921
          When escape_char == enclosed_char, we treat it like we do for
922
          handling quotes in SQL parsing -- you can double-up the
923
          escape_char to include it literally, but it doesn't do escapes
924
          like \n. This allows: LOAD DATA ... ENCLOSED BY '"' ESCAPED BY '"'
925
          with data like: "fie""ld1", "field2"
926
         */
927
        if (escape_char != enclosed_char || chr == escape_char)
928
        {
481 by Brian Aker
Remove all of uchar.
929
          *to++ = (unsigned char) unescape((char) chr);
1 by brian
clean slate
930
          continue;
931
        }
932
        PUSH(chr);
933
        chr= escape_char;
934
      }
935
#ifdef ALLOW_LINESEPARATOR_IN_STRINGS
936
      if (chr == line_term_char)
937
#else
938
      if (chr == line_term_char && found_enclosed_char == INT_MAX)
939
#endif
940
      {
941
	if (terminator(line_term_ptr,line_term_length))
942
	{					// Maybe unexpected linefeed
943
	  enclosed=0;
944
	  found_end_of_line=1;
945
	  row_start=buffer;
946
	  row_end=  to;
947
	  return 0;
948
	}
949
      }
950
      if (chr == found_enclosed_char)
951
      {
952
	if ((chr=GET) == found_enclosed_char)
953
	{					// Remove dupplicated
481 by Brian Aker
Remove all of uchar.
954
	  *to++ = (unsigned char) chr;
1 by brian
clean slate
955
	  continue;
956
	}
957
	// End of enclosed field if followed by field_term or line_term
958
	if (chr == my_b_EOF ||
959
	    (chr == line_term_char && terminator(line_term_ptr, line_term_length)))
960
	{					// Maybe unexpected linefeed
961
	  enclosed=1;
962
	  found_end_of_line=1;
963
	  row_start=buffer+1;
964
	  row_end=  to;
965
	  return 0;
966
	}
967
	if (chr == field_term_char &&
968
	    terminator(field_term_ptr,field_term_length))
969
	{
970
	  enclosed=1;
971
	  row_start=buffer+1;
972
	  row_end=  to;
973
	  return 0;
974
	}
975
	/*
976
	  The string didn't terminate yet.
977
	  Store back next character for the loop
978
	*/
979
	PUSH(chr);
980
	/* copy the found term character to 'to' */
981
	chr= found_enclosed_char;
982
      }
983
      else if (chr == field_term_char && found_enclosed_char == INT_MAX)
984
      {
985
	if (terminator(field_term_ptr,field_term_length))
986
	{
987
	  enclosed=0;
988
	  row_start=buffer;
989
	  row_end=  to;
990
	  return 0;
991
	}
992
      }
481 by Brian Aker
Remove all of uchar.
993
      *to++ = (unsigned char) chr;
1 by brian
clean slate
994
    }
995
    /*
996
    ** We come here if buffer is too small. Enlarge it and continue
997
    */
656.1.26 by Monty Taylor
Finally removed all of the my_malloc stuff.
998
    if (!(new_buffer=(unsigned char*) realloc(buffer, buff_length+1+IO_SIZE)))
1 by brian
clean slate
999
      return (error=1);
1000
    to=new_buffer + (to-buffer);
1001
    buffer=new_buffer;
1002
    buff_length+=IO_SIZE;
1003
    end_of_buff=buffer+buff_length;
1004
  }
1005
1006
found_eof:
1007
  enclosed=0;
1008
  found_end_of_line=eof=1;
1009
  row_start=buffer;
1010
  row_end=to;
1011
  return 0;
1012
}
1013
1014
/*
1015
  Read a row with fixed length.
1016
1017
  NOTES
1018
    The row may not be fixed size on disk if there are escape
1019
    characters in the file.
1020
1021
  IMPLEMENTATION NOTE
1022
    One can't use fixed length with multi-byte charset **
1023
1024
  RETURN
1025
    0  ok
1026
    1  error
1027
*/
1028
1029
int READ_INFO::read_fixed_length()
1030
{
1031
  int chr;
481 by Brian Aker
Remove all of uchar.
1032
  unsigned char *to;
1 by brian
clean slate
1033
  if (found_end_of_line)
1034
    return 1;					// One have to call next_line
1035
1036
  if (start_of_line)
1037
  {						// Skip until line_start
1038
    start_of_line=0;
1039
    if (find_start_of_fields())
1040
      return 1;
1041
  }
1042
1043
  to=row_start=buffer;
1044
  while (to < end_of_buff)
1045
  {
1046
    if ((chr=GET) == my_b_EOF)
1047
      goto found_eof;
1048
    if (chr == escape_char)
1049
    {
1050
      if ((chr=GET) == my_b_EOF)
1051
      {
481 by Brian Aker
Remove all of uchar.
1052
	*to++= (unsigned char) escape_char;
1 by brian
clean slate
1053
	goto found_eof;
1054
      }
481 by Brian Aker
Remove all of uchar.
1055
      *to++ =(unsigned char) unescape((char) chr);
1 by brian
clean slate
1056
      continue;
1057
    }
1058
    if (chr == line_term_char)
1059
    {
1060
      if (terminator(line_term_ptr,line_term_length))
1061
      {						// Maybe unexpected linefeed
1062
	found_end_of_line=1;
1063
	row_end=  to;
1064
	return 0;
1065
      }
1066
    }
481 by Brian Aker
Remove all of uchar.
1067
    *to++ = (unsigned char) chr;
1 by brian
clean slate
1068
  }
1069
  row_end=to;					// Found full line
1070
  return 0;
1071
1072
found_eof:
1073
  found_end_of_line=eof=1;
1074
  row_start=buffer;
1075
  row_end=to;
1076
  return to == buffer ? 1 : 0;
1077
}
1078
1079
1080
int READ_INFO::next_line()
1081
{
1082
  line_cuted=0;
1083
  start_of_line= line_start_ptr != 0;
1084
  if (found_end_of_line || eof)
1085
  {
1086
    found_end_of_line=0;
1087
    return eof;
1088
  }
1089
  found_end_of_line=0;
1090
  if (!line_term_length)
1091
    return 0;					// No lines
1092
  for (;;)
1093
  {
1094
    int chr = GET;
1095
#ifdef USE_MB
1096
   if (my_mbcharlen(read_charset, chr) > 1)
1097
   {
482 by Brian Aker
Remove uint.
1098
       for (uint32_t i=1;
1 by brian
clean slate
1099
            chr != my_b_EOF && i<my_mbcharlen(read_charset, chr);
1100
            i++)
1101
	   chr = GET;
1102
       if (chr == escape_char)
1103
	   continue;
1104
   }
1105
#endif
1106
   if (chr == my_b_EOF)
1107
   {
1108
      eof=1;
1109
      return 1;
1110
    }
1111
    if (chr == escape_char)
1112
    {
1113
      line_cuted=1;
1114
      if (GET == my_b_EOF)
1115
	return 1;
1116
      continue;
1117
    }
1118
    if (chr == line_term_char && terminator(line_term_ptr,line_term_length))
1119
      return 0;
1120
    line_cuted=1;
1121
  }
1122
}
1123
1124
1125
bool READ_INFO::find_start_of_fields()
1126
{
1127
  int chr;
1128
 try_again:
1129
  do
1130
  {
1131
    if ((chr=GET) == my_b_EOF)
1132
    {
1133
      found_end_of_line=eof=1;
1134
      return 1;
1135
    }
1136
  } while ((char) chr != line_start_ptr[0]);
1137
  for (char *ptr=line_start_ptr+1 ; ptr != line_start_end ; ptr++)
1138
  {
1139
    chr=GET;					// Eof will be checked later
1140
    if ((char) chr != *ptr)
1141
    {						// Can't be line_start
1142
      PUSH(chr);
1143
      while (--ptr != line_start_ptr)
1144
      {						// Restart with next char
481 by Brian Aker
Remove all of uchar.
1145
	PUSH((unsigned char) *ptr);
1 by brian
clean slate
1146
      }
1147
      goto try_again;
1148
    }
1149
  }
1150
  return 0;
1151
}
1152
1153