~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to server/sql_load.cc

Replacing all bzero() calls with memset() calls and removing the bzero.c file.
Also removing check for bzero from the 'configure.ac' autoconf file.

Show diffs side-by-side

added added

removed removed

Lines of Context:
15
15
 
16
16
 
17
17
/* Copy data from a textfile to table */
 
18
/* 2006-12 Erik Wetterberg : LOAD XML added */
18
19
 
19
 
#include <drizzled/server_includes.h>
 
20
#include "mysql_priv.h"
 
21
#include <my_dir.h>
 
22
#include <m_ctype.h>
20
23
#include "sql_repl.h"
21
 
#include <drizzled/error.h>
22
 
#include <drizzled/data_home.h>
 
24
 
 
25
class XML_TAG {
 
26
public:
 
27
  int level;
 
28
  String field;
 
29
  String value;
 
30
  XML_TAG(int l, String f, String v);
 
31
};
 
32
 
 
33
 
 
34
XML_TAG::XML_TAG(int l, String f, String v)
 
35
{
 
36
  level= l;
 
37
  field.append(f);
 
38
  value.append(v);
 
39
}
23
40
 
24
41
 
25
42
class READ_INFO {
26
43
  File  file;
27
 
  unsigned char *buffer,                        /* Buffer for read text */
 
44
  uchar *buffer,                        /* Buffer for read text */
28
45
        *end_of_buff;                   /* Data in bufferts ends here */
29
46
  uint  buff_length,                    /* Length of buffert */
30
47
        max_length;                     /* Max length of row */
36
53
  bool  need_end_io_cache;
37
54
  IO_CACHE cache;
38
55
  NET *io_net;
 
56
  int level; /* for load xml */
39
57
 
40
58
public:
41
59
  bool error,line_cuted,found_null,enclosed;
42
 
  unsigned char *row_start,                     /* Found row starts here */
 
60
  uchar *row_start,                     /* Found row starts here */
43
61
        *row_end;                       /* Found row ends here */
44
 
  const CHARSET_INFO *read_charset;
 
62
  CHARSET_INFO *read_charset;
45
63
 
46
 
  READ_INFO(File file,uint32_t tot_length, const CHARSET_INFO * const cs,
 
64
  READ_INFO(File file,uint tot_length,CHARSET_INFO *cs,
47
65
            String &field_term,String &line_start,String &line_term,
48
66
            String &enclosed,int escape,bool get_it_from_net, bool is_fifo);
49
67
  ~READ_INFO();
51
69
  int read_fixed_length(void);
52
70
  int next_line(void);
53
71
  char unescape(char chr);
54
 
  int terminator(char *ptr,uint32_t length);
 
72
  int terminator(char *ptr,uint length);
55
73
  bool find_start_of_fields();
 
74
  /* load xml */
 
75
  List<XML_TAG> taglist;
 
76
  int read_value(int delim, String *val);
 
77
  int read_xml();
 
78
  int clear_level(int level);
56
79
 
57
80
  /*
58
81
    We need to force cache close before destructor is invoked to log
67
90
  /*
68
91
    Either this method, or we need to make cache public
69
92
    Arg must be set from mysql_load() since constructor does not see
70
 
    either the table or Session value
 
93
    either the table or THD value
71
94
  */
72
95
  void set_io_cache_arg(void* arg) { cache.arg = arg; }
73
96
};
74
97
 
75
 
static int read_fixed_length(Session *session, COPY_INFO &info, TableList *table_list,
 
98
static int read_fixed_length(THD *thd, COPY_INFO &info, TABLE_LIST *table_list,
76
99
                             List<Item> &fields_vars, List<Item> &set_fields,
77
100
                             List<Item> &set_values, READ_INFO &read_info,
78
 
                             uint32_t skip_lines,
 
101
                             ulong skip_lines,
79
102
                             bool ignore_check_option_errors);
80
 
static int read_sep_field(Session *session, COPY_INFO &info, TableList *table_list,
 
103
static int read_sep_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list,
81
104
                          List<Item> &fields_vars, List<Item> &set_fields,
82
105
                          List<Item> &set_values, READ_INFO &read_info,
83
 
                          String &enclosed, uint32_t skip_lines,
 
106
                          String &enclosed, ulong skip_lines,
84
107
                          bool ignore_check_option_errors);
85
108
 
86
 
static bool write_execute_load_query_log_event(Session *session,
 
109
static int read_xml_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list,
 
110
                          List<Item> &fields_vars, List<Item> &set_fields,
 
111
                          List<Item> &set_values, READ_INFO &read_info,
 
112
                          String &enclosed, ulong skip_lines,
 
113
                          bool ignore_check_option_errors);
 
114
 
 
115
static bool write_execute_load_query_log_event(THD *thd,
87
116
                                               bool duplicates, bool ignore,
88
117
                                               bool transactional_table,
89
 
                                               Session::killed_state killed_status);
 
118
                                               THD::killed_state killed_status);
90
119
 
91
120
/*
92
121
  Execute LOAD DATA query
93
122
 
94
123
  SYNOPSYS
95
124
    mysql_load()
96
 
      session - current thread
 
125
      thd - current thread
97
126
      ex  - sql_exchange object representing source file and its parsing rules
98
127
      table_list  - list of tables to which we are loading data
99
128
      fields_vars - list of fields and variables to which we read
109
138
    true - error / false - success
110
139
*/
111
140
 
112
 
int mysql_load(Session *session,sql_exchange *ex,TableList *table_list,
 
141
int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
113
142
                List<Item> &fields_vars, List<Item> &set_fields,
114
143
                List<Item> &set_values,
115
144
                enum enum_duplicates handle_duplicates, bool ignore,
117
146
{
118
147
  char name[FN_REFLEN];
119
148
  File file;
120
 
  Table *table= NULL;
 
149
  TABLE *table= NULL;
121
150
  int error;
122
151
  String *field_term=ex->field_term,*escaped=ex->escaped;
123
152
  String *enclosed=ex->enclosed;
129
158
    If this is not set, we will use the directory where the table to be
130
159
    loaded is located
131
160
  */
132
 
  char *tdb= session->db ? session->db : db;            // Result is never null
133
 
  uint32_t skip_lines= ex->skip_lines;
 
161
  char *tdb= thd->db ? thd->db : db;            // Result is never null
 
162
  ulong skip_lines= ex->skip_lines;
134
163
  bool transactional_table;
135
 
  Session::killed_state killed_status= Session::NOT_KILLED;
 
164
  THD::killed_state killed_status= THD::NOT_KILLED;
136
165
 
137
166
  if (escaped->length() > 1 || enclosed->length() > 1)
138
167
  {
140
169
               MYF(0));
141
170
    return(true);
142
171
  }
143
 
  if (open_and_lock_tables(session, table_list))
 
172
  if (open_and_lock_tables(thd, table_list))
144
173
    return(true);
145
 
  if (setup_tables_and_check_access(session, &session->lex->select_lex.context,
146
 
                                    &session->lex->select_lex.top_join_list,
 
174
  if (setup_tables_and_check_access(thd, &thd->lex->select_lex.context,
 
175
                                    &thd->lex->select_lex.top_join_list,
147
176
                                    table_list,
148
 
                                    &session->lex->select_lex.leaf_tables, true))
 
177
                                    &thd->lex->select_lex.leaf_tables, true))
149
178
     return(-1);
150
179
 
151
180
  /*
156
185
    table is marked to be 'used for insert' in which case we should never
157
186
    mark this table as 'const table' (ie, one that has only one row).
158
187
  */
159
 
  if (unique_table(session, table_list, table_list->next_global, 0))
 
188
  if (unique_table(thd, table_list, table_list->next_global, 0))
160
189
  {
161
190
    my_error(ER_UPDATE_TABLE_USED, MYF(0), table_list->table_name);
162
191
    return(true);
176
205
      Let us also prepare SET clause, altough it is probably empty
177
206
      in this case.
178
207
    */
179
 
    if (setup_fields(session, 0, set_fields, MARK_COLUMNS_WRITE, 0, 0) ||
180
 
        setup_fields(session, 0, set_values, MARK_COLUMNS_READ, 0, 0))
 
208
    if (setup_fields(thd, 0, set_fields, MARK_COLUMNS_WRITE, 0, 0) ||
 
209
        setup_fields(thd, 0, set_values, MARK_COLUMNS_READ, 0, 0))
181
210
      return(true);
182
211
  }
183
212
  else
184
213
  {                                             // Part field list
185
214
    /* TODO: use this conds for 'WITH CHECK OPTIONS' */
186
 
    if (setup_fields(session, 0, fields_vars, MARK_COLUMNS_WRITE, 0, 0) ||
187
 
        setup_fields(session, 0, set_fields, MARK_COLUMNS_WRITE, 0, 0) ||
188
 
        check_that_all_fields_are_given_values(session, table, table_list))
 
215
    if (setup_fields(thd, 0, fields_vars, MARK_COLUMNS_WRITE, 0, 0) ||
 
216
        setup_fields(thd, 0, set_fields, MARK_COLUMNS_WRITE, 0, 0) ||
 
217
        check_that_all_fields_are_given_values(thd, table, table_list))
189
218
      return(true);
190
219
    /*
191
220
      Check whenever TIMESTAMP field with auto-set feature specified
203
232
      }
204
233
    }
205
234
    /* Fix the expressions in SET clause */
206
 
    if (setup_fields(session, 0, set_values, MARK_COLUMNS_READ, 0, 0))
 
235
    if (setup_fields(thd, 0, set_values, MARK_COLUMNS_READ, 0, 0))
207
236
      return(true);
208
237
  }
209
238
 
210
239
  table->mark_columns_needed_for_insert();
211
240
 
212
 
  uint32_t tot_length=0;
 
241
  uint tot_length=0;
213
242
  bool use_blobs= 0, use_vars= 0;
214
243
  List_iterator_fast<Item> it(fields_vars);
215
244
  Item *item;
250
279
 
251
280
  if (read_file_from_client)
252
281
  {
253
 
    (void)net_request_file(&session->net,ex->file_name);
 
282
    (void)net_request_file(&thd->net,ex->file_name);
254
283
    file = -1;
255
284
  }
256
285
  else
260
289
#endif
261
290
    if (!dirname_length(ex->file_name))
262
291
    {
263
 
      strcpy(name, mysql_real_data_home);
264
 
      strncat(name, tdb, FN_REFLEN-strlen(mysql_real_data_home)-1);
 
292
      strxnmov(name, FN_REFLEN-1, mysql_real_data_home, tdb, NullS);
265
293
      (void) fn_format(name, ex->file_name, name, "",
266
294
                       MY_RELATIVE_PATH | MY_UNPACK_FILENAME);
267
295
    }
283
311
        return(true);
284
312
 
285
313
      // if we are not in slave thread, the file must be:
286
 
      if (!session->slave_thread &&
 
314
      if (!thd->slave_thread &&
287
315
          !((stat_info.st_mode & S_IROTH) == S_IROTH &&  // readable by others
288
316
            (stat_info.st_mode & S_IFLNK) != S_IFLNK && // and not a symlink
289
317
            ((stat_info.st_mode & S_IFREG) == S_IFREG ||
300
328
  }
301
329
 
302
330
  COPY_INFO info;
303
 
  memset(&info, 0, sizeof(info));
 
331
  memset((char*) &info, 0, sizeof(info));
304
332
  info.ignore= ignore;
305
333
  info.handle_duplicates=handle_duplicates;
306
334
  info.escape_char=escaped->length() ? (*escaped)[0] : INT_MAX;
307
335
 
308
336
  READ_INFO read_info(file,tot_length,
309
 
                      ex->cs ? ex->cs : session->variables.collation_database,
 
337
                      ex->cs ? ex->cs : thd->variables.collation_database,
310
338
                      *field_term,*ex->line_start, *ex->line_term, *enclosed,
311
339
                      info.escape_char, read_file_from_client, is_fifo);
312
340
  if (read_info.error)
318
346
 
319
347
  if (mysql_bin_log.is_open())
320
348
  {
321
 
    lf_info.session = session;
 
349
    lf_info.thd = thd;
322
350
    lf_info.wrote_create_file = 0;
323
351
    lf_info.last_pos_in_file = HA_POS_ERROR;
324
352
    lf_info.log_delayed= transactional_table;
325
353
    read_info.set_io_cache_arg((void*) &lf_info);
326
354
  }
327
355
 
328
 
  session->count_cuted_fields= CHECK_FIELD_WARN;                /* calc cuted fields */
329
 
  session->cuted_fields=0L;
 
356
  thd->count_cuted_fields= CHECK_FIELD_WARN;            /* calc cuted fields */
 
357
  thd->cuted_fields=0L;
330
358
  /* Skip lines if there is a line terminator */
331
 
  if (ex->line_term->length())
 
359
  if (ex->line_term->length() && ex->filetype != FILETYPE_XML)
332
360
  {
333
361
    /* ex->skip_lines needs to be preserved for logging */
334
362
    while (skip_lines > 0)
351
379
    table->file->ha_start_bulk_insert((ha_rows) 0);
352
380
    table->copy_blobs=1;
353
381
 
354
 
    session->abort_on_warning= true;
 
382
    thd->abort_on_warning= (!ignore &&
 
383
                            (thd->variables.sql_mode &
 
384
                             (MODE_STRICT_TRANS_TABLES |
 
385
                              MODE_STRICT_ALL_TABLES)));
355
386
 
356
 
    if (!field_term->length() && !enclosed->length())
357
 
      error= read_fixed_length(session, info, table_list, fields_vars,
 
387
    if (ex->filetype == FILETYPE_XML) /* load xml */
 
388
      error= read_xml_field(thd, info, table_list, fields_vars,
 
389
                            set_fields, set_values, read_info,
 
390
                            *(ex->line_term), skip_lines, ignore);
 
391
    else if (!field_term->length() && !enclosed->length())
 
392
      error= read_fixed_length(thd, info, table_list, fields_vars,
358
393
                               set_fields, set_values, read_info,
359
394
                               skip_lines, ignore);
360
395
    else
361
 
      error= read_sep_field(session, info, table_list, fields_vars,
 
396
      error= read_sep_field(thd, info, table_list, fields_vars,
362
397
                            set_fields, set_values, read_info,
363
398
                            *enclosed, skip_lines, ignore);
364
399
    if (table->file->ha_end_bulk_insert() && !error)
374
409
    my_close(file,MYF(0));
375
410
  free_blobs(table);                            /* if pack_blob was used */
376
411
  table->copy_blobs=0;
377
 
  session->count_cuted_fields= CHECK_FIELD_IGNORE;
 
412
  thd->count_cuted_fields= CHECK_FIELD_IGNORE;
378
413
  /* 
379
414
     simulated killing in the middle of per-row loop
380
415
     must be effective for binlogging
381
416
  */
382
 
  killed_status= (error == 0)? Session::NOT_KILLED : session->killed;
 
417
  killed_status= (error == 0)? THD::NOT_KILLED : thd->killed;
383
418
  if (error)
384
419
  {
385
420
    if (read_file_from_client)
415
450
        /* If the file was not empty, wrote_create_file is true */
416
451
        if (lf_info.wrote_create_file)
417
452
        {
418
 
          if (session->transaction.stmt.modified_non_trans_table)
419
 
            write_execute_load_query_log_event(session, handle_duplicates,
 
453
          if (thd->transaction.stmt.modified_non_trans_table)
 
454
            write_execute_load_query_log_event(thd, handle_duplicates,
420
455
                                               ignore, transactional_table,
421
456
                                               killed_status);
422
457
          else
423
458
          {
424
 
            Delete_file_log_event d(session, db, transactional_table);
 
459
            Delete_file_log_event d(thd, db, transactional_table);
425
460
            d.flags|= LOG_EVENT_UPDATE_TABLE_MAP_VERSION_F;
426
461
            mysql_bin_log.write(&d);
427
462
          }
431
466
    error= -1;                          // Error on read
432
467
    goto err;
433
468
  }
434
 
  sprintf(name, ER(ER_LOAD_INFO), (uint32_t) info.records, (uint32_t) info.deleted,
435
 
          (uint32_t) (info.records - info.copied), (uint32_t) session->cuted_fields);
 
469
  sprintf(name, ER(ER_LOAD_INFO), (ulong) info.records, (ulong) info.deleted,
 
470
          (ulong) (info.records - info.copied), (ulong) thd->cuted_fields);
436
471
 
437
 
  if (session->transaction.stmt.modified_non_trans_table)
438
 
    session->transaction.all.modified_non_trans_table= true;
 
472
  if (thd->transaction.stmt.modified_non_trans_table)
 
473
    thd->transaction.all.modified_non_trans_table= true;
439
474
 
440
475
  if (mysql_bin_log.is_open())
441
476
  {
447
482
      version for the binary log to mark that table maps are invalid
448
483
      after this point.
449
484
     */
450
 
    if (session->current_stmt_binlog_row_based)
451
 
      session->binlog_flush_pending_rows_event(true);
 
485
    if (thd->current_stmt_binlog_row_based)
 
486
      thd->binlog_flush_pending_rows_event(true);
452
487
    else
453
488
    {
454
489
      /*
459
494
      read_info.end_io_cache();
460
495
      if (lf_info.wrote_create_file)
461
496
      {
462
 
        write_execute_load_query_log_event(session, handle_duplicates, ignore,
 
497
        write_execute_load_query_log_event(thd, handle_duplicates, ignore,
463
498
                                           transactional_table,killed_status);
464
499
      }
465
500
    }
466
501
  }
467
502
 
468
503
  /* ok to client sent only after binlog write and engine commit */
469
 
  my_ok(session, info.copied + info.deleted, 0L, name);
 
504
  my_ok(thd, info.copied + info.deleted, 0L, name);
470
505
err:
471
506
  assert(transactional_table || !(info.copied || info.deleted) ||
472
 
              session->transaction.stmt.modified_non_trans_table);
 
507
              thd->transaction.stmt.modified_non_trans_table);
473
508
  table->file->ha_release_auto_increment();
474
509
  table->auto_increment_field_not_null= false;
475
 
  session->abort_on_warning= 0;
 
510
  thd->abort_on_warning= 0;
476
511
  return(error);
477
512
}
478
513
 
479
514
 
480
515
/* Not a very useful function; just to avoid duplication of code */
481
 
static bool write_execute_load_query_log_event(Session *session,
 
516
static bool write_execute_load_query_log_event(THD *thd,
482
517
                                               bool duplicates, bool ignore,
483
518
                                               bool transactional_table,
484
 
                                               Session::killed_state killed_err_arg)
 
519
                                               THD::killed_state killed_err_arg)
485
520
{
486
521
  Execute_load_query_log_event
487
 
    e(session, session->query, session->query_length,
488
 
      (char*)session->lex->fname_start - (char*)session->query,
489
 
      (char*)session->lex->fname_end - (char*)session->query,
 
522
    e(thd, thd->query, thd->query_length,
 
523
      (char*)thd->lex->fname_start - (char*)thd->query,
 
524
      (char*)thd->lex->fname_end - (char*)thd->query,
490
525
      (duplicates == DUP_REPLACE) ? LOAD_DUP_REPLACE :
491
526
      (ignore ? LOAD_DUP_IGNORE : LOAD_DUP_ERROR),
492
527
      transactional_table, false, killed_err_arg);
500
535
****************************************************************************/
501
536
 
502
537
static int
503
 
read_fixed_length(Session *session, COPY_INFO &info, TableList *table_list,
 
538
read_fixed_length(THD *thd, COPY_INFO &info, TABLE_LIST *table_list,
504
539
                  List<Item> &fields_vars, List<Item> &set_fields,
505
540
                  List<Item> &set_values, READ_INFO &read_info,
506
 
                  uint32_t skip_lines, bool ignore_check_option_errors)
 
541
                  ulong skip_lines, bool ignore_check_option_errors)
507
542
{
508
543
  List_iterator_fast<Item> it(fields_vars);
509
544
  Item_field *sql_field;
510
 
  Table *table= table_list->table;
 
545
  TABLE *table= table_list->table;
511
546
  uint64_t id;
512
547
  bool err;
513
548
 
515
550
 
516
551
  while (!read_info.read_fixed_length())
517
552
  {
518
 
    if (session->killed)
 
553
    if (thd->killed)
519
554
    {
520
 
      session->send_kill_message();
 
555
      thd->send_kill_message();
521
556
      return(1);
522
557
    }
523
558
    if (skip_lines)
532
567
      continue;
533
568
    }
534
569
    it.rewind();
535
 
    unsigned char *pos=read_info.row_start;
 
570
    uchar *pos=read_info.row_start;
536
571
#ifdef HAVE_purify
537
572
    read_info.row_end[0]=0;
538
573
#endif
556
591
 
557
592
      if (pos == read_info.row_end)
558
593
      {
559
 
        session->cuted_fields++;                        /* Not enough fields */
560
 
        push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_WARN, 
 
594
        thd->cuted_fields++;                    /* Not enough fields */
 
595
        push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, 
561
596
                            ER_WARN_TOO_FEW_RECORDS, 
562
 
                            ER(ER_WARN_TOO_FEW_RECORDS), session->row_count);
563
 
        if (!field->maybe_null() && field->type() == DRIZZLE_TYPE_TIMESTAMP)
 
597
                            ER(ER_WARN_TOO_FEW_RECORDS), thd->row_count);
 
598
        if (!field->maybe_null() && field->type() == FIELD_TYPE_TIMESTAMP)
564
599
            ((Field_timestamp*) field)->set_time();
565
600
      }
566
601
      else
567
602
      {
568
 
        uint32_t length;
569
 
        unsigned char save_chr;
 
603
        uint length;
 
604
        uchar save_chr;
570
605
        if ((length=(uint) (read_info.row_end-pos)) >
571
606
            field->field_length)
572
607
          length=field->field_length;
579
614
    }
580
615
    if (pos != read_info.row_end)
581
616
    {
582
 
      session->cuted_fields++;                  /* To long row */
583
 
      push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_WARN, 
 
617
      thd->cuted_fields++;                      /* To long row */
 
618
      push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, 
584
619
                          ER_WARN_TOO_MANY_RECORDS, 
585
 
                          ER(ER_WARN_TOO_MANY_RECORDS), session->row_count); 
 
620
                          ER(ER_WARN_TOO_MANY_RECORDS), thd->row_count); 
586
621
    }
587
622
 
588
 
    if (session->killed ||
589
 
        fill_record(session, set_fields, set_values,
 
623
    if (thd->killed ||
 
624
        fill_record(thd, set_fields, set_values,
590
625
                    ignore_check_option_errors))
591
626
      return(1);
592
627
 
593
 
    err= write_record(session, table, &info);
 
628
    err= write_record(thd, table, &info);
594
629
    table->auto_increment_field_not_null= false;
595
630
    if (err)
596
631
      return(1);
603
638
      break;
604
639
    if (read_info.line_cuted)
605
640
    {
606
 
      session->cuted_fields++;                  /* To long row */
607
 
      push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_WARN, 
 
641
      thd->cuted_fields++;                      /* To long row */
 
642
      push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, 
608
643
                          ER_WARN_TOO_MANY_RECORDS, 
609
 
                          ER(ER_WARN_TOO_MANY_RECORDS), session->row_count); 
 
644
                          ER(ER_WARN_TOO_MANY_RECORDS), thd->row_count); 
610
645
    }
611
 
    session->row_count++;
 
646
    thd->row_count++;
612
647
  }
613
648
  return(test(read_info.error));
614
649
}
616
651
 
617
652
 
618
653
static int
619
 
read_sep_field(Session *session, COPY_INFO &info, TableList *table_list,
 
654
read_sep_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list,
620
655
               List<Item> &fields_vars, List<Item> &set_fields,
621
656
               List<Item> &set_values, READ_INFO &read_info,
622
 
               String &enclosed, uint32_t skip_lines,
 
657
               String &enclosed, ulong skip_lines,
623
658
               bool ignore_check_option_errors)
624
659
{
625
660
  List_iterator_fast<Item> it(fields_vars);
626
661
  Item *item;
627
 
  Table *table= table_list->table;
628
 
  uint32_t enclosed_length;
 
662
  TABLE *table= table_list->table;
 
663
  uint enclosed_length;
629
664
  uint64_t id;
630
665
  bool err;
631
666
 
634
669
 
635
670
  for (;;it.rewind())
636
671
  {
637
 
    if (session->killed)
 
672
    if (thd->killed)
638
673
    {
639
 
      session->send_kill_message();
 
674
      thd->send_kill_message();
640
675
      return(1);
641
676
    }
642
677
 
644
679
 
645
680
    while ((item= it++))
646
681
    {
647
 
      uint32_t length;
648
 
      unsigned char *pos;
 
682
      uint length;
 
683
      uchar *pos;
649
684
      Item *real_item;
650
685
 
651
686
      if (read_info.read_field())
670
705
          if (field->reset())
671
706
          {
672
707
            my_error(ER_WARN_NULL_TO_NOTNULL, MYF(0), field->field_name,
673
 
                     session->row_count);
 
708
                     thd->row_count);
674
709
            return(1);
675
710
          }
676
711
          field->set_null();
677
712
          if (!field->maybe_null())
678
713
          {
679
 
            if (field->type() == DRIZZLE_TYPE_TIMESTAMP)
 
714
            if (field->type() == MYSQL_TYPE_TIMESTAMP)
680
715
              ((Field_timestamp*) field)->set_time();
681
716
            else if (field != table->next_number_field)
682
 
              field->set_warning(DRIZZLE_ERROR::WARN_LEVEL_WARN,
 
717
              field->set_warning(MYSQL_ERROR::WARN_LEVEL_WARN,
683
718
                                 ER_WARN_NULL_TO_NOTNULL, 1);
684
719
          }
685
720
        }
738
773
          if (field->reset())
739
774
          {
740
775
            my_error(ER_WARN_NULL_TO_NOTNULL, MYF(0),field->field_name,
741
 
                     session->row_count);
 
776
                     thd->row_count);
742
777
            return(1);
743
778
          }
744
 
          if (!field->maybe_null() && field->type() == DRIZZLE_TYPE_TIMESTAMP)
 
779
          if (!field->maybe_null() && field->type() == FIELD_TYPE_TIMESTAMP)
745
780
              ((Field_timestamp*) field)->set_time();
746
781
          /*
747
782
            QQ: We probably should not throw warning for each field.
748
783
            But how about intention to always have the same number
749
 
            of warnings in Session::cuted_fields (and get rid of cuted_fields
 
784
            of warnings in THD::cuted_fields (and get rid of cuted_fields
750
785
            in the end ?)
751
786
          */
752
 
          session->cuted_fields++;
753
 
          push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_WARN,
 
787
          thd->cuted_fields++;
 
788
          push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
754
789
                              ER_WARN_TOO_FEW_RECORDS,
755
 
                              ER(ER_WARN_TOO_FEW_RECORDS), session->row_count);
 
790
                              ER(ER_WARN_TOO_FEW_RECORDS), thd->row_count);
756
791
        }
757
792
        else if (item->type() == Item::STRING_ITEM)
758
793
        {
767
802
      }
768
803
    }
769
804
 
770
 
    if (session->killed ||
771
 
        fill_record(session, set_fields, set_values,
 
805
    if (thd->killed ||
 
806
        fill_record(thd, set_fields, set_values,
772
807
                    ignore_check_option_errors))
773
808
      return(1);
774
809
 
775
 
    err= write_record(session, table, &info);
 
810
    err= write_record(thd, table, &info);
776
811
    table->auto_increment_field_not_null= false;
777
812
    if (err)
778
813
      return(1);
784
819
      break;
785
820
    if (read_info.line_cuted)
786
821
    {
787
 
      session->cuted_fields++;                  /* To long row */
788
 
      push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_WARN, 
 
822
      thd->cuted_fields++;                      /* To long row */
 
823
      push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, 
789
824
                          ER_WARN_TOO_MANY_RECORDS, ER(ER_WARN_TOO_MANY_RECORDS), 
790
 
                          session->row_count);   
791
 
      if (session->killed)
 
825
                          thd->row_count);   
 
826
      if (thd->killed)
792
827
        return(1);
793
828
    }
794
 
    session->row_count++;
 
829
    thd->row_count++;
795
830
  }
796
831
  return(test(read_info.error));
797
832
}
798
833
 
799
834
 
 
835
/****************************************************************************
 
836
** Read rows in xml format
 
837
****************************************************************************/
 
838
static int
 
839
read_xml_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list,
 
840
               List<Item> &fields_vars, List<Item> &set_fields,
 
841
               List<Item> &set_values, READ_INFO &read_info,
 
842
               String &row_tag __attribute__((__unused__)),
 
843
               ulong skip_lines,
 
844
               bool ignore_check_option_errors)
 
845
{
 
846
  List_iterator_fast<Item> it(fields_vars);
 
847
  Item *item;
 
848
  TABLE *table= table_list->table;
 
849
  bool no_trans_update_stmt;
 
850
  CHARSET_INFO *cs= read_info.read_charset;
 
851
 
 
852
  no_trans_update_stmt= !table->file->has_transactions();
 
853
 
 
854
  for ( ; ; it.rewind())
 
855
  {
 
856
    if (thd->killed)
 
857
    {
 
858
      thd->send_kill_message();
 
859
      return(1);
 
860
    }
 
861
    
 
862
    // read row tag and save values into tag list
 
863
    if (read_info.read_xml())
 
864
      break;
 
865
    
 
866
    List_iterator_fast<XML_TAG> xmlit(read_info.taglist);
 
867
    xmlit.rewind();
 
868
    XML_TAG *tag= NULL;
 
869
    
 
870
    
 
871
    restore_record(table, s->default_values);
 
872
    
 
873
    while ((item= it++))
 
874
    {
 
875
      /* If this line is to be skipped we don't want to fill field or var */
 
876
      if (skip_lines)
 
877
        continue;
 
878
      
 
879
      /* find field in tag list */
 
880
      xmlit.rewind();
 
881
      tag= xmlit++;
 
882
      
 
883
      while(tag && strcmp(tag->field.c_ptr(), item->name) != 0)
 
884
        tag= xmlit++;
 
885
      
 
886
      if (!tag) // found null
 
887
      {
 
888
        if (item->type() == Item::FIELD_ITEM)
 
889
        {
 
890
          Field *field= ((Item_field *) item)->field;
 
891
          field->reset();
 
892
          field->set_null();
 
893
          if (field == table->next_number_field)
 
894
            table->auto_increment_field_not_null= true;
 
895
          if (!field->maybe_null())
 
896
          {
 
897
            if (field->type() == FIELD_TYPE_TIMESTAMP)
 
898
              ((Field_timestamp *) field)->set_time();
 
899
            else if (field != table->next_number_field)
 
900
              field->set_warning(MYSQL_ERROR::WARN_LEVEL_WARN,
 
901
                                 ER_WARN_NULL_TO_NOTNULL, 1);
 
902
          }
 
903
        }
 
904
        else
 
905
          ((Item_user_var_as_out_param *) item)->set_null_value(cs);
 
906
        continue;
 
907
      }
 
908
 
 
909
      if (item->type() == Item::FIELD_ITEM)
 
910
      {
 
911
 
 
912
        Field *field= ((Item_field *)item)->field;
 
913
        field->set_notnull();
 
914
        if (field == table->next_number_field)
 
915
          table->auto_increment_field_not_null= true;
 
916
        field->store((char *) tag->value.ptr(), tag->value.length(), cs);
 
917
      }
 
918
      else
 
919
        ((Item_user_var_as_out_param *) item)->set_value(
 
920
                                                 (char *) tag->value.ptr(), 
 
921
                                                 tag->value.length(), cs);
 
922
    }
 
923
    
 
924
    if (read_info.error)
 
925
      break;
 
926
    
 
927
    if (skip_lines)
 
928
    {
 
929
      skip_lines--;
 
930
      continue;
 
931
    }
 
932
    
 
933
    if (item)
 
934
    {
 
935
      /* Have not read any field, thus input file is simply ended */
 
936
      if (item == fields_vars.head())
 
937
        break;
 
938
      
 
939
      for ( ; item; item= it++)
 
940
      {
 
941
        if (item->type() == Item::FIELD_ITEM)
 
942
        {
 
943
          /*
 
944
            QQ: We probably should not throw warning for each field.
 
945
            But how about intention to always have the same number
 
946
            of warnings in THD::cuted_fields (and get rid of cuted_fields
 
947
            in the end ?)
 
948
          */
 
949
          thd->cuted_fields++;
 
950
          push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
 
951
                              ER_WARN_TOO_FEW_RECORDS,
 
952
                              ER(ER_WARN_TOO_FEW_RECORDS), thd->row_count);
 
953
        }
 
954
        else
 
955
          ((Item_user_var_as_out_param *)item)->set_null_value(cs);
 
956
      }
 
957
    }
 
958
 
 
959
    if (thd->killed || fill_record(thd, set_fields, set_values,
 
960
                    ignore_check_option_errors))
 
961
      return(1);
 
962
 
 
963
    if (write_record(thd, table, &info))
 
964
      return(1);
 
965
    
 
966
    /*
 
967
      We don't need to reset auto-increment field since we are restoring
 
968
      its default value at the beginning of each loop iteration.
 
969
    */
 
970
    thd->transaction.stmt.modified_non_trans_table= no_trans_update_stmt;
 
971
    thd->row_count++;
 
972
  }
 
973
  return(test(read_info.error));
 
974
} /* load xml end */
 
975
 
 
976
 
800
977
/* Unescape all escape characters, mark \N as null */
801
978
 
802
979
char
824
1001
*/
825
1002
 
826
1003
 
827
 
READ_INFO::READ_INFO(File file_par, uint32_t tot_length, const CHARSET_INFO * const cs,
 
1004
READ_INFO::READ_INFO(File file_par, uint tot_length, CHARSET_INFO *cs,
828
1005
                     String &field_term, String &line_start, String &line_term,
829
1006
                     String &enclosed_par, int escape, bool get_it_from_net,
830
1007
                     bool is_fifo)
835
1012
  field_term_length= field_term.length();
836
1013
  line_term_ptr=(char*) line_term.ptr();
837
1014
  line_term_length= line_term.length();
 
1015
  level= 0; /* for load xml */
838
1016
  if (line_start.length() == 0)
839
1017
  {
840
1018
    line_start_ptr=0;
854
1032
    line_term_ptr=(char*) "";
855
1033
  }
856
1034
  enclosed_char= (enclosed_length=enclosed_par.length()) ?
857
 
    (unsigned char) enclosed_par[0] : INT_MAX;
858
 
  field_term_char= field_term_length ? (unsigned char) field_term_ptr[0] : INT_MAX;
859
 
  line_term_char= line_term_length ? (unsigned char) line_term_ptr[0] : INT_MAX;
 
1035
    (uchar) enclosed_par[0] : INT_MAX;
 
1036
  field_term_char= field_term_length ? (uchar) field_term_ptr[0] : INT_MAX;
 
1037
  line_term_char= line_term_length ? (uchar) line_term_ptr[0] : INT_MAX;
860
1038
  error=eof=found_end_of_line=found_null=line_cuted=0;
861
1039
  buff_length=tot_length;
862
1040
 
863
1041
 
864
1042
  /* Set of a stack for unget if long terminators */
865
 
  uint32_t length=cmax(field_term_length,line_term_length)+1;
 
1043
  uint length=max(field_term_length,line_term_length)+1;
866
1044
  set_if_bigger(length,line_start.length());
867
1045
  stack=stack_pos=(int*) sql_alloc(sizeof(int)*length);
868
1046
 
869
 
  if (!(buffer=(unsigned char*) my_malloc(buff_length+1,MYF(0))))
 
1047
  if (!(buffer=(uchar*) my_malloc(buff_length+1,MYF(0))))
870
1048
    error=1; /* purecov: inspected */
871
1049
  else
872
1050
  {
876
1054
                      (is_fifo ? READ_FIFO : READ_CACHE),0L,1,
877
1055
                      MYF(MY_WME)))
878
1056
    {
879
 
      free((unsigned char*) buffer); /* purecov: inspected */
 
1057
      my_free((uchar*) buffer,MYF(0)); /* purecov: inspected */
880
1058
      error=1;
881
1059
    }
882
1060
    else
905
1083
  {
906
1084
    if (need_end_io_cache)
907
1085
      ::end_io_cache(&cache);
908
 
    free((unsigned char*) buffer);
 
1086
    my_free((uchar*) buffer,MYF(0));
909
1087
    error=1;
910
1088
  }
 
1089
  List_iterator<XML_TAG> xmlit(taglist);
 
1090
  XML_TAG *t;
 
1091
  while ((t= xmlit++))
 
1092
    delete(t);
911
1093
}
912
1094
 
913
1095
 
915
1097
#define PUSH(A) *(stack_pos++)=(A)
916
1098
 
917
1099
 
918
 
inline int READ_INFO::terminator(char *ptr,uint32_t length)
 
1100
inline int READ_INFO::terminator(char *ptr,uint length)
919
1101
{
920
1102
  int chr=0;                                    // Keep gcc happy
921
 
  uint32_t i;
 
1103
  uint i;
922
1104
  for (i=1 ; i < length ; i++)
923
1105
  {
924
1106
    if ((chr=GET) != *++ptr)
930
1112
    return 1;
931
1113
  PUSH(chr);
932
1114
  while (i-- > 1)
933
 
    PUSH((unsigned char) *--ptr);
 
1115
    PUSH((uchar) *--ptr);
934
1116
  return 0;
935
1117
}
936
1118
 
938
1120
int READ_INFO::read_field()
939
1121
{
940
1122
  int chr,found_enclosed_char;
941
 
  unsigned char *to,*new_buffer;
 
1123
  uchar *to,*new_buffer;
942
1124
 
943
1125
  found_null=0;
944
1126
  if (found_end_of_line)
961
1143
  if (chr == enclosed_char)
962
1144
  {
963
1145
    found_enclosed_char=enclosed_char;
964
 
    *to++=(unsigned char) chr;                          // If error
 
1146
    *to++=(uchar) chr;                          // If error
965
1147
  }
966
1148
  else
967
1149
  {
978
1160
      if ((my_mbcharlen(read_charset, chr) > 1) &&
979
1161
          to+my_mbcharlen(read_charset, chr) <= end_of_buff)
980
1162
      {
981
 
          unsigned char* p = (unsigned char*)to;
 
1163
          uchar* p = (uchar*)to;
982
1164
          *to++ = chr;
983
1165
          int ml = my_mbcharlen(read_charset, chr);
984
1166
          int i;
993
1175
                          (const char *)to))
994
1176
            continue;
995
1177
          for (i=0; i<ml; i++)
996
 
            PUSH((unsigned char) *--to);
 
1178
            PUSH((uchar) *--to);
997
1179
          chr = GET;
998
1180
      }
999
1181
#endif
1003
1185
      {
1004
1186
        if ((chr=GET) == my_b_EOF)
1005
1187
        {
1006
 
          *to++= (unsigned char) escape_char;
 
1188
          *to++= (uchar) escape_char;
1007
1189
          goto found_eof;
1008
1190
        }
1009
1191
        /*
1015
1197
         */
1016
1198
        if (escape_char != enclosed_char || chr == escape_char)
1017
1199
        {
1018
 
          *to++ = (unsigned char) unescape((char) chr);
 
1200
          *to++ = (uchar) unescape((char) chr);
1019
1201
          continue;
1020
1202
        }
1021
1203
        PUSH(chr);
1040
1222
      {
1041
1223
        if ((chr=GET) == found_enclosed_char)
1042
1224
        {                                       // Remove dupplicated
1043
 
          *to++ = (unsigned char) chr;
 
1225
          *to++ = (uchar) chr;
1044
1226
          continue;
1045
1227
        }
1046
1228
        // End of enclosed field if followed by field_term or line_term
1079
1261
          return 0;
1080
1262
        }
1081
1263
      }
1082
 
      *to++ = (unsigned char) chr;
 
1264
      *to++ = (uchar) chr;
1083
1265
    }
1084
1266
    /*
1085
1267
    ** We come here if buffer is too small. Enlarge it and continue
1086
1268
    */
1087
 
    if (!(new_buffer=(unsigned char*) my_realloc((char*) buffer,buff_length+1+IO_SIZE,
 
1269
    if (!(new_buffer=(uchar*) my_realloc((char*) buffer,buff_length+1+IO_SIZE,
1088
1270
                                        MYF(MY_WME))))
1089
1271
      return (error=1);
1090
1272
    to=new_buffer + (to-buffer);
1119
1301
int READ_INFO::read_fixed_length()
1120
1302
{
1121
1303
  int chr;
1122
 
  unsigned char *to;
 
1304
  uchar *to;
1123
1305
  if (found_end_of_line)
1124
1306
    return 1;                                   // One have to call next_line
1125
1307
 
1139
1321
    {
1140
1322
      if ((chr=GET) == my_b_EOF)
1141
1323
      {
1142
 
        *to++= (unsigned char) escape_char;
 
1324
        *to++= (uchar) escape_char;
1143
1325
        goto found_eof;
1144
1326
      }
1145
 
      *to++ =(unsigned char) unescape((char) chr);
 
1327
      *to++ =(uchar) unescape((char) chr);
1146
1328
      continue;
1147
1329
    }
1148
1330
    if (chr == line_term_char)
1154
1336
        return 0;
1155
1337
      }
1156
1338
    }
1157
 
    *to++ = (unsigned char) chr;
 
1339
    *to++ = (uchar) chr;
1158
1340
  }
1159
1341
  row_end=to;                                   // Found full line
1160
1342
  return 0;
1185
1367
#ifdef USE_MB
1186
1368
   if (my_mbcharlen(read_charset, chr) > 1)
1187
1369
   {
1188
 
       for (uint32_t i=1;
 
1370
       for (uint i=1;
1189
1371
            chr != my_b_EOF && i<my_mbcharlen(read_charset, chr);
1190
1372
            i++)
1191
1373
           chr = GET;
1232
1414
      PUSH(chr);
1233
1415
      while (--ptr != line_start_ptr)
1234
1416
      {                                         // Restart with next char
1235
 
        PUSH((unsigned char) *ptr);
 
1417
        PUSH((uchar) *ptr);
1236
1418
      }
1237
1419
      goto try_again;
1238
1420
    }
1241
1423
}
1242
1424
 
1243
1425
 
 
1426
/*
 
1427
  Clear taglist from tags with a specified level
 
1428
*/
 
1429
int READ_INFO::clear_level(int level)
 
1430
{
 
1431
  List_iterator<XML_TAG> xmlit(taglist);
 
1432
  xmlit.rewind();
 
1433
  XML_TAG *tag;
 
1434
  
 
1435
  while ((tag= xmlit++))
 
1436
  {
 
1437
     if(tag->level >= level)
 
1438
     {
 
1439
       xmlit.remove();
 
1440
       delete tag;
 
1441
     }
 
1442
  }
 
1443
  return(0);
 
1444
}
 
1445
 
 
1446
 
 
1447
/*
 
1448
  Convert an XML entity to Unicode value.
 
1449
  Return -1 on error;
 
1450
*/
 
1451
static int
 
1452
my_xml_entity_to_char(const char *name, uint length)
 
1453
{
 
1454
  if (length == 2)
 
1455
  {
 
1456
    if (!memcmp(name, "gt", length))
 
1457
      return '>';
 
1458
    if (!memcmp(name, "lt", length))
 
1459
      return '<';
 
1460
  }
 
1461
  else if (length == 3)
 
1462
  {
 
1463
    if (!memcmp(name, "amp", length))
 
1464
      return '&';
 
1465
  }
 
1466
  else if (length == 4)
 
1467
  {
 
1468
    if (!memcmp(name, "quot", length))
 
1469
      return '"';
 
1470
    if (!memcmp(name, "apos", length))
 
1471
      return '\'';
 
1472
  }
 
1473
  return -1;
 
1474
}
 
1475
 
 
1476
 
 
1477
/**
 
1478
  @brief Convert newline, linefeed, tab to space
 
1479
  
 
1480
  @param chr    character
 
1481
  
 
1482
  @details According to the "XML 1.0" standard,
 
1483
           only space (#x20) characters, carriage returns,
 
1484
           line feeds or tabs are considered as spaces.
 
1485
           Convert all of them to space (#x20) for parsing simplicity.
 
1486
*/
 
1487
static int
 
1488
my_tospace(int chr)
 
1489
{
 
1490
  return (chr == '\t' || chr == '\r' || chr == '\n') ? ' ' : chr;
 
1491
}
 
1492
 
 
1493
 
 
1494
/*
 
1495
  Read an xml value: handle multibyte and xml escape
 
1496
*/
 
1497
int READ_INFO::read_value(int delim, String *val)
 
1498
{
 
1499
  int chr;
 
1500
  String tmp;
 
1501
 
 
1502
  for (chr= my_tospace(GET); chr != delim && chr != my_b_EOF; )
 
1503
  {
 
1504
#ifdef USE_MB
 
1505
    if (my_mbcharlen(read_charset, chr) > 1)
 
1506
    {
 
1507
      int i, ml= my_mbcharlen(read_charset, chr);
 
1508
      for (i= 1; i < ml; i++) 
 
1509
      {
 
1510
        val->append(chr);
 
1511
        /*
 
1512
          Don't use my_tospace() in the middle of a multi-byte character
 
1513
          TODO: check that the multi-byte sequence is valid.
 
1514
        */
 
1515
        chr= GET; 
 
1516
        if (chr == my_b_EOF)
 
1517
          return chr;
 
1518
      }
 
1519
    }
 
1520
#endif
 
1521
    if(chr == '&')
 
1522
    {
 
1523
      tmp.length(0);
 
1524
      for (chr= my_tospace(GET) ; chr != ';' ; chr= my_tospace(GET))
 
1525
      {
 
1526
        if (chr == my_b_EOF)
 
1527
          return chr;
 
1528
        tmp.append(chr);
 
1529
      }
 
1530
      if ((chr= my_xml_entity_to_char(tmp.ptr(), tmp.length())) >= 0)
 
1531
        val->append(chr);
 
1532
      else
 
1533
      {
 
1534
        val->append('&');
 
1535
        val->append(tmp);
 
1536
        val->append(';'); 
 
1537
      }
 
1538
    }
 
1539
    else
 
1540
      val->append(chr);
 
1541
    chr= my_tospace(GET);
 
1542
  }            
 
1543
  return chr;
 
1544
}
 
1545
 
 
1546
 
 
1547
/*
 
1548
  Read a record in xml format
 
1549
  tags and attributes are stored in taglist
 
1550
  when tag set in ROWS IDENTIFIED BY is closed, we are ready and return
 
1551
*/
 
1552
int READ_INFO::read_xml()
 
1553
{
 
1554
  int chr, chr2, chr3;
 
1555
  int delim= 0;
 
1556
  String tag, attribute, value;
 
1557
  bool in_tag= false;
 
1558
  
 
1559
  tag.length(0);
 
1560
  attribute.length(0);
 
1561
  value.length(0);
 
1562
  
 
1563
  for (chr= my_tospace(GET); chr != my_b_EOF ; )
 
1564
  {
 
1565
    switch(chr){
 
1566
    case '<':  /* read tag */
 
1567
        /* TODO: check if this is a comment <!-- comment -->  */
 
1568
      chr= my_tospace(GET);
 
1569
      if(chr == '!')
 
1570
      {
 
1571
        chr2= GET;
 
1572
        chr3= GET;
 
1573
        
 
1574
        if(chr2 == '-' && chr3 == '-')
 
1575
        {
 
1576
          chr2= 0;
 
1577
          chr3= 0;
 
1578
          chr= my_tospace(GET);
 
1579
          
 
1580
          while(chr != '>' || chr2 != '-' || chr3 != '-')
 
1581
          {
 
1582
            if(chr == '-')
 
1583
            {
 
1584
              chr3= chr2;
 
1585
              chr2= chr;
 
1586
            }
 
1587
            else if (chr2 == '-')
 
1588
            {
 
1589
              chr2= 0;
 
1590
              chr3= 0;
 
1591
            }
 
1592
            chr= my_tospace(GET);
 
1593
            if (chr == my_b_EOF)
 
1594
              goto found_eof;
 
1595
          }
 
1596
          break;
 
1597
        }
 
1598
      }
 
1599
      
 
1600
      tag.length(0);
 
1601
      while(chr != '>' && chr != ' ' && chr != '/' && chr != my_b_EOF)
 
1602
      {
 
1603
        if(chr != delim) /* fix for the '<field name =' format */
 
1604
          tag.append(chr);
 
1605
        chr= my_tospace(GET);
 
1606
      }
 
1607
      
 
1608
      if(chr == ' ' || chr == '>')
 
1609
      {
 
1610
        level++;
 
1611
        clear_level(level + 1);
 
1612
      }
 
1613
      
 
1614
      if (chr == ' ')
 
1615
        in_tag= true;
 
1616
      else 
 
1617
        in_tag= false;
 
1618
      break;
 
1619
      
 
1620
    case ' ': /* read attribute */
 
1621
      while(chr == ' ')  /* skip blanks */
 
1622
        chr= my_tospace(GET);
 
1623
      
 
1624
      if(!in_tag)
 
1625
        break;
 
1626
      
 
1627
      while(chr != '=' && chr != '/' && chr != '>' && chr != my_b_EOF)
 
1628
      {
 
1629
        attribute.append(chr);
 
1630
        chr= my_tospace(GET);
 
1631
      }
 
1632
      break;
 
1633
      
 
1634
    case '>': /* end tag - read tag value */
 
1635
      in_tag= false;
 
1636
      chr= read_value('<', &value);
 
1637
      if(chr == my_b_EOF)
 
1638
        goto found_eof;
 
1639
      
 
1640
      /* save value to list */
 
1641
      if(tag.length() > 0 && value.length() > 0)
 
1642
        taglist.push_front( new XML_TAG(level, tag, value));
 
1643
 
 
1644
      tag.length(0);
 
1645
      value.length(0);
 
1646
      attribute.length(0);
 
1647
      break;
 
1648
      
 
1649
    case '/': /* close tag */
 
1650
      level--;
 
1651
      chr= my_tospace(GET);
 
1652
      if(chr != '>')   /* if this is an empty tag <tag   /> */
 
1653
        tag.length(0); /* we should keep tag value          */
 
1654
      while(chr != '>' && chr != my_b_EOF)
 
1655
      {
 
1656
        tag.append(chr);
 
1657
        chr= my_tospace(GET);
 
1658
      }
 
1659
      
 
1660
      if((tag.length() == line_term_length -2) &&
 
1661
         (strncmp(tag.c_ptr_safe(), line_term_ptr + 1, tag.length()) == 0))
 
1662
         return(0); //normal return
 
1663
 
 
1664
      chr= my_tospace(GET);
 
1665
      break;   
 
1666
      
 
1667
    case '=': /* attribute name end - read the value */
 
1668
      //check for tag field and attribute name
 
1669
      if(!memcmp(tag.c_ptr_safe(), STRING_WITH_LEN("field")) &&
 
1670
         !memcmp(attribute.c_ptr_safe(), STRING_WITH_LEN("name")))
 
1671
      {
 
1672
        /*
 
1673
          this is format <field name="xx">xx</field>
 
1674
          where actual fieldname is in attribute
 
1675
        */
 
1676
        delim= my_tospace(GET);
 
1677
        tag.length(0);
 
1678
        attribute.length(0);
 
1679
        chr= '<'; /* we pretend that it is a tag */
 
1680
        level--;
 
1681
        break;
 
1682
      }
 
1683
      
 
1684
      //check for " or '
 
1685
      chr= GET;
 
1686
      if (chr == my_b_EOF)
 
1687
        goto found_eof;
 
1688
      if(chr == '"' || chr == '\'')
 
1689
      {
 
1690
        delim= chr;
 
1691
      }
 
1692
      else
 
1693
      {
 
1694
        delim= ' '; /* no delimiter, use space */
 
1695
        PUSH(chr);
 
1696
      }
 
1697
      
 
1698
      chr= read_value(delim, &value);
 
1699
      if(attribute.length() > 0 && value.length() > 0)
 
1700
        taglist.push_front(new XML_TAG(level + 1, attribute, value));
 
1701
 
 
1702
      attribute.length(0);
 
1703
      value.length(0);
 
1704
      if (chr != ' ')
 
1705
        chr= my_tospace(GET);
 
1706
      break;
 
1707
    
 
1708
    default:
 
1709
      chr= my_tospace(GET);
 
1710
    } /* end switch */
 
1711
  } /* end while */
 
1712
  
 
1713
found_eof:
 
1714
  eof= 1;
 
1715
  return(1);
 
1716
}