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 / records.cpp < prev    next >
C/C++ Source or Header  |  2000-08-31  |  9KB  |  336 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. /* Functions to read, write and lock records */
  19.  
  20. #include "mysql_priv.h"
  21.  
  22. static int rr_quick(READ_RECORD *info);
  23. static int rr_sequential(READ_RECORD *info);
  24. static int rr_from_tempfile(READ_RECORD *info);
  25. static int rr_from_pointers(READ_RECORD *info);
  26. static int rr_from_cache(READ_RECORD *info);
  27. static int init_rr_cache(READ_RECORD *info);
  28. static int rr_cmp(uchar *a,uchar *b);
  29.  
  30.     /* init struct for read with info->read_record */
  31.  
  32. void init_read_record(READ_RECORD *info,THD *thd, TABLE *table,
  33.               SQL_SELECT *select,
  34.               bool use_record_cache, bool print_error)
  35. {
  36.   IO_CACHE *tempfile;
  37.   DBUG_ENTER("init_read_record");
  38.  
  39.   bzero((char*) info,sizeof(*info));
  40.   info->thd=thd;
  41.   info->table=table;
  42.   info->file= table->file;
  43.   info->forms= &info->table;        /* Only one table */
  44.   info->record=table->record[0];
  45.   info->ref_length=table->file->ref_length;
  46.   info->select=select;
  47.   info->print_error=print_error;
  48.   table->status=0;            /* And it's allways found */
  49.  
  50.   if (select && my_b_inited(&select->file))
  51.     tempfile= &select->file;
  52.   else
  53.     tempfile= table->io_cache;
  54.   if (select && select->quick && (! tempfile || !tempfile->buffer))
  55.   {
  56.     DBUG_PRINT("info",("using rr_quick"));
  57.     info->read_record=rr_quick;
  58.   }
  59.   else if (tempfile && my_b_inited(tempfile)) // Test if ref-records was used
  60.   {
  61.     DBUG_PRINT("info",("using rr_from_tempfile"));
  62.     info->read_record=rr_from_tempfile;
  63.     info->io_cache=tempfile;
  64.     reinit_io_cache(info->io_cache,READ_CACHE,0L,0,0);
  65.     info->ref_pos=table->file->ref;
  66.     table->file->rnd_init(0);
  67.  
  68.     if (! (specialflag & SPECIAL_SAFE_MODE) &&
  69.     my_default_record_cache_size &&
  70.     !table->file->fast_key_read() &&
  71.     (table->db_stat & HA_READ_ONLY ||
  72.      table->reginfo.lock_type == TL_READ) &&
  73.     (ulonglong) table->reclength*(table->file->records+
  74.                       table->file->deleted) >
  75.     (ulonglong) MIN_FILE_LENGTH_TO_USE_ROW_CACHE &&
  76.     info->io_cache->end_of_file/info->ref_length*table->reclength >
  77.     (my_off_t) MIN_ROWS_TO_USE_TABLE_CACHE &&
  78.     !table->blob_fields)
  79.     {
  80.       if (! init_rr_cache(info))
  81.       {
  82.     DBUG_PRINT("info",("using rr_from_cache"));
  83.     info->read_record=rr_from_cache;
  84.       }
  85.     }
  86.   }
  87.   else if (table->record_pointers)
  88.   {
  89.     table->file->rnd_init(0);
  90.     info->cache_pos=table->record_pointers;
  91.     info->cache_end=info->cache_pos+ table->found_records*info->ref_length;
  92.     info->read_record= rr_from_pointers;
  93.   }
  94.   else
  95.   {
  96.     DBUG_PRINT("info",("using rr_sequential"));
  97.     info->read_record=rr_sequential;
  98.     table->file->rnd_init();
  99.     /* We can use record cache if we don't update dynamic length tables */
  100.     if (use_record_cache ||
  101.     (int) table->reginfo.lock_type <= (int) TL_READ_HIGH_PRIORITY ||
  102.     !(table->db_options_in_use & HA_OPTION_PACK_RECORD))
  103.       VOID(table->file->extra(HA_EXTRA_CACHE));    // Cache reads
  104.   }
  105.   DBUG_VOID_RETURN;
  106. } /* init_read_record */
  107.  
  108.  
  109. void end_read_record(READ_RECORD *info)
  110. {                    /* free cache if used */
  111.   if (info->cache)
  112.   {
  113.     my_free_lock((char*) info->cache,MYF(0));
  114.     info->cache=0;
  115.   }
  116.   if (info->table)
  117.   {
  118.     (void) info->file->extra(HA_EXTRA_NO_CACHE);
  119.     (void) info->file->rnd_end();
  120.     info->table=0;
  121.   }
  122. }
  123.  
  124.     /* Read a record from head-database */
  125.  
  126. static int rr_quick(READ_RECORD *info)
  127. {
  128.   int tmp=info->select->quick->get_next();
  129.   if (tmp)
  130.   {
  131.     if (tmp == HA_ERR_END_OF_FILE)
  132.       tmp= -1;
  133.     else if (info->print_error)
  134.       info->file->print_error(tmp,MYF(0));
  135.   }
  136.   return tmp;
  137. }
  138.  
  139.  
  140. static int rr_sequential(READ_RECORD *info)
  141. {
  142.   int tmp;
  143.   while ((tmp=info->file->rnd_next(info->record)))
  144.   {
  145.     if (info->thd->killed)
  146.     {
  147.       my_error(ER_SERVER_SHUTDOWN,MYF(0));
  148.       return 1;
  149.     }
  150.     if (tmp != HA_ERR_RECORD_DELETED)
  151.     {
  152.       if (tmp == HA_ERR_END_OF_FILE)
  153.     tmp= -1;
  154.       else if (info->print_error)
  155.     info->table->file->print_error(tmp,MYF(0));
  156.       break;
  157.     }
  158.   }
  159.   return tmp;
  160. }
  161.  
  162.  
  163. static int rr_from_tempfile(READ_RECORD *info)
  164. {
  165.   if (my_b_read(info->io_cache,info->ref_pos,info->ref_length))
  166.     return -1;                    /* End of file */
  167.   if (TEST_IF_LASTREF(info->ref_pos,info->ref_length))
  168.     return -1;                    /* File ends with this */
  169.   int tmp=info->file->rnd_pos(info->record,info->ref_pos);
  170.   if (tmp)
  171.   {
  172.     if (tmp == HA_ERR_END_OF_FILE)
  173.       tmp= -1;
  174.     else if (info->print_error)
  175.       info->file->print_error(tmp,MYF(0));
  176.   }
  177.   return tmp;
  178. } /* rr_from_tempfile */
  179.  
  180.  
  181. static int rr_from_pointers(READ_RECORD *info)
  182. {
  183.   if (info->cache_pos == info->cache_end)
  184.     return -1;                    /* End of file */
  185.   byte *cache_pos=info->cache_pos;
  186.   info->cache_pos+=info->ref_length;
  187.  
  188.   int tmp=info->file->rnd_pos(info->record,cache_pos);
  189.   if (tmp)
  190.   {
  191.     if (tmp == HA_ERR_END_OF_FILE)
  192.       tmp= -1;
  193.     else if (info->print_error)
  194.       info->file->print_error(tmp,MYF(0));
  195.   }
  196.   return tmp;
  197. }
  198.  
  199.     /* cacheing of records from a database */
  200.  
  201. static int init_rr_cache(READ_RECORD *info)
  202. {
  203.   uint rec_cache_size;
  204.   DBUG_ENTER("init_rr_cache");
  205.  
  206.   info->struct_length=3+MAX_REFLENGTH;
  207.   info->reclength=ALIGN_SIZE(info->table->reclength+1);
  208.   if (info->reclength < info->struct_length)
  209.     info->reclength=ALIGN_SIZE(info->struct_length);
  210.  
  211.   info->error_offset=info->table->reclength;
  212.   info->cache_records=my_default_record_cache_size/
  213.     (info->reclength+info->struct_length);
  214.   rec_cache_size=info->cache_records*info->reclength;
  215.   info->rec_cache_size=info->cache_records*info->ref_length;
  216.  
  217.   if (info->cache_records <= 2 ||
  218.       !(info->cache=(byte*) my_malloc_lock(rec_cache_size+info->cache_records*
  219.                        info->struct_length,
  220.                        MYF(0))))
  221.     DBUG_RETURN(1);
  222. #ifdef HAVE_purify
  223.   bzero(info->cache,rec_cache_size);        // Avoid warnings in qsort
  224. #endif
  225.   DBUG_PRINT("info",("Allocated buffert for %d records",info->cache_records));
  226.   info->read_positions=info->cache+rec_cache_size;
  227.   info->cache_pos=info->cache_end=info->cache;
  228.   DBUG_RETURN(0);
  229. } /* init_rr_cache */
  230.  
  231.  
  232. static int rr_from_cache(READ_RECORD *info)
  233. {
  234.   reg1 uint i;
  235.   ulong length;
  236.   my_off_t rest_of_file;
  237.   int16 error;
  238.   byte *position,*ref_position,*record_pos;
  239.   ulong record;
  240.  
  241.   for (;;)
  242.   {
  243.     if (info->cache_pos != info->cache_end)
  244.     {
  245.       if (info->cache_pos[info->error_offset])
  246.       {
  247.     shortget(error,info->cache_pos);
  248.     if (info->print_error)
  249.       info->table->file->print_error(error,MYF(0));
  250.       }
  251.       else
  252.       {
  253.     error=0;
  254.     memcpy(info->record,info->cache_pos,(size_t) info->table->reclength);
  255.       }
  256.       info->cache_pos+=info->reclength;
  257.       return ((int) error);
  258.     }
  259.     length=info->rec_cache_size;
  260.     rest_of_file=info->io_cache->end_of_file - my_b_tell(info->io_cache);
  261.     if ((my_off_t) length > rest_of_file)
  262.       length= (ulong) rest_of_file;
  263.     if (!length || my_b_read(info->io_cache,info->cache,length))
  264.     {
  265.       DBUG_PRINT("info",("Found end of file"));
  266.       return -1;            /* End of file */
  267.     }
  268.  
  269.     length/=info->ref_length;
  270.     position=info->cache;
  271.     ref_position=info->read_positions;
  272.     for (i=0 ; i < length ; i++,position+=info->ref_length)
  273.     {
  274.       if (memcmp(position,last_ref,(size_s) info->ref_length) == 0)
  275.       {                    /* End of file */
  276.     if (!i)
  277.     {
  278.       DBUG_PRINT("info",("Found end of file"));
  279.       return -1;            /* Last record and no in buffert */
  280.     }
  281.     length=i;                // rows in buffer
  282.     break;
  283.       }
  284.       memcpy(ref_position,position,(size_s) info->ref_length);
  285.       ref_position+=MAX_REFLENGTH;
  286.       int3store(ref_position,(long) i);
  287.       ref_position+=3;
  288.     }
  289.     qsort(info->read_positions,length,info->struct_length,(qsort_cmp) rr_cmp);
  290.  
  291.     position=info->read_positions;
  292.     for (i=0 ; i < length ; i++)
  293.     {
  294.       memcpy(info->ref_pos,position,(size_s) info->ref_length);
  295.       position+=MAX_REFLENGTH;
  296.       record=uint3korr(position);
  297.       position+=3;
  298.       record_pos=info->cache+record*info->reclength;
  299.       if ((error=(int16) info->file->rnd_pos(record_pos,info->ref_pos)))
  300.       {
  301.     record_pos[info->error_offset]=1;
  302.     shortstore(record_pos,error);
  303.     DBUG_PRINT("error",("Got error: %d:%d when reading row",
  304.                 my_errno, error));
  305.       }
  306.       else
  307.     record_pos[info->error_offset]=0;
  308.     }
  309.     info->cache_end=(info->cache_pos=info->cache)+length*info->reclength;
  310.   }
  311. } /* rr_from_cache */
  312.  
  313.  
  314. static int rr_cmp(uchar *a,uchar *b)
  315. {
  316.   if (a[0] != b[0])
  317.     return (int) a[0] - (int) b[0];
  318.   if (a[1] != b[1])
  319.     return (int) a[1] - (int) b[1];
  320.   if (a[2] != b[2])
  321.     return (int) a[2] - (int) b[2];
  322. #if MAX_REFLENGTH == 4
  323.   return (int) a[3] - (int) b[3];
  324. #else
  325.   if (a[3] != b[3])
  326.     return (int) a[3] - (int) b[3];
  327.   if (a[4] != b[4])
  328.     return (int) a[4] - (int) b[4];
  329.   if (a[5] != b[5])
  330.     return (int) a[1] - (int) b[5];
  331.   if (a[6] != b[6])
  332.     return (int) a[6] - (int) b[6];
  333.   return (int) a[7] - (int) b[7];
  334. #endif
  335. }
  336.