sql_load.cc 28.6 KB
Newer Older
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
2

bk@work.mysql.com's avatar
bk@work.mysql.com committed
3 4 5 6
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2 of the License, or
   (at your option) any later version.
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
7

bk@work.mysql.com's avatar
bk@work.mysql.com committed
8 9 10 11
   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
12

bk@work.mysql.com's avatar
bk@work.mysql.com committed
13 14 15 16 17 18 19 20 21 22
   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */


/* Copy data from a textfile to table */

#include "mysql_priv.h"
#include <my_dir.h>
#include <m_ctype.h>
23
#include "sql_repl.h"
bk@work.mysql.com's avatar
bk@work.mysql.com committed
24 25 26 27 28 29 30 31 32 33 34 35

class READ_INFO {
  File	file;
  byte	*buffer,			/* Buffer for read text */
	*end_of_buff;			/* Data in bufferts ends here */
  uint	buff_length,			/* Length of buffert */
	max_length;			/* Max length of row */
  char	*field_term_ptr,*line_term_ptr,*line_start_ptr,*line_start_end;
  uint	field_term_length,line_term_length,enclosed_length;
  int	field_term_char,line_term_char,enclosed_char,escape_char;
  int	*stack,*stack_pos;
  bool	found_end_of_line,start_of_line,eof;
36
  bool  need_end_io_cache;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
37 38 39 40 41 42 43
  IO_CACHE cache;
  NET *io_net;

public:
  bool error,line_cuted,found_null,enclosed;
  byte	*row_start,			/* Found row starts here */
	*row_end;			/* Found row ends here */
bar@bar.mysql.r18.ru's avatar
bar@bar.mysql.r18.ru committed
44
  CHARSET_INFO *read_charset;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
45

bar@bar.mysql.r18.ru's avatar
bar@bar.mysql.r18.ru committed
46
  READ_INFO(File file,uint tot_length,CHARSET_INFO *cs,
bk@work.mysql.com's avatar
bk@work.mysql.com committed
47
	    String &field_term,String &line_start,String &line_term,
48
	    String &enclosed,int escape,bool get_it_from_net, bool is_fifo);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
49 50 51 52 53 54 55
  ~READ_INFO();
  int read_field();
  int read_fixed_length(void);
  int next_line(void);
  char unescape(char chr);
  int terminator(char *ptr,uint length);
  bool find_start_of_fields();
56 57 58 59
  /*
    We need to force cache close before destructor is invoked to log
    the last read block
  */
60 61 62 63 64 65
  void end_io_cache()
  {
    ::end_io_cache(&cache);
    need_end_io_cache = 0;
  }

66 67 68 69 70
  /*
    Either this method, or we need to make cache public
    Arg must be set from mysql_load() since constructor does not see
    either the table or THD value
  */
71
  void set_io_cache_arg(void* arg) { cache.arg = arg; }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
72 73
};

74
static int read_fixed_length(THD *thd, COPY_INFO &info, TABLE_LIST *table_list,
75
			     List<Item> &fields, READ_INFO &read_info,
76 77 78
			     ulong skip_lines,
			     bool ignore_check_option_errors);
static int read_sep_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list,
bk@work.mysql.com's avatar
bk@work.mysql.com committed
79
			  List<Item> &fields, READ_INFO &read_info,
80 81
			  String &enclosed, ulong skip_lines,
			  bool ignore_check_option_errors);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
82

83
bool mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
bk@work.mysql.com's avatar
bk@work.mysql.com committed
84
	       List<Item> &fields, enum enum_duplicates handle_duplicates,
85 86
	       bool read_file_from_client,thr_lock_type lock_type,
	       bool ignore_check_option_errors)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
87 88 89 90 91
{
  char name[FN_REFLEN];
  File file;
  TABLE *table;
  int error;
92 93
  String *field_term=ex->field_term,*escaped=ex->escaped;
  String *enclosed=ex->enclosed;
94
  Item *unused_conds= 0;
95
  bool is_fifo=0;
96
#ifndef EMBEDDED_LIBRARY
97
  LOAD_FILE_INFO lf_info;
98
#endif
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
99
  char *db = table_list->db;			// This is never null
monty@mysql.com's avatar
monty@mysql.com committed
100 101 102 103 104
  /*
    If path for file is not defined, we will use the current database.
    If this is not set, we will use the directory where the table to be
    loaded is located
  */
monty@mysql.com's avatar
monty@mysql.com committed
105
  char *tdb= thd->db ? thd->db : db;		// Result is never null
106
  ulong skip_lines= ex->skip_lines;
107 108
  int res;
  bool transactional_table, log_delayed;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
109 110
  DBUG_ENTER("mysql_load");

111 112 113 114
#ifdef EMBEDDED_LIBRARY
  read_file_from_client  = 0; //server is always in the same process 
#endif

bk@work.mysql.com's avatar
bk@work.mysql.com committed
115 116 117 118
  if (escaped->length() > 1 || enclosed->length() > 1)
  {
    my_message(ER_WRONG_FIELD_TERMINATORS,ER(ER_WRONG_FIELD_TERMINATORS),
	       MYF(0));
119
    DBUG_RETURN(TRUE);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
120
  }
bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
121
  table_list->lock_type= lock_type;
122 123
  if (open_and_lock_tables(thd, table_list))
    DBUG_RETURN(TRUE);
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
124
  if (setup_tables(thd, table_list, &unused_conds,
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
125
		   &thd->lex->select_lex.leaf_tables, FALSE, FALSE))
126
     DBUG_RETURN(-1);
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
127 128 129
  if (!table_list->table ||               // do not suport join view
      !table_list->updatable ||           // and derived tables
      check_key_in_view(thd, table_list))
bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
130
  {
131
    my_error(ER_NON_UPDATABLE_TABLE, MYF(0), table_list->alias, "LOAD");
132
    DBUG_RETURN(TRUE);
bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
133 134
  }
  table= table_list->table;
135 136 137
  transactional_table= table->file->has_transactions();
  log_delayed= (transactional_table || table->tmp_table);

bk@work.mysql.com's avatar
bk@work.mysql.com committed
138 139 140 141 142 143 144 145 146
  if (!fields.elements)
  {
    Field **field;
    for (field=table->field; *field ; field++)
      fields.push_back(new Item_field(*field));
  }
  else
  {						// Part field list
    thd->dupp_field=0;
bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
147 148
    /* TODO: use this conds for 'WITH CHECK OPTIONS' */
    Item *unused_conds= 0;
149
    TABLE_LIST *leaves= 0;
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
150
    if (setup_fields(thd, 0, table_list, fields, 1, 0, 0))
151
      DBUG_RETURN(TRUE);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
152 153
    if (thd->dupp_field)
    {
154
      my_error(ER_FIELD_SPECIFIED_TWICE, MYF(0), thd->dupp_field->field_name);
155
      DBUG_RETURN(TRUE);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
156
    }
157
    if (check_that_all_fields_are_given_values(thd, table))
158
      DBUG_RETURN(TRUE);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
159 160 161 162
  }

  uint tot_length=0;
  bool use_blobs=0,use_timestamp=0;
monty@tik.mysql.fi's avatar
monty@tik.mysql.fi committed
163
  List_iterator_fast<Item> it(fields);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183

  Item_field *field;
  while ((field=(Item_field*) it++))
  {
    if (field->field->flags & BLOB_FLAG)
    {
      use_blobs=1;
      tot_length+=256;				// Will be extended if needed
    }
    else
      tot_length+=field->field->field_length;
    if (!field_term->length() && !(field->field->flags & NOT_NULL_FLAG))
      field->field->set_notnull();
    if (field->field == table->timestamp_field)
      use_timestamp=1;
  }
  if (use_blobs && !ex->line_term->length() && !field_term->length())
  {
    my_message(ER_BLOBS_AND_NO_TERMINATED,ER(ER_BLOBS_AND_NO_TERMINATED),
	       MYF(0));
184
    DBUG_RETURN(TRUE);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
185 186 187 188 189 190
  }

  /* We can't give an error in the middle when using LOCAL files */
  if (read_file_from_client && handle_duplicates == DUP_ERROR)
    handle_duplicates=DUP_IGNORE;

191
#ifndef EMBEDDED_LIBRARY
192
  if (read_file_from_client)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
193
  {
194
    (void)net_request_file(&thd->net,ex->file_name);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
195 196 197
    file = -1;
  }
  else
198
#endif
bk@work.mysql.com's avatar
bk@work.mysql.com committed
199 200 201 202
  {
#ifdef DONT_ALLOW_FULL_LOAD_DATA_PATHS
    ex->file_name+=dirname_length(ex->file_name);
#endif
203
    if (!dirname_length(ex->file_name))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
204
    {
205
      strxnmov(name, FN_REFLEN, mysql_real_data_home, tdb, NullS);
hf@deer.(none)'s avatar
hf@deer.(none) committed
206 207
      (void) fn_format(name, ex->file_name, name, "",
		       MY_RELATIVE_PATH | MY_UNPACK_FILENAME);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
208 209 210
    }
    else
    {
hf@deer.(none)'s avatar
hf@deer.(none) committed
211 212
      (void) fn_format(name, ex->file_name, mysql_real_data_home, "",
		       MY_RELATIVE_PATH | MY_UNPACK_FILENAME);
213
#if !defined(__WIN__) && !defined(OS2) && ! defined(__NETWARE__)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
214
      MY_STAT stat_info;
215
      if (!my_stat(name,&stat_info,MYF(MY_WME)))
216
	DBUG_RETURN(TRUE);
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
217

218 219 220
      // if we are not in slave thread, the file must be:
      if (!thd->slave_thread &&
	  !((stat_info.st_mode & S_IROTH) == S_IROTH &&  // readable by others
221
#ifndef __EMX__
222
	    (stat_info.st_mode & S_IFLNK) != S_IFLNK && // and not a symlink
223
#endif
224 225
	    ((stat_info.st_mode & S_IFREG) == S_IFREG ||
	     (stat_info.st_mode & S_IFIFO) == S_IFIFO)))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
226
      {
227
	my_error(ER_TEXTFILE_NOT_READABLE, MYF(0), name);
228
	DBUG_RETURN(TRUE);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
229
      }
230 231
      if ((stat_info.st_mode & S_IFIFO) == S_IFIFO)
	is_fifo = 1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
232 233 234
#endif
    }
    if ((file=my_open(name,O_RDONLY,MYF(MY_WME))) < 0)
235
      DBUG_RETURN(TRUE);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
236 237 238 239 240 241 242
  }

  COPY_INFO info;
  bzero((char*) &info,sizeof(info));
  info.handle_duplicates=handle_duplicates;
  info.escape_char=escaped->length() ? (*escaped)[0] : INT_MAX;

243
  READ_INFO read_info(file,tot_length,thd->variables.collation_database,
bar@bar.mysql.r18.ru's avatar
bar@bar.mysql.r18.ru committed
244
		      *field_term,*ex->line_start, *ex->line_term, *enclosed,
245
		      info.escape_char, read_file_from_client, is_fifo);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
246 247 248 249
  if (read_info.error)
  {
    if	(file >= 0)
      my_close(file,MYF(0));			// no files in net reading
250
    DBUG_RETURN(TRUE);				// Can't allocate buffers
bk@work.mysql.com's avatar
bk@work.mysql.com committed
251 252
  }

253
#ifndef EMBEDDED_LIBRARY
254
  if (mysql_bin_log.is_open())
255 256 257 258 259 260 261 262 263
  {
    lf_info.thd = thd;
    lf_info.ex = ex;
    lf_info.db = db;
    lf_info.table_name = table_list->real_name;
    lf_info.fields = &fields;
    lf_info.handle_dup = handle_duplicates;
    lf_info.wrote_create_file = 0;
    lf_info.last_pos_in_file = HA_POS_ERROR;
264
    lf_info.log_delayed= log_delayed;
265
    read_info.set_io_cache_arg((void*) &lf_info);
266
  }
267 268
#endif /*!EMBEDDED_LIBRARY*/

269
  restore_record(table,default_values);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
270

271
  thd->count_cuted_fields= CHECK_FIELD_WARN;		/* calc cuted fields */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
272
  thd->cuted_fields=0L;
273 274
  /* Skip lines if there is a line terminator */
  if (ex->line_term->length())
bk@work.mysql.com's avatar
bk@work.mysql.com committed
275
  {
276 277
    /* ex->skip_lines needs to be preserved for logging */
    while (skip_lines > 0)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
278
    {
279
      skip_lines--;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
280 281 282 283
      if (read_info.next_line())
	break;
    }
  }
284

bk@work.mysql.com's avatar
bk@work.mysql.com committed
285 286 287
  if (!(error=test(read_info.error)))
  {
    if (use_timestamp)
288
      table->timestamp_field_type= TIMESTAMP_NO_AUTO_SET;
serg@serg.mylan's avatar
serg@serg.mylan committed
289

bk@work.mysql.com's avatar
bk@work.mysql.com committed
290
    table->next_number_field=table->found_next_number_field;
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
291 292 293
    if (handle_duplicates == DUP_IGNORE ||
	handle_duplicates == DUP_REPLACE)
      table->file->extra(HA_EXTRA_IGNORE_DUP_KEY);
294
    ha_enable_transaction(thd, FALSE); 
295
    table->file->start_bulk_insert((ha_rows) 0);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
296
    table->copy_blobs=1;
297 298 299 300 301 302 303

    thd->no_trans_update= 0;
    thd->abort_on_warning= (handle_duplicates != DUP_IGNORE &&
                            (thd->variables.sql_mode &
                             (MODE_STRICT_TRANS_TABLES |
                              MODE_STRICT_ALL_TABLES)));

bk@work.mysql.com's avatar
bk@work.mysql.com committed
304
    if (!field_term->length() && !enclosed->length())
305 306
      error= read_fixed_length(thd, info, table_list, fields,read_info,
			       skip_lines, ignore_check_option_errors);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
307
    else
308 309 310
      error= read_sep_field(thd, info, table_list, fields, read_info,
			    *enclosed, skip_lines,
			    ignore_check_option_errors);
311
    if (table->file->end_bulk_insert())
312
      error=1;					/* purecov: inspected */
313
    ha_enable_transaction(thd, TRUE);
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
314
    table->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
315 316
    table->next_number_field=0;
  }
317 318
  if (file >= 0)
    my_close(file,MYF(0));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
319 320
  free_blobs(table);				/* if pack_blob was used */
  table->copy_blobs=0;
321
  thd->count_cuted_fields= CHECK_FIELD_IGNORE;
322

323 324 325 326
  /*
    We must invalidate the table in query cache before binlog writing and
    ha_autocommit_...
  */
heikki@hundin.mysql.fi's avatar
heikki@hundin.mysql.fi committed
327 328
  query_cache_invalidate3(thd, table_list, 0);

bk@work.mysql.com's avatar
bk@work.mysql.com committed
329
  if (error)
330
  {
331
    if (transactional_table)
332
      ha_autocommit_or_rollback(thd,error);
serg@serg.mylan's avatar
serg@serg.mylan committed
333

334 335 336
    if (read_file_from_client)
      while (!read_info.next_line())
	;
serg@serg.mylan's avatar
serg@serg.mylan committed
337

338
#ifndef EMBEDDED_LIBRARY
339
    if (mysql_bin_log.is_open())
340
    {
guilhem@mysql.com's avatar
guilhem@mysql.com committed
341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363
      /*
        Make sure last block (the one which caused the error) gets logged.
        This is needed because otherwise after write of
        (to the binlog, not to read_info (which is a cache))
        Delete_file_log_event the bad block will remain in read_info (because
        pre_read is not called at the end of the last block; remember pre_read
        is called whenever a new block is read from disk).
        At the end of mysql_load(), the destructor of read_info will call
        end_io_cache() which will flush read_info, so we will finally have
        this in the binlog:
        Append_block # The last successfull block
        Delete_file
        Append_block # The failing block
        which is nonsense.
        Or could also be (for a small file)
        Create_file  # The failing block
        which is nonsense (Delete_file is not written in this case, because:
        Create_file has not been written, so Delete_file is not written, then
        when read_info is destroyed end_io_cache() is called which writes
        Create_file.
      */
      read_info.end_io_cache();
      /* If the file was not empty, wrote_create_file is true */
sasha@mysql.sashanet.com's avatar
sasha@mysql.sashanet.com committed
364 365
      if (lf_info.wrote_create_file)
      {
366
        Delete_file_log_event d(thd, db, log_delayed);
sasha@mysql.sashanet.com's avatar
sasha@mysql.sashanet.com committed
367 368
        mysql_bin_log.write(&d);
      }
369
    }
370
#endif /*!EMBEDDED_LIBRARY*/
371 372
    error= -1;				// Error on read
    goto err;
373
  }
374 375
  sprintf(name, ER(ER_LOAD_INFO), (ulong) info.records, (ulong) info.deleted,
	  (ulong) (info.records - info.copied), (ulong) thd->cuted_fields);
376
  send_ok(thd,info.copied+info.deleted,0L,name);
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
377

378
  if (!log_delayed)
379
    thd->options|=OPTION_STATUS_NO_TRANS_UPDATE;
380
#ifndef EMBEDDED_LIBRARY
381
  if (mysql_bin_log.is_open())
382
  {
383 384 385 386 387 388 389
    /*
      As already explained above, we need to call end_io_cache() or the last
      block will be logged only after Execute_load_log_event (which is wrong),
      when read_info is destroyed.
    */
    read_info.end_io_cache(); 
    if (lf_info.wrote_create_file)
390
    {
391 392
      Execute_load_log_event e(thd, db, log_delayed);
      mysql_bin_log.write(&e);
393
    }
394
  }
395
#endif /*!EMBEDDED_LIBRARY*/
396
  if (transactional_table)
397
    error=ha_autocommit_or_rollback(thd,error); 
398

399 400 401 402 403 404
err:
  if (thd->lock)
  {
    mysql_unlock_tables(thd, thd->lock);
    thd->lock=0;
  }
405
  thd->abort_on_warning= 0;  
406
  DBUG_RETURN(error);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
407 408 409 410 411 412 413
}

/****************************************************************************
** Read of rows of fixed size + optional garage + optonal newline
****************************************************************************/

static int
414 415 416
read_fixed_length(THD *thd, COPY_INFO &info, TABLE_LIST *table_list,
		  List<Item> &fields, READ_INFO &read_info, ulong skip_lines,
		  bool ignore_check_option_errors)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
417
{
monty@tik.mysql.fi's avatar
monty@tik.mysql.fi committed
418
  List_iterator_fast<Item> it(fields);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
419
  Item_field *sql_field;
420
  TABLE *table= table_list->table;
421
  ulonglong id;
422
  bool no_trans_update;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
423 424
  DBUG_ENTER("read_fixed_length");

425
  id= 0;
426
  
bk@work.mysql.com's avatar
bk@work.mysql.com committed
427 428 429 430 431 432 433 434
  /* No fields can be null in this format. mark all fields as not null */
  while ((sql_field= (Item_field*) it++))
      sql_field->field->set_notnull();

  while (!read_info.read_fixed_length())
  {
    if (thd->killed)
    {
hf@deer.mysql.r18.ru's avatar
SCRUM  
hf@deer.mysql.r18.ru committed
435
      thd->send_kill_message();
bk@work.mysql.com's avatar
bk@work.mysql.com committed
436 437
      DBUG_RETURN(1);
    }
438 439 440 441 442 443 444 445 446 447 448
    if (skip_lines)
    {
      /*
	We could implement this with a simple seek if:
	- We are not using DATA INFILE LOCAL
	- escape character is  ""
	- line starting prefix is ""
      */
      skip_lines--;
      continue;
    }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
449 450 451 452 453
    it.rewind();
    byte *pos=read_info.row_start;
#ifdef HAVE_purify
    read_info.row_end[0]=0;
#endif
454
    no_trans_update= !table->file->has_transactions();
bk@work.mysql.com's avatar
bk@work.mysql.com committed
455 456
    while ((sql_field= (Item_field*) it++))
    {
457
      Field *field= sql_field->field;                  
bk@work.mysql.com's avatar
bk@work.mysql.com committed
458 459
      if (pos == read_info.row_end)
      {
460 461 462
        thd->cuted_fields++;			/* Not enough fields */
        push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, 
                            ER_WARN_TOO_FEW_RECORDS, 
463 464
                            ER(ER_WARN_TOO_FEW_RECORDS), thd->row_count);
	      field->reset();
bk@work.mysql.com's avatar
bk@work.mysql.com committed
465 466 467 468 469 470 471 472 473
      }
      else
      {
	uint length;
	byte save_chr;
	if ((length=(uint) (read_info.row_end-pos)) >
	    field->field_length)
	  length=field->field_length;
	save_chr=pos[length]; pos[length]='\0'; // Safeguard aganst malloc
474
        field->store((char*) pos,length,read_info.read_charset);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
475 476 477 478 479 480
	pos[length]=save_chr;
	if ((pos+=length) > read_info.row_end)
	  pos= read_info.row_end;	/* Fills rest with space */
      }
    }
    if (pos != read_info.row_end)
481
    {
bk@work.mysql.com's avatar
bk@work.mysql.com committed
482
      thd->cuted_fields++;			/* To long row */
483 484
      push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, 
                          ER_WARN_TOO_MANY_RECORDS, 
485
                          ER(ER_WARN_TOO_MANY_RECORDS), thd->row_count); 
486
    }
487 488 489 490 491 492 493 494 495 496 497

    switch(table_list->view_check_option(thd,
					 ignore_check_option_errors))
    {
    case VIEW_CHECK_SKIP:
      read_info.next_line();
      goto continue_loop;
    case VIEW_CHECK_ERROR:
      DBUG_RETURN(-1);
    }

498
    if (thd->killed || write_record(thd,table,&info))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
499
      DBUG_RETURN(1);
500 501
    thd->no_trans_update= no_trans_update;
   
502 503 504 505 506 507 508 509
    /*
      If auto_increment values are used, save the first one
       for LAST_INSERT_ID() and for the binary/update log.
       We can't use insert_id() as we don't want to touch the
       last_insert_id_used flag.
    */
    if (!id && thd->insert_id_used)
      id= thd->last_insert_id;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
510 511
    if (table->next_number_field)
      table->next_number_field->reset();	// Clear for next record
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
512
    if (read_info.next_line())			// Skip to next line
bk@work.mysql.com's avatar
bk@work.mysql.com committed
513 514
      break;
    if (read_info.line_cuted)
515
    {
bk@work.mysql.com's avatar
bk@work.mysql.com committed
516
      thd->cuted_fields++;			/* To long row */
517 518
      push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, 
                          ER_WARN_TOO_MANY_RECORDS, 
519
                          ER(ER_WARN_TOO_MANY_RECORDS), thd->row_count); 
520
    }
521
    thd->row_count++;
522
continue_loop:;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
523
  }
524 525
  if (id && !read_info.error)
    thd->insert_id(id);			// For binary/update log
bk@work.mysql.com's avatar
bk@work.mysql.com committed
526 527 528 529 530 531
  DBUG_RETURN(test(read_info.error));
}



static int
532
read_sep_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list,
bk@work.mysql.com's avatar
bk@work.mysql.com committed
533
	       List<Item> &fields, READ_INFO &read_info,
534 535
	       String &enclosed, ulong skip_lines,
	       bool ignore_check_option_errors)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
536
{
monty@tik.mysql.fi's avatar
monty@tik.mysql.fi committed
537
  List_iterator_fast<Item> it(fields);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
538
  Item_field *sql_field;
539
  TABLE *table= table_list->table;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
540
  uint enclosed_length;
541
  ulonglong id;
542
  bool no_trans_update;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
543 544 545
  DBUG_ENTER("read_sep_field");

  enclosed_length=enclosed.length();
546
  id= 0;
547
  no_trans_update= !table->file->has_transactions();
548

bk@work.mysql.com's avatar
bk@work.mysql.com committed
549 550 551 552
  for (;;it.rewind())
  {
    if (thd->killed)
    {
hf@deer.mysql.r18.ru's avatar
SCRUM  
hf@deer.mysql.r18.ru committed
553
      thd->send_kill_message();
bk@work.mysql.com's avatar
bk@work.mysql.com committed
554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576
      DBUG_RETURN(1);
    }
    while ((sql_field=(Item_field*) it++))
    {
      uint length;
      byte *pos;

      if (read_info.read_field())
	break;
      pos=read_info.row_start;
      length=(uint) (read_info.row_end-pos);
      Field *field=sql_field->field;

      if (!read_info.enclosed &&
	  (enclosed_length && length == 4 && !memcmp(pos,"NULL",4)) ||
	  (length == 1 && read_info.found_null))
      {
	field->reset();
	field->set_null();
	if (!field->maybe_null())
	{
	  if (field->type() == FIELD_TYPE_TIMESTAMP)
	    ((Field_timestamp*) field)->set_time();
577
	  else if (field != table->next_number_field)      
578
	    field->set_warning((uint) MYSQL_ERROR::WARN_LEVEL_WARN, 
579
			       ER_WARN_NULL_TO_NOTNULL, 1);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
580 581 582 583 584
	}
	continue;
      }
      field->set_notnull();
      read_info.row_end[0]=0;			// Safe to change end marker
585
      field->store((char*) read_info.row_start,length,read_info.read_charset);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
586 587 588
    }
    if (read_info.error)
      break;
589 590 591 592 593 594
    if (skip_lines)
    {
      if (!--skip_lines)
	thd->cuted_fields= 0L;			// Reset warnings
      continue;
    }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
595 596 597 598
    if (sql_field)
    {						// Last record
      if (sql_field == (Item_field*) fields.head())
	break;
599
      for (; sql_field ; sql_field=(Item_field*) it++)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
600 601 602 603
      {
	sql_field->field->set_null();
	sql_field->field->reset();
	thd->cuted_fields++;
604 605
 	push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, 
                	    ER_WARN_TOO_FEW_RECORDS,
606
                	    ER(ER_WARN_TOO_FEW_RECORDS), thd->row_count);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
607 608
      }
    }
609 610 611 612 613 614 615 616 617 618 619 620

    switch(table_list->view_check_option(thd,
					 ignore_check_option_errors))
    {
    case VIEW_CHECK_SKIP:
      read_info.next_line();
      goto continue_loop;
    case VIEW_CHECK_ERROR:
      DBUG_RETURN(-1);
    }


621
    if (thd->killed || write_record(thd, table, &info))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
622
      DBUG_RETURN(1);
623 624 625 626 627 628 629 630
    /*
      If auto_increment values are used, save the first one
       for LAST_INSERT_ID() and for the binary/update log.
       We can't use insert_id() as we don't want to touch the
       last_insert_id_used flag.
    */
    if (!id && thd->insert_id_used)
      id= thd->last_insert_id;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
631 632
    if (table->next_number_field)
      table->next_number_field->reset();	// Clear for next record
633
    thd->no_trans_update= no_trans_update;
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
634
    if (read_info.next_line())			// Skip to next line
bk@work.mysql.com's avatar
bk@work.mysql.com committed
635 636
      break;
    if (read_info.line_cuted)
637
    {
bk@work.mysql.com's avatar
bk@work.mysql.com committed
638
      thd->cuted_fields++;			/* To long row */
639
      push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, 
640 641
                          ER_WARN_TOO_MANY_RECORDS, ER(ER_WARN_TOO_MANY_RECORDS), 
                          thd->row_count);   
642 643
      if (thd->killed)
        DBUG_RETURN(1);
644
    }
645
    thd->row_count++;
646
continue_loop:;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
647
  }
648 649
  if (id && !read_info.error)
    thd->insert_id(id);			// For binary/update log
bk@work.mysql.com's avatar
bk@work.mysql.com committed
650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673
  DBUG_RETURN(test(read_info.error));
}


/* Unescape all escape characters, mark \N as null */

char
READ_INFO::unescape(char chr)
{
  switch(chr) {
  case 'n': return '\n';
  case 't': return '\t';
  case 'r': return '\r';
  case 'b': return '\b';
  case '0': return 0;				// Ascii null
  case 'Z': return '\032';			// Win32 end of file
  case 'N': found_null=1;

    /* fall through */
  default:  return chr;
  }
}


674 675 676 677
/*
  Read a line using buffering
  If last line is empty (in line mode) then it isn't outputed
*/
bk@work.mysql.com's avatar
bk@work.mysql.com committed
678 679


bar@bar.mysql.r18.ru's avatar
bar@bar.mysql.r18.ru committed
680 681
READ_INFO::READ_INFO(File file_par, uint tot_length, CHARSET_INFO *cs,
		     String &field_term, String &line_start, String &line_term,
682 683
		     String &enclosed_par, int escape, bool get_it_from_net,
		     bool is_fifo)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
684 685
  :file(file_par),escape_char(escape)
{
bar@bar.mysql.r18.ru's avatar
bar@bar.mysql.r18.ru committed
686
  read_charset= cs;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727
  field_term_ptr=(char*) field_term.ptr();
  field_term_length= field_term.length();
  line_term_ptr=(char*) line_term.ptr();
  line_term_length= line_term.length();
  if (line_start.length() == 0)
  {
    line_start_ptr=0;
    start_of_line= 0;
  }
  else
  {
    line_start_ptr=(char*) line_start.ptr();
    line_start_end=line_start_ptr+line_start.length();
    start_of_line= 1;
  }
  /* If field_terminator == line_terminator, don't use line_terminator */
  if (field_term_length == line_term_length &&
      !memcmp(field_term_ptr,line_term_ptr,field_term_length))
  {
    line_term_length=0;
    line_term_ptr=(char*) "";
  }
  enclosed_char= (enclosed_length=enclosed_par.length()) ?
    (uchar) enclosed_par[0] : INT_MAX;
  field_term_char= field_term_length ? (uchar) field_term_ptr[0] : INT_MAX;
  line_term_char= line_term_length ? (uchar) line_term_ptr[0] : INT_MAX;
  error=eof=found_end_of_line=found_null=line_cuted=0;
  buff_length=tot_length;


  /* Set of a stack for unget if long terminators */
  uint length=max(field_term_length,line_term_length)+1;
  set_if_bigger(length,line_start.length());
  stack=stack_pos=(int*) sql_alloc(sizeof(int)*length);

  if (!(buffer=(byte*) my_malloc(buff_length+1,MYF(0))))
    error=1; /* purecov: inspected */
  else
  {
    end_of_buff=buffer+buff_length;
    if (init_io_cache(&cache,(get_it_from_net) ? -1 : file, 0,
728 729
		      (get_it_from_net) ? READ_NET :
		      (is_fifo ? READ_FIFO : READ_CACHE),0L,1,
bk@work.mysql.com's avatar
bk@work.mysql.com committed
730 731 732 733 734
		      MYF(MY_WME)))
    {
      my_free((gptr) buffer,MYF(0)); /* purecov: inspected */
      error=1;
    }
735 736
    else 
    {
737 738 739 740 741
      /*
	init_io_cache() will not initialize read_function member
	if the cache is READ_NET. The reason is explained in
	mysys/mf_iocache.c. So we work around the problem with a
	manual assignment
sasha@mysql.sashanet.com's avatar
sasha@mysql.sashanet.com committed
742
      */
743 744 745
      need_end_io_cache = 1;

#ifndef EMBEDDED_LIBRARY
sasha@mysql.sashanet.com's avatar
sasha@mysql.sashanet.com committed
746 747
      if (get_it_from_net)
	cache.read_function = _my_b_net_read;
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
748

749
      if (mysql_bin_log.is_open())
750
	cache.pre_read = cache.pre_close =
monty@bitch.mysql.fi's avatar
monty@bitch.mysql.fi committed
751
	  (IO_CACHE_CALLBACK) log_loaded_block;
752
#endif
753
    }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
754 755 756 757 758 759 760 761
  }
}


READ_INFO::~READ_INFO()
{
  if (!error)
  {
762 763
    if (need_end_io_cache)
      ::end_io_cache(&cache);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802
    my_free((gptr) buffer,MYF(0));
    error=1;
  }
}


#define GET (stack_pos != stack ? *--stack_pos : my_b_get(&cache))
#define PUSH(A) *(stack_pos++)=(A)


inline int READ_INFO::terminator(char *ptr,uint length)
{
  int chr=0;					// Keep gcc happy
  uint i;
  for (i=1 ; i < length ; i++)
  {
    if ((chr=GET) != *++ptr)
    {
      break;
    }
  }
  if (i == length)
    return 1;
  PUSH(chr);
  while (i-- > 1)
    PUSH((uchar) *--ptr);
  return 0;
}


int READ_INFO::read_field()
{
  int chr,found_enclosed_char;
  byte *to,*new_buffer;

  found_null=0;
  if (found_end_of_line)
    return 1;					// One have to call next_line

monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
803
  /* Skip until we find 'line_start' */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
804 805

  if (start_of_line)
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
806
  {						// Skip until line_start
bk@work.mysql.com's avatar
bk@work.mysql.com committed
807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833
    start_of_line=0;
    if (find_start_of_fields())
      return 1;
  }
  if ((chr=GET) == my_b_EOF)
  {
    found_end_of_line=eof=1;
    return 1;
  }
  to=buffer;
  if (chr == enclosed_char)
  {
    found_enclosed_char=enclosed_char;
    *to++=(byte) chr;				// If error
  }
  else
  {
    found_enclosed_char= INT_MAX;
    PUSH(chr);
  }

  for (;;)
  {
    while ( to < end_of_buff)
    {
      chr = GET;
#ifdef USE_MB
834
      if ((my_mbcharlen(read_charset, chr) > 1) &&
bar@bar.mysql.r18.ru's avatar
bar@bar.mysql.r18.ru committed
835
          to+my_mbcharlen(read_charset, chr) <= end_of_buff)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
836 837 838
      {
	  uchar* p = (uchar*)to;
	  *to++ = chr;
bar@bar.mysql.r18.ru's avatar
bar@bar.mysql.r18.ru committed
839
	  int ml = my_mbcharlen(read_charset, chr);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
840 841 842 843 844 845 846
	  int i;
	  for (i=1; i<ml; i++) {
	      chr = GET;
	      if (chr == my_b_EOF)
		  goto found_eof;
	      *to++ = chr;
	  }
bar@bar.mysql.r18.ru's avatar
bar@bar.mysql.r18.ru committed
847
	  if (my_ismbchar(read_charset,
bk@work.mysql.com's avatar
bk@work.mysql.com committed
848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908
                          (const char *)p,
                          (const char *)to))
	    continue;
	  for (i=0; i<ml; i++)
	    PUSH((uchar) *--to);
	  chr = GET;
      }
#endif
      if (chr == my_b_EOF)
	goto found_eof;
      if (chr == escape_char)
      {
	if ((chr=GET) == my_b_EOF)
	{
	  *to++= (byte) escape_char;
	  goto found_eof;
	}
	*to++ = (byte) unescape((char) chr);
	continue;
      }
#ifdef ALLOW_LINESEPARATOR_IN_STRINGS
      if (chr == line_term_char)
#else
      if (chr == line_term_char && found_enclosed_char == INT_MAX)
#endif
      {
	if (terminator(line_term_ptr,line_term_length))
	{					// Maybe unexpected linefeed
	  enclosed=0;
	  found_end_of_line=1;
	  row_start=buffer;
	  row_end=  to;
	  return 0;
	}
      }
      if (chr == found_enclosed_char)
      {
	if ((chr=GET) == found_enclosed_char)
	{					// Remove dupplicated
	  *to++ = (byte) chr;
	  continue;
	}
	// End of enclosed field if followed by field_term or line_term
	if (chr == my_b_EOF ||
	    chr == line_term_char && terminator(line_term_ptr,
						line_term_length))
	{					// Maybe unexpected linefeed
	  enclosed=1;
	  found_end_of_line=1;
	  row_start=buffer+1;
	  row_end=  to;
	  return 0;
	}
	if (chr == field_term_char &&
	    terminator(field_term_ptr,field_term_length))
	{
	  enclosed=1;
	  row_start=buffer+1;
	  row_end=  to;
	  return 0;
	}
909 910 911 912
	/*
	  The string didn't terminate yet.
	  Store back next character for the loop
	*/
bk@work.mysql.com's avatar
bk@work.mysql.com committed
913
	PUSH(chr);
914 915
	/* copy the found term character to 'to' */
	chr= found_enclosed_char;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949
      }
      else if (chr == field_term_char && found_enclosed_char == INT_MAX)
      {
	if (terminator(field_term_ptr,field_term_length))
	{
	  enclosed=0;
	  row_start=buffer;
	  row_end=  to;
	  return 0;
	}
      }
      *to++ = (byte) chr;
    }
    /*
    ** We come here if buffer is too small. Enlarge it and continue
    */
    if (!(new_buffer=(byte*) my_realloc((char*) buffer,buff_length+1+IO_SIZE,
					MYF(MY_WME))))
      return (error=1);
    to=new_buffer + (to-buffer);
    buffer=new_buffer;
    buff_length+=IO_SIZE;
    end_of_buff=buffer+buff_length;
  }

found_eof:
  enclosed=0;
  found_end_of_line=eof=1;
  row_start=buffer;
  row_end=to;
  return 0;
}

/*
950 951 952 953 954 955 956 957 958 959 960 961
  Read a row with fixed length.

  NOTES
    The row may not be fixed size on disk if there are escape
    characters in the file.

  IMPLEMENTATION NOTE
    One can't use fixed length with multi-byte charset **

  RETURN
    0  ok
    1  error
bk@work.mysql.com's avatar
bk@work.mysql.com committed
962
*/
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
963

bk@work.mysql.com's avatar
bk@work.mysql.com committed
964 965 966 967 968 969 970 971
int READ_INFO::read_fixed_length()
{
  int chr;
  byte *to;
  if (found_end_of_line)
    return 1;					// One have to call next_line

  if (start_of_line)
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
972
  {						// Skip until line_start
bk@work.mysql.com's avatar
bk@work.mysql.com committed
973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030
    start_of_line=0;
    if (find_start_of_fields())
      return 1;
  }

  to=row_start=buffer;
  while (to < end_of_buff)
  {
    if ((chr=GET) == my_b_EOF)
      goto found_eof;
    if (chr == escape_char)
    {
      if ((chr=GET) == my_b_EOF)
      {
	*to++= (byte) escape_char;
	goto found_eof;
      }
      *to++ =(byte) unescape((char) chr);
      continue;
    }
    if (chr == line_term_char)
    {
      if (terminator(line_term_ptr,line_term_length))
      {						// Maybe unexpected linefeed
	found_end_of_line=1;
	row_end=  to;
	return 0;
      }
    }
    *to++ = (byte) chr;
  }
  row_end=to;					// Found full line
  return 0;

found_eof:
  found_end_of_line=eof=1;
  row_start=buffer;
  row_end=to;
  return to == buffer ? 1 : 0;
}


int READ_INFO::next_line()
{
  line_cuted=0;
  start_of_line= line_start_ptr != 0;
  if (found_end_of_line || eof)
  {
    found_end_of_line=0;
    return eof;
  }
  found_end_of_line=0;
  if (!line_term_length)
    return 0;					// No lines
  for (;;)
  {
    int chr = GET;
#ifdef USE_MB
1031
   if (my_mbcharlen(read_charset, chr) > 1)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1032 1033
   {
       for (int i=1;
bar@bar.mysql.r18.ru's avatar
bar@bar.mysql.r18.ru committed
1034
            chr != my_b_EOF && i<my_mbcharlen(read_charset, chr);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078
            i++)
	   chr = GET;
       if (chr == escape_char)
	   continue;
   }
#endif
   if (chr == my_b_EOF)
   {
      eof=1;
      return 1;
    }
    if (chr == escape_char)
    {
      line_cuted=1;
      if (GET == my_b_EOF)
	return 1;
      continue;
    }
    if (chr == line_term_char && terminator(line_term_ptr,line_term_length))
      return 0;
    line_cuted=1;
  }
}


bool READ_INFO::find_start_of_fields()
{
  int chr;
 try_again:
  do
  {
    if ((chr=GET) == my_b_EOF)
    {
      found_end_of_line=eof=1;
      return 1;
    }
  } while ((char) chr != line_start_ptr[0]);
  for (char *ptr=line_start_ptr+1 ; ptr != line_start_end ; ptr++)
  {
    chr=GET;					// Eof will be checked later
    if ((char) chr != *ptr)
    {						// Can't be line_start
      PUSH(chr);
      while (--ptr != line_start_ptr)
1079
      {						// Restart with next char
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1080 1081 1082 1083 1084 1085 1086
	PUSH((uchar) *ptr);
      }
      goto try_again;
    }
  }
  return 0;
}