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