~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to server/sql_load.cc

  • Committer: Jim Winstead
  • Date: 2008-07-19 02:56:45 UTC
  • mto: (202.1.8 codestyle)
  • mto: This revision was merged to the branch mainline in revision 207.
  • Revision ID: jimw@mysql.com-20080719025645-w2pwytebgzusjzjb
Various fixes to enable compilation on Mac OS X, and remove the glib dependency.
Temporarily disables tab-completion in the drizzle client until an appropriate
autoconf check can be added/enabled.

Show diffs side-by-side

added added

removed removed

Lines of Context:
11
11
 
12
12
   You should have received a copy of the GNU General Public License
13
13
   along with this program; if not, write to the Free Software
14
 
   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA */
 
14
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
15
15
 
16
16
 
17
17
/* Copy data from a textfile to table */
18
 
 
19
 
#include <config.h>
20
 
 
21
 
#include <drizzled/sql_load.h>
22
 
#include <drizzled/error.h>
23
 
#include <drizzled/data_home.h>
24
 
#include <drizzled/session.h>
25
 
#include <drizzled/sql_base.h>
26
 
#include <drizzled/field/epoch.h>
27
 
#include <drizzled/internal/my_sys.h>
28
 
#include <drizzled/internal/iocache.h>
29
 
#include <drizzled/plugin/storage_engine.h>
30
 
 
31
 
#include <sys/stat.h>
32
 
#include <fcntl.h>
33
 
#include <algorithm>
34
 
#include <climits>
35
 
#include <boost/filesystem.hpp>
36
 
 
37
 
namespace fs=boost::filesystem;
38
 
using namespace std;
39
 
namespace drizzled
 
18
/* 2006-12 Erik Wetterberg : LOAD XML added */
 
19
 
 
20
#include "mysql_priv.h"
 
21
#include <my_dir.h>
 
22
#include <m_ctype.h>
 
23
#include "sql_repl.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)
40
35
{
 
36
  level= l;
 
37
  field.append(f);
 
38
  value.append(v);
 
39
}
 
40
 
41
41
 
42
42
class READ_INFO {
43
 
  int   cursor;
44
 
  unsigned char *buffer;                /* Buffer for read text */
45
 
  unsigned char *end_of_buff;           /* Data in bufferts ends here */
46
 
  size_t buff_length;                   /* Length of buffert */
47
 
  size_t max_length;                    /* Max length of row */
 
43
  File  file;
 
44
  uchar *buffer,                        /* Buffer for read text */
 
45
        *end_of_buff;                   /* Data in bufferts ends here */
 
46
  uint  buff_length,                    /* Length of buffert */
 
47
        max_length;                     /* Max length of row */
48
48
  char  *field_term_ptr,*line_term_ptr,*line_start_ptr,*line_start_end;
49
49
  uint  field_term_length,line_term_length,enclosed_length;
50
50
  int   field_term_char,line_term_char,enclosed_char,escape_char;
51
51
  int   *stack,*stack_pos;
52
52
  bool  found_end_of_line,start_of_line,eof;
53
53
  bool  need_end_io_cache;
54
 
  internal::IO_CACHE cache;
 
54
  IO_CACHE cache;
 
55
  NET *io_net;
 
56
  int level; /* for load xml */
55
57
 
56
58
public:
57
59
  bool error,line_cuted,found_null,enclosed;
58
 
  unsigned char *row_start,                     /* Found row starts here */
 
60
  uchar *row_start,                     /* Found row starts here */
59
61
        *row_end;                       /* Found row ends here */
60
 
  const CHARSET_INFO *read_charset;
 
62
  CHARSET_INFO *read_charset;
61
63
 
62
 
  READ_INFO(int cursor, size_t tot_length, const CHARSET_INFO * const cs,
 
64
  READ_INFO(File file,uint tot_length,CHARSET_INFO *cs,
63
65
            String &field_term,String &line_start,String &line_term,
64
 
            String &enclosed,int escape, bool is_fifo);
 
66
            String &enclosed,int escape,bool get_it_from_net, bool is_fifo);
65
67
  ~READ_INFO();
66
68
  int read_field();
67
69
  int read_fixed_length(void);
68
70
  int next_line(void);
69
71
  char unescape(char chr);
70
 
  int terminator(char *ptr,uint32_t length);
 
72
  int terminator(char *ptr,uint length);
71
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);
72
79
 
73
80
  /*
74
81
    We need to force cache close before destructor is invoked to log
76
83
  */
77
84
  void end_io_cache()
78
85
  {
79
 
    cache.end_io_cache();
 
86
    ::end_io_cache(&cache);
80
87
    need_end_io_cache = 0;
81
88
  }
82
89
 
83
90
  /*
84
91
    Either this method, or we need to make cache public
85
 
    Arg must be set from load() since constructor does not see
86
 
    either the table or Session value
 
92
    Arg must be set from mysql_load() since constructor does not see
 
93
    either the table or THD value
87
94
  */
88
95
  void set_io_cache_arg(void* arg) { cache.arg = arg; }
89
96
};
90
97
 
91
 
static int read_fixed_length(Session *session, CopyInfo &info, TableList *table_list,
 
98
static int read_fixed_length(THD *thd, COPY_INFO &info, TABLE_LIST *table_list,
92
99
                             List<Item> &fields_vars, List<Item> &set_fields,
93
100
                             List<Item> &set_values, READ_INFO &read_info,
94
 
                             uint32_t skip_lines,
 
101
                             ulong skip_lines,
95
102
                             bool ignore_check_option_errors);
96
 
static int read_sep_field(Session *session, CopyInfo &info, TableList *table_list,
 
103
static int read_sep_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list,
97
104
                          List<Item> &fields_vars, List<Item> &set_fields,
98
105
                          List<Item> &set_values, READ_INFO &read_info,
99
 
                          String &enclosed, uint32_t skip_lines,
 
106
                          String &enclosed, ulong skip_lines,
100
107
                          bool ignore_check_option_errors);
101
108
 
 
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,
 
116
                                               bool duplicates, bool ignore,
 
117
                                               bool transactional_table,
 
118
                                               THD::killed_state killed_status);
102
119
 
103
120
/*
104
121
  Execute LOAD DATA query
105
122
 
106
123
  SYNOPSYS
107
 
    load()
108
 
      session - current thread
109
 
      ex  - file_exchange object representing source cursor and its parsing rules
 
124
    mysql_load()
 
125
      thd - current thread
 
126
      ex  - sql_exchange object representing source file and its parsing rules
110
127
      table_list  - list of tables to which we are loading data
111
128
      fields_vars - list of fields and variables to which we read
112
 
                    data from cursor
 
129
                    data from file
113
130
      set_fields  - list of fields mentioned in set clause
114
131
      set_values  - expressions to assign to fields in previous list
115
132
      handle_duplicates - indicates whenever we should emit error or
116
133
                          replace row if we will meet duplicates.
117
134
      ignore -          - indicates whenever we should ignore duplicates
 
135
      read_file_from_client - is this LOAD DATA LOCAL ?
118
136
 
119
137
  RETURN VALUES
120
138
    true - error / false - success
121
139
*/
122
140
 
123
 
int load(Session *session,file_exchange *ex,TableList *table_list,
 
141
int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
124
142
                List<Item> &fields_vars, List<Item> &set_fields,
125
143
                List<Item> &set_values,
126
 
                enum enum_duplicates handle_duplicates, bool ignore)
 
144
                enum enum_duplicates handle_duplicates, bool ignore,
 
145
                bool read_file_from_client)
127
146
{
128
 
  int file;
129
 
  Table *table= NULL;
 
147
  char name[FN_REFLEN];
 
148
  File file;
 
149
  TABLE *table= NULL;
130
150
  int error;
131
151
  String *field_term=ex->field_term,*escaped=ex->escaped;
132
152
  String *enclosed=ex->enclosed;
133
153
  bool is_fifo=0;
134
 
 
135
 
  assert(table_list->getSchemaName()); // This should never be null
136
 
 
 
154
  LOAD_FILE_INFO lf_info;
 
155
  char *db = table_list->db;                    // This is never null
137
156
  /*
138
 
    If path for cursor is not defined, we will use the current database.
 
157
    If path for file is not defined, we will use the current database.
139
158
    If this is not set, we will use the directory where the table to be
140
159
    loaded is located
141
160
  */
142
 
  util::string::const_shared_ptr schema(session->schema());
143
 
  const char *tdb= (schema and not schema->empty()) ? schema->c_str() : table_list->getSchemaName(); // Result should never be null
144
 
  assert(tdb);
145
 
  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;
146
163
  bool transactional_table;
147
 
  Session::killed_state_t killed_status= Session::NOT_KILLED;
 
164
  THD::killed_state killed_status= THD::NOT_KILLED;
148
165
 
149
 
  /* Escape and enclosed character may be a utf8 4-byte character */
150
 
  if (escaped->length() > 4 || enclosed->length() > 4)
 
166
  if (escaped->length() > 1 || enclosed->length() > 1)
151
167
  {
152
 
    my_error(ER_WRONG_FIELD_TERMINATORS,MYF(0),enclosed->c_ptr(), enclosed->length());
 
168
    my_message(ER_WRONG_FIELD_TERMINATORS,ER(ER_WRONG_FIELD_TERMINATORS),
 
169
               MYF(0));
153
170
    return(true);
154
171
  }
155
 
 
156
 
  if (session->openTablesLock(table_list))
 
172
  if (open_and_lock_tables(thd, table_list))
157
173
    return(true);
158
 
 
159
 
  if (setup_tables_and_check_access(session, &session->getLex()->select_lex.context,
160
 
                                    &session->getLex()->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,
161
176
                                    table_list,
162
 
                                    &session->getLex()->select_lex.leaf_tables, true))
 
177
                                    &thd->lex->select_lex.leaf_tables, true))
163
178
     return(-1);
164
179
 
165
180
  /*
170
185
    table is marked to be 'used for insert' in which case we should never
171
186
    mark this table as 'const table' (ie, one that has only one row).
172
187
  */
173
 
  if (unique_table(table_list, table_list->next_global))
 
188
  if (unique_table(thd, table_list, table_list->next_global, 0))
174
189
  {
175
 
    my_error(ER_UPDATE_TABLE_USED, MYF(0), table_list->getTableName());
 
190
    my_error(ER_UPDATE_TABLE_USED, MYF(0), table_list->table_name);
176
191
    return(true);
177
192
  }
178
193
 
179
194
  table= table_list->table;
180
 
  transactional_table= table->cursor->has_transactions();
 
195
  transactional_table= table->file->has_transactions();
181
196
 
182
197
  if (!fields_vars.elements)
183
198
  {
184
199
    Field **field;
185
 
    for (field= table->getFields(); *field ; field++)
 
200
    for (field=table->field; *field ; field++)
186
201
      fields_vars.push_back(new Item_field(*field));
187
 
    table->setWriteSet();
 
202
    bitmap_set_all(table->write_set);
188
203
    table->timestamp_field_type= TIMESTAMP_NO_AUTO_SET;
189
204
    /*
190
205
      Let us also prepare SET clause, altough it is probably empty
191
206
      in this case.
192
207
    */
193
 
    if (setup_fields(session, 0, set_fields, MARK_COLUMNS_WRITE, 0, 0) ||
194
 
        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))
195
210
      return(true);
196
211
  }
197
212
  else
198
213
  {                                             // Part field list
199
214
    /* TODO: use this conds for 'WITH CHECK OPTIONS' */
200
 
    if (setup_fields(session, 0, fields_vars, MARK_COLUMNS_WRITE, 0, 0) ||
201
 
        setup_fields(session, 0, set_fields, MARK_COLUMNS_WRITE, 0, 0) ||
202
 
        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))
203
218
      return(true);
204
219
    /*
205
220
      Check whenever TIMESTAMP field with auto-set feature specified
207
222
    */
208
223
    if (table->timestamp_field)
209
224
    {
210
 
      if (table->isWriteSet(table->timestamp_field->position()))
211
 
      {
 
225
      if (bitmap_is_set(table->write_set,
 
226
                        table->timestamp_field->field_index))
212
227
        table->timestamp_field_type= TIMESTAMP_NO_AUTO_SET;
213
 
      }
214
228
      else
215
229
      {
216
 
        table->setWriteSet(table->timestamp_field->position());
 
230
        bitmap_set_bit(table->write_set,
 
231
                       table->timestamp_field->field_index);
217
232
      }
218
233
    }
219
234
    /* Fix the expressions in SET clause */
220
 
    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))
221
236
      return(true);
222
237
  }
223
238
 
224
239
  table->mark_columns_needed_for_insert();
225
240
 
226
 
  size_t tot_length=0;
 
241
  uint tot_length=0;
227
242
  bool use_blobs= 0, use_vars= 0;
228
 
  List<Item>::iterator it(fields_vars.begin());
 
243
  List_iterator_fast<Item> it(fields_vars);
229
244
  Item *item;
230
245
 
231
246
  while ((item= it++))
258
273
    return(true);
259
274
  }
260
275
 
261
 
  fs::path to_file(ex->file_name);
262
 
  fs::path target_path(fs::system_complete(getDataHomeCatalog()));
263
 
  if (not to_file.has_root_directory())
 
276
  /* We can't give an error in the middle when using LOCAL files */
 
277
  if (read_file_from_client && handle_duplicates == DUP_ERROR)
 
278
    ignore= 1;
 
279
 
 
280
  if (read_file_from_client)
264
281
  {
265
 
    int count_elements= 0;
266
 
    for (fs::path::iterator iter= to_file.begin();
267
 
         iter != to_file.end();
268
 
         ++iter, ++count_elements)
269
 
    { }
270
 
 
271
 
    if (count_elements == 1)
272
 
    {
273
 
      target_path /= tdb;
274
 
    }
275
 
    target_path /= to_file;
 
282
    (void)net_request_file(&thd->net,ex->file_name);
 
283
    file = -1;
276
284
  }
277
285
  else
278
286
  {
279
 
    target_path= to_file;
280
 
  }
281
 
 
282
 
  if (not secure_file_priv.string().empty())
283
 
  {
284
 
    if (target_path.file_string().substr(0, secure_file_priv.file_string().size()) != secure_file_priv.file_string())
285
 
    {
286
 
      /* Read only allowed from within dir specified by secure_file_priv */
287
 
      my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--secure-file-priv");
 
287
#ifdef DONT_ALLOW_FULL_LOAD_DATA_PATHS
 
288
    ex->file_name+=dirname_length(ex->file_name);
 
289
#endif
 
290
    if (!dirname_length(ex->file_name))
 
291
    {
 
292
      strxnmov(name, FN_REFLEN-1, mysql_real_data_home, tdb, NullS);
 
293
      (void) fn_format(name, ex->file_name, name, "",
 
294
                       MY_RELATIVE_PATH | MY_UNPACK_FILENAME);
 
295
    }
 
296
    else
 
297
    {
 
298
      (void) fn_format(name, ex->file_name, mysql_real_data_home, "",
 
299
                       MY_RELATIVE_PATH | MY_UNPACK_FILENAME);
 
300
 
 
301
      if (opt_secure_file_priv &&
 
302
          strncmp(opt_secure_file_priv, name, strlen(opt_secure_file_priv)))
 
303
      {
 
304
        /* Read only allowed from within dir specified by secure_file_priv */
 
305
        my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--secure-file-priv");
 
306
        return(true);
 
307
      }
 
308
 
 
309
      struct stat stat_info;
 
310
      if (stat(name,&stat_info))
 
311
        return(true);
 
312
 
 
313
      // if we are not in slave thread, the file must be:
 
314
      if (!thd->slave_thread &&
 
315
          !((stat_info.st_mode & S_IROTH) == S_IROTH &&  // readable by others
 
316
            (stat_info.st_mode & S_IFLNK) != S_IFLNK && // and not a symlink
 
317
            ((stat_info.st_mode & S_IFREG) == S_IFREG ||
 
318
             (stat_info.st_mode & S_IFIFO) == S_IFIFO)))
 
319
      {
 
320
        my_error(ER_TEXTFILE_NOT_READABLE, MYF(0), name);
 
321
        return(true);
 
322
      }
 
323
      if ((stat_info.st_mode & S_IFIFO) == S_IFIFO)
 
324
        is_fifo = 1;
 
325
    }
 
326
    if ((file=my_open(name,O_RDONLY,MYF(MY_WME))) < 0)
288
327
      return(true);
289
 
    }
290
 
  }
291
 
 
292
 
  struct stat stat_info;
293
 
  if (stat(target_path.file_string().c_str(), &stat_info))
294
 
  {
295
 
    my_error(ER_FILE_NOT_FOUND, MYF(0), target_path.file_string().c_str(), errno);
296
 
    return(true);
297
 
  }
298
 
 
299
 
  // if we are not in slave thread, the cursor must be:
300
 
  if (!((stat_info.st_mode & S_IROTH) == S_IROTH &&  // readable by others
301
 
        (stat_info.st_mode & S_IFLNK) != S_IFLNK && // and not a symlink
302
 
        ((stat_info.st_mode & S_IFREG) == S_IFREG ||
303
 
         (stat_info.st_mode & S_IFIFO) == S_IFIFO)))
304
 
  {
305
 
    my_error(ER_TEXTFILE_NOT_READABLE, MYF(0), target_path.file_string().c_str());
306
 
    return(true);
307
 
  }
308
 
  if ((stat_info.st_mode & S_IFIFO) == S_IFIFO)
309
 
    is_fifo = 1;
310
 
 
311
 
 
312
 
  if ((file=internal::my_open(target_path.file_string().c_str(), O_RDONLY,MYF(MY_WME))) < 0)
313
 
  {
314
 
    my_error(ER_CANT_OPEN_FILE, MYF(0), target_path.file_string().c_str(), errno);
315
 
    return(true);
316
 
  }
317
 
  CopyInfo info;
318
 
  memset(&info, 0, sizeof(info));
 
328
  }
 
329
 
 
330
  COPY_INFO info;
 
331
  bzero((char*) &info,sizeof(info));
319
332
  info.ignore= ignore;
320
333
  info.handle_duplicates=handle_duplicates;
321
334
  info.escape_char=escaped->length() ? (*escaped)[0] : INT_MAX;
322
335
 
323
 
  identifier::Schema identifier(*schema);
324
 
  READ_INFO read_info(file, tot_length,
325
 
                      ex->cs ? ex->cs : plugin::StorageEngine::getSchemaCollation(identifier),
326
 
                      *field_term, *ex->line_start, *ex->line_term, *enclosed,
327
 
                      info.escape_char, is_fifo);
 
336
  READ_INFO read_info(file,tot_length,
 
337
                      ex->cs ? ex->cs : thd->variables.collation_database,
 
338
                      *field_term,*ex->line_start, *ex->line_term, *enclosed,
 
339
                      info.escape_char, read_file_from_client, is_fifo);
328
340
  if (read_info.error)
329
341
  {
330
342
    if  (file >= 0)
331
 
      internal::my_close(file,MYF(0));                  // no files in net reading
 
343
      my_close(file,MYF(0));                    // no files in net reading
332
344
    return(true);                               // Can't allocate buffers
333
345
  }
334
346
 
335
 
  /*
336
 
   * Per the SQL standard, inserting NULL into a NOT NULL
337
 
   * field requires an error to be thrown.
338
 
   *
339
 
   * @NOTE
340
 
   *
341
 
   * NULL check and handling occurs in field_conv.cc
342
 
   */
343
 
  session->count_cuted_fields= CHECK_FIELD_ERROR_FOR_NULL;
344
 
  session->cuted_fields=0L;
 
347
  if (mysql_bin_log.is_open())
 
348
  {
 
349
    lf_info.thd = thd;
 
350
    lf_info.wrote_create_file = 0;
 
351
    lf_info.last_pos_in_file = HA_POS_ERROR;
 
352
    lf_info.log_delayed= transactional_table;
 
353
    read_info.set_io_cache_arg((void*) &lf_info);
 
354
  }
 
355
 
 
356
  thd->count_cuted_fields= CHECK_FIELD_WARN;            /* calc cuted fields */
 
357
  thd->cuted_fields=0L;
345
358
  /* Skip lines if there is a line terminator */
346
 
  if (ex->line_term->length())
 
359
  if (ex->line_term->length() && ex->filetype != FILETYPE_XML)
347
360
  {
348
361
    /* ex->skip_lines needs to be preserved for logging */
349
362
    while (skip_lines > 0)
360
373
    table->next_number_field=table->found_next_number_field;
361
374
    if (ignore ||
362
375
        handle_duplicates == DUP_REPLACE)
363
 
      table->cursor->extra(HA_EXTRA_IGNORE_DUP_KEY);
 
376
      table->file->extra(HA_EXTRA_IGNORE_DUP_KEY);
364
377
    if (handle_duplicates == DUP_REPLACE)
365
 
        table->cursor->extra(HA_EXTRA_WRITE_CAN_REPLACE);
366
 
    table->cursor->ha_start_bulk_insert((ha_rows) 0);
 
378
        table->file->extra(HA_EXTRA_WRITE_CAN_REPLACE);
 
379
    table->file->ha_start_bulk_insert((ha_rows) 0);
367
380
    table->copy_blobs=1;
368
381
 
369
 
    session->setAbortOnWarning(true);
 
382
    thd->abort_on_warning= (!ignore &&
 
383
                            (thd->variables.sql_mode &
 
384
                             (MODE_STRICT_TRANS_TABLES |
 
385
                              MODE_STRICT_ALL_TABLES)));
370
386
 
371
 
    if (!field_term->length() && !enclosed->length())
372
 
      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,
373
393
                               set_fields, set_values, read_info,
374
394
                               skip_lines, ignore);
375
395
    else
376
 
      error= read_sep_field(session, info, table_list, fields_vars,
 
396
      error= read_sep_field(thd, info, table_list, fields_vars,
377
397
                            set_fields, set_values, read_info,
378
398
                            *enclosed, skip_lines, ignore);
379
 
    if (table->cursor->ha_end_bulk_insert() && !error)
 
399
    if (table->file->ha_end_bulk_insert() && !error)
380
400
    {
381
 
      table->print_error(errno, MYF(0));
 
401
      table->file->print_error(my_errno, MYF(0));
382
402
      error= 1;
383
403
    }
384
 
    table->cursor->extra(HA_EXTRA_NO_IGNORE_DUP_KEY);
385
 
    table->cursor->extra(HA_EXTRA_WRITE_CANNOT_REPLACE);
 
404
    table->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY);
 
405
    table->file->extra(HA_EXTRA_WRITE_CANNOT_REPLACE);
386
406
    table->next_number_field=0;
387
407
  }
388
408
  if (file >= 0)
389
 
    internal::my_close(file,MYF(0));
 
409
    my_close(file,MYF(0));
390
410
  free_blobs(table);                            /* if pack_blob was used */
391
411
  table->copy_blobs=0;
392
 
  session->count_cuted_fields= CHECK_FIELD_ERROR_FOR_NULL;
393
 
  /*
 
412
  thd->count_cuted_fields= CHECK_FIELD_IGNORE;
 
413
  /* 
394
414
     simulated killing in the middle of per-row loop
395
415
     must be effective for binlogging
396
416
  */
397
 
  killed_status= (error == 0)? Session::NOT_KILLED : session->getKilled();
 
417
  killed_status= (error == 0)? THD::NOT_KILLED : thd->killed;
398
418
  if (error)
399
419
  {
 
420
    if (read_file_from_client)
 
421
      while (!read_info.next_line())
 
422
        ;
 
423
 
 
424
    if (mysql_bin_log.is_open())
 
425
    {
 
426
      {
 
427
        /*
 
428
          Make sure last block (the one which caused the error) gets
 
429
          logged.  This is needed because otherwise after write of (to
 
430
          the binlog, not to read_info (which is a cache))
 
431
          Delete_file_log_event the bad block will remain in read_info
 
432
          (because pre_read is not called at the end of the last
 
433
          block; remember pre_read is called whenever a new block is
 
434
          read from disk).  At the end of mysql_load(), the destructor
 
435
          of read_info will call end_io_cache() which will flush
 
436
          read_info, so we will finally have this in the binlog:
 
437
 
 
438
          Append_block # The last successfull block
 
439
          Delete_file
 
440
          Append_block # The failing block
 
441
          which is nonsense.
 
442
          Or could also be (for a small file)
 
443
          Create_file  # The failing block
 
444
          which is nonsense (Delete_file is not written in this case, because:
 
445
          Create_file has not been written, so Delete_file is not written, then
 
446
          when read_info is destroyed end_io_cache() is called which writes
 
447
          Create_file.
 
448
        */
 
449
        read_info.end_io_cache();
 
450
        /* If the file was not empty, wrote_create_file is true */
 
451
        if (lf_info.wrote_create_file)
 
452
        {
 
453
          if (thd->transaction.stmt.modified_non_trans_table)
 
454
            write_execute_load_query_log_event(thd, handle_duplicates,
 
455
                                               ignore, transactional_table,
 
456
                                               killed_status);
 
457
          else
 
458
          {
 
459
            Delete_file_log_event d(thd, db, transactional_table);
 
460
            d.flags|= LOG_EVENT_UPDATE_TABLE_MAP_VERSION_F;
 
461
            mysql_bin_log.write(&d);
 
462
          }
 
463
        }
 
464
      }
 
465
    }
400
466
    error= -1;                          // Error on read
401
467
    goto err;
402
468
  }
403
 
 
404
 
  char msg[FN_REFLEN];
405
 
  snprintf(msg, sizeof(msg), ER(ER_LOAD_INFO), info.records, info.deleted,
406
 
           (info.records - info.copied), session->cuted_fields);
407
 
 
408
 
  if (session->transaction.stmt.hasModifiedNonTransData())
409
 
    session->transaction.all.markModifiedNonTransData();
 
469
  sprintf(name, ER(ER_LOAD_INFO), (ulong) info.records, (ulong) info.deleted,
 
470
          (ulong) (info.records - info.copied), (ulong) thd->cuted_fields);
 
471
 
 
472
  if (thd->transaction.stmt.modified_non_trans_table)
 
473
    thd->transaction.all.modified_non_trans_table= true;
 
474
 
 
475
  if (mysql_bin_log.is_open())
 
476
  {
 
477
    /*
 
478
      We need to do the job that is normally done inside
 
479
      binlog_query() here, which is to ensure that the pending event
 
480
      is written before tables are unlocked and before any other
 
481
      events are written.  We also need to update the table map
 
482
      version for the binary log to mark that table maps are invalid
 
483
      after this point.
 
484
     */
 
485
    if (thd->current_stmt_binlog_row_based)
 
486
      thd->binlog_flush_pending_rows_event(true);
 
487
    else
 
488
    {
 
489
      /*
 
490
        As already explained above, we need to call end_io_cache() or the last
 
491
        block will be logged only after Execute_load_query_log_event (which is
 
492
        wrong), when read_info is destroyed.
 
493
      */
 
494
      read_info.end_io_cache();
 
495
      if (lf_info.wrote_create_file)
 
496
      {
 
497
        write_execute_load_query_log_event(thd, handle_duplicates, ignore,
 
498
                                           transactional_table,killed_status);
 
499
      }
 
500
    }
 
501
  }
410
502
 
411
503
  /* ok to client sent only after binlog write and engine commit */
412
 
  session->my_ok(info.copied + info.deleted, 0, 0L, msg);
 
504
  my_ok(thd, info.copied + info.deleted, 0L, name);
413
505
err:
414
506
  assert(transactional_table || !(info.copied || info.deleted) ||
415
 
              session->transaction.stmt.hasModifiedNonTransData());
416
 
  table->cursor->ha_release_auto_increment();
 
507
              thd->transaction.stmt.modified_non_trans_table);
 
508
  table->file->ha_release_auto_increment();
417
509
  table->auto_increment_field_not_null= false;
418
 
  session->setAbortOnWarning(false);
419
 
 
 
510
  thd->abort_on_warning= 0;
420
511
  return(error);
421
512
}
422
513
 
423
514
 
 
515
/* Not a very useful function; just to avoid duplication of code */
 
516
static bool write_execute_load_query_log_event(THD *thd,
 
517
                                               bool duplicates, bool ignore,
 
518
                                               bool transactional_table,
 
519
                                               THD::killed_state killed_err_arg)
 
520
{
 
521
  Execute_load_query_log_event
 
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,
 
525
      (duplicates == DUP_REPLACE) ? LOAD_DUP_REPLACE :
 
526
      (ignore ? LOAD_DUP_IGNORE : LOAD_DUP_ERROR),
 
527
      transactional_table, false, killed_err_arg);
 
528
  e.flags|= LOG_EVENT_UPDATE_TABLE_MAP_VERSION_F;
 
529
  return mysql_bin_log.write(&e);
 
530
}
 
531
 
 
532
 
424
533
/****************************************************************************
425
534
** Read of rows of fixed size + optional garage + optonal newline
426
535
****************************************************************************/
427
536
 
428
537
static int
429
 
read_fixed_length(Session *session, CopyInfo &info, TableList *table_list,
 
538
read_fixed_length(THD *thd, COPY_INFO &info, TABLE_LIST *table_list,
430
539
                  List<Item> &fields_vars, List<Item> &set_fields,
431
540
                  List<Item> &set_values, READ_INFO &read_info,
432
 
                  uint32_t skip_lines, bool ignore_check_option_errors)
 
541
                  ulong skip_lines, bool ignore_check_option_errors)
433
542
{
434
 
  List<Item>::iterator it(fields_vars.begin());
 
543
  List_iterator_fast<Item> it(fields_vars);
435
544
  Item_field *sql_field;
436
 
  Table *table= table_list->table;
 
545
  TABLE *table= table_list->table;
437
546
  uint64_t id;
438
547
  bool err;
439
548
 
440
549
  id= 0;
441
 
 
 
550
 
442
551
  while (!read_info.read_fixed_length())
443
552
  {
444
 
    if (session->getKilled())
 
553
    if (thd->killed)
445
554
    {
446
 
      session->send_kill_message();
 
555
      thd->send_kill_message();
447
556
      return(1);
448
557
    }
449
558
    if (skip_lines)
457
566
      skip_lines--;
458
567
      continue;
459
568
    }
460
 
    it= fields_vars.begin();
461
 
    unsigned char *pos=read_info.row_start;
462
 
#ifdef HAVE_VALGRIND
 
569
    it.rewind();
 
570
    uchar *pos=read_info.row_start;
 
571
#ifdef HAVE_purify
463
572
    read_info.row_end[0]=0;
464
573
#endif
465
574
 
466
 
    table->restoreRecordAsDefault();
 
575
    restore_record(table, s->default_values);
467
576
    /*
468
577
      There is no variables in fields_vars list in this format so
469
578
      this conversion is safe.
470
579
    */
471
580
    while ((sql_field= (Item_field*) it++))
472
581
    {
473
 
      Field *field= sql_field->field;
 
582
      Field *field= sql_field->field;                  
474
583
      if (field == table->next_number_field)
475
584
        table->auto_increment_field_not_null= true;
476
585
      /*
482
591
 
483
592
      if (pos == read_info.row_end)
484
593
      {
485
 
        session->cuted_fields++;                        /* Not enough fields */
486
 
        push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_WARN,
487
 
                            ER_WARN_TOO_FEW_RECORDS,
488
 
                            ER(ER_WARN_TOO_FEW_RECORDS), session->row_count);
489
 
 
490
 
        if (not field->maybe_null() and field->is_timestamp())
491
 
            ((field::Epoch::pointer) field)->set_time();
 
594
        thd->cuted_fields++;                    /* Not enough fields */
 
595
        push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, 
 
596
                            ER_WARN_TOO_FEW_RECORDS, 
 
597
                            ER(ER_WARN_TOO_FEW_RECORDS), thd->row_count);
 
598
        if (!field->maybe_null() && field->type() == FIELD_TYPE_TIMESTAMP)
 
599
            ((Field_timestamp*) field)->set_time();
492
600
      }
493
601
      else
494
602
      {
495
 
        uint32_t length;
496
 
        unsigned char save_chr;
497
 
        if ((length=(uint32_t) (read_info.row_end-pos)) >
 
603
        uint length;
 
604
        uchar save_chr;
 
605
        if ((length=(uint) (read_info.row_end-pos)) >
498
606
            field->field_length)
499
 
        {
500
607
          length=field->field_length;
501
 
        }
502
 
        save_chr=pos[length];
503
 
        pos[length]='\0'; // Add temp null terminator for store()
 
608
        save_chr=pos[length]; pos[length]='\0'; // Safeguard aganst malloc
504
609
        field->store((char*) pos,length,read_info.read_charset);
505
610
        pos[length]=save_chr;
506
611
        if ((pos+=length) > read_info.row_end)
509
614
    }
510
615
    if (pos != read_info.row_end)
511
616
    {
512
 
      session->cuted_fields++;                  /* To long row */
513
 
      push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_WARN,
514
 
                          ER_WARN_TOO_MANY_RECORDS,
515
 
                          ER(ER_WARN_TOO_MANY_RECORDS), session->row_count);
 
617
      thd->cuted_fields++;                      /* To long row */
 
618
      push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, 
 
619
                          ER_WARN_TOO_MANY_RECORDS, 
 
620
                          ER(ER_WARN_TOO_MANY_RECORDS), thd->row_count); 
516
621
    }
517
622
 
518
 
    if (session->getKilled() ||
519
 
        fill_record(session, set_fields, set_values,
 
623
    if (thd->killed ||
 
624
        fill_record(thd, set_fields, set_values,
520
625
                    ignore_check_option_errors))
521
626
      return(1);
522
627
 
523
 
    err= write_record(session, table, &info);
 
628
    err= write_record(thd, table, &info);
524
629
    table->auto_increment_field_not_null= false;
525
630
    if (err)
526
631
      return(1);
527
 
 
 
632
   
528
633
    /*
529
634
      We don't need to reset auto-increment field since we are restoring
530
635
      its default value at the beginning of each loop iteration.
533
638
      break;
534
639
    if (read_info.line_cuted)
535
640
    {
536
 
      session->cuted_fields++;                  /* To long row */
537
 
      push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_WARN,
538
 
                          ER_WARN_TOO_MANY_RECORDS,
539
 
                          ER(ER_WARN_TOO_MANY_RECORDS), session->row_count);
 
641
      thd->cuted_fields++;                      /* To long row */
 
642
      push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, 
 
643
                          ER_WARN_TOO_MANY_RECORDS, 
 
644
                          ER(ER_WARN_TOO_MANY_RECORDS), thd->row_count); 
540
645
    }
541
 
    session->row_count++;
 
646
    thd->row_count++;
542
647
  }
543
648
  return(test(read_info.error));
544
649
}
546
651
 
547
652
 
548
653
static int
549
 
read_sep_field(Session *session, CopyInfo &info, TableList *table_list,
 
654
read_sep_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list,
550
655
               List<Item> &fields_vars, List<Item> &set_fields,
551
656
               List<Item> &set_values, READ_INFO &read_info,
552
 
               String &enclosed, uint32_t skip_lines,
 
657
               String &enclosed, ulong skip_lines,
553
658
               bool ignore_check_option_errors)
554
659
{
555
 
  List<Item>::iterator it(fields_vars.begin());
 
660
  List_iterator_fast<Item> it(fields_vars);
556
661
  Item *item;
557
 
  Table *table= table_list->table;
558
 
  uint32_t enclosed_length;
 
662
  TABLE *table= table_list->table;
 
663
  uint enclosed_length;
559
664
  uint64_t id;
560
665
  bool err;
561
666
 
562
667
  enclosed_length=enclosed.length();
563
668
  id= 0;
564
669
 
565
 
  for (;;it= fields_vars.begin())
 
670
  for (;;it.rewind())
566
671
  {
567
 
    if (session->getKilled())
 
672
    if (thd->killed)
568
673
    {
569
 
      session->send_kill_message();
 
674
      thd->send_kill_message();
570
675
      return(1);
571
676
    }
572
677
 
573
 
    table->restoreRecordAsDefault();
 
678
    restore_record(table, s->default_values);
574
679
 
575
680
    while ((item= it++))
576
681
    {
577
 
      uint32_t length;
578
 
      unsigned char *pos;
 
682
      uint length;
 
683
      uchar *pos;
579
684
      Item *real_item;
580
685
 
581
686
      if (read_info.read_field())
586
691
        continue;
587
692
 
588
693
      pos=read_info.row_start;
589
 
      length=(uint32_t) (read_info.row_end-pos);
 
694
      length=(uint) (read_info.row_end-pos);
590
695
 
591
696
      real_item= item->real_item();
592
697
 
600
705
          if (field->reset())
601
706
          {
602
707
            my_error(ER_WARN_NULL_TO_NOTNULL, MYF(0), field->field_name,
603
 
                     session->row_count);
 
708
                     thd->row_count);
604
709
            return(1);
605
710
          }
606
711
          field->set_null();
607
 
          if (not field->maybe_null())
 
712
          if (!field->maybe_null())
608
713
          {
609
 
            if (field->is_timestamp())
610
 
            {
611
 
              ((field::Epoch::pointer) field)->set_time();
612
 
            }
 
714
            if (field->type() == MYSQL_TYPE_TIMESTAMP)
 
715
              ((Field_timestamp*) field)->set_time();
613
716
            else if (field != table->next_number_field)
614
 
            {
615
 
              field->set_warning(DRIZZLE_ERROR::WARN_LEVEL_WARN, ER_WARN_NULL_TO_NOTNULL, 1);
616
 
            }
 
717
              field->set_warning(MYSQL_ERROR::WARN_LEVEL_WARN,
 
718
                                 ER_WARN_NULL_TO_NOTNULL, 1);
617
719
          }
618
720
        }
619
721
        else if (item->type() == Item::STRING_ITEM)
659
761
    }
660
762
    if (item)
661
763
    {
662
 
      /* Have not read any field, thus input cursor is simply ended */
 
764
      /* Have not read any field, thus input file is simply ended */
663
765
      if (item == fields_vars.head())
664
766
        break;
665
767
      for (; item ; item= it++)
671
773
          if (field->reset())
672
774
          {
673
775
            my_error(ER_WARN_NULL_TO_NOTNULL, MYF(0),field->field_name,
674
 
                     session->row_count);
 
776
                     thd->row_count);
675
777
            return(1);
676
778
          }
677
 
          if (not field->maybe_null() and field->is_timestamp())
678
 
              ((field::Epoch::pointer) field)->set_time();
 
779
          if (!field->maybe_null() && field->type() == FIELD_TYPE_TIMESTAMP)
 
780
              ((Field_timestamp*) field)->set_time();
679
781
          /*
680
782
            QQ: We probably should not throw warning for each field.
681
783
            But how about intention to always have the same number
682
 
            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
683
785
            in the end ?)
684
786
          */
685
 
          session->cuted_fields++;
686
 
          push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_WARN,
 
787
          thd->cuted_fields++;
 
788
          push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
687
789
                              ER_WARN_TOO_FEW_RECORDS,
688
 
                              ER(ER_WARN_TOO_FEW_RECORDS), session->row_count);
 
790
                              ER(ER_WARN_TOO_FEW_RECORDS), thd->row_count);
689
791
        }
690
792
        else if (item->type() == Item::STRING_ITEM)
691
793
        {
700
802
      }
701
803
    }
702
804
 
703
 
    if (session->getKilled() ||
704
 
        fill_record(session, set_fields, set_values,
 
805
    if (thd->killed ||
 
806
        fill_record(thd, set_fields, set_values,
705
807
                    ignore_check_option_errors))
706
808
      return(1);
707
809
 
708
 
    err= write_record(session, table, &info);
 
810
    err= write_record(thd, table, &info);
709
811
    table->auto_increment_field_not_null= false;
710
812
    if (err)
711
813
      return(1);
717
819
      break;
718
820
    if (read_info.line_cuted)
719
821
    {
720
 
      session->cuted_fields++;                  /* To long row */
721
 
      push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_WARN,
722
 
                          ER_WARN_TOO_MANY_RECORDS, ER(ER_WARN_TOO_MANY_RECORDS),
723
 
                          session->row_count);
724
 
      if (session->getKilled())
 
822
      thd->cuted_fields++;                      /* To long row */
 
823
      push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, 
 
824
                          ER_WARN_TOO_MANY_RECORDS, ER(ER_WARN_TOO_MANY_RECORDS), 
 
825
                          thd->row_count);   
 
826
      if (thd->killed)
725
827
        return(1);
726
828
    }
727
 
    session->row_count++;
 
829
    thd->row_count++;
728
830
  }
729
831
  return(test(read_info.error));
730
832
}
731
833
 
732
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
 
733
977
/* Unescape all escape characters, mark \N as null */
734
978
 
735
979
char
742
986
  case 'r': return '\r';
743
987
  case 'b': return '\b';
744
988
  case '0': return 0;                           // Ascii null
745
 
  case 'Z': return '\032';                      // Win32 end of cursor
 
989
  case 'Z': return '\032';                      // Win32 end of file
746
990
  case 'N': found_null=1;
747
991
 
748
992
    /* fall through */
757
1001
*/
758
1002
 
759
1003
 
760
 
READ_INFO::READ_INFO(int file_par, size_t tot_length,
761
 
                     const CHARSET_INFO * const cs,
 
1004
READ_INFO::READ_INFO(File file_par, uint tot_length, CHARSET_INFO *cs,
762
1005
                     String &field_term, String &line_start, String &line_term,
763
 
                     String &enclosed_par, int escape, bool is_fifo)
764
 
  :cursor(file_par),escape_char(escape)
 
1006
                     String &enclosed_par, int escape, bool get_it_from_net,
 
1007
                     bool is_fifo)
 
1008
  :file(file_par),escape_char(escape)
765
1009
{
766
1010
  read_charset= cs;
767
1011
  field_term_ptr=(char*) field_term.ptr();
768
1012
  field_term_length= field_term.length();
769
1013
  line_term_ptr=(char*) line_term.ptr();
770
1014
  line_term_length= line_term.length();
 
1015
  level= 0; /* for load xml */
771
1016
  if (line_start.length() == 0)
772
1017
  {
773
1018
    line_start_ptr=0;
787
1032
    line_term_ptr=(char*) "";
788
1033
  }
789
1034
  enclosed_char= (enclosed_length=enclosed_par.length()) ?
790
 
    (unsigned char) enclosed_par[0] : INT_MAX;
791
 
  field_term_char= field_term_length ? (unsigned char) field_term_ptr[0] : INT_MAX;
792
 
  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;
793
1038
  error=eof=found_end_of_line=found_null=line_cuted=0;
794
1039
  buff_length=tot_length;
795
1040
 
796
1041
 
797
1042
  /* Set of a stack for unget if long terminators */
798
 
  size_t length= max(field_term_length,line_term_length)+1;
799
 
  set_if_bigger(length, line_start.length());
800
 
  stack= stack_pos= (int*) memory::sql_alloc(sizeof(int)*length);
 
1043
  uint length=max(field_term_length,line_term_length)+1;
 
1044
  set_if_bigger(length,line_start.length());
 
1045
  stack=stack_pos=(int*) sql_alloc(sizeof(int)*length);
801
1046
 
802
 
  if (!(buffer=(unsigned char*) calloc(1, buff_length+1)))
803
 
    error=1;
 
1047
  if (!(buffer=(uchar*) my_malloc(buff_length+1,MYF(0))))
 
1048
    error=1; /* purecov: inspected */
804
1049
  else
805
1050
  {
806
1051
    end_of_buff=buffer+buff_length;
807
 
    if (cache.init_io_cache((false) ? -1 : cursor, 0,
808
 
                            (false) ? internal::READ_NET :
809
 
                            (is_fifo ? internal::READ_FIFO : internal::READ_CACHE),0L,1,
810
 
                            MYF(MY_WME)))
 
1052
    if (init_io_cache(&cache,(get_it_from_net) ? -1 : file, 0,
 
1053
                      (get_it_from_net) ? READ_NET :
 
1054
                      (is_fifo ? READ_FIFO : READ_CACHE),0L,1,
 
1055
                      MYF(MY_WME)))
811
1056
    {
812
 
      free((unsigned char*) buffer);
 
1057
      my_free((uchar*) buffer,MYF(0)); /* purecov: inspected */
813
1058
      error=1;
814
1059
    }
815
1060
    else
820
1065
        manual assignment
821
1066
      */
822
1067
      need_end_io_cache = 1;
 
1068
 
 
1069
      if (get_it_from_net)
 
1070
        cache.read_function = _my_b_net_read;
 
1071
 
 
1072
      if (mysql_bin_log.is_open())
 
1073
        cache.pre_read = cache.pre_close =
 
1074
          (IO_CACHE_CALLBACK) log_loaded_block;
823
1075
    }
824
1076
  }
825
1077
}
830
1082
  if (!error)
831
1083
  {
832
1084
    if (need_end_io_cache)
833
 
      cache.end_io_cache();
834
 
    free(buffer);
 
1085
      ::end_io_cache(&cache);
 
1086
    my_free((uchar*) buffer,MYF(0));
835
1087
    error=1;
836
1088
  }
 
1089
  List_iterator<XML_TAG> xmlit(taglist);
 
1090
  XML_TAG *t;
 
1091
  while ((t= xmlit++))
 
1092
    delete(t);
837
1093
}
838
1094
 
839
1095
 
841
1097
#define PUSH(A) *(stack_pos++)=(A)
842
1098
 
843
1099
 
844
 
inline int READ_INFO::terminator(char *ptr,uint32_t length)
 
1100
inline int READ_INFO::terminator(char *ptr,uint length)
845
1101
{
846
1102
  int chr=0;                                    // Keep gcc happy
847
 
  uint32_t i;
 
1103
  uint i;
848
1104
  for (i=1 ; i < length ; i++)
849
1105
  {
850
1106
    if ((chr=GET) != *++ptr)
856
1112
    return 1;
857
1113
  PUSH(chr);
858
1114
  while (i-- > 1)
859
 
    PUSH((unsigned char) *--ptr);
 
1115
    PUSH((uchar) *--ptr);
860
1116
  return 0;
861
1117
}
862
1118
 
864
1120
int READ_INFO::read_field()
865
1121
{
866
1122
  int chr,found_enclosed_char;
867
 
  unsigned char *to,*new_buffer;
 
1123
  uchar *to,*new_buffer;
868
1124
 
869
1125
  found_null=0;
870
1126
  if (found_end_of_line)
887
1143
  if (chr == enclosed_char)
888
1144
  {
889
1145
    found_enclosed_char=enclosed_char;
890
 
    *to++=(unsigned char) chr;                          // If error
 
1146
    *to++=(uchar) chr;                          // If error
891
1147
  }
892
1148
  else
893
1149
  {
900
1156
    while ( to < end_of_buff)
901
1157
    {
902
1158
      chr = GET;
 
1159
#ifdef USE_MB
903
1160
      if ((my_mbcharlen(read_charset, chr) > 1) &&
904
1161
          to+my_mbcharlen(read_charset, chr) <= end_of_buff)
905
1162
      {
906
 
        unsigned char* p = (unsigned char*)to;
907
 
        *to++ = chr;
908
 
        int ml = my_mbcharlen(read_charset, chr);
909
 
        int i;
910
 
        for (i=1; i<ml; i++) {
911
 
          chr = GET;
912
 
          if (chr == my_b_EOF)
913
 
            goto found_eof;
914
 
          *to++ = chr;
915
 
        }
916
 
        if (my_ismbchar(read_charset,
917
 
              (const char *)p,
918
 
              (const char *)to))
919
 
          continue;
920
 
        for (i=0; i<ml; i++)
921
 
          PUSH((unsigned char) *--to);
922
 
        chr = GET;
 
1163
          uchar* p = (uchar*)to;
 
1164
          *to++ = chr;
 
1165
          int ml = my_mbcharlen(read_charset, chr);
 
1166
          int i;
 
1167
          for (i=1; i<ml; i++) {
 
1168
              chr = GET;
 
1169
              if (chr == my_b_EOF)
 
1170
                  goto found_eof;
 
1171
              *to++ = chr;
 
1172
          }
 
1173
          if (my_ismbchar(read_charset,
 
1174
                          (const char *)p,
 
1175
                          (const char *)to))
 
1176
            continue;
 
1177
          for (i=0; i<ml; i++)
 
1178
            PUSH((uchar) *--to);
 
1179
          chr = GET;
923
1180
      }
 
1181
#endif
924
1182
      if (chr == my_b_EOF)
925
 
        goto found_eof;
 
1183
        goto found_eof;
926
1184
      if (chr == escape_char)
927
1185
      {
928
 
        if ((chr=GET) == my_b_EOF)
929
 
        {
930
 
          *to++= (unsigned char) escape_char;
931
 
          goto found_eof;
932
 
        }
 
1186
        if ((chr=GET) == my_b_EOF)
 
1187
        {
 
1188
          *to++= (uchar) escape_char;
 
1189
          goto found_eof;
 
1190
        }
933
1191
        /*
934
1192
          When escape_char == enclosed_char, we treat it like we do for
935
1193
          handling quotes in SQL parsing -- you can double-up the
939
1197
         */
940
1198
        if (escape_char != enclosed_char || chr == escape_char)
941
1199
        {
942
 
          *to++ = (unsigned char) unescape((char) chr);
 
1200
          *to++ = (uchar) unescape((char) chr);
943
1201
          continue;
944
1202
        }
945
1203
        PUSH(chr);
948
1206
#ifdef ALLOW_LINESEPARATOR_IN_STRINGS
949
1207
      if (chr == line_term_char)
950
1208
#else
951
 
        if (chr == line_term_char && found_enclosed_char == INT_MAX)
 
1209
      if (chr == line_term_char && found_enclosed_char == INT_MAX)
952
1210
#endif
953
 
        {
954
 
          if (terminator(line_term_ptr,line_term_length))
955
 
          {                                     // Maybe unexpected linefeed
956
 
            enclosed=0;
957
 
            found_end_of_line=1;
958
 
            row_start=buffer;
959
 
            row_end=  to;
960
 
            return 0;
961
 
          }
962
 
        }
 
1211
      {
 
1212
        if (terminator(line_term_ptr,line_term_length))
 
1213
        {                                       // Maybe unexpected linefeed
 
1214
          enclosed=0;
 
1215
          found_end_of_line=1;
 
1216
          row_start=buffer;
 
1217
          row_end=  to;
 
1218
          return 0;
 
1219
        }
 
1220
      }
963
1221
      if (chr == found_enclosed_char)
964
1222
      {
965
 
        if ((chr=GET) == found_enclosed_char)
966
 
        {                                       // Remove dupplicated
967
 
          *to++ = (unsigned char) chr;
968
 
          continue;
969
 
        }
970
 
        // End of enclosed field if followed by field_term or line_term
971
 
        if (chr == my_b_EOF ||
972
 
            (chr == line_term_char && terminator(line_term_ptr, line_term_length)))
973
 
        {                                       // Maybe unexpected linefeed
974
 
          enclosed=1;
975
 
          found_end_of_line=1;
976
 
          row_start=buffer+1;
977
 
          row_end=  to;
978
 
          return 0;
979
 
        }
980
 
        if (chr == field_term_char &&
981
 
            terminator(field_term_ptr,field_term_length))
982
 
        {
983
 
          enclosed=1;
984
 
          row_start=buffer+1;
985
 
          row_end=  to;
986
 
          return 0;
987
 
        }
988
 
        /*
989
 
           The string didn't terminate yet.
990
 
           Store back next character for the loop
991
 
         */
992
 
        PUSH(chr);
993
 
        /* copy the found term character to 'to' */
994
 
        chr= found_enclosed_char;
 
1223
        if ((chr=GET) == found_enclosed_char)
 
1224
        {                                       // Remove dupplicated
 
1225
          *to++ = (uchar) chr;
 
1226
          continue;
 
1227
        }
 
1228
        // End of enclosed field if followed by field_term or line_term
 
1229
        if (chr == my_b_EOF ||
 
1230
            (chr == line_term_char && terminator(line_term_ptr, line_term_length)))
 
1231
        {                                       // Maybe unexpected linefeed
 
1232
          enclosed=1;
 
1233
          found_end_of_line=1;
 
1234
          row_start=buffer+1;
 
1235
          row_end=  to;
 
1236
          return 0;
 
1237
        }
 
1238
        if (chr == field_term_char &&
 
1239
            terminator(field_term_ptr,field_term_length))
 
1240
        {
 
1241
          enclosed=1;
 
1242
          row_start=buffer+1;
 
1243
          row_end=  to;
 
1244
          return 0;
 
1245
        }
 
1246
        /*
 
1247
          The string didn't terminate yet.
 
1248
          Store back next character for the loop
 
1249
        */
 
1250
        PUSH(chr);
 
1251
        /* copy the found term character to 'to' */
 
1252
        chr= found_enclosed_char;
995
1253
      }
996
1254
      else if (chr == field_term_char && found_enclosed_char == INT_MAX)
997
1255
      {
998
 
        if (terminator(field_term_ptr,field_term_length))
999
 
        {
1000
 
          enclosed=0;
1001
 
          row_start=buffer;
1002
 
          row_end=  to;
1003
 
          return 0;
1004
 
        }
 
1256
        if (terminator(field_term_ptr,field_term_length))
 
1257
        {
 
1258
          enclosed=0;
 
1259
          row_start=buffer;
 
1260
          row_end=  to;
 
1261
          return 0;
 
1262
        }
1005
1263
      }
1006
 
      *to++ = (unsigned char) chr;
 
1264
      *to++ = (uchar) chr;
1007
1265
    }
1008
1266
    /*
1009
 
     ** We come here if buffer is too small. Enlarge it and continue
1010
 
     */
1011
 
    if (!(new_buffer=(unsigned char*) realloc(buffer, buff_length+1+IO_SIZE)))
 
1267
    ** We come here if buffer is too small. Enlarge it and continue
 
1268
    */
 
1269
    if (!(new_buffer=(uchar*) my_realloc((char*) buffer,buff_length+1+IO_SIZE,
 
1270
                                        MYF(MY_WME))))
1012
1271
      return (error=1);
1013
1272
    to=new_buffer + (to-buffer);
1014
1273
    buffer=new_buffer;
1029
1288
 
1030
1289
  NOTES
1031
1290
    The row may not be fixed size on disk if there are escape
1032
 
    characters in the cursor.
 
1291
    characters in the file.
1033
1292
 
1034
1293
  IMPLEMENTATION NOTE
1035
1294
    One can't use fixed length with multi-byte charset **
1042
1301
int READ_INFO::read_fixed_length()
1043
1302
{
1044
1303
  int chr;
1045
 
  unsigned char *to;
 
1304
  uchar *to;
1046
1305
  if (found_end_of_line)
1047
1306
    return 1;                                   // One have to call next_line
1048
1307
 
1062
1321
    {
1063
1322
      if ((chr=GET) == my_b_EOF)
1064
1323
      {
1065
 
        *to++= (unsigned char) escape_char;
 
1324
        *to++= (uchar) escape_char;
1066
1325
        goto found_eof;
1067
1326
      }
1068
 
      *to++ =(unsigned char) unescape((char) chr);
 
1327
      *to++ =(uchar) unescape((char) chr);
1069
1328
      continue;
1070
1329
    }
1071
1330
    if (chr == line_term_char)
1077
1336
        return 0;
1078
1337
      }
1079
1338
    }
1080
 
    *to++ = (unsigned char) chr;
 
1339
    *to++ = (uchar) chr;
1081
1340
  }
1082
1341
  row_end=to;                                   // Found full line
1083
1342
  return 0;
1105
1364
  for (;;)
1106
1365
  {
1107
1366
    int chr = GET;
1108
 
    if (my_mbcharlen(read_charset, chr) > 1)
1109
 
    {
1110
 
      for (uint32_t i=1;
1111
 
          chr != my_b_EOF && i<my_mbcharlen(read_charset, chr);
1112
 
          i++)
1113
 
        chr = GET;
1114
 
      if (chr == escape_char)
1115
 
        continue;
1116
 
    }
1117
 
    if (chr == my_b_EOF)
1118
 
    {
 
1367
#ifdef USE_MB
 
1368
   if (my_mbcharlen(read_charset, chr) > 1)
 
1369
   {
 
1370
       for (uint i=1;
 
1371
            chr != my_b_EOF && i<my_mbcharlen(read_charset, chr);
 
1372
            i++)
 
1373
           chr = GET;
 
1374
       if (chr == escape_char)
 
1375
           continue;
 
1376
   }
 
1377
#endif
 
1378
   if (chr == my_b_EOF)
 
1379
   {
1119
1380
      eof=1;
1120
1381
      return 1;
1121
1382
    }
1123
1384
    {
1124
1385
      line_cuted=1;
1125
1386
      if (GET == my_b_EOF)
1126
 
        return 1;
 
1387
        return 1;
1127
1388
      continue;
1128
1389
    }
1129
1390
    if (chr == line_term_char && terminator(line_term_ptr,line_term_length))
1153
1414
      PUSH(chr);
1154
1415
      while (--ptr != line_start_ptr)
1155
1416
      {                                         // Restart with next char
1156
 
        PUSH((unsigned char) *ptr);
 
1417
        PUSH((uchar) *ptr);
1157
1418
      }
1158
1419
      goto try_again;
1159
1420
    }
1162
1423
}
1163
1424
 
1164
1425
 
1165
 
} /* namespace drizzled */
 
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
}