1
/* Copyright (C) 2000-2006 MySQL AB
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.
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.
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 */
17
/* Copy data from a textfile to table */
20
#include <drizzled/sql_load.h>
21
#include <drizzled/error.h>
22
#include <drizzled/data_home.h>
23
#include <drizzled/session.h>
24
#include <drizzled/sql_base.h>
25
#include <drizzled/field/timestamp.h>
26
#include "drizzled/internal/my_sys.h"
27
#include "drizzled/internal/iocache.h"
28
#include <drizzled/db.h>
41
unsigned char *buffer; /* Buffer for read text */
42
unsigned char *end_of_buff; /* Data in bufferts ends here */
43
size_t buff_length; /* Length of buffert */
44
size_t max_length; /* Max length of row */
45
char *field_term_ptr,*line_term_ptr,*line_start_ptr,*line_start_end;
46
uint field_term_length,line_term_length,enclosed_length;
47
int field_term_char,line_term_char,enclosed_char,escape_char;
48
int *stack,*stack_pos;
49
bool found_end_of_line,start_of_line,eof;
50
bool need_end_io_cache;
51
internal::IO_CACHE cache;
54
bool error,line_cuted,found_null,enclosed;
55
unsigned char *row_start, /* Found row starts here */
56
*row_end; /* Found row ends here */
57
const CHARSET_INFO *read_charset;
59
READ_INFO(int cursor, size_t tot_length, const CHARSET_INFO * const cs,
60
String &field_term,String &line_start,String &line_term,
61
String &enclosed,int escape, bool is_fifo);
64
int read_fixed_length(void);
66
char unescape(char chr);
67
int terminator(char *ptr,uint32_t length);
68
bool find_start_of_fields();
71
We need to force cache close before destructor is invoked to log
76
internal::end_io_cache(&cache);
77
need_end_io_cache = 0;
81
Either this method, or we need to make cache public
82
Arg must be set from mysql_load() since constructor does not see
83
either the table or Session value
85
void set_io_cache_arg(void* arg) { cache.arg = arg; }
88
static int read_fixed_length(Session *session, COPY_INFO &info, TableList *table_list,
89
List<Item> &fields_vars, List<Item> &set_fields,
90
List<Item> &set_values, READ_INFO &read_info,
92
bool ignore_check_option_errors);
93
static int read_sep_field(Session *session, COPY_INFO &info, TableList *table_list,
94
List<Item> &fields_vars, List<Item> &set_fields,
95
List<Item> &set_values, READ_INFO &read_info,
96
String &enclosed, uint32_t skip_lines,
97
bool ignore_check_option_errors);
101
Execute LOAD DATA query
105
session - current thread
106
ex - file_exchange object representing source cursor and its parsing rules
107
table_list - list of tables to which we are loading data
108
fields_vars - list of fields and variables to which we read
110
set_fields - list of fields mentioned in set clause
111
set_values - expressions to assign to fields in previous list
112
handle_duplicates - indicates whenever we should emit error or
113
replace row if we will meet duplicates.
114
ignore - - indicates whenever we should ignore duplicates
117
true - error / false - success
120
int mysql_load(Session *session,file_exchange *ex,TableList *table_list,
121
List<Item> &fields_vars, List<Item> &set_fields,
122
List<Item> &set_values,
123
enum enum_duplicates handle_duplicates, bool ignore)
125
char name[FN_REFLEN];
129
String *field_term=ex->field_term,*escaped=ex->escaped;
130
String *enclosed=ex->enclosed;
132
char *db= table_list->db; // This is never null
135
If path for cursor is not defined, we will use the current database.
136
If this is not set, we will use the directory where the table to be
139
const char *tdb= session->db.empty() ? db : session->db.c_str(); // Result is never null
141
uint32_t skip_lines= ex->skip_lines;
142
bool transactional_table;
143
Session::killed_state killed_status= Session::NOT_KILLED;
145
/* Escape and enclosed character may be a utf8 4-byte character */
146
if (escaped->length() > 4 || enclosed->length() > 4)
148
my_error(ER_WRONG_FIELD_TERMINATORS,MYF(0),enclosed->c_ptr(), enclosed->length());
152
if (session->openTablesLock(table_list))
155
if (setup_tables_and_check_access(session, &session->lex->select_lex.context,
156
&session->lex->select_lex.top_join_list,
158
&session->lex->select_lex.leaf_tables, true))
162
Let us emit an error if we are loading data to table which is used
163
in subselect in SET clause like we do it for INSERT.
165
The main thing to fix to remove this restriction is to ensure that the
166
table is marked to be 'used for insert' in which case we should never
167
mark this table as 'const table' (ie, one that has only one row).
169
if (unique_table(table_list, table_list->next_global))
171
my_error(ER_UPDATE_TABLE_USED, MYF(0), table_list->table_name);
175
table= table_list->table;
176
transactional_table= table->cursor->has_transactions();
178
if (!fields_vars.elements)
181
for (field=table->field; *field ; field++)
182
fields_vars.push_back(new Item_field(*field));
183
table->setWriteSet();
184
table->timestamp_field_type= TIMESTAMP_NO_AUTO_SET;
186
Let us also prepare SET clause, altough it is probably empty
189
if (setup_fields(session, 0, set_fields, MARK_COLUMNS_WRITE, 0, 0) ||
190
setup_fields(session, 0, set_values, MARK_COLUMNS_READ, 0, 0))
195
/* TODO: use this conds for 'WITH CHECK OPTIONS' */
196
if (setup_fields(session, 0, fields_vars, MARK_COLUMNS_WRITE, 0, 0) ||
197
setup_fields(session, 0, set_fields, MARK_COLUMNS_WRITE, 0, 0) ||
198
check_that_all_fields_are_given_values(session, table, table_list))
201
Check whenever TIMESTAMP field with auto-set feature specified
204
if (table->timestamp_field)
206
if (table->isWriteSet(table->timestamp_field->field_index))
207
table->timestamp_field_type= TIMESTAMP_NO_AUTO_SET;
210
table->setWriteSet(table->timestamp_field->field_index);
213
/* Fix the expressions in SET clause */
214
if (setup_fields(session, 0, set_values, MARK_COLUMNS_READ, 0, 0))
218
table->mark_columns_needed_for_insert();
221
bool use_blobs= 0, use_vars= 0;
222
List_iterator_fast<Item> it(fields_vars);
227
Item *real_item= item->real_item();
229
if (real_item->type() == Item::FIELD_ITEM)
231
Field *field= ((Item_field*)real_item)->field;
232
if (field->flags & BLOB_FLAG)
235
tot_length+= 256; // Will be extended if needed
238
tot_length+= field->field_length;
240
else if (item->type() == Item::STRING_ITEM)
243
if (use_blobs && !ex->line_term->length() && !field_term->length())
245
my_message(ER_BLOBS_AND_NO_TERMINATED,ER(ER_BLOBS_AND_NO_TERMINATED),
249
if (use_vars && !field_term->length() && !enclosed->length())
251
my_error(ER_LOAD_FROM_FIXED_SIZE_ROWS_TO_VAR, MYF(0));
256
#ifdef DONT_ALLOW_FULL_LOAD_DATA_PATHS
257
ex->file_name+=dirname_length(ex->file_name);
259
if (!internal::dirname_length(ex->file_name))
261
strcpy(name, drizzle_real_data_home);
262
strncat(name, tdb, FN_REFLEN-strlen(drizzle_real_data_home)-1);
263
(void) internal::fn_format(name, ex->file_name, name, "",
264
MY_RELATIVE_PATH | MY_UNPACK_FILENAME);
268
(void) internal::fn_format(name, ex->file_name, drizzle_real_data_home, "",
269
MY_RELATIVE_PATH | MY_UNPACK_FILENAME);
271
if (opt_secure_file_priv &&
272
strncmp(opt_secure_file_priv, name, strlen(opt_secure_file_priv)))
274
/* Read only allowed from within dir specified by secure_file_priv */
275
my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--secure-file-priv");
279
struct stat stat_info;
280
if (stat(name,&stat_info))
282
my_error(ER_FILE_NOT_FOUND, MYF(0), name, errno);
286
// if we are not in slave thread, the cursor must be:
287
if (!((stat_info.st_mode & S_IROTH) == S_IROTH && // readable by others
288
(stat_info.st_mode & S_IFLNK) != S_IFLNK && // and not a symlink
289
((stat_info.st_mode & S_IFREG) == S_IFREG ||
290
(stat_info.st_mode & S_IFIFO) == S_IFIFO)))
292
my_error(ER_TEXTFILE_NOT_READABLE, MYF(0), name);
295
if ((stat_info.st_mode & S_IFIFO) == S_IFIFO)
298
if ((file=internal::my_open(name,O_RDONLY,MYF(MY_WME))) < 0)
300
my_error(ER_CANT_OPEN_FILE, MYF(0), name, errno);
306
memset(&info, 0, sizeof(info));
308
info.handle_duplicates=handle_duplicates;
309
info.escape_char=escaped->length() ? (*escaped)[0] : INT_MAX;
311
READ_INFO read_info(file, tot_length,
312
ex->cs ? ex->cs : plugin::StorageEngine::getSchemaCollation(session->db.c_str()),
313
*field_term,*ex->line_start, *ex->line_term, *enclosed,
314
info.escape_char, is_fifo);
318
internal::my_close(file,MYF(0)); // no files in net reading
319
return(true); // Can't allocate buffers
323
* Per the SQL standard, inserting NULL into a NOT NULL
324
* field requires an error to be thrown.
328
* NULL check and handling occurs in field_conv.cc
330
session->count_cuted_fields= CHECK_FIELD_ERROR_FOR_NULL;
331
session->cuted_fields=0L;
332
/* Skip lines if there is a line terminator */
333
if (ex->line_term->length())
335
/* ex->skip_lines needs to be preserved for logging */
336
while (skip_lines > 0)
339
if (read_info.next_line())
344
if (!(error=test(read_info.error)))
347
table->next_number_field=table->found_next_number_field;
349
handle_duplicates == DUP_REPLACE)
350
table->cursor->extra(HA_EXTRA_IGNORE_DUP_KEY);
351
if (handle_duplicates == DUP_REPLACE)
352
table->cursor->extra(HA_EXTRA_WRITE_CAN_REPLACE);
353
table->cursor->ha_start_bulk_insert((ha_rows) 0);
356
session->abort_on_warning= true;
358
if (!field_term->length() && !enclosed->length())
359
error= read_fixed_length(session, info, table_list, fields_vars,
360
set_fields, set_values, read_info,
363
error= read_sep_field(session, info, table_list, fields_vars,
364
set_fields, set_values, read_info,
365
*enclosed, skip_lines, ignore);
366
if (table->cursor->ha_end_bulk_insert() && !error)
368
table->print_error(errno, MYF(0));
371
table->cursor->extra(HA_EXTRA_NO_IGNORE_DUP_KEY);
372
table->cursor->extra(HA_EXTRA_WRITE_CANNOT_REPLACE);
373
table->next_number_field=0;
376
internal::my_close(file,MYF(0));
377
free_blobs(table); /* if pack_blob was used */
379
session->count_cuted_fields= CHECK_FIELD_IGNORE;
381
simulated killing in the middle of per-row loop
382
must be effective for binlogging
384
killed_status= (error == 0)? Session::NOT_KILLED : session->killed;
387
error= -1; // Error on read
390
sprintf(name, ER(ER_LOAD_INFO), (uint32_t) info.records, (uint32_t) info.deleted,
391
(uint32_t) (info.records - info.copied), (uint32_t) session->cuted_fields);
393
if (session->transaction.stmt.hasModifiedNonTransData())
394
session->transaction.all.markModifiedNonTransData();
396
/* ok to client sent only after binlog write and engine commit */
397
session->my_ok(info.copied + info.deleted, 0, 0L, name);
399
assert(transactional_table || !(info.copied || info.deleted) ||
400
session->transaction.stmt.hasModifiedNonTransData());
401
table->cursor->ha_release_auto_increment();
402
table->auto_increment_field_not_null= false;
403
session->abort_on_warning= 0;
408
/****************************************************************************
409
** Read of rows of fixed size + optional garage + optonal newline
410
****************************************************************************/
413
read_fixed_length(Session *session, COPY_INFO &info, TableList *table_list,
414
List<Item> &fields_vars, List<Item> &set_fields,
415
List<Item> &set_values, READ_INFO &read_info,
416
uint32_t skip_lines, bool ignore_check_option_errors)
418
List_iterator_fast<Item> it(fields_vars);
419
Item_field *sql_field;
420
Table *table= table_list->table;
426
while (!read_info.read_fixed_length())
430
session->send_kill_message();
436
We could implement this with a simple seek if:
437
- We are not using DATA INFILE LOCAL
438
- escape character is ""
439
- line starting prefix is ""
445
unsigned char *pos=read_info.row_start;
447
read_info.row_end[0]=0;
450
table->restoreRecordAsDefault();
452
There is no variables in fields_vars list in this format so
453
this conversion is safe.
455
while ((sql_field= (Item_field*) it++))
457
Field *field= sql_field->field;
458
if (field == table->next_number_field)
459
table->auto_increment_field_not_null= true;
461
No fields specified in fields_vars list can be null in this format.
462
Mark field as not null, we should do this for each row because of
465
field->set_notnull();
467
if (pos == read_info.row_end)
469
session->cuted_fields++; /* Not enough fields */
470
push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_WARN,
471
ER_WARN_TOO_FEW_RECORDS,
472
ER(ER_WARN_TOO_FEW_RECORDS), session->row_count);
473
if (!field->maybe_null() && field->type() == DRIZZLE_TYPE_TIMESTAMP)
474
((Field_timestamp*) field)->set_time();
479
unsigned char save_chr;
480
if ((length=(uint32_t) (read_info.row_end-pos)) >
483
length=field->field_length;
485
save_chr=pos[length];
486
pos[length]='\0'; // Add temp null terminator for store()
487
field->store((char*) pos,length,read_info.read_charset);
488
pos[length]=save_chr;
489
if ((pos+=length) > read_info.row_end)
490
pos= read_info.row_end; /* Fills rest with space */
493
if (pos != read_info.row_end)
495
session->cuted_fields++; /* To long row */
496
push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_WARN,
497
ER_WARN_TOO_MANY_RECORDS,
498
ER(ER_WARN_TOO_MANY_RECORDS), session->row_count);
501
if (session->killed ||
502
fill_record(session, set_fields, set_values,
503
ignore_check_option_errors))
506
err= write_record(session, table, &info);
507
table->auto_increment_field_not_null= false;
512
We don't need to reset auto-increment field since we are restoring
513
its default value at the beginning of each loop iteration.
515
if (read_info.next_line()) // Skip to next line
517
if (read_info.line_cuted)
519
session->cuted_fields++; /* To long row */
520
push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_WARN,
521
ER_WARN_TOO_MANY_RECORDS,
522
ER(ER_WARN_TOO_MANY_RECORDS), session->row_count);
524
session->row_count++;
526
return(test(read_info.error));
532
read_sep_field(Session *session, COPY_INFO &info, TableList *table_list,
533
List<Item> &fields_vars, List<Item> &set_fields,
534
List<Item> &set_values, READ_INFO &read_info,
535
String &enclosed, uint32_t skip_lines,
536
bool ignore_check_option_errors)
538
List_iterator_fast<Item> it(fields_vars);
540
Table *table= table_list->table;
541
uint32_t enclosed_length;
545
enclosed_length=enclosed.length();
552
session->send_kill_message();
556
table->restoreRecordAsDefault();
564
if (read_info.read_field())
567
/* If this line is to be skipped we don't want to fill field or var */
571
pos=read_info.row_start;
572
length=(uint32_t) (read_info.row_end-pos);
574
real_item= item->real_item();
576
if ((!read_info.enclosed && (enclosed_length && length == 4 && !memcmp(pos, STRING_WITH_LEN("NULL")))) ||
577
(length == 1 && read_info.found_null))
580
if (real_item->type() == Item::FIELD_ITEM)
582
Field *field= ((Item_field *)real_item)->field;
585
my_error(ER_WARN_NULL_TO_NOTNULL, MYF(0), field->field_name,
590
if (!field->maybe_null())
592
if (field->type() == DRIZZLE_TYPE_TIMESTAMP)
593
((Field_timestamp*) field)->set_time();
594
else if (field != table->next_number_field)
595
field->set_warning(DRIZZLE_ERROR::WARN_LEVEL_WARN,
596
ER_WARN_NULL_TO_NOTNULL, 1);
599
else if (item->type() == Item::STRING_ITEM)
601
((Item_user_var_as_out_param *)item)->set_null_value(
602
read_info.read_charset);
606
my_error(ER_LOAD_DATA_INVALID_COLUMN, MYF(0), item->full_name());
613
if (real_item->type() == Item::FIELD_ITEM)
615
Field *field= ((Item_field *)real_item)->field;
616
field->set_notnull();
617
read_info.row_end[0]=0; // Safe to change end marker
618
if (field == table->next_number_field)
619
table->auto_increment_field_not_null= true;
620
field->store((char*) pos, length, read_info.read_charset);
622
else if (item->type() == Item::STRING_ITEM)
624
((Item_user_var_as_out_param *)item)->set_value((char*) pos, length,
625
read_info.read_charset);
629
my_error(ER_LOAD_DATA_INVALID_COLUMN, MYF(0), item->full_name());
642
/* Have not read any field, thus input cursor is simply ended */
643
if (item == fields_vars.head())
645
for (; item ; item= it++)
647
Item *real_item= item->real_item();
648
if (real_item->type() == Item::FIELD_ITEM)
650
Field *field= ((Item_field *)real_item)->field;
653
my_error(ER_WARN_NULL_TO_NOTNULL, MYF(0),field->field_name,
657
if (!field->maybe_null() && field->type() == DRIZZLE_TYPE_TIMESTAMP)
658
((Field_timestamp*) field)->set_time();
660
QQ: We probably should not throw warning for each field.
661
But how about intention to always have the same number
662
of warnings in Session::cuted_fields (and get rid of cuted_fields
665
session->cuted_fields++;
666
push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_WARN,
667
ER_WARN_TOO_FEW_RECORDS,
668
ER(ER_WARN_TOO_FEW_RECORDS), session->row_count);
670
else if (item->type() == Item::STRING_ITEM)
672
((Item_user_var_as_out_param *)item)->set_null_value(
673
read_info.read_charset);
677
my_error(ER_LOAD_DATA_INVALID_COLUMN, MYF(0), item->full_name());
683
if (session->killed ||
684
fill_record(session, set_fields, set_values,
685
ignore_check_option_errors))
688
err= write_record(session, table, &info);
689
table->auto_increment_field_not_null= false;
693
We don't need to reset auto-increment field since we are restoring
694
its default value at the beginning of each loop iteration.
696
if (read_info.next_line()) // Skip to next line
698
if (read_info.line_cuted)
700
session->cuted_fields++; /* To long row */
701
push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_WARN,
702
ER_WARN_TOO_MANY_RECORDS, ER(ER_WARN_TOO_MANY_RECORDS),
707
session->row_count++;
709
return(test(read_info.error));
713
/* Unescape all escape characters, mark \N as null */
716
READ_INFO::unescape(char chr)
718
/* keep this switch synchornous with the ESCAPE_CHARS macro */
720
case 'n': return '\n';
721
case 't': return '\t';
722
case 'r': return '\r';
723
case 'b': return '\b';
724
case '0': return 0; // Ascii null
725
case 'Z': return '\032'; // Win32 end of cursor
726
case 'N': found_null=1;
735
Read a line using buffering
736
If last line is empty (in line mode) then it isn't outputed
740
READ_INFO::READ_INFO(int file_par, size_t tot_length,
741
const CHARSET_INFO * const cs,
742
String &field_term, String &line_start, String &line_term,
743
String &enclosed_par, int escape, bool is_fifo)
744
:cursor(file_par),escape_char(escape)
747
field_term_ptr=(char*) field_term.ptr();
748
field_term_length= field_term.length();
749
line_term_ptr=(char*) line_term.ptr();
750
line_term_length= line_term.length();
751
if (line_start.length() == 0)
758
line_start_ptr=(char*) line_start.ptr();
759
line_start_end=line_start_ptr+line_start.length();
762
/* If field_terminator == line_terminator, don't use line_terminator */
763
if (field_term_length == line_term_length &&
764
!memcmp(field_term_ptr,line_term_ptr,field_term_length))
767
line_term_ptr=(char*) "";
769
enclosed_char= (enclosed_length=enclosed_par.length()) ?
770
(unsigned char) enclosed_par[0] : INT_MAX;
771
field_term_char= field_term_length ? (unsigned char) field_term_ptr[0] : INT_MAX;
772
line_term_char= line_term_length ? (unsigned char) line_term_ptr[0] : INT_MAX;
773
error=eof=found_end_of_line=found_null=line_cuted=0;
774
buff_length=tot_length;
777
/* Set of a stack for unget if long terminators */
778
uint32_t length= max(field_term_length,line_term_length)+1;
779
set_if_bigger(length,line_start.length());
780
stack= stack_pos= (int*) memory::sql_alloc(sizeof(int)*length);
782
if (!(buffer=(unsigned char*) calloc(1, buff_length+1)))
786
end_of_buff=buffer+buff_length;
787
if (init_io_cache(&cache,(false) ? -1 : cursor, 0,
788
(false) ? internal::READ_NET :
789
(is_fifo ? internal::READ_FIFO : internal::READ_CACHE),0L,1,
792
free((unsigned char*) buffer);
798
init_io_cache() will not initialize read_function member
799
if the cache is READ_NET. So we work around the problem with a
802
need_end_io_cache = 1;
808
READ_INFO::~READ_INFO()
812
if (need_end_io_cache)
813
internal::end_io_cache(&cache);
820
#define GET (stack_pos != stack ? *--stack_pos : my_b_get(&cache))
821
#define PUSH(A) *(stack_pos++)=(A)
824
inline int READ_INFO::terminator(char *ptr,uint32_t length)
826
int chr=0; // Keep gcc happy
828
for (i=1 ; i < length ; i++)
830
if ((chr=GET) != *++ptr)
839
PUSH((unsigned char) *--ptr);
844
int READ_INFO::read_field()
846
int chr,found_enclosed_char;
847
unsigned char *to,*new_buffer;
850
if (found_end_of_line)
851
return 1; // One have to call next_line
853
/* Skip until we find 'line_start' */
856
{ // Skip until line_start
858
if (find_start_of_fields())
861
if ((chr=GET) == my_b_EOF)
863
found_end_of_line=eof=1;
867
if (chr == enclosed_char)
869
found_enclosed_char=enclosed_char;
870
*to++=(unsigned char) chr; // If error
874
found_enclosed_char= INT_MAX;
880
while ( to < end_of_buff)
883
if ((my_mbcharlen(read_charset, chr) > 1) &&
884
to+my_mbcharlen(read_charset, chr) <= end_of_buff)
886
unsigned char* p = (unsigned char*)to;
888
int ml = my_mbcharlen(read_charset, chr);
890
for (i=1; i<ml; i++) {
896
if (my_ismbchar(read_charset,
901
PUSH((unsigned char) *--to);
906
if (chr == escape_char)
908
if ((chr=GET) == my_b_EOF)
910
*to++= (unsigned char) escape_char;
914
When escape_char == enclosed_char, we treat it like we do for
915
handling quotes in SQL parsing -- you can double-up the
916
escape_char to include it literally, but it doesn't do escapes
917
like \n. This allows: LOAD DATA ... ENCLOSED BY '"' ESCAPED BY '"'
918
with data like: "fie""ld1", "field2"
920
if (escape_char != enclosed_char || chr == escape_char)
922
*to++ = (unsigned char) unescape((char) chr);
928
#ifdef ALLOW_LINESEPARATOR_IN_STRINGS
929
if (chr == line_term_char)
931
if (chr == line_term_char && found_enclosed_char == INT_MAX)
934
if (terminator(line_term_ptr,line_term_length))
935
{ // Maybe unexpected linefeed
943
if (chr == found_enclosed_char)
945
if ((chr=GET) == found_enclosed_char)
946
{ // Remove dupplicated
947
*to++ = (unsigned char) chr;
950
// End of enclosed field if followed by field_term or line_term
951
if (chr == my_b_EOF ||
952
(chr == line_term_char && terminator(line_term_ptr, line_term_length)))
953
{ // Maybe unexpected linefeed
960
if (chr == field_term_char &&
961
terminator(field_term_ptr,field_term_length))
969
The string didn't terminate yet.
970
Store back next character for the loop
973
/* copy the found term character to 'to' */
974
chr= found_enclosed_char;
976
else if (chr == field_term_char && found_enclosed_char == INT_MAX)
978
if (terminator(field_term_ptr,field_term_length))
986
*to++ = (unsigned char) chr;
989
** We come here if buffer is too small. Enlarge it and continue
991
if (!(new_buffer=(unsigned char*) realloc(buffer, buff_length+1+IO_SIZE)))
993
to=new_buffer + (to-buffer);
995
buff_length+=IO_SIZE;
996
end_of_buff=buffer+buff_length;
1001
found_end_of_line=eof=1;
1008
Read a row with fixed length.
1011
The row may not be fixed size on disk if there are escape
1012
characters in the cursor.
1015
One can't use fixed length with multi-byte charset **
1022
int READ_INFO::read_fixed_length()
1026
if (found_end_of_line)
1027
return 1; // One have to call next_line
1030
{ // Skip until line_start
1032
if (find_start_of_fields())
1036
to=row_start=buffer;
1037
while (to < end_of_buff)
1039
if ((chr=GET) == my_b_EOF)
1041
if (chr == escape_char)
1043
if ((chr=GET) == my_b_EOF)
1045
*to++= (unsigned char) escape_char;
1048
*to++ =(unsigned char) unescape((char) chr);
1051
if (chr == line_term_char)
1053
if (terminator(line_term_ptr,line_term_length))
1054
{ // Maybe unexpected linefeed
1055
found_end_of_line=1;
1060
*to++ = (unsigned char) chr;
1062
row_end=to; // Found full line
1066
found_end_of_line=eof=1;
1069
return to == buffer ? 1 : 0;
1073
int READ_INFO::next_line()
1076
start_of_line= line_start_ptr != 0;
1077
if (found_end_of_line || eof)
1079
found_end_of_line=0;
1082
found_end_of_line=0;
1083
if (!line_term_length)
1084
return 0; // No lines
1088
if (my_mbcharlen(read_charset, chr) > 1)
1091
chr != my_b_EOF && i<my_mbcharlen(read_charset, chr);
1094
if (chr == escape_char)
1097
if (chr == my_b_EOF)
1102
if (chr == escape_char)
1105
if (GET == my_b_EOF)
1109
if (chr == line_term_char && terminator(line_term_ptr,line_term_length))
1116
bool READ_INFO::find_start_of_fields()
1122
if ((chr=GET) == my_b_EOF)
1124
found_end_of_line=eof=1;
1127
} while ((char) chr != line_start_ptr[0]);
1128
for (char *ptr=line_start_ptr+1 ; ptr != line_start_end ; ptr++)
1130
chr=GET; // Eof will be checked later
1131
if ((char) chr != *ptr)
1132
{ // Can't be line_start
1134
while (--ptr != line_start_ptr)
1135
{ // Restart with next char
1136
PUSH((unsigned char) *ptr);
1145
} /* namespace drizzled */