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