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