home *** CD-ROM | disk | FTP | other *** search
/ Chip 2001 January / Chip_2001-01_cd1.bin / tema / mysql / mysql-3.23.28g-win-source.exe / sql / sql_load.cpp < prev    next >
C/C++ Source or Header  |  2000-11-14  |  20KB  |  791 lines

  1. /* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
  2.    
  3.    This program is free software; you can redistribute it and/or modify
  4.    it under the terms of the GNU General Public License as published by
  5.    the Free Software Foundation; either version 2 of the License, or
  6.    (at your option) any later version.
  7.    
  8.    This program is distributed in the hope that it will be useful,
  9.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  10.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  11.    GNU General Public License for more details.
  12.    
  13.    You should have received a copy of the GNU General Public License
  14.    along with this program; if not, write to the Free Software
  15.    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
  16.  
  17.  
  18. /* Copy data from a textfile to table */
  19.  
  20. #include "mysql_priv.h"
  21. #include <my_dir.h>
  22. #include <m_ctype.h>
  23.  
  24. class READ_INFO {
  25.   File    file;
  26.   byte    *buffer,            /* Buffer for read text */
  27.     *end_of_buff;            /* Data in bufferts ends here */
  28.   uint    buff_length,            /* Length of buffert */
  29.     max_length;            /* Max length of row */
  30.   char    *field_term_ptr,*line_term_ptr,*line_start_ptr,*line_start_end;
  31.   uint    field_term_length,line_term_length,enclosed_length;
  32.   int    field_term_char,line_term_char,enclosed_char,escape_char;
  33.   int    *stack,*stack_pos;
  34.   bool    found_end_of_line,start_of_line,eof;
  35.   IO_CACHE cache;
  36.   NET *io_net;
  37.  
  38. public:
  39.   bool error,line_cuted,found_null,enclosed;
  40.   byte    *row_start,            /* Found row starts here */
  41.     *row_end;            /* Found row ends here */
  42.  
  43.   READ_INFO(File file,uint tot_length,
  44.         String &field_term,String &line_start,String &line_term,
  45.         String &enclosed,int escape,bool get_it_from_net, bool is_fifo);
  46.   ~READ_INFO();
  47.   int read_field();
  48.   int read_fixed_length(void);
  49.   int next_line(void);
  50.   char unescape(char chr);
  51.   int terminator(char *ptr,uint length);
  52.   bool find_start_of_fields();
  53. };
  54.  
  55. static int read_fixed_length(THD *thd,COPY_INFO &info,TABLE *table,
  56.                  List<Item> &fields, READ_INFO &read_info);
  57. static int read_sep_field(THD *thd,COPY_INFO &info,TABLE *table,
  58.               List<Item> &fields, READ_INFO &read_info,
  59.               String &enclosed);
  60.  
  61.  
  62. int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
  63.            List<Item> &fields, enum enum_duplicates handle_duplicates,
  64.            bool read_file_from_client,thr_lock_type lock_type)
  65. {
  66.   char name[FN_REFLEN];
  67.   File file;
  68.   TABLE *table;
  69.   int error;
  70.   uint save_skip_lines = ex->skip_lines;
  71.   String *field_term=ex->field_term,*escaped=ex->escaped,
  72.     *enclosed=ex->enclosed;
  73.   bool is_fifo=0;
  74.   DBUG_ENTER("mysql_load");
  75.  
  76.   if (escaped->length() > 1 || enclosed->length() > 1)
  77.   {
  78.     my_message(ER_WRONG_FIELD_TERMINATORS,ER(ER_WRONG_FIELD_TERMINATORS),
  79.            MYF(0));
  80.     DBUG_RETURN(-1);
  81.   }
  82.  
  83.   if (!(table = open_ltable(thd,table_list,lock_type)))
  84.     DBUG_RETURN(-1);
  85.   if (!fields.elements)
  86.   {
  87.     Field **field;
  88.     for (field=table->field; *field ; field++)
  89.       fields.push_back(new Item_field(*field));
  90.   }
  91.   else
  92.   {                        // Part field list
  93.     thd->dupp_field=0;
  94.     if (setup_fields(thd,table_list,fields,1,0) < 0)
  95.       DBUG_RETURN(-1);
  96.     if (thd->dupp_field)
  97.     {
  98.       my_error(ER_FIELD_SPECIFIED_TWICE, MYF(0), thd->dupp_field->field_name);
  99.       DBUG_RETURN(-1);
  100.     }
  101.   }
  102.  
  103.   uint tot_length=0;
  104.   bool use_blobs=0,use_timestamp=0;
  105.   List_iterator<Item> it(fields);
  106.  
  107.   Item_field *field;
  108.   while ((field=(Item_field*) it++))
  109.   {
  110.     if (field->field->flags & BLOB_FLAG)
  111.     {
  112.       use_blobs=1;
  113.       tot_length+=256;                // Will be extended if needed
  114.     }
  115.     else
  116.       tot_length+=field->field->field_length;
  117.     if (!field_term->length() && !(field->field->flags & NOT_NULL_FLAG))
  118.       field->field->set_notnull();
  119.     if (field->field == table->timestamp_field)
  120.       use_timestamp=1;
  121.   }
  122.   if (use_blobs && !ex->line_term->length() && !field_term->length())
  123.   {
  124.     my_message(ER_BLOBS_AND_NO_TERMINATED,ER(ER_BLOBS_AND_NO_TERMINATED),
  125.            MYF(0));
  126.     DBUG_RETURN(-1);
  127.   }
  128.  
  129.   /* We can't give an error in the middle when using LOCAL files */
  130.   if (read_file_from_client && handle_duplicates == DUP_ERROR)
  131.     handle_duplicates=DUP_IGNORE;
  132.  
  133.   if (read_file_from_client && (thd->client_capabilities & CLIENT_LOCAL_FILES))
  134.   {
  135.     char tmp [FN_REFLEN+1],*end;
  136.     DBUG_PRINT("info",("reading local file"));
  137.     tmp[0] = (char) 251;                /* NULL_LENGTH */
  138.     end=strnmov(tmp+1,ex->file_name,sizeof(tmp)-2);
  139.     (void) my_net_write(&thd->net,tmp,(uint) (end-tmp));
  140.     (void) net_flush(&thd->net);
  141.     file = -1;
  142.   }
  143.   else
  144.   {
  145.     read_file_from_client=0;
  146. #ifdef DONT_ALLOW_FULL_LOAD_DATA_PATHS
  147.     ex->file_name+=dirname_length(ex->file_name);
  148. #endif
  149.     if (!dirname_length(ex->file_name) &&
  150.     strlen(ex->file_name)+strlen(mysql_data_home)+strlen(thd->db)+3 <
  151.     FN_REFLEN)
  152.     {
  153.       (void) sprintf(name,"%s/%s/%s",mysql_data_home,thd->db,ex->file_name);
  154.       unpack_filename(name,name);        /* Convert to system format */
  155.     }
  156.     else
  157.     {
  158.       unpack_filename(name,ex->file_name);
  159. #ifndef __WIN__
  160.       MY_STAT stat_info;
  161.       if (!my_stat(name,&stat_info,MYF(MY_WME)))
  162.     DBUG_RETURN(-1);
  163.       
  164.       // the file must be:
  165.       if (!((stat_info.st_mode & S_IROTH) == S_IROTH &&  // readable by others
  166.         (stat_info.st_mode & S_IFLNK) != S_IFLNK && // and not a symlink
  167.         ((stat_info.st_mode & S_IFREG) == S_IFREG ||
  168.          (stat_info.st_mode & S_IFIFO) == S_IFIFO)))
  169.       {
  170.     my_error(ER_TEXTFILE_NOT_READABLE,MYF(0),name);
  171.     DBUG_RETURN(-1);
  172.       }
  173.       if ((stat_info.st_mode & S_IFIFO) == S_IFIFO)
  174.     is_fifo = 1;
  175. #endif
  176.     }
  177.     if ((file=my_open(name,O_RDONLY,MYF(MY_WME))) < 0)
  178.       DBUG_RETURN(-1);
  179.   }
  180.  
  181.   COPY_INFO info;
  182.   bzero((char*) &info,sizeof(info));
  183.   info.handle_duplicates=handle_duplicates;
  184.   info.escape_char=escaped->length() ? (*escaped)[0] : INT_MAX;
  185.  
  186.   READ_INFO read_info(file,tot_length,*field_term,
  187.               *ex->line_start, *ex->line_term, *enclosed,
  188.               info.escape_char, read_file_from_client, is_fifo);
  189.   if (read_info.error)
  190.   {
  191.     if    (file >= 0)
  192.       my_close(file,MYF(0));            // no files in net reading
  193.     DBUG_RETURN(-1);                // Can't allocate buffers
  194.   }
  195.  
  196.   restore_record(table,2);
  197.  
  198.   thd->count_cuted_fields=1;            /* calc cuted fields */
  199.   thd->cuted_fields=0L;
  200.   if (ex->line_term->length() && field_term->length())
  201.   {
  202.     while (ex->skip_lines--)
  203.     {
  204.       if (read_info.next_line())
  205.     break;
  206.     }
  207.   }
  208.   if (!(error=test(read_info.error)))
  209.   {
  210.     uint save_time_stamp=table->time_stamp;
  211.     if (use_timestamp)
  212.       table->time_stamp=0;
  213.     table->next_number_field=table->found_next_number_field;
  214.     VOID(table->file->extra(HA_EXTRA_WRITE_CACHE));
  215.     table->file->deactivate_non_unique_index((ha_rows) 0);
  216.     table->copy_blobs=1;
  217.     if (!field_term->length() && !enclosed->length())
  218.       error=read_fixed_length(thd,info,table,fields,read_info);
  219.     else
  220.       error=read_sep_field(thd,info,table,fields,read_info,*enclosed);
  221.     if (table->file->extra(HA_EXTRA_NO_CACHE) ||
  222.     table->file->activate_all_index(thd))
  223.       error=1; /* purecov: inspected */
  224.       
  225.     table->time_stamp=save_time_stamp;
  226.     table->next_number_field=0;
  227.     if (thd->lock)
  228.     {
  229.       mysql_unlock_tables(thd, thd->lock);
  230.       thd->lock=0;
  231.     }
  232.   }
  233.   if  (file >= 0) my_close(file,MYF(0));
  234.   free_blobs(table);                /* if pack_blob was used */
  235.   table->copy_blobs=0;
  236.   thd->count_cuted_fields=0;            /* Don`t calc cuted fields */
  237.   if (error)
  238.     DBUG_RETURN(-1);                // Error on read
  239.   sprintf(name,ER(ER_LOAD_INFO),info.records,info.deleted,
  240.       info.records-info.copied,thd->cuted_fields);
  241.   send_ok(&thd->net,info.copied+info.deleted,0L,name);
  242.   mysql_update_log.write(thd,thd->query,thd->query_length);
  243.   
  244.   if (!read_file_from_client)
  245.   {
  246.     ex->skip_lines = save_skip_lines; 
  247.     Load_log_event qinfo(thd, ex, table->table_name, fields, handle_duplicates);
  248.     mysql_bin_log.write(&qinfo);
  249.   }
  250.   DBUG_RETURN(0);
  251. }
  252.  
  253.  
  254. /****************************************************************************
  255. ** Read of rows of fixed size + optional garage + optonal newline
  256. ****************************************************************************/
  257.  
  258. static int
  259. read_fixed_length(THD *thd,COPY_INFO &info,TABLE *table,List<Item> &fields,
  260.           READ_INFO &read_info)
  261. {
  262.   List_iterator<Item> it(fields);
  263.   Item_field *sql_field;
  264.   DBUG_ENTER("read_fixed_length");
  265.  
  266.   /* No fields can be null in this format. mark all fields as not null */
  267.   while ((sql_field= (Item_field*) it++))
  268.       sql_field->field->set_notnull();
  269.  
  270.   while (!read_info.read_fixed_length())
  271.   {
  272.     if (thd->killed)
  273.     {
  274.       my_error(ER_SERVER_SHUTDOWN,MYF(0));
  275.       DBUG_RETURN(1);
  276.     }
  277.     it.rewind();
  278.     byte *pos=read_info.row_start;
  279. #ifdef HAVE_purify
  280.     read_info.row_end[0]=0;
  281. #endif
  282.     while ((sql_field= (Item_field*) it++))
  283.     {
  284.       Field *field=sql_field->field;
  285.       if (pos == read_info.row_end)
  286.       {
  287.     thd->cuted_fields++;            /* Not enough fields */
  288.     field->reset();
  289.       }
  290.       else
  291.       {
  292.     uint length;
  293.     byte save_chr;
  294.     if ((length=(uint) (read_info.row_end-pos)) >
  295.         field->field_length)
  296.       length=field->field_length;
  297.     save_chr=pos[length]; pos[length]='\0'; // Safeguard aganst malloc
  298.     field->store((char*) pos,length);
  299.     pos[length]=save_chr;
  300.     if ((pos+=length) > read_info.row_end)
  301.       pos= read_info.row_end;    /* Fills rest with space */
  302.       }
  303.     }
  304.     if (pos != read_info.row_end)
  305.       thd->cuted_fields++;            /* To long row */
  306.     if (write_record(table,&info))
  307.       DBUG_RETURN(1);
  308.     if (table->next_number_field)
  309.       table->next_number_field->reset();    // Clear for next record
  310.     if (read_info.next_line())            // Skipp to next line
  311.       break;
  312.     if (read_info.line_cuted)
  313.       thd->cuted_fields++;            /* To long row */
  314.   }
  315.   DBUG_RETURN(test(read_info.error));
  316. }
  317.  
  318.  
  319.  
  320. static int
  321. read_sep_field(THD *thd,COPY_INFO &info,TABLE *table,
  322.            List<Item> &fields, READ_INFO &read_info,
  323.            String &enclosed)
  324. {
  325.   List_iterator<Item> it(fields);
  326.   Item_field *sql_field;
  327.   uint enclosed_length;
  328.   DBUG_ENTER("read_sep_field");
  329.  
  330.   enclosed_length=enclosed.length();
  331.  
  332.   for (;;it.rewind())
  333.   {
  334.     if (thd->killed)
  335.     {
  336.       my_error(ER_SERVER_SHUTDOWN,MYF(0));
  337.       DBUG_RETURN(1);
  338.     }
  339.     while ((sql_field=(Item_field*) it++))
  340.     {
  341.       uint length;
  342.       byte *pos;
  343.  
  344.       if (read_info.read_field())
  345.     break;
  346.       pos=read_info.row_start;
  347.       length=(uint) (read_info.row_end-pos);
  348.       Field *field=sql_field->field;
  349.  
  350.       if (!read_info.enclosed &&
  351.       (enclosed_length && length == 4 && !memcmp(pos,"NULL",4)) ||
  352.       (length == 1 && read_info.found_null))
  353.       {
  354.     field->reset();
  355.     field->set_null();
  356.     if (!field->maybe_null())
  357.     {
  358.       if (field->type() == FIELD_TYPE_TIMESTAMP)
  359.         ((Field_timestamp*) field)->set_time();
  360.       else
  361.         thd->cuted_fields++;
  362.     }
  363.     continue;
  364.       }
  365.       field->set_notnull();
  366.       read_info.row_end[0]=0;            // Safe to change end marker
  367.       field->store((char*) read_info.row_start,length);
  368.     }
  369.     if (read_info.error)
  370.       break;
  371.     if (sql_field)
  372.     {                        // Last record
  373.       if (sql_field == (Item_field*) fields.head())
  374.     break;
  375.       for ( ; sql_field ; sql_field=(Item_field*) it++)
  376.       {
  377.     sql_field->field->set_null();
  378.     sql_field->field->reset();
  379.     thd->cuted_fields++;
  380.       }
  381.     }
  382.     if (write_record(table,&info))
  383.       DBUG_RETURN(1);
  384.     if (table->next_number_field)
  385.       table->next_number_field->reset();    // Clear for next record
  386.     if (read_info.next_line())            // Skipp to next line
  387.       break;
  388.     if (read_info.line_cuted)
  389.       thd->cuted_fields++;            /* To long row */
  390.   }
  391.   DBUG_RETURN(test(read_info.error));
  392. }
  393.  
  394.  
  395. /* Unescape all escape characters, mark \N as null */
  396.  
  397. char
  398. READ_INFO::unescape(char chr)
  399. {
  400.   switch(chr) {
  401.   case 'n': return '\n';
  402.   case 't': return '\t';
  403.   case 'r': return '\r';
  404.   case 'b': return '\b';
  405.   case '0': return 0;                // Ascii null
  406.   case 'Z': return '\032';            // Win32 end of file
  407.   case 'N': found_null=1;
  408.  
  409.     /* fall through */
  410.   default:  return chr;
  411.   }
  412. }
  413.  
  414.  
  415.     /* Read a line using buffering */
  416.     /* If last line is empty (in line mode) then it isn't outputed */
  417.  
  418.  
  419. READ_INFO::READ_INFO(File file_par, uint tot_length, String &field_term,
  420.              String &line_start, String &line_term,
  421.              String &enclosed_par, int escape, bool get_it_from_net,
  422.              bool is_fifo)
  423.   :file(file_par),escape_char(escape)
  424. {
  425.   field_term_ptr=(char*) field_term.ptr();
  426.   field_term_length= field_term.length();
  427.   line_term_ptr=(char*) line_term.ptr();
  428.   line_term_length= line_term.length();
  429.   if (line_start.length() == 0)
  430.   {
  431.     line_start_ptr=0;
  432.     start_of_line= 0;
  433.   }
  434.   else
  435.   {
  436.     line_start_ptr=(char*) line_start.ptr();
  437.     line_start_end=line_start_ptr+line_start.length();
  438.     start_of_line= 1;
  439.   }
  440.   /* If field_terminator == line_terminator, don't use line_terminator */
  441.   if (field_term_length == line_term_length &&
  442.       !memcmp(field_term_ptr,line_term_ptr,field_term_length))
  443.   {
  444.     line_term_length=0;
  445.     line_term_ptr=(char*) "";
  446.   }
  447.   enclosed_char= (enclosed_length=enclosed_par.length()) ?
  448.     (uchar) enclosed_par[0] : INT_MAX;
  449.   field_term_char= field_term_length ? (uchar) field_term_ptr[0] : INT_MAX;
  450.   line_term_char= line_term_length ? (uchar) line_term_ptr[0] : INT_MAX;
  451.   error=eof=found_end_of_line=found_null=line_cuted=0;
  452.   buff_length=tot_length;
  453.  
  454.  
  455.   /* Set of a stack for unget if long terminators */
  456.   uint length=max(field_term_length,line_term_length)+1;
  457.   set_if_bigger(length,line_start.length());
  458.   stack=stack_pos=(int*) sql_alloc(sizeof(int)*length);
  459.  
  460.   if (!(buffer=(byte*) my_malloc(buff_length+1,MYF(0))))
  461.     error=1; /* purecov: inspected */
  462.   else
  463.   {
  464.     end_of_buff=buffer+buff_length;
  465.     if (init_io_cache(&cache,(get_it_from_net) ? -1 : file, 0,
  466.               (get_it_from_net) ? READ_NET :
  467.               (is_fifo ? READ_FIFO : READ_CACHE),0L,1,
  468.               MYF(MY_WME)))
  469.     {
  470.       my_free((gptr) buffer,MYF(0)); /* purecov: inspected */
  471.       error=1;
  472.     }
  473.   }
  474. }
  475.  
  476.  
  477. READ_INFO::~READ_INFO()
  478. {
  479.   if (!error)
  480.   {
  481.     end_io_cache(&cache);
  482.     my_free((gptr) buffer,MYF(0));
  483.     error=1;
  484.   }
  485. }
  486.  
  487.  
  488. #define GET (stack_pos != stack ? *--stack_pos : my_b_get(&cache))
  489. #define PUSH(A) *(stack_pos++)=(A)
  490.  
  491.  
  492. inline int READ_INFO::terminator(char *ptr,uint length)
  493. {
  494.   int chr=0;                    // Keep gcc happy
  495.   uint i;
  496.   for (i=1 ; i < length ; i++)
  497.   {
  498.     if ((chr=GET) != *++ptr)
  499.     {
  500.       break;
  501.     }
  502.   }
  503.   if (i == length)
  504.     return 1;
  505.   PUSH(chr);
  506.   while (i-- > 1)
  507.     PUSH((uchar) *--ptr);
  508.   return 0;
  509. }
  510.  
  511.  
  512. int READ_INFO::read_field()
  513. {
  514.   int chr,found_enclosed_char;
  515.   byte *to,*new_buffer;
  516.  
  517.   found_null=0;
  518.   if (found_end_of_line)
  519.     return 1;                    // One have to call next_line
  520.  
  521.   /* Skipp until we find 'line_start' */
  522.  
  523.   if (start_of_line)
  524.   {                        // Skipp until line_start
  525.     start_of_line=0;
  526.     if (find_start_of_fields())
  527.       return 1;
  528.   }
  529.   if ((chr=GET) == my_b_EOF)
  530.   {
  531.     found_end_of_line=eof=1;
  532.     return 1;
  533.   }
  534.   to=buffer;
  535.   if (chr == enclosed_char)
  536.   {
  537.     found_enclosed_char=enclosed_char;
  538.     *to++=(byte) chr;                // If error
  539.   }
  540.   else
  541.   {
  542.     found_enclosed_char= INT_MAX;
  543.     PUSH(chr);
  544.   }
  545.  
  546.   for (;;)
  547.   {
  548.     while ( to < end_of_buff)
  549.     {
  550.       chr = GET;
  551. #ifdef USE_MB
  552.       if (use_mb(default_charset_info) &&
  553.           my_ismbhead(default_charset_info, chr) &&
  554.           to+my_mbcharlen(default_charset_info, chr) <= end_of_buff)
  555.       {
  556.       uchar* p = (uchar*)to;
  557.       *to++ = chr;
  558.       int ml = my_mbcharlen(default_charset_info, chr);
  559.       int i;
  560.       for (i=1; i<ml; i++) {
  561.           chr = GET;
  562.           if (chr == my_b_EOF)
  563.           goto found_eof;
  564.           *to++ = chr;
  565.       }
  566.       if (my_ismbchar(default_charset_info,
  567.                           (const char *)p,
  568.                           (const char *)to))
  569.         continue;
  570.       for (i=0; i<ml; i++)
  571.         PUSH((uchar) *--to);
  572.       chr = GET;
  573.       }
  574. #endif
  575.       if (chr == my_b_EOF)
  576.     goto found_eof;
  577.       if (chr == escape_char)
  578.       {
  579.     if ((chr=GET) == my_b_EOF)
  580.     {
  581.       *to++= (byte) escape_char;
  582.       goto found_eof;
  583.     }
  584.     *to++ = (byte) unescape((char) chr);
  585.     continue;
  586.       }
  587. #ifdef ALLOW_LINESEPARATOR_IN_STRINGS
  588.       if (chr == line_term_char)
  589. #else
  590.       if (chr == line_term_char && found_enclosed_char == INT_MAX)
  591. #endif
  592.       {
  593.     if (terminator(line_term_ptr,line_term_length))
  594.     {                    // Maybe unexpected linefeed
  595.       enclosed=0;
  596.       found_end_of_line=1;
  597.       row_start=buffer;
  598.       row_end=  to;
  599.       return 0;
  600.     }
  601.       }
  602.       if (chr == found_enclosed_char)
  603.       {
  604.     if ((chr=GET) == found_enclosed_char)
  605.     {                    // Remove dupplicated
  606.       *to++ = (byte) chr;
  607.       continue;
  608.     }
  609.     // End of enclosed field if followed by field_term or line_term
  610.     if (chr == my_b_EOF ||
  611.         chr == line_term_char && terminator(line_term_ptr,
  612.                         line_term_length))
  613.     {                    // Maybe unexpected linefeed
  614.       enclosed=1;
  615.       found_end_of_line=1;
  616.       row_start=buffer+1;
  617.       row_end=  to;
  618.       return 0;
  619.     }
  620.     if (chr == field_term_char &&
  621.         terminator(field_term_ptr,field_term_length))
  622.     {
  623.       enclosed=1;
  624.       row_start=buffer+1;
  625.       row_end=  to;
  626.       return 0;
  627.     }
  628.     /* Copy the found '"' character */
  629.     PUSH(chr);
  630.     chr='"';
  631.       }
  632.       else if (chr == field_term_char && found_enclosed_char == INT_MAX)
  633.       {
  634.     if (terminator(field_term_ptr,field_term_length))
  635.     {
  636.       enclosed=0;
  637.       row_start=buffer;
  638.       row_end=  to;
  639.       return 0;
  640.     }
  641.       }
  642.       *to++ = (byte) chr;
  643.     }
  644.     /*
  645.     ** We come here if buffer is too small. Enlarge it and continue
  646.     */
  647.     if (!(new_buffer=(byte*) my_realloc((char*) buffer,buff_length+1+IO_SIZE,
  648.                     MYF(MY_WME))))
  649.       return (error=1);
  650.     to=new_buffer + (to-buffer);
  651.     buffer=new_buffer;
  652.     buff_length+=IO_SIZE;
  653.     end_of_buff=buffer+buff_length;
  654.   }
  655.  
  656. found_eof:
  657.   enclosed=0;
  658.   found_end_of_line=eof=1;
  659.   row_start=buffer;
  660.   row_end=to;
  661.   return 0;
  662. }
  663.  
  664. /*
  665. ** One can't use fixed length with multi-byte charset **
  666. */
  667.  
  668. int READ_INFO::read_fixed_length()
  669. {
  670.   int chr;
  671.   byte *to;
  672.   if (found_end_of_line)
  673.     return 1;                    // One have to call next_line
  674.  
  675.   if (start_of_line)
  676.   {                        // Skipp until line_start
  677.     start_of_line=0;
  678.     if (find_start_of_fields())
  679.       return 1;
  680.   }
  681.  
  682.   to=row_start=buffer;
  683.   while (to < end_of_buff)
  684.   {
  685.     if ((chr=GET) == my_b_EOF)
  686.       goto found_eof;
  687.     if (chr == escape_char)
  688.     {
  689.       if ((chr=GET) == my_b_EOF)
  690.       {
  691.     *to++= (byte) escape_char;
  692.     goto found_eof;
  693.       }
  694.       *to++ =(byte) unescape((char) chr);
  695.       continue;
  696.     }
  697.     if (chr == line_term_char)
  698.     {
  699.       if (terminator(line_term_ptr,line_term_length))
  700.       {                        // Maybe unexpected linefeed
  701.     found_end_of_line=1;
  702.     row_end=  to;
  703.     return 0;
  704.       }
  705.     }
  706.     *to++ = (byte) chr;
  707.   }
  708.   row_end=to;                    // Found full line
  709.   return 0;
  710.  
  711. found_eof:
  712.   found_end_of_line=eof=1;
  713.   row_start=buffer;
  714.   row_end=to;
  715.   return to == buffer ? 1 : 0;
  716. }
  717.  
  718.  
  719. int READ_INFO::next_line()
  720. {
  721.   line_cuted=0;
  722.   start_of_line= line_start_ptr != 0;
  723.   if (found_end_of_line || eof)
  724.   {
  725.     found_end_of_line=0;
  726.     return eof;
  727.   }
  728.   found_end_of_line=0;
  729.   if (!line_term_length)
  730.     return 0;                    // No lines
  731.   for (;;)
  732.   {
  733.     int chr = GET;
  734. #ifdef USE_MB
  735.    if (use_mb(default_charset_info) && my_ismbhead(default_charset_info, chr))
  736.    {
  737.        for (int i=1;
  738.             chr != my_b_EOF && i<my_mbcharlen(default_charset_info, chr);
  739.             i++)
  740.        chr = GET;
  741.        if (chr == escape_char)
  742.        continue;
  743.    }
  744. #endif
  745.    if (chr == my_b_EOF)
  746.    {
  747.       eof=1;
  748.       return 1;
  749.     }
  750.     if (chr == escape_char)
  751.     {
  752.       line_cuted=1;
  753.       if (GET == my_b_EOF)
  754.     return 1;
  755.       continue;
  756.     }
  757.     if (chr == line_term_char && terminator(line_term_ptr,line_term_length))
  758.       return 0;
  759.     line_cuted=1;
  760.   }
  761. }
  762.  
  763.  
  764. bool READ_INFO::find_start_of_fields()
  765. {
  766.   int chr;
  767.  try_again:
  768.   do
  769.   {
  770.     if ((chr=GET) == my_b_EOF)
  771.     {
  772.       found_end_of_line=eof=1;
  773.       return 1;
  774.     }
  775.   } while ((char) chr != line_start_ptr[0]);
  776.   for (char *ptr=line_start_ptr+1 ; ptr != line_start_end ; ptr++)
  777.   {
  778.     chr=GET;                    // Eof will be checked later
  779.     if ((char) chr != *ptr)
  780.     {                        // Can't be line_start
  781.       PUSH(chr);
  782.       while (--ptr != line_start_ptr)
  783.       {                    // Restart with next char
  784.     PUSH((uchar) *ptr);
  785.       }
  786.       goto try_again;
  787.     }
  788.   }
  789.   return 0;
  790. }
  791.