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