1 /*
2 Copyright (c) 2000, 2016, Oracle and/or its affiliates.
3 Copyright (c) 2010, 2018, MariaDB Corporation.
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; version 2 of the License.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */
17
18
19 /* Copy data from a textfile to table */
20 /* 2006-12 Erik Wetterberg : LOAD XML added */
21
22 #include "mariadb.h"
23 #include "sql_priv.h"
24 #include "unireg.h"
25 #include "sql_load.h"
26 #include "sql_load.h"
27 #include "sql_cache.h" // query_cache_*
28 #include "sql_base.h" // fill_record_n_invoke_before_triggers
29 #include <my_dir.h>
30 #include "sql_view.h" // check_key_in_view
31 #include "sql_insert.h" // check_that_all_fields_are_given_values,
32 // write_record
33 #include "sql_acl.h" // INSERT_ACL, UPDATE_ACL
34 #include "log_event.h" // Delete_file_log_event,
35 // Execute_load_query_log_event,
36 // LOG_EVENT_UPDATE_TABLE_MAP_VERSION_F
37 #include <m_ctype.h>
38 #include "rpl_mi.h"
39 #include "sql_repl.h"
40 #include "sp_head.h"
41 #include "sql_trigger.h"
42 #include "sql_derived.h"
43 #include "sql_show.h"
44
45 #include "wsrep_mysqld.h"
46
47 extern "C" int _my_b_net_read(IO_CACHE *info, uchar *Buffer, size_t Count);
48
49 class XML_TAG {
50 public:
51 int level;
52 String field;
53 String value;
54 XML_TAG(int l, String f, String v);
55 };
56
57
XML_TAG(int l,String f,String v)58 XML_TAG::XML_TAG(int l, String f, String v)
59 {
60 level= l;
61 field.append(f);
62 value.append(v);
63 }
64
65
66 /*
67 Field and line terminators must be interpreted as sequence of unsigned char.
68 Otherwise, non-ascii terminators will be negative on some platforms,
69 and positive on others (depending on the implementation of char).
70 */
71 class Term_string
72 {
73 const uchar *m_ptr;
74 uint m_length;
75 int m_initial_byte;
76 public:
Term_string(const String & str)77 Term_string(const String &str) :
78 m_ptr(static_cast<const uchar*>(static_cast<const void*>(str.ptr()))),
79 m_length(str.length()),
80 m_initial_byte((uchar) (str.length() ? str.ptr()[0] : INT_MAX))
81 { }
set(const uchar * str,uint length,int initial_byte)82 void set(const uchar *str, uint length, int initial_byte)
83 {
84 m_ptr= str;
85 m_length= length;
86 m_initial_byte= initial_byte;
87 }
reset()88 void reset() { set(NULL, 0, INT_MAX); }
ptr() const89 const uchar *ptr() const { return m_ptr; }
length() const90 uint length() const { return m_length; }
initial_byte() const91 int initial_byte() const { return m_initial_byte; }
eq(const Term_string & other) const92 bool eq(const Term_string &other) const
93 {
94 return length() == other.length() && !memcmp(ptr(), other.ptr(), length());
95 }
96 };
97
98
99 #define GET (stack_pos != stack ? *--stack_pos : my_b_get(&cache))
100 #define PUSH(A) *(stack_pos++)=(A)
101
102 #ifdef WITH_WSREP
103 /** If requested by wsrep_load_data_splitting and streaming replication is
104 not enabled, replicate a streaming fragment every 10,000 rows.*/
105 class Wsrep_load_data_split
106 {
107 public:
Wsrep_load_data_split(THD * thd)108 Wsrep_load_data_split(THD *thd)
109 : m_thd(thd)
110 , m_load_data_splitting(wsrep_load_data_splitting)
111 , m_fragment_unit(thd->wsrep_trx().streaming_context().fragment_unit())
112 , m_fragment_size(thd->wsrep_trx().streaming_context().fragment_size())
113 {
114 if (WSREP(m_thd) && m_load_data_splitting)
115 {
116 /* Override streaming settings with backward compatible values for
117 load data splitting */
118 m_thd->wsrep_cs().streaming_params(wsrep::streaming_context::row, 10000);
119 }
120 }
121
~Wsrep_load_data_split()122 ~Wsrep_load_data_split()
123 {
124 if (WSREP(m_thd) && m_load_data_splitting)
125 {
126 /* Restore original settings */
127 m_thd->wsrep_cs().streaming_params(m_fragment_unit, m_fragment_size);
128 }
129 }
130 private:
131 THD *m_thd;
132 my_bool m_load_data_splitting;
133 enum wsrep::streaming_context::fragment_unit m_fragment_unit;
134 size_t m_fragment_size;
135 };
136 #endif /* WITH_WSREP */
137
138 class READ_INFO: public Load_data_param
139 {
140 File file;
141 String data; /* Read buffer */
142 Term_string m_field_term; /* FIELDS TERMINATED BY 'string' */
143 Term_string m_line_term; /* LINES TERMINATED BY 'string' */
144 Term_string m_line_start; /* LINES STARTING BY 'string' */
145 int enclosed_char,escape_char;
146 int *stack,*stack_pos;
147 bool found_end_of_line,start_of_line,eof;
148 int level; /* for load xml */
149
getbyte(char * to)150 bool getbyte(char *to)
151 {
152 int chr= GET;
153 if (chr == my_b_EOF)
154 return (eof= true);
155 *to= chr;
156 return false;
157 }
158
159 /**
160 Read a tail of a multi-byte character.
161 The first byte of the character is assumed to be already
162 read from the file and appended to "str".
163
164 @returns true - if EOF happened unexpectedly
165 @returns false - no EOF happened: found a good multi-byte character,
166 or a bad byte sequence
167
168 Note:
169 The return value depends only on EOF:
170 - read_mbtail() returns "false" is a good character was read, but also
171 - read_mbtail() returns "false" if an incomplete byte sequence was found
172 and no EOF happened.
173
174 For example, suppose we have an ujis file with bytes 0x8FA10A, where:
175 - 0x8FA1 is an incomplete prefix of a 3-byte character
176 (it should be [8F][A1-FE][A1-FE] to make a full 3-byte character)
177 - 0x0A is a line demiliter
178 This file has some broken data, the trailing [A1-FE] is missing.
179
180 In this example it works as follows:
181 - 0x8F is read from the file and put into "data" before the call
182 for read_mbtail()
183 - 0xA1 is read from the file and put into "data" by read_mbtail()
184 - 0x0A is kept in the read queue, so the next read iteration after
185 the current read_mbtail() call will normally find it and recognize as
186 a line delimiter
187 - the current call for read_mbtail() returns "false",
188 because no EOF happened
189 */
read_mbtail(String * str)190 bool read_mbtail(String *str)
191 {
192 int chlen;
193 if ((chlen= my_charlen(charset(), str->end() - 1, str->end())) == 1)
194 return false; // Single byte character found
195 for (uint32 length0= str->length() - 1 ; MY_CS_IS_TOOSMALL(chlen); )
196 {
197 int chr= GET;
198 if (chr == my_b_EOF)
199 {
200 DBUG_PRINT("info", ("read_mbtail: chlen=%d; unexpected EOF", chlen));
201 return true; // EOF
202 }
203 str->append(chr);
204 chlen= my_charlen(charset(), str->ptr() + length0, str->end());
205 if (chlen == MY_CS_ILSEQ)
206 {
207 /**
208 It has been an incomplete (but a valid) sequence so far,
209 but the last byte turned it into a bad byte sequence.
210 Unget the very last byte.
211 */
212 str->length(str->length() - 1);
213 PUSH(chr);
214 DBUG_PRINT("info", ("read_mbtail: ILSEQ"));
215 return false; // Bad byte sequence
216 }
217 }
218 DBUG_PRINT("info", ("read_mbtail: chlen=%d", chlen));
219 return false; // Good multi-byte character
220 }
221
222 public:
223 bool error,line_cuted,found_null,enclosed;
224 uchar *row_start, /* Found row starts here */
225 *row_end; /* Found row ends here */
226 LOAD_FILE_IO_CACHE cache;
227
228 READ_INFO(THD *thd, File file, const Load_data_param ¶m,
229 String &field_term,String &line_start,String &line_term,
230 String &enclosed,int escape,bool get_it_from_net, bool is_fifo);
231 ~READ_INFO();
232 int read_field();
233 int read_fixed_length(void);
234 int next_line(void);
235 char unescape(char chr);
236 bool terminator(const uchar *ptr, uint length);
terminator(const Term_string & str)237 bool terminator(const Term_string &str)
238 { return terminator(str.ptr(), str.length()); }
terminator(int chr,const Term_string & str)239 bool terminator(int chr, const Term_string &str)
240 { return str.initial_byte() == chr && terminator(str); }
241 bool find_start_of_fields();
242 /* load xml */
243 List<XML_TAG> taglist;
244 int read_value(int delim, String *val);
245 int read_xml(THD *thd);
246 int clear_level(int level);
247
file_length()248 my_off_t file_length() { return cache.end_of_file; }
position()249 my_off_t position() { return my_b_tell(&cache); }
250
251 /**
252 skip all data till the eof.
253 */
skip_data_till_eof()254 void skip_data_till_eof()
255 {
256 while (GET != my_b_EOF)
257 ;
258 }
259 };
260
261 static int read_fixed_length(THD *thd, COPY_INFO &info, TABLE_LIST *table_list,
262 List<Item> &fields_vars, List<Item> &set_fields,
263 List<Item> &set_values, READ_INFO &read_info,
264 ulong skip_lines,
265 bool ignore_check_option_errors);
266 static int read_sep_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list,
267 List<Item> &fields_vars, List<Item> &set_fields,
268 List<Item> &set_values, READ_INFO &read_info,
269 String &enclosed, ulong skip_lines,
270 bool ignore_check_option_errors);
271
272 static int read_xml_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list,
273 List<Item> &fields_vars, List<Item> &set_fields,
274 List<Item> &set_values, READ_INFO &read_info,
275 String &enclosed, ulong skip_lines,
276 bool ignore_check_option_errors);
277
278 #ifndef EMBEDDED_LIBRARY
279 static bool write_execute_load_query_log_event(THD *, const sql_exchange*, const
280 char*, const char*, bool, enum enum_duplicates, bool, bool, int);
281 #endif /* EMBEDDED_LIBRARY */
282
283
add_outvar_field(THD * thd,const Field * field)284 bool Load_data_param::add_outvar_field(THD *thd, const Field *field)
285 {
286 if (field->flags & BLOB_FLAG)
287 {
288 m_use_blobs= true;
289 m_fixed_length+= 256; // Will be extended if needed
290 }
291 else
292 m_fixed_length+= field->field_length;
293 return false;
294 }
295
296
add_outvar_user_var(THD * thd)297 bool Load_data_param::add_outvar_user_var(THD *thd)
298 {
299 if (m_is_fixed_length)
300 {
301 my_error(ER_LOAD_FROM_FIXED_SIZE_ROWS_TO_VAR, MYF(0));
302 return true;
303 }
304 return false;
305 }
306
307
308 /*
309 Execute LOAD DATA query
310
311 SYNOPSYS
312 mysql_load()
313 thd - current thread
314 ex - sql_exchange object representing source file and its parsing rules
315 table_list - list of tables to which we are loading data
316 fields_vars - list of fields and variables to which we read
317 data from file
318 set_fields - list of fields mentioned in set clause
319 set_values - expressions to assign to fields in previous list
320 handle_duplicates - indicates whenever we should emit error or
321 replace row if we will meet duplicates.
322 ignore - - indicates whenever we should ignore duplicates
323 read_file_from_client - is this LOAD DATA LOCAL ?
324
325 RETURN VALUES
326 TRUE - error / FALSE - success
327 */
328
mysql_load(THD * thd,const sql_exchange * ex,TABLE_LIST * table_list,List<Item> & fields_vars,List<Item> & set_fields,List<Item> & set_values,enum enum_duplicates handle_duplicates,bool ignore,bool read_file_from_client)329 int mysql_load(THD *thd, const sql_exchange *ex, TABLE_LIST *table_list,
330 List<Item> &fields_vars, List<Item> &set_fields,
331 List<Item> &set_values,
332 enum enum_duplicates handle_duplicates, bool ignore,
333 bool read_file_from_client)
334 {
335 char name[FN_REFLEN];
336 File file;
337 TABLE *table= NULL;
338 int error= 0;
339 bool is_fifo=0;
340 #ifndef EMBEDDED_LIBRARY
341 killed_state killed_status;
342 bool is_concurrent;
343 #endif
344 const char *db= table_list->db.str; // This is never null
345 /*
346 If path for file is not defined, we will use the current database.
347 If this is not set, we will use the directory where the table to be
348 loaded is located
349 */
350 const char *tdb= thd->db.str ? thd->db.str : db; // Result is never null
351 ulong skip_lines= ex->skip_lines;
352 bool transactional_table __attribute__((unused));
353 DBUG_ENTER("mysql_load");
354
355 #ifdef WITH_WSREP
356 Wsrep_load_data_split wsrep_load_data_split(thd);
357 #endif /* WITH_WSREP */
358 /*
359 Bug #34283
360 mysqlbinlog leaves tmpfile after termination if binlog contains
361 load data infile, so in mixed mode we go to row-based for
362 avoiding the problem.
363 */
364 thd->set_current_stmt_binlog_format_row_if_mixed();
365
366 #ifdef EMBEDDED_LIBRARY
367 read_file_from_client = 0; //server is always in the same process
368 #endif
369
370 if (ex->escaped->length() > 1 || ex->enclosed->length() > 1)
371 {
372 my_message(ER_WRONG_FIELD_TERMINATORS,
373 ER_THD(thd, ER_WRONG_FIELD_TERMINATORS),
374 MYF(0));
375 DBUG_RETURN(TRUE);
376 }
377
378 /* Report problems with non-ascii separators */
379 if (!ex->escaped->is_ascii() || !ex->enclosed->is_ascii() ||
380 !ex->field_term->is_ascii() ||
381 !ex->line_term->is_ascii() || !ex->line_start->is_ascii())
382 {
383 push_warning(thd, Sql_condition::WARN_LEVEL_WARN,
384 WARN_NON_ASCII_SEPARATOR_NOT_IMPLEMENTED,
385 ER_THD(thd, WARN_NON_ASCII_SEPARATOR_NOT_IMPLEMENTED));
386 }
387
388 if (open_and_lock_tables(thd, table_list, TRUE, 0))
389 DBUG_RETURN(TRUE);
390 if (table_list->handle_derived(thd->lex, DT_MERGE_FOR_INSERT))
391 DBUG_RETURN(TRUE);
392 if (thd->lex->handle_list_of_derived(table_list, DT_PREPARE))
393 DBUG_RETURN(TRUE);
394 if (setup_tables_and_check_access(thd,
395 &thd->lex->first_select_lex()->context,
396 &thd->lex->first_select_lex()->
397 top_join_list,
398 table_list,
399 thd->lex->first_select_lex()->leaf_tables,
400 FALSE,
401 INSERT_ACL | UPDATE_ACL,
402 INSERT_ACL | UPDATE_ACL, FALSE))
403 DBUG_RETURN(-1);
404 if (!table_list->table || // do not suport join view
405 !table_list->single_table_updatable() || // and derived tables
406 check_key_in_view(thd, table_list))
407 {
408 my_error(ER_NON_UPDATABLE_TABLE, MYF(0), table_list->alias.str, "LOAD");
409 DBUG_RETURN(TRUE);
410 }
411 if (table_list->is_multitable())
412 {
413 my_error(ER_WRONG_USAGE, MYF(0), "Multi-table VIEW", "LOAD");
414 DBUG_RETURN(TRUE);
415 }
416 if (table_list->prepare_where(thd, 0, TRUE) ||
417 table_list->prepare_check_option(thd))
418 {
419 DBUG_RETURN(TRUE);
420 }
421 thd_proc_info(thd, "Executing");
422 /*
423 Let us emit an error if we are loading data to table which is used
424 in subselect in SET clause like we do it for INSERT.
425
426 The main thing to fix to remove this restriction is to ensure that the
427 table is marked to be 'used for insert' in which case we should never
428 mark this table as 'const table' (ie, one that has only one row).
429 */
430 if (unique_table(thd, table_list, table_list->next_global, 0))
431 {
432 my_error(ER_UPDATE_TABLE_USED, MYF(0), table_list->table_name.str,
433 "LOAD DATA");
434 DBUG_RETURN(TRUE);
435 }
436
437 table= table_list->table;
438 transactional_table= table->file->has_transactions();
439 #ifndef EMBEDDED_LIBRARY
440 is_concurrent= (table_list->lock_type == TL_WRITE_CONCURRENT_INSERT);
441 #endif
442
443 if (!fields_vars.elements)
444 {
445 Field_iterator_table_ref field_iterator;
446 field_iterator.set(table_list);
447 for (; !field_iterator.end_of_fields(); field_iterator.next())
448 {
449 if (field_iterator.field() &&
450 field_iterator.field()->invisible > VISIBLE)
451 continue;
452 Item *item;
453 if (!(item= field_iterator.create_item(thd)))
454 DBUG_RETURN(TRUE);
455 fields_vars.push_back(item->real_item(), thd->mem_root);
456 }
457 bitmap_set_all(table->write_set);
458 /*
459 Let us also prepare SET clause, altough it is probably empty
460 in this case.
461 */
462 if (setup_fields(thd, Ref_ptr_array(),
463 set_fields, MARK_COLUMNS_WRITE, 0, NULL, 0) ||
464 setup_fields(thd, Ref_ptr_array(),
465 set_values, MARK_COLUMNS_READ, 0, NULL, 0))
466 DBUG_RETURN(TRUE);
467 }
468 else
469 { // Part field list
470 /* TODO: use this conds for 'WITH CHECK OPTIONS' */
471 if (setup_fields(thd, Ref_ptr_array(),
472 fields_vars, MARK_COLUMNS_WRITE, 0, NULL, 0) ||
473 setup_fields(thd, Ref_ptr_array(),
474 set_fields, MARK_COLUMNS_WRITE, 0, NULL, 0) ||
475 check_that_all_fields_are_given_values(thd, table, table_list))
476 DBUG_RETURN(TRUE);
477 /* Fix the expressions in SET clause */
478 if (setup_fields(thd, Ref_ptr_array(),
479 set_values, MARK_COLUMNS_READ, 0, NULL, 0))
480 DBUG_RETURN(TRUE);
481 }
482 switch_to_nullable_trigger_fields(fields_vars, table);
483 switch_to_nullable_trigger_fields(set_fields, table);
484 switch_to_nullable_trigger_fields(set_values, table);
485
486 table->prepare_triggers_for_insert_stmt_or_event();
487 table->mark_columns_needed_for_insert();
488
489 Load_data_param param(ex->cs ? ex->cs : thd->variables.collation_database,
490 !ex->field_term->length() && !ex->enclosed->length());
491 List_iterator_fast<Item> it(fields_vars);
492 Item *item;
493
494 while ((item= it++))
495 {
496 const Load_data_outvar *var= item->get_load_data_outvar_or_error();
497 if (!var || var->load_data_add_outvar(thd, ¶m))
498 DBUG_RETURN(true);
499 }
500 if (param.use_blobs() && !ex->line_term->length() && !ex->field_term->length())
501 {
502 my_message(ER_BLOBS_AND_NO_TERMINATED,
503 ER_THD(thd, ER_BLOBS_AND_NO_TERMINATED), MYF(0));
504 DBUG_RETURN(TRUE);
505 }
506
507 /* We can't give an error in the middle when using LOCAL files */
508 if (read_file_from_client && handle_duplicates == DUP_ERROR)
509 ignore= 1;
510
511 #ifndef EMBEDDED_LIBRARY
512 if (read_file_from_client)
513 {
514 (void)net_request_file(&thd->net,ex->file_name);
515 file = -1;
516 }
517 else
518 #endif
519 {
520 #ifdef DONT_ALLOW_FULL_LOAD_DATA_PATHS
521 ex->file_name+=dirname_length(ex->file_name);
522 #endif
523 if (!dirname_length(ex->file_name))
524 {
525 strxnmov(name, FN_REFLEN-1, mysql_real_data_home, tdb, NullS);
526 (void) fn_format(name, ex->file_name, name, "",
527 MY_RELATIVE_PATH | MY_UNPACK_FILENAME);
528 }
529 else
530 {
531 (void) fn_format(name, ex->file_name, mysql_real_data_home, "",
532 MY_RELATIVE_PATH | MY_UNPACK_FILENAME |
533 MY_RETURN_REAL_PATH);
534 }
535
536 if (thd->rgi_slave)
537 {
538 #if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
539 if (strncmp(thd->rgi_slave->rli->slave_patternload_file, name,
540 thd->rgi_slave->rli->slave_patternload_file_size))
541 {
542 /*
543 LOAD DATA INFILE in the slave SQL Thread can only read from
544 --slave-load-tmpdir". This should never happen. Please, report a bug.
545 */
546
547 sql_print_error("LOAD DATA INFILE in the slave SQL Thread can only read from --slave-load-tmpdir. " \
548 "Please, report a bug.");
549 my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--slave-load-tmpdir");
550 DBUG_RETURN(TRUE);
551 }
552 #else
553 /*
554 This is impossible and should never happen.
555 */
556 DBUG_ASSERT(FALSE);
557 #endif
558 }
559 else if (!is_secure_file_path(name))
560 {
561 /* Read only allowed from within dir specified by secure_file_priv */
562 my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--secure-file-priv");
563 DBUG_RETURN(TRUE);
564 }
565
566 #if !defined(__WIN__) && ! defined(__NETWARE__)
567 MY_STAT stat_info;
568 if (!my_stat(name, &stat_info, MYF(MY_WME)))
569 DBUG_RETURN(TRUE);
570
571 // if we are not in slave thread, the file must be:
572 if (!thd->slave_thread &&
573 !((stat_info.st_mode & S_IFLNK) != S_IFLNK && // symlink
574 ((stat_info.st_mode & S_IFREG) == S_IFREG || // regular file
575 (stat_info.st_mode & S_IFIFO) == S_IFIFO))) // named pipe
576 {
577 my_error(ER_TEXTFILE_NOT_READABLE, MYF(0), name);
578 DBUG_RETURN(TRUE);
579 }
580 if ((stat_info.st_mode & S_IFIFO) == S_IFIFO)
581 is_fifo= 1;
582 #endif
583 if ((file= mysql_file_open(key_file_load,
584 name, O_RDONLY, MYF(MY_WME))) < 0)
585
586 DBUG_RETURN(TRUE);
587 }
588
589 COPY_INFO info;
590 bzero((char*) &info,sizeof(info));
591 info.ignore= ignore;
592 info.handle_duplicates=handle_duplicates;
593 info.escape_char= (ex->escaped->length() && (ex->escaped_given() ||
594 !(thd->variables.sql_mode & MODE_NO_BACKSLASH_ESCAPES)))
595 ? (*ex->escaped)[0] : INT_MAX;
596
597 READ_INFO read_info(thd, file, param,
598 *ex->field_term, *ex->line_start,
599 *ex->line_term, *ex->enclosed,
600 info.escape_char, read_file_from_client, is_fifo);
601 if (unlikely(read_info.error))
602 {
603 if (file >= 0)
604 mysql_file_close(file, MYF(0)); // no files in net reading
605 DBUG_RETURN(TRUE); // Can't allocate buffers
606 }
607
608 #ifndef EMBEDDED_LIBRARY
609 if (mysql_bin_log.is_open())
610 {
611 read_info.cache.thd = thd;
612 read_info.cache.wrote_create_file = 0;
613 read_info.cache.last_pos_in_file = HA_POS_ERROR;
614 read_info.cache.log_delayed= transactional_table;
615 }
616 #endif /*!EMBEDDED_LIBRARY*/
617
618 thd->count_cuted_fields= CHECK_FIELD_WARN; /* calc cuted fields */
619 thd->cuted_fields=0L;
620 /* Skip lines if there is a line terminator */
621 if (ex->line_term->length() && ex->filetype != FILETYPE_XML)
622 {
623 /* ex->skip_lines needs to be preserved for logging */
624 while (skip_lines > 0)
625 {
626 skip_lines--;
627 if (read_info.next_line())
628 break;
629 }
630 }
631
632 thd_proc_info(thd, "Reading file");
633 if (likely(!(error= MY_TEST(read_info.error))))
634 {
635 table->reset_default_fields();
636 table->next_number_field=table->found_next_number_field;
637 if (ignore ||
638 handle_duplicates == DUP_REPLACE)
639 table->file->extra(HA_EXTRA_IGNORE_DUP_KEY);
640 if (handle_duplicates == DUP_REPLACE &&
641 (!table->triggers ||
642 !table->triggers->has_delete_triggers()))
643 table->file->extra(HA_EXTRA_WRITE_CAN_REPLACE);
644 if (thd->locked_tables_mode <= LTM_LOCK_TABLES)
645 table->file->ha_start_bulk_insert((ha_rows) 0);
646 table->copy_blobs=1;
647
648 thd->abort_on_warning= !ignore && thd->is_strict_mode();
649
650 if ((table_list->table->file->ha_table_flags() & HA_DUPLICATE_POS) &&
651 (error= table_list->table->file->ha_rnd_init_with_error(0)))
652 goto err;
653
654 thd_progress_init(thd, 2);
655 if (table_list->table->validate_default_values_of_unset_fields(thd))
656 {
657 read_info.error= true;
658 error= 1;
659 }
660 else if (ex->filetype == FILETYPE_XML) /* load xml */
661 error= read_xml_field(thd, info, table_list, fields_vars,
662 set_fields, set_values, read_info,
663 *(ex->line_term), skip_lines, ignore);
664 else if (read_info.is_fixed_length())
665 error= read_fixed_length(thd, info, table_list, fields_vars,
666 set_fields, set_values, read_info,
667 skip_lines, ignore);
668 else
669 error= read_sep_field(thd, info, table_list, fields_vars,
670 set_fields, set_values, read_info,
671 *ex->enclosed, skip_lines, ignore);
672
673 if (table_list->table->file->ha_table_flags() & HA_DUPLICATE_POS)
674 table_list->table->file->ha_rnd_end();
675
676 thd_proc_info(thd, "End bulk insert");
677 if (likely(!error))
678 thd_progress_next_stage(thd);
679 if (thd->locked_tables_mode <= LTM_LOCK_TABLES &&
680 table->file->ha_end_bulk_insert() && !error)
681 {
682 table->file->print_error(my_errno, MYF(0));
683 error= 1;
684 }
685 table->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY);
686 table->file->extra(HA_EXTRA_WRITE_CANNOT_REPLACE);
687 table->next_number_field=0;
688 }
689 if (file >= 0)
690 mysql_file_close(file, MYF(0));
691 free_blobs(table); /* if pack_blob was used */
692 table->copy_blobs=0;
693 thd->count_cuted_fields= CHECK_FIELD_IGNORE;
694 /*
695 simulated killing in the middle of per-row loop
696 must be effective for binlogging
697 */
698 DBUG_EXECUTE_IF("simulate_kill_bug27571",
699 {
700 error=1;
701 thd->set_killed(KILL_QUERY);
702 };);
703
704 #ifndef EMBEDDED_LIBRARY
705 killed_status= (error == 0) ? NOT_KILLED : thd->killed;
706 #endif
707
708 /*
709 We must invalidate the table in query cache before binlog writing and
710 ha_autocommit_...
711 */
712 query_cache_invalidate3(thd, table_list, 0);
713 if (error)
714 {
715 if (read_file_from_client)
716 read_info.skip_data_till_eof();
717
718 #ifndef EMBEDDED_LIBRARY
719 if (mysql_bin_log.is_open())
720 {
721 {
722 /*
723 Make sure last block (the one which caused the error) gets
724 logged.
725 */
726 log_loaded_block(&read_info.cache, 0, 0);
727 /* If the file was not empty, wrote_create_file is true */
728 if (read_info.cache.wrote_create_file)
729 {
730 int errcode= query_error_code(thd, killed_status == NOT_KILLED);
731
732 /* since there is already an error, the possible error of
733 writing binary log will be ignored */
734 if (thd->transaction.stmt.modified_non_trans_table)
735 (void) write_execute_load_query_log_event(thd, ex,
736 table_list->db.str,
737 table_list->table_name.str,
738 is_concurrent,
739 handle_duplicates, ignore,
740 transactional_table,
741 errcode);
742 else
743 {
744 Delete_file_log_event d(thd, db, transactional_table);
745 (void) mysql_bin_log.write(&d);
746 }
747 }
748 }
749 }
750 #endif /*!EMBEDDED_LIBRARY*/
751 error= -1; // Error on read
752 goto err;
753 }
754 sprintf(name, ER_THD(thd, ER_LOAD_INFO),
755 (ulong) info.records, (ulong) info.deleted,
756 (ulong) (info.records - info.copied),
757 (long) thd->get_stmt_da()->current_statement_warn_count());
758
759 if (thd->transaction.stmt.modified_non_trans_table)
760 thd->transaction.all.modified_non_trans_table= TRUE;
761 thd->transaction.all.m_unsafe_rollback_flags|=
762 (thd->transaction.stmt.m_unsafe_rollback_flags & THD_TRANS::DID_WAIT);
763 #ifndef EMBEDDED_LIBRARY
764 if (mysql_bin_log.is_open())
765 {
766 /*
767 We need to do the job that is normally done inside
768 binlog_query() here, which is to ensure that the pending event
769 is written before tables are unlocked and before any other
770 events are written. We also need to update the table map
771 version for the binary log to mark that table maps are invalid
772 after this point.
773 */
774 if (thd->is_current_stmt_binlog_format_row())
775 error= thd->binlog_flush_pending_rows_event(TRUE, transactional_table);
776 else
777 {
778 /*
779 As already explained above, we need to call log_loaded_block() to have
780 the last block logged
781 */
782 log_loaded_block(&read_info.cache, 0, 0);
783 if (read_info.cache.wrote_create_file)
784 {
785 int errcode= query_error_code(thd, killed_status == NOT_KILLED);
786 error= write_execute_load_query_log_event(thd, ex,
787 table_list->db.str,
788 table_list->table_name.str,
789 is_concurrent,
790 handle_duplicates, ignore,
791 transactional_table,
792 errcode);
793 }
794
795 /*
796 Flushing the IO CACHE while writing the execute load query log event
797 may result in error (for instance, because the max_binlog_size has been
798 reached, and rotation of the binary log failed).
799 */
800 error= error || mysql_bin_log.get_log_file()->error;
801 }
802 if (unlikely(error))
803 goto err;
804 }
805 #endif /*!EMBEDDED_LIBRARY*/
806
807 /* ok to client sent only after binlog write and engine commit */
808 my_ok(thd, info.copied + info.deleted, 0L, name);
809 err:
810 DBUG_ASSERT(transactional_table || !(info.copied || info.deleted) ||
811 thd->transaction.stmt.modified_non_trans_table);
812 table->file->ha_release_auto_increment();
813 table->auto_increment_field_not_null= FALSE;
814 thd->abort_on_warning= 0;
815 DBUG_RETURN(error);
816 }
817
818
819 #ifndef EMBEDDED_LIBRARY
820
821 /* Not a very useful function; just to avoid duplication of code */
write_execute_load_query_log_event(THD * thd,const sql_exchange * ex,const char * db_arg,const char * table_name_arg,bool is_concurrent,enum enum_duplicates duplicates,bool ignore,bool transactional_table,int errcode)822 static bool write_execute_load_query_log_event(THD *thd, const sql_exchange* ex,
823 const char* db_arg, /* table's database */
824 const char* table_name_arg,
825 bool is_concurrent,
826 enum enum_duplicates duplicates,
827 bool ignore,
828 bool transactional_table,
829 int errcode)
830 {
831 char *load_data_query;
832 my_off_t fname_start,
833 fname_end;
834 List<Item> fv;
835 Item *item, *val;
836 int n;
837 const char *tdb= (thd->db.str != NULL ? thd->db.str : db_arg);
838 const char *qualify_db= NULL;
839 char command_buffer[1024];
840 String query_str(command_buffer, sizeof(command_buffer),
841 system_charset_info);
842
843 Load_log_event lle(thd, ex, tdb, table_name_arg, fv, is_concurrent,
844 duplicates, ignore, transactional_table);
845
846 /*
847 force in a LOCAL if there was one in the original.
848 */
849 if (thd->lex->local_file)
850 lle.set_fname_outside_temp_buf(ex->file_name, strlen(ex->file_name));
851
852 query_str.length(0);
853 if (!thd->db.str || strcmp(db_arg, thd->db.str))
854 {
855 /*
856 If used database differs from table's database,
857 prefix table name with database name so that it
858 becomes a FQ name.
859 */
860 qualify_db= db_arg;
861 }
862 lle.print_query(thd, FALSE, (const char *) ex->cs?ex->cs->csname:NULL,
863 &query_str, &fname_start, &fname_end, qualify_db);
864
865 /*
866 prepare fields-list and SET if needed; print_query won't do that for us.
867 */
868 if (!thd->lex->field_list.is_empty())
869 {
870 List_iterator<Item> li(thd->lex->field_list);
871
872 query_str.append(" (");
873 n= 0;
874
875 while ((item= li++))
876 {
877 if (n++)
878 query_str.append(", ");
879 const Load_data_outvar *var= item->get_load_data_outvar();
880 DBUG_ASSERT(var);
881 var->load_data_print_for_log_event(thd, &query_str);
882 }
883 query_str.append(")");
884 }
885
886 if (!thd->lex->update_list.is_empty())
887 {
888 List_iterator<Item> lu(thd->lex->update_list);
889 List_iterator<Item> lv(thd->lex->value_list);
890
891 query_str.append(STRING_WITH_LEN(" SET "));
892 n= 0;
893
894 while ((item= lu++))
895 {
896 val= lv++;
897 if (n++)
898 query_str.append(STRING_WITH_LEN(", "));
899 append_identifier(thd, &query_str, &item->name);
900 query_str.append(&val->name);
901 }
902 }
903
904 if (!(load_data_query= (char *)thd->strmake(query_str.ptr(), query_str.length())))
905 return TRUE;
906
907 Execute_load_query_log_event
908 e(thd, load_data_query, query_str.length(),
909 (uint) (fname_start - 1), (uint) fname_end,
910 (duplicates == DUP_REPLACE) ? LOAD_DUP_REPLACE :
911 (ignore ? LOAD_DUP_IGNORE : LOAD_DUP_ERROR),
912 transactional_table, FALSE, FALSE, errcode);
913 return mysql_bin_log.write(&e);
914 }
915
916 #endif
917
918 /****************************************************************************
919 ** Read of rows of fixed size + optional garage + optonal newline
920 ****************************************************************************/
921
922 static int
read_fixed_length(THD * thd,COPY_INFO & info,TABLE_LIST * table_list,List<Item> & fields_vars,List<Item> & set_fields,List<Item> & set_values,READ_INFO & read_info,ulong skip_lines,bool ignore_check_option_errors)923 read_fixed_length(THD *thd, COPY_INFO &info, TABLE_LIST *table_list,
924 List<Item> &fields_vars, List<Item> &set_fields,
925 List<Item> &set_values, READ_INFO &read_info,
926 ulong skip_lines, bool ignore_check_option_errors)
927 {
928 List_iterator_fast<Item> it(fields_vars);
929 Item *item;
930 TABLE *table= table_list->table;
931 bool err, progress_reports;
932 ulonglong counter, time_to_report_progress;
933 DBUG_ENTER("read_fixed_length");
934
935 counter= 0;
936 time_to_report_progress= MY_HOW_OFTEN_TO_WRITE/10;
937 progress_reports= 1;
938 if ((thd->progress.max_counter= read_info.file_length()) == ~(my_off_t) 0)
939 progress_reports= 0;
940
941 while (!read_info.read_fixed_length())
942 {
943 if (thd->killed)
944 {
945 thd->send_kill_message();
946 DBUG_RETURN(1);
947 }
948 if (progress_reports)
949 {
950 thd->progress.counter= read_info.position();
951 if (++counter >= time_to_report_progress)
952 {
953 time_to_report_progress+= MY_HOW_OFTEN_TO_WRITE/10;
954 thd_progress_report(thd, thd->progress.counter,
955 thd->progress.max_counter);
956 }
957 }
958 if (skip_lines)
959 {
960 /*
961 We could implement this with a simple seek if:
962 - We are not using DATA INFILE LOCAL
963 - escape character is ""
964 - line starting prefix is ""
965 */
966 skip_lines--;
967 continue;
968 }
969 it.rewind();
970 uchar *pos=read_info.row_start;
971 #ifdef HAVE_valgrind
972 read_info.row_end[0]=0;
973 #endif
974
975 restore_record(table, s->default_values);
976
977 while ((item= it++))
978 {
979 Load_data_outvar *dst= item->get_load_data_outvar();
980 DBUG_ASSERT(dst);
981 if (pos == read_info.row_end)
982 {
983 if (dst->load_data_set_no_data(thd, &read_info))
984 DBUG_RETURN(1);
985 }
986 else
987 {
988 uint length, fixed_length= dst->load_data_fixed_length();
989 uchar save_chr;
990 if ((length=(uint) (read_info.row_end - pos)) > fixed_length)
991 length= fixed_length;
992 save_chr= pos[length]; pos[length]= '\0'; // Safeguard aganst malloc
993 dst->load_data_set_value(thd, (const char *) pos, length, &read_info);
994 pos[length]= save_chr;
995 if ((pos+= length) > read_info.row_end)
996 pos= read_info.row_end; // Fills rest with space
997 }
998 }
999 if (pos != read_info.row_end)
1000 {
1001 thd->cuted_fields++; /* To long row */
1002 push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
1003 ER_WARN_TOO_MANY_RECORDS,
1004 ER_THD(thd, ER_WARN_TOO_MANY_RECORDS),
1005 thd->get_stmt_da()->current_row_for_warning());
1006 }
1007
1008 if (thd->killed ||
1009 fill_record_n_invoke_before_triggers(thd, table, set_fields, set_values,
1010 ignore_check_option_errors,
1011 TRG_EVENT_INSERT))
1012 DBUG_RETURN(1);
1013
1014 switch (table_list->view_check_option(thd, ignore_check_option_errors)) {
1015 case VIEW_CHECK_SKIP:
1016 read_info.next_line();
1017 goto continue_loop;
1018 case VIEW_CHECK_ERROR:
1019 DBUG_RETURN(-1);
1020 }
1021
1022 err= write_record(thd, table, &info);
1023 table->auto_increment_field_not_null= FALSE;
1024 if (err)
1025 DBUG_RETURN(1);
1026
1027 /*
1028 We don't need to reset auto-increment field since we are restoring
1029 its default value at the beginning of each loop iteration.
1030 */
1031 if (read_info.next_line()) // Skip to next line
1032 break;
1033 if (read_info.line_cuted)
1034 {
1035 thd->cuted_fields++; /* To long row */
1036 push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
1037 ER_WARN_TOO_MANY_RECORDS,
1038 ER_THD(thd, ER_WARN_TOO_MANY_RECORDS),
1039 thd->get_stmt_da()->current_row_for_warning());
1040 }
1041 thd->get_stmt_da()->inc_current_row_for_warning();
1042 continue_loop:;
1043 }
1044 DBUG_RETURN(MY_TEST(read_info.error));
1045 }
1046
1047
1048 static int
read_sep_field(THD * thd,COPY_INFO & info,TABLE_LIST * table_list,List<Item> & fields_vars,List<Item> & set_fields,List<Item> & set_values,READ_INFO & read_info,String & enclosed,ulong skip_lines,bool ignore_check_option_errors)1049 read_sep_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list,
1050 List<Item> &fields_vars, List<Item> &set_fields,
1051 List<Item> &set_values, READ_INFO &read_info,
1052 String &enclosed, ulong skip_lines,
1053 bool ignore_check_option_errors)
1054 {
1055 List_iterator_fast<Item> it(fields_vars);
1056 Item *item;
1057 TABLE *table= table_list->table;
1058 uint enclosed_length;
1059 bool err, progress_reports;
1060 ulonglong counter, time_to_report_progress;
1061 DBUG_ENTER("read_sep_field");
1062
1063 enclosed_length=enclosed.length();
1064
1065 counter= 0;
1066 time_to_report_progress= MY_HOW_OFTEN_TO_WRITE/10;
1067 progress_reports= 1;
1068 if ((thd->progress.max_counter= read_info.file_length()) == ~(my_off_t) 0)
1069 progress_reports= 0;
1070
1071 for (;;it.rewind())
1072 {
1073 if (thd->killed)
1074 {
1075 thd->send_kill_message();
1076 DBUG_RETURN(1);
1077 }
1078
1079 if (progress_reports)
1080 {
1081 thd->progress.counter= read_info.position();
1082 if (++counter >= time_to_report_progress)
1083 {
1084 time_to_report_progress+= MY_HOW_OFTEN_TO_WRITE/10;
1085 thd_progress_report(thd, thd->progress.counter,
1086 thd->progress.max_counter);
1087 }
1088 }
1089 restore_record(table, s->default_values);
1090
1091 while ((item= it++))
1092 {
1093 uint length;
1094 uchar *pos;
1095 if (read_info.read_field())
1096 break;
1097
1098 /* If this line is to be skipped we don't want to fill field or var */
1099 if (skip_lines)
1100 continue;
1101
1102 pos=read_info.row_start;
1103 length=(uint) (read_info.row_end-pos);
1104
1105 Load_data_outvar *dst= item->get_load_data_outvar_or_error();
1106 DBUG_ASSERT(dst);
1107
1108 if ((!read_info.enclosed &&
1109 (enclosed_length && length == 4 &&
1110 !memcmp(pos, STRING_WITH_LEN("NULL")))) ||
1111 (length == 1 && read_info.found_null))
1112 {
1113 if (dst->load_data_set_null(thd, &read_info))
1114 DBUG_RETURN(1);
1115 }
1116 else
1117 {
1118 read_info.row_end[0]= 0; // Safe to change end marker
1119 if (dst->load_data_set_value(thd, (const char *) pos, length, &read_info))
1120 DBUG_RETURN(1);
1121 }
1122 }
1123
1124 if (unlikely(thd->is_error()))
1125 read_info.error= 1;
1126 if (unlikely(read_info.error))
1127 break;
1128
1129 if (skip_lines)
1130 {
1131 skip_lines--;
1132 continue;
1133 }
1134 if (item)
1135 {
1136 /* Have not read any field, thus input file is simply ended */
1137 if (item == fields_vars.head())
1138 break;
1139 for (; item ; item= it++)
1140 {
1141 Load_data_outvar *dst= item->get_load_data_outvar_or_error();
1142 DBUG_ASSERT(dst);
1143 if (unlikely(dst->load_data_set_no_data(thd, &read_info)))
1144 DBUG_RETURN(1);
1145 }
1146 }
1147
1148 if (unlikely(thd->killed) ||
1149 unlikely(fill_record_n_invoke_before_triggers(thd, table, set_fields,
1150 set_values,
1151 ignore_check_option_errors,
1152 TRG_EVENT_INSERT)))
1153 DBUG_RETURN(1);
1154
1155 switch (table_list->view_check_option(thd,
1156 ignore_check_option_errors)) {
1157 case VIEW_CHECK_SKIP:
1158 read_info.next_line();
1159 goto continue_loop;
1160 case VIEW_CHECK_ERROR:
1161 DBUG_RETURN(-1);
1162 }
1163
1164 err= write_record(thd, table, &info);
1165 table->auto_increment_field_not_null= FALSE;
1166 if (err)
1167 DBUG_RETURN(1);
1168 /*
1169 We don't need to reset auto-increment field since we are restoring
1170 its default value at the beginning of each loop iteration.
1171 */
1172 if (read_info.next_line()) // Skip to next line
1173 break;
1174 if (read_info.line_cuted)
1175 {
1176 thd->cuted_fields++; /* To long row */
1177 push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
1178 ER_WARN_TOO_MANY_RECORDS,
1179 ER_THD(thd, ER_WARN_TOO_MANY_RECORDS),
1180 thd->get_stmt_da()->current_row_for_warning());
1181 if (thd->killed)
1182 DBUG_RETURN(1);
1183 }
1184 thd->get_stmt_da()->inc_current_row_for_warning();
1185 continue_loop:;
1186 }
1187 DBUG_RETURN(MY_TEST(read_info.error));
1188 }
1189
1190
1191 /****************************************************************************
1192 ** Read rows in xml format
1193 ****************************************************************************/
1194 static int
read_xml_field(THD * thd,COPY_INFO & info,TABLE_LIST * table_list,List<Item> & fields_vars,List<Item> & set_fields,List<Item> & set_values,READ_INFO & read_info,String & row_tag,ulong skip_lines,bool ignore_check_option_errors)1195 read_xml_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list,
1196 List<Item> &fields_vars, List<Item> &set_fields,
1197 List<Item> &set_values, READ_INFO &read_info,
1198 String &row_tag, ulong skip_lines,
1199 bool ignore_check_option_errors)
1200 {
1201 List_iterator_fast<Item> it(fields_vars);
1202 Item *item;
1203 TABLE *table= table_list->table;
1204 bool no_trans_update_stmt;
1205 DBUG_ENTER("read_xml_field");
1206
1207 no_trans_update_stmt= !table->file->has_transactions();
1208
1209 for ( ; ; it.rewind())
1210 {
1211 bool err;
1212 if (thd->killed)
1213 {
1214 thd->send_kill_message();
1215 DBUG_RETURN(1);
1216 }
1217
1218 // read row tag and save values into tag list
1219 if (read_info.read_xml(thd))
1220 break;
1221
1222 List_iterator_fast<XML_TAG> xmlit(read_info.taglist);
1223 xmlit.rewind();
1224 XML_TAG *tag= NULL;
1225
1226 #ifndef DBUG_OFF
1227 DBUG_PRINT("read_xml_field", ("skip_lines=%d", (int) skip_lines));
1228 while ((tag= xmlit++))
1229 {
1230 DBUG_PRINT("read_xml_field", ("got tag:%i '%s' '%s'",
1231 tag->level, tag->field.c_ptr(),
1232 tag->value.c_ptr()));
1233 }
1234 #endif
1235
1236 restore_record(table, s->default_values);
1237
1238 while ((item= it++))
1239 {
1240 /* If this line is to be skipped we don't want to fill field or var */
1241 if (skip_lines)
1242 continue;
1243
1244 /* find field in tag list */
1245 xmlit.rewind();
1246 tag= xmlit++;
1247
1248 while(tag && strcmp(tag->field.c_ptr(), item->name.str) != 0)
1249 tag= xmlit++;
1250
1251 Load_data_outvar *dst= item->get_load_data_outvar_or_error();
1252 DBUG_ASSERT(dst);
1253 if (!tag ? dst->load_data_set_null(thd, &read_info) :
1254 dst->load_data_set_value(thd, tag->value.ptr(),
1255 tag->value.length(),
1256 &read_info))
1257 DBUG_RETURN(1);
1258 }
1259
1260 if (unlikely(read_info.error))
1261 break;
1262
1263 if (skip_lines)
1264 {
1265 skip_lines--;
1266 continue;
1267 }
1268
1269 DBUG_ASSERT(!item);
1270
1271 if (thd->killed ||
1272 fill_record_n_invoke_before_triggers(thd, table, set_fields, set_values,
1273 ignore_check_option_errors,
1274 TRG_EVENT_INSERT))
1275 DBUG_RETURN(1);
1276
1277 switch (table_list->view_check_option(thd,
1278 ignore_check_option_errors)) {
1279 case VIEW_CHECK_SKIP:
1280 read_info.next_line();
1281 goto continue_loop;
1282 case VIEW_CHECK_ERROR:
1283 DBUG_RETURN(-1);
1284 }
1285
1286 err= write_record(thd, table, &info);
1287 table->auto_increment_field_not_null= false;
1288 if (err)
1289 DBUG_RETURN(1);
1290
1291 /*
1292 We don't need to reset auto-increment field since we are restoring
1293 its default value at the beginning of each loop iteration.
1294 */
1295 thd->transaction.stmt.modified_non_trans_table= no_trans_update_stmt;
1296 thd->get_stmt_da()->inc_current_row_for_warning();
1297 continue_loop:;
1298 }
1299 DBUG_RETURN(MY_TEST(read_info.error) || thd->is_error());
1300 } /* load xml end */
1301
1302
1303 /* Unescape all escape characters, mark \N as null */
1304
1305 char
unescape(char chr)1306 READ_INFO::unescape(char chr)
1307 {
1308 /* keep this switch synchornous with the ESCAPE_CHARS macro */
1309 switch(chr) {
1310 case 'n': return '\n';
1311 case 't': return '\t';
1312 case 'r': return '\r';
1313 case 'b': return '\b';
1314 case '0': return 0; // Ascii null
1315 case 'Z': return '\032'; // Win32 end of file
1316 case 'N': found_null=1;
1317
1318 /* fall through */
1319 default: return chr;
1320 }
1321 }
1322
1323
1324 /*
1325 Read a line using buffering
1326 If last line is empty (in line mode) then it isn't outputed
1327 */
1328
1329
READ_INFO(THD * thd,File file_par,const Load_data_param & param,String & field_term,String & line_start,String & line_term,String & enclosed_par,int escape,bool get_it_from_net,bool is_fifo)1330 READ_INFO::READ_INFO(THD *thd, File file_par,
1331 const Load_data_param ¶m,
1332 String &field_term, String &line_start, String &line_term,
1333 String &enclosed_par, int escape, bool get_it_from_net,
1334 bool is_fifo)
1335 :Load_data_param(param),
1336 file(file_par),
1337 m_field_term(field_term), m_line_term(line_term), m_line_start(line_start),
1338 escape_char(escape), found_end_of_line(false), eof(false),
1339 error(false), line_cuted(false), found_null(false)
1340 {
1341 data.set_thread_specific();
1342 /*
1343 Field and line terminators must be interpreted as sequence of unsigned char.
1344 Otherwise, non-ascii terminators will be negative on some platforms,
1345 and positive on others (depending on the implementation of char).
1346 */
1347
1348 level= 0; /* for load xml */
1349 start_of_line= line_start.length() != 0;
1350 /* If field_terminator == line_terminator, don't use line_terminator */
1351 if (m_field_term.eq(m_line_term))
1352 m_line_term.reset();
1353 enclosed_char= enclosed_par.length() ? (uchar) enclosed_par[0] : INT_MAX;
1354
1355 /* Set of a stack for unget if long terminators */
1356 uint length= MY_MAX(charset()->mbmaxlen, MY_MAX(m_field_term.length(),
1357 m_line_term.length())) + 1;
1358 set_if_bigger(length,line_start.length());
1359 stack= stack_pos= (int*) thd->alloc(sizeof(int) * length);
1360
1361 DBUG_ASSERT(m_fixed_length < UINT_MAX32);
1362 if (data.reserve((size_t) m_fixed_length))
1363 error=1; /* purecov: inspected */
1364 else
1365 {
1366 if (init_io_cache(&cache,(get_it_from_net) ? -1 : file, 0,
1367 (get_it_from_net) ? READ_NET :
1368 (is_fifo ? READ_FIFO : READ_CACHE),0L,1,
1369 MYF(MY_WME | MY_THREAD_SPECIFIC)))
1370 {
1371 error=1;
1372 }
1373 else
1374 {
1375 #ifndef EMBEDDED_LIBRARY
1376 if (get_it_from_net)
1377 cache.read_function = _my_b_net_read;
1378
1379 if (mysql_bin_log.is_open())
1380 {
1381 cache.real_read_function= cache.read_function;
1382 cache.read_function= log_loaded_block;
1383 }
1384 #endif
1385 }
1386 }
1387 }
1388
1389
~READ_INFO()1390 READ_INFO::~READ_INFO()
1391 {
1392 ::end_io_cache(&cache);
1393 List_iterator<XML_TAG> xmlit(taglist);
1394 XML_TAG *t;
1395 while ((t= xmlit++))
1396 delete(t);
1397 }
1398
1399
terminator(const uchar * ptr,uint length)1400 inline bool READ_INFO::terminator(const uchar *ptr, uint length)
1401 {
1402 int chr=0; // Keep gcc happy
1403 uint i;
1404 for (i=1 ; i < length ; i++)
1405 {
1406 if ((chr=GET) != *(uchar*)++ptr)
1407 {
1408 break;
1409 }
1410 }
1411 if (i == length)
1412 return true;
1413 PUSH(chr);
1414 while (i-- > 1)
1415 PUSH(*--ptr);
1416 return false;
1417 }
1418
1419
1420 /**
1421 Read a field.
1422
1423 The data in the loaded file was presumably escaped using
1424 - either select_export::send_data() OUTFILE
1425 - or mysql_real_escape_string()
1426 using the same character set with the one specified in the current
1427 "LOAD DATA INFILE ... CHARACTER SET ..." (or the default LOAD character set).
1428
1429 Note, non-escaped multi-byte characters are scanned as a single entity.
1430 This is needed to correctly distinguish between:
1431 - 0x5C as an escape character versus
1432 - 0x5C as the second byte in a multi-byte sequence (big5, cp932, gbk, sjis)
1433
1434 Parts of escaped multi-byte characters are scanned on different loop
1435 iterations. See the comment about 0x5C handling in select_export::send_data()
1436 in sql_class.cc.
1437
1438 READ_INFO::read_field() does not check wellformedness.
1439 Raising wellformedness errors or warnings in READ_INFO::read_field()
1440 would be wrong, as the data after unescaping can go into a BLOB field,
1441 or into a TEXT/VARCHAR field of a different character set.
1442 The loop below only makes sure to revert escaping made by
1443 select_export::send_data() or mysql_real_escape_string().
1444 Wellformedness is checked later, during Field::store(str,length,cs) time.
1445
1446 Note, in some cases users can supply data which did not go through
1447 escaping properly. For example, utf8 "\<C3><A4>"
1448 (backslash followed by LATIN SMALL LETTER A WITH DIAERESIS)
1449 is improperly escaped data that could not be generated by
1450 select_export::send_data() / mysql_real_escape_string():
1451 - either there should be two backslashes: "\\<C3><A4>"
1452 - or there should be no backslashes at all: "<C3><A4>"
1453 "\<C3>" and "<A4> are scanned on two different loop iterations and
1454 store "<C3><A4>" into the field.
1455
1456 Note, adding useless escapes before multi-byte characters like in the
1457 example above is safe in case of utf8, but is not safe in case of
1458 character sets that have escape_with_backslash_is_dangerous==TRUE,
1459 such as big5, cp932, gbk, sjis. This can lead to mis-interpretation of the
1460 data. Suppose we have a big5 character "<EE><5C>" followed by <30> (digit 0).
1461 If we add an extra escape before this sequence, then we'll get
1462 <5C><EE><5C><30>. The first loop iteration will turn <5C><EE> into <EE>.
1463 The second loop iteration will turn <5C><30> into <30>.
1464 So the program that generates a dump file for further use with LOAD DATA
1465 must make sure to use escapes properly.
1466 */
1467
read_field()1468 int READ_INFO::read_field()
1469 {
1470 int chr,found_enclosed_char;
1471
1472 found_null=0;
1473 if (found_end_of_line)
1474 return 1; // One have to call next_line
1475
1476 /* Skip until we find 'line_start' */
1477
1478 if (start_of_line)
1479 { // Skip until line_start
1480 start_of_line=0;
1481 if (find_start_of_fields())
1482 return 1;
1483 }
1484 if ((chr=GET) == my_b_EOF)
1485 {
1486 found_end_of_line=eof=1;
1487 return 1;
1488 }
1489 data.length(0);
1490 if (chr == enclosed_char)
1491 {
1492 found_enclosed_char=enclosed_char;
1493 data.append(chr); // If error
1494 }
1495 else
1496 {
1497 found_enclosed_char= INT_MAX;
1498 PUSH(chr);
1499 }
1500
1501 for (;;)
1502 {
1503 // Make sure we have enough space for the longest multi-byte character.
1504 while (data.length() + charset()->mbmaxlen <= data.alloced_length())
1505 {
1506 chr = GET;
1507 if (chr == my_b_EOF)
1508 goto found_eof;
1509 if (chr == escape_char)
1510 {
1511 if ((chr=GET) == my_b_EOF)
1512 {
1513 data.append(escape_char);
1514 goto found_eof;
1515 }
1516 /*
1517 When escape_char == enclosed_char, we treat it like we do for
1518 handling quotes in SQL parsing -- you can double-up the
1519 escape_char to include it literally, but it doesn't do escapes
1520 like \n. This allows: LOAD DATA ... ENCLOSED BY '"' ESCAPED BY '"'
1521 with data like: "fie""ld1", "field2"
1522 */
1523 if (escape_char != enclosed_char || chr == escape_char)
1524 {
1525 data.append(unescape((char) chr));
1526 continue;
1527 }
1528 PUSH(chr);
1529 chr= escape_char;
1530 }
1531 #ifdef ALLOW_LINESEPARATOR_IN_STRINGS
1532 if (chr == m_line_term.initial_byte())
1533 #else
1534 if (chr == m_line_term.initial_byte() && found_enclosed_char == INT_MAX)
1535 #endif
1536 {
1537 if (terminator(m_line_term))
1538 { // Maybe unexpected linefeed
1539 enclosed=0;
1540 found_end_of_line=1;
1541 row_start= (uchar *) data.ptr();
1542 row_end= (uchar *) data.end();
1543 return 0;
1544 }
1545 }
1546 if (chr == found_enclosed_char)
1547 {
1548 if ((chr=GET) == found_enclosed_char)
1549 { // Remove dupplicated
1550 data.append(chr);
1551 continue;
1552 }
1553 // End of enclosed field if followed by field_term or line_term
1554 if (chr == my_b_EOF || terminator(chr, m_line_term))
1555 {
1556 /* Maybe unexpected linefeed */
1557 enclosed=1;
1558 found_end_of_line=1;
1559 row_start= (uchar *) data.ptr() + 1;
1560 row_end= (uchar *) data.end();
1561 return 0;
1562 }
1563 if (terminator(chr, m_field_term))
1564 {
1565 enclosed=1;
1566 row_start= (uchar *) data.ptr() + 1;
1567 row_end= (uchar *) data.end();
1568 return 0;
1569 }
1570 /*
1571 The string didn't terminate yet.
1572 Store back next character for the loop
1573 */
1574 PUSH(chr);
1575 /* copy the found term character to 'to' */
1576 chr= found_enclosed_char;
1577 }
1578 else if (chr == m_field_term.initial_byte() &&
1579 found_enclosed_char == INT_MAX)
1580 {
1581 if (terminator(m_field_term))
1582 {
1583 enclosed=0;
1584 row_start= (uchar *) data.ptr();
1585 row_end= (uchar *) data.end();
1586 return 0;
1587 }
1588 }
1589 data.append(chr);
1590 if (use_mb(charset()) && read_mbtail(&data))
1591 goto found_eof;
1592 }
1593 /*
1594 ** We come here if buffer is too small. Enlarge it and continue
1595 */
1596 if (data.reserve(IO_SIZE))
1597 return (error= 1);
1598 }
1599
1600 found_eof:
1601 enclosed=0;
1602 found_end_of_line=eof=1;
1603 row_start= (uchar *) data.ptr();
1604 row_end= (uchar *) data.end();
1605 return 0;
1606 }
1607
1608 /*
1609 Read a row with fixed length.
1610
1611 NOTES
1612 The row may not be fixed size on disk if there are escape
1613 characters in the file.
1614
1615 IMPLEMENTATION NOTE
1616 One can't use fixed length with multi-byte charset **
1617
1618 RETURN
1619 0 ok
1620 1 error
1621 */
1622
read_fixed_length()1623 int READ_INFO::read_fixed_length()
1624 {
1625 int chr;
1626 if (found_end_of_line)
1627 return 1; // One have to call next_line
1628
1629 if (start_of_line)
1630 { // Skip until line_start
1631 start_of_line=0;
1632 if (find_start_of_fields())
1633 return 1;
1634 }
1635
1636 for (data.length(0); data.length() < m_fixed_length ; )
1637 {
1638 if ((chr=GET) == my_b_EOF)
1639 goto found_eof;
1640 if (chr == escape_char)
1641 {
1642 if ((chr=GET) == my_b_EOF)
1643 {
1644 data.append(escape_char);
1645 goto found_eof;
1646 }
1647 data.append((uchar) unescape((char) chr));
1648 continue;
1649 }
1650 if (terminator(chr, m_line_term))
1651 { // Maybe unexpected linefeed
1652 found_end_of_line= true;
1653 break;
1654 }
1655 data.append(chr);
1656 }
1657 row_start= (uchar *) data.ptr();
1658 row_end= (uchar *) data.end(); // Found full line
1659 return 0;
1660
1661 found_eof:
1662 found_end_of_line=eof=1;
1663 row_start= (uchar *) data.ptr();
1664 row_end= (uchar *) data.end();
1665 return data.length() == 0 ? 1 : 0;
1666 }
1667
1668
next_line()1669 int READ_INFO::next_line()
1670 {
1671 line_cuted=0;
1672 start_of_line= m_line_start.length() != 0;
1673 if (found_end_of_line || eof)
1674 {
1675 found_end_of_line=0;
1676 return eof;
1677 }
1678 found_end_of_line=0;
1679 if (!m_line_term.length())
1680 return 0; // No lines
1681 for (;;)
1682 {
1683 int chlen;
1684 char buf[MY_CS_MBMAXLEN];
1685
1686 if (getbyte(&buf[0]))
1687 return 1; // EOF
1688
1689 if (use_mb(charset()) &&
1690 (chlen= my_charlen(charset(), buf, buf + 1)) != 1)
1691 {
1692 uint i;
1693 for (i= 1; MY_CS_IS_TOOSMALL(chlen); )
1694 {
1695 DBUG_ASSERT(i < sizeof(buf));
1696 DBUG_ASSERT(chlen != 1);
1697 if (getbyte(&buf[i++]))
1698 return 1; // EOF
1699 chlen= my_charlen(charset(), buf, buf + i);
1700 }
1701
1702 /*
1703 Either a complete multi-byte sequence,
1704 or a broken byte sequence was found.
1705 Check if the sequence is a prefix of the "LINES TERMINATED BY" string.
1706 */
1707 if ((uchar) buf[0] == m_line_term.initial_byte() &&
1708 i <= m_line_term.length() &&
1709 !memcmp(buf, m_line_term.ptr(), i))
1710 {
1711 if (m_line_term.length() == i)
1712 {
1713 /*
1714 We found a "LINES TERMINATED BY" string that consists
1715 of a single multi-byte character.
1716 */
1717 return 0;
1718 }
1719 /*
1720 buf[] is a prefix of "LINES TERMINATED BY".
1721 Now check the suffix. Length of the suffix of line_term_ptr
1722 that still needs to be checked is (line_term_length - i).
1723 Note, READ_INFO::terminator() assumes that the leftmost byte of the
1724 argument is already scanned from the file and is checked to
1725 be a known prefix (e.g. against line_term.initial_char()).
1726 So we need to pass one extra byte.
1727 */
1728 if (terminator(m_line_term.ptr() + i - 1,
1729 m_line_term.length() - i + 1))
1730 return 0;
1731 }
1732 /*
1733 Here we have a good multi-byte sequence or a broken byte sequence,
1734 and the sequence is not equal to "LINES TERMINATED BY".
1735 No needs to check for escape_char, because:
1736 - multi-byte escape characters in "FIELDS ESCAPED BY" are not
1737 supported and are rejected at parse time.
1738 - broken single-byte sequences are not recognized as escapes,
1739 they are considered to be a part of the data and are converted to
1740 question marks.
1741 */
1742 line_cuted= true;
1743 continue;
1744 }
1745 if (buf[0] == escape_char)
1746 {
1747 line_cuted= true;
1748 if (GET == my_b_EOF)
1749 return 1;
1750 continue;
1751 }
1752 if (terminator(buf[0], m_line_term))
1753 return 0;
1754 line_cuted= true;
1755 }
1756 }
1757
1758
find_start_of_fields()1759 bool READ_INFO::find_start_of_fields()
1760 {
1761 for (int chr= GET ; chr != my_b_EOF ; chr= GET)
1762 {
1763 if (terminator(chr, m_line_start))
1764 return false;
1765 }
1766 return (found_end_of_line= eof= true);
1767 }
1768
1769
1770 /*
1771 Clear taglist from tags with a specified level
1772 */
clear_level(int level_arg)1773 int READ_INFO::clear_level(int level_arg)
1774 {
1775 DBUG_ENTER("READ_INFO::read_xml clear_level");
1776 List_iterator<XML_TAG> xmlit(taglist);
1777 xmlit.rewind();
1778 XML_TAG *tag;
1779
1780 while ((tag= xmlit++))
1781 {
1782 if(tag->level >= level_arg)
1783 {
1784 xmlit.remove();
1785 delete tag;
1786 }
1787 }
1788 DBUG_RETURN(0);
1789 }
1790
1791
1792 /*
1793 Convert an XML entity to Unicode value.
1794 Return -1 on error;
1795 */
1796 static int
my_xml_entity_to_char(const char * name,uint length)1797 my_xml_entity_to_char(const char *name, uint length)
1798 {
1799 if (length == 2)
1800 {
1801 if (!memcmp(name, "gt", length))
1802 return '>';
1803 if (!memcmp(name, "lt", length))
1804 return '<';
1805 }
1806 else if (length == 3)
1807 {
1808 if (!memcmp(name, "amp", length))
1809 return '&';
1810 }
1811 else if (length == 4)
1812 {
1813 if (!memcmp(name, "quot", length))
1814 return '"';
1815 if (!memcmp(name, "apos", length))
1816 return '\'';
1817 }
1818 return -1;
1819 }
1820
1821
1822 /**
1823 @brief Convert newline, linefeed, tab to space
1824
1825 @param chr character
1826
1827 @details According to the "XML 1.0" standard,
1828 only space (#x20) characters, carriage returns,
1829 line feeds or tabs are considered as spaces.
1830 Convert all of them to space (#x20) for parsing simplicity.
1831 */
1832 static int
my_tospace(int chr)1833 my_tospace(int chr)
1834 {
1835 return (chr == '\t' || chr == '\r' || chr == '\n') ? ' ' : chr;
1836 }
1837
1838
1839 /*
1840 Read an xml value: handle multibyte and xml escape
1841 */
read_value(int delim,String * val)1842 int READ_INFO::read_value(int delim, String *val)
1843 {
1844 int chr;
1845 String tmp;
1846
1847 for (chr= GET; my_tospace(chr) != delim && chr != my_b_EOF; chr= GET)
1848 {
1849 if(chr == '&')
1850 {
1851 tmp.length(0);
1852 for (chr= my_tospace(GET) ; chr != ';' ; chr= my_tospace(GET))
1853 {
1854 if (chr == my_b_EOF)
1855 return chr;
1856 tmp.append(chr);
1857 }
1858 if ((chr= my_xml_entity_to_char(tmp.ptr(), tmp.length())) >= 0)
1859 val->append(chr);
1860 else
1861 {
1862 val->append('&');
1863 val->append(tmp);
1864 val->append(';');
1865 }
1866 }
1867 else
1868 {
1869 val->append(chr);
1870 if (use_mb(charset()) && read_mbtail(val))
1871 return my_b_EOF;
1872 }
1873 }
1874 return my_tospace(chr);
1875 }
1876
1877
1878 /*
1879 Read a record in xml format
1880 tags and attributes are stored in taglist
1881 when tag set in ROWS IDENTIFIED BY is closed, we are ready and return
1882 */
read_xml(THD * thd)1883 int READ_INFO::read_xml(THD *thd)
1884 {
1885 DBUG_ENTER("READ_INFO::read_xml");
1886 int chr, chr2, chr3;
1887 int delim= 0;
1888 String tag, attribute, value;
1889 bool in_tag= false;
1890
1891 tag.length(0);
1892 attribute.length(0);
1893 value.length(0);
1894
1895 for (chr= my_tospace(GET); chr != my_b_EOF ; )
1896 {
1897 switch(chr){
1898 case '<': /* read tag */
1899 /* TODO: check if this is a comment <!-- comment --> */
1900 chr= my_tospace(GET);
1901 if(chr == '!')
1902 {
1903 chr2= GET;
1904 chr3= GET;
1905
1906 if(chr2 == '-' && chr3 == '-')
1907 {
1908 chr2= 0;
1909 chr3= 0;
1910 chr= my_tospace(GET);
1911
1912 while(chr != '>' || chr2 != '-' || chr3 != '-')
1913 {
1914 if(chr == '-')
1915 {
1916 chr3= chr2;
1917 chr2= chr;
1918 }
1919 else if (chr2 == '-')
1920 {
1921 chr2= 0;
1922 chr3= 0;
1923 }
1924 chr= my_tospace(GET);
1925 if (chr == my_b_EOF)
1926 goto found_eof;
1927 }
1928 break;
1929 }
1930 }
1931
1932 tag.length(0);
1933 while(chr != '>' && chr != ' ' && chr != '/' && chr != my_b_EOF)
1934 {
1935 if(chr != delim) /* fix for the '<field name =' format */
1936 tag.append(chr);
1937 chr= my_tospace(GET);
1938 }
1939
1940 // row tag should be in ROWS IDENTIFIED BY '<row>' - stored in line_term
1941 if((tag.length() == m_line_term.length() - 2) &&
1942 (memcmp(tag.ptr(), m_line_term.ptr() + 1, tag.length()) == 0))
1943 {
1944 DBUG_PRINT("read_xml", ("start-of-row: %i %s %s",
1945 level,tag.c_ptr_safe(), m_line_term.ptr()));
1946 }
1947
1948 if(chr == ' ' || chr == '>')
1949 {
1950 level++;
1951 clear_level(level + 1);
1952 }
1953
1954 if (chr == ' ')
1955 in_tag= true;
1956 else
1957 in_tag= false;
1958 break;
1959
1960 case ' ': /* read attribute */
1961 while(chr == ' ') /* skip blanks */
1962 chr= my_tospace(GET);
1963
1964 if(!in_tag)
1965 break;
1966
1967 while(chr != '=' && chr != '/' && chr != '>' && chr != my_b_EOF)
1968 {
1969 attribute.append(chr);
1970 chr= my_tospace(GET);
1971 }
1972 break;
1973
1974 case '>': /* end tag - read tag value */
1975 in_tag= false;
1976 chr= read_value('<', &value);
1977 if(chr == my_b_EOF)
1978 goto found_eof;
1979
1980 /* save value to list */
1981 if (tag.length() > 0 && value.length() > 0)
1982 {
1983 DBUG_PRINT("read_xml", ("lev:%i tag:%s val:%s",
1984 level,tag.c_ptr_safe(), value.c_ptr_safe()));
1985 XML_TAG *tmp= new XML_TAG(level, tag, value);
1986 if (!tmp || taglist.push_front(tmp, thd->mem_root))
1987 DBUG_RETURN(1); // End of memory
1988 }
1989 tag.length(0);
1990 value.length(0);
1991 attribute.length(0);
1992 break;
1993
1994 case '/': /* close tag */
1995 chr= my_tospace(GET);
1996 /* Decrease the 'level' only when (i) It's not an */
1997 /* (without space) empty tag i.e. <tag/> or, (ii) */
1998 /* It is of format <row col="val" .../> */
1999 if(chr != '>' || in_tag)
2000 {
2001 level--;
2002 in_tag= false;
2003 }
2004 if(chr != '>') /* if this is an empty tag <tag /> */
2005 tag.length(0); /* we should keep tag value */
2006 while(chr != '>' && chr != my_b_EOF)
2007 {
2008 tag.append(chr);
2009 chr= my_tospace(GET);
2010 }
2011
2012 if((tag.length() == m_line_term.length() - 2) &&
2013 (memcmp(tag.ptr(), m_line_term.ptr() + 1, tag.length()) == 0))
2014 {
2015 DBUG_PRINT("read_xml", ("found end-of-row %i %s",
2016 level, tag.c_ptr_safe()));
2017 DBUG_RETURN(0); //normal return
2018 }
2019 chr= my_tospace(GET);
2020 break;
2021
2022 case '=': /* attribute name end - read the value */
2023 //check for tag field and attribute name
2024 if(!strcmp(tag.c_ptr_safe(), "field") &&
2025 !strcmp(attribute.c_ptr_safe(), "name"))
2026 {
2027 /*
2028 this is format <field name="xx">xx</field>
2029 where actual fieldname is in attribute
2030 */
2031 delim= my_tospace(GET);
2032 tag.length(0);
2033 attribute.length(0);
2034 chr= '<'; /* we pretend that it is a tag */
2035 level--;
2036 break;
2037 }
2038
2039 //check for " or '
2040 chr= GET;
2041 if (chr == my_b_EOF)
2042 goto found_eof;
2043 if(chr == '"' || chr == '\'')
2044 {
2045 delim= chr;
2046 }
2047 else
2048 {
2049 delim= ' '; /* no delimiter, use space */
2050 PUSH(chr);
2051 }
2052
2053 chr= read_value(delim, &value);
2054 if (attribute.length() > 0 && value.length() > 0)
2055 {
2056 DBUG_PRINT("read_xml", ("lev:%i att:%s val:%s",
2057 level + 1,
2058 attribute.c_ptr_safe(),
2059 value.c_ptr_safe()));
2060 XML_TAG *tmp= new XML_TAG(level + 1, attribute, value);
2061 if (!tmp || taglist.push_front(tmp, thd->mem_root))
2062 DBUG_RETURN(1); // End of memory
2063 }
2064 attribute.length(0);
2065 value.length(0);
2066 if (chr != ' ')
2067 chr= my_tospace(GET);
2068 break;
2069
2070 default:
2071 chr= my_tospace(GET);
2072 } /* end switch */
2073 } /* end while */
2074
2075 found_eof:
2076 DBUG_PRINT("read_xml",("Found eof"));
2077 eof= 1;
2078 DBUG_RETURN(1);
2079 }
2080