myisampack.c
上传用户:tsgydb
上传日期:2007-04-14
资源大小:10674k
文件大小:59k
源码类别:

MySQL数据库

开发平台:

Visual C++

  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. /* Pack MyISAM file */
  17. #ifndef USE_MY_FUNC
  18. #define USE_MY_FUNC /* We need at least my_malloc */
  19. #endif
  20. #include "myisamdef.h"
  21. #include <queues.h>
  22. #include <my_tree.h>
  23. #include "mysys_err.h"
  24. #ifdef MSDOS
  25. #include <io.h>
  26. #endif
  27. #ifndef __GNU_LIBRARY__
  28. #define __GNU_LIBRARY__ /* Skip warnings in getopt.h */
  29. #endif
  30. #include <getopt.h>
  31. #if INT_MAX > 32767
  32. #define BITS_SAVED 32
  33. #else
  34. #define BITS_SAVED 16
  35. #endif
  36. #define IS_OFFSET ((uint) 32768) /* Bit if offset or char in tree */
  37. #define HEAD_LENGTH 32
  38. #define ALLOWED_JOIN_DIFF 256 /* Diff allowed to join trees */
  39. #define DATA_TMP_EXT ".TMD"
  40. #define OLD_EXT ".OLD"
  41. #define WRITE_COUNT MY_HOW_OFTEN_TO_WRITE
  42. struct st_file_buffer {
  43.   File file;
  44.   char *buffer,*pos,*end;
  45.   my_off_t pos_in_file;
  46.   int bits;
  47.   uint byte;
  48. };
  49. struct st_huff_tree;
  50. struct st_huff_element;
  51. typedef struct st_huff_counts {
  52.   uint field_length,max_zero_fill;
  53.   uint pack_type;
  54.   uint max_end_space,max_pre_space,length_bits,min_space;
  55.   ulong max_length;
  56.   enum en_fieldtype field_type;
  57.   struct st_huff_tree *tree; /* Tree for field */
  58.   my_off_t counts[256];
  59.   my_off_t end_space[8];
  60.   my_off_t pre_space[8];
  61.   my_off_t tot_end_space,tot_pre_space,zero_fields,empty_fields,bytes_packed;
  62.   TREE int_tree;
  63.   byte *tree_buff;
  64.   byte *tree_pos;
  65. } HUFF_COUNTS;
  66. typedef struct st_huff_element HUFF_ELEMENT;
  67. struct st_huff_element {
  68.   my_off_t count;
  69.   union un_element {
  70.     struct st_nod {
  71.       HUFF_ELEMENT *left,*right;
  72.     } nod;
  73.     struct st_leaf {
  74.       HUFF_ELEMENT *null;
  75.       uint element_nr; /* Number of element */
  76.     } leaf;
  77.   } a;
  78. };
  79. typedef struct st_huff_tree {
  80.   HUFF_ELEMENT *root,*element_buffer;
  81.   HUFF_COUNTS *counts;
  82.   uint tree_number;
  83.   uint elements;
  84.   my_off_t bytes_packed;
  85.   uint tree_pack_length;
  86.   uint min_chr,max_chr,char_bits,offset_bits,max_offset,height;
  87.   ulong *code;
  88.   uchar *code_len;
  89. } HUFF_TREE;
  90. typedef struct st_isam_mrg {
  91.   MI_INFO **file,**current,**end;
  92.   uint free_file;
  93.   uint count;
  94.   uint min_pack_length; /* Theese is used by packed data */
  95.   uint max_pack_length;
  96.   uint ref_length;
  97.   uint max_blob_length;
  98.   my_off_t records;
  99. } MRG_INFO;
  100. extern int main(int argc,char * *argv);
  101. static void get_options(int *argc,char ***argv);
  102. static MI_INFO *open_isam_file(char *name,int mode);
  103. static bool open_isam_files(MRG_INFO *mrg,char **names,uint count);
  104. static int compress(MRG_INFO *file,char *join_name);
  105. static HUFF_COUNTS *init_huff_count(MI_INFO *info,my_off_t records);
  106. static void free_counts_and_tree_and_queue(HUFF_TREE *huff_trees,
  107.    uint trees,
  108.    HUFF_COUNTS *huff_counts,
  109.    uint fields);
  110. static int compare_tree(const uchar *s,const uchar *t);
  111. static int get_statistic(MRG_INFO *mrg,HUFF_COUNTS *huff_counts);
  112. static void check_counts(HUFF_COUNTS *huff_counts,uint trees,
  113.  my_off_t records);
  114. static int test_space_compress(HUFF_COUNTS *huff_counts,my_off_t records,
  115.        uint max_space_length,my_off_t *space_counts,
  116.        my_off_t tot_space_count,
  117.        enum en_fieldtype field_type);
  118. static HUFF_TREE* make_huff_trees(HUFF_COUNTS *huff_counts,uint trees);
  119. static int make_huff_tree(HUFF_TREE *tree,HUFF_COUNTS *huff_counts);
  120. static int compare_huff_elements(void *not_used, byte *a,byte *b);
  121. static int save_counts_in_queue(byte *key,element_count count,
  122.     HUFF_TREE *tree);
  123. static my_off_t calc_packed_length(HUFF_COUNTS *huff_counts,uint flag);
  124. static uint join_same_trees(HUFF_COUNTS *huff_counts,uint trees);
  125. static int make_huff_decode_table(HUFF_TREE *huff_tree,uint trees);
  126. static void make_traverse_code_tree(HUFF_TREE *huff_tree,
  127.     HUFF_ELEMENT *element,uint size,
  128.     ulong code);
  129. static int write_header(MRG_INFO *isam_file, uint header_length,uint trees,
  130. my_off_t tot_elements,my_off_t filelength);
  131. static void write_field_info(HUFF_COUNTS *counts, uint fields,uint trees);
  132. static my_off_t write_huff_tree(HUFF_TREE *huff_tree,uint trees);
  133. static uint *make_offset_code_tree(HUFF_TREE *huff_tree,
  134.        HUFF_ELEMENT *element,
  135.        uint *offset);
  136. static uint max_bit(uint value);
  137. static int compress_isam_file(MRG_INFO *file,HUFF_COUNTS *huff_counts);
  138. static char *make_new_name(char *new_name,char *old_name);
  139. static char *make_old_name(char *new_name,char *old_name);
  140. static void init_file_buffer(File file,pbool read_buffer);
  141. static int flush_buffer(ulong neaded_length);
  142. static void end_file_buffer(void);
  143. static void write_bits(ulong value,uint bits);
  144. static void flush_bits(void);
  145. static int save_state(MI_INFO *isam_file,MRG_INFO *mrg,my_off_t new_length,
  146.       ha_checksum crc);
  147. static int save_state_mrg(File file,MRG_INFO *isam_file,my_off_t new_length,
  148.   ha_checksum crc);
  149. static int mrg_close(MRG_INFO *mrg);
  150. static int mrg_rrnd(MRG_INFO *info,byte *buf);
  151. static void mrg_reset(MRG_INFO *mrg);
  152. static int backup=0,error_on_write=0,test_only=0,verbose=0,silent=0,
  153.    write_loop=0,force_pack=0,opt_wait=0,isamchk_neaded=0;
  154. static int tmpfile_createflag=O_RDWR | O_TRUNC | O_EXCL;
  155. static uint tree_buff_length=8196-MALLOC_OVERHEAD;
  156. static char tmp_dir[FN_REFLEN]={0},*join_table;
  157. static my_off_t intervall_length;
  158. static ha_checksum glob_crc;
  159. static struct st_file_buffer file_buffer;
  160. static QUEUE queue;
  161. static HUFF_COUNTS *global_count;
  162. static char zero_string[]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
  163. static const char *load_default_groups[]= { "myisampack",0 };
  164. /* The main program */
  165. int main(int argc, char **argv)
  166. {
  167.   int error,ok;
  168.   MRG_INFO merge;
  169.   char **default_argv;
  170.   MY_INIT(argv[0]);
  171.   load_defaults("my",load_default_groups,&argc,&argv);
  172.   default_argv= argv;
  173.   get_options(&argc,&argv);
  174.   error=ok=isamchk_neaded=0;
  175.   if (join_table)
  176.   { /* Join files into one */
  177.     if (open_isam_files(&merge,argv,(uint) argc) ||
  178. compress(&merge,join_table))
  179.       error=1;
  180.   }
  181.   else while (argc--)
  182.   {
  183.     MI_INFO *isam_file;
  184.     if (!(isam_file=open_isam_file(*argv++,O_RDWR)))
  185.       error=1;
  186.     else
  187.     {
  188.       merge.file= &isam_file;
  189.       merge.current=0;
  190.       merge.free_file=0;
  191.       merge.count=1;
  192.       if (compress(&merge,0))
  193. error=1;
  194.       else
  195. ok=1;
  196.     }
  197.   }
  198.   if (ok && isamchk_neaded && !silent)
  199.     puts("Remember to run myisamchk -rq on compressed tables");
  200.   VOID(fflush(stdout)); VOID(fflush(stderr));
  201.   free_defaults(default_argv);
  202.   my_end(verbose ? MY_CHECK_ERROR | MY_GIVE_INFO : MY_CHECK_ERROR);
  203.   exit(error ? 2 : 0);
  204. #ifndef _lint
  205.   return 0; /* No compiler warning */
  206. #endif
  207. }
  208. enum options {OPT_CHARSETS_DIR=256};
  209. static struct option long_options[] =
  210. {
  211.   {"backup", no_argument,    0, 'b'},
  212.   {"character-sets-dir",required_argument,0,  OPT_CHARSETS_DIR},
  213.   {"debug", optional_argument, 0, '#'},
  214.   {"force", no_argument,    0, 'f'},
  215.   {"join", required_argument, 0, 'j'},
  216.   {"help", no_argument,    0, '?'},
  217.   {"packlength",required_argument, 0, 'p'},
  218.   {"silent", no_argument,    0, 's'},
  219.   {"tmpdir", required_argument, 0, 'T'},
  220.   {"test", no_argument,    0, 't'},
  221.   {"verbose", no_argument,    0, 'v'},
  222.   {"version", no_argument,    0, 'V'},
  223.   {"wait", no_argument,    0, 'w'},
  224.   {0, 0, 0, 0}
  225. };
  226. static void print_version(void)
  227. {
  228.   printf("%s  Ver 1.9 for %s on %sn",my_progname,SYSTEM_TYPE,MACHINE_TYPE);
  229. }
  230. static void usage(void)
  231. {
  232.   print_version();
  233.   puts("Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB");
  234.   puts("This software comes with ABSOLUTELY NO WARRANTY. This is free software,");
  235.   puts("and you are welcome to modify and redistribute it under the GPL licensen");
  236.   puts("Pack a MyISAM-table to take much less space.");
  237.   puts("Keys are not updated, you must run myisamchk -rq on the datafile");
  238.   puts("afterwards to update the keys.");
  239.   puts("You should give the .MSI file as the filename argument.");
  240.   printf("nUsage: %s [OPTIONS] filename...n", my_progname);
  241.   puts("n
  242.   -b, --backup Make a backup of the table as table_name.OLDn
  243.   -f, --force Force packing of table even if it gets bigger or ifn
  244. tempfile exists.n
  245.   -j, --join='new_table_name'n
  246. Join all given tables into 'new_table_name'.n
  247. All tables MUST have identical layouts.n
  248.   -s, --silent Be more silent.n
  249.   -t, --test Don't pack table, only test packing it.n
  250.   -v, --verbose Write info about progress and packing result.n
  251.   -w, --wait Wait and retry if table is in use.n
  252.   -T, --tmpdir=... Use temporary directory to store temporary table.n
  253.   -#, --debug=...       Output debug log. Often this is 'd:t:o,filename`n
  254.   -?, --help Display this help and exit.n
  255.   -V, --version Output version information and exit.");
  256.   print_defaults("my",load_default_groups);
  257. };
  258. /* reads options */
  259. /* Initiates DEBUG - but no debugging here ! */
  260. static void get_options(int *argc,char ***argv)
  261. {
  262.   int c,option_index=0;
  263.   uint length;
  264.   my_progname= argv[0][0];
  265.   if (isatty(fileno(stdout)))
  266.     write_loop=1;
  267.   while ((c=getopt_long(*argc,*argv,"bfj:stvwT:#::?V",long_options,
  268. &option_index)) != EOF)
  269.   {
  270.     switch(c) {
  271.     case 'b':
  272.       backup=1;
  273.       break;
  274.     case 'f':
  275.       force_pack=1;
  276.       tmpfile_createflag=O_RDWR | O_TRUNC;
  277.       break;
  278.     case 'j':
  279.       join_table=optarg;
  280.       break;
  281.     case 's':
  282.       write_loop=verbose=0; silent=1;
  283.       break;
  284.     case 't':
  285.       test_only=verbose=1;
  286.       break;
  287.     case 'T':
  288.       length=(uint) (strmov(tmp_dir,optarg)-tmp_dir);
  289.       if (length != dirname_length(tmp_dir))
  290.       {
  291. tmp_dir[length]=FN_LIBCHAR;
  292. tmp_dir[length+1]=0;
  293.       }
  294.       break;
  295.     case 'v':
  296.       verbose=1; silent=0;
  297.       break;
  298.     case 'w':
  299.       opt_wait=1;
  300.       break;
  301.     case '#':
  302.       DBUG_PUSH(optarg ? optarg : "d:t:o");
  303.       break;
  304.     case OPT_CHARSETS_DIR:
  305.       charsets_dir = optarg;
  306.       break;
  307.     case 'V': print_version(); exit(0);
  308.     case 'I':
  309.     case '?':
  310.       usage();
  311.       exit(0);
  312.     default:
  313.       fprintf(stderr,"%s: Illegal option: -%cn",my_progname,opterr);
  314.       usage();
  315.       exit(1);
  316.     }
  317.   }
  318.   (*argc)-=optind;
  319.   (*argv)+=optind;
  320.   if (!*argc)
  321.   {
  322.     usage();
  323.     exit(1);
  324.   }
  325.   if (join_table)
  326.   {
  327.     backup=0; /* Not needed */
  328.     tmp_dir[0]=0;
  329.   }
  330.   return;
  331. }
  332. static MI_INFO *open_isam_file(char *name,int mode)
  333. {
  334.   MI_INFO *isam_file;
  335.   MYISAM_SHARE *share;
  336.   DBUG_ENTER("open_isam_file");
  337.   if (!(isam_file=mi_open(name,mode,
  338.   (opt_wait ? HA_OPEN_WAIT_IF_LOCKED :
  339.    HA_OPEN_ABORT_IF_LOCKED))))
  340.   {
  341.     VOID(fprintf(stderr,"%s gave error %d on openn",name,my_errno));
  342.     DBUG_RETURN(0);
  343.   }
  344.   share=isam_file->s;
  345.   if (share->options & HA_OPTION_COMPRESS_RECORD && !join_table)
  346.   {
  347.     if (!force_pack)
  348.     {
  349.       VOID(fprintf(stderr,"%s is already compressedn",name));
  350.       VOID(mi_close(isam_file));
  351.       DBUG_RETURN(0);
  352.     }
  353.     if (verbose)
  354.       puts("Recompressing already compressed table");
  355.     share->options&= ~HA_OPTION_READ_ONLY_DATA; /* We are modifing it */
  356.   }
  357.   if (! force_pack && share->state.state.records != 0 &&
  358.       (share->state.state.records <= 1 ||
  359.        share->state.state.data_file_length < 1024))
  360.   {
  361.     VOID(fprintf(stderr,"%s is too small to compressn",name));
  362.     VOID(mi_close(isam_file));
  363.     DBUG_RETURN(0);
  364.   }
  365.   VOID(mi_lock_database(isam_file,F_WRLCK));
  366.   DBUG_RETURN(isam_file);
  367. }
  368. static bool open_isam_files(MRG_INFO *mrg,char **names,uint count)
  369. {
  370.   uint i,j;
  371.   mrg->count=0;
  372.   mrg->current=0;
  373.   mrg->file=(MI_INFO**) my_malloc(sizeof(MI_INFO*)*count,MYF(MY_FAE));
  374.   mrg->free_file=1;
  375.   for (i=0; i < count ; i++)
  376.   {
  377.     if (!(mrg->file[i]=open_isam_file(names[i],O_RDONLY)))
  378.       goto error;
  379.   }
  380.   /* Check that files are identical */
  381.   for (j=0 ; j < count-1 ; j++)
  382.   {
  383.     MI_COLUMNDEF *m1,*m2,*end;
  384.     if (mrg->file[j]->s->base.reclength != mrg->file[j+1]->s->base.reclength ||
  385. mrg->file[j]->s->base.fields != mrg->file[j+1]->s->base.fields)
  386.       goto diff_file;
  387.     m1=mrg->file[j]->s->rec;
  388.     end=m1+mrg->file[j]->s->base.fields;
  389.     m2=mrg->file[j+1]->s->rec;
  390.     for ( ; m1 != end ; m1++,m2++)
  391.     {
  392.       if (m1->type != m2->type || m1->length != m2->length)
  393. goto diff_file;
  394.     }
  395.   }
  396.   mrg->count=count;
  397.   return 0;
  398.  diff_file:
  399.   fprintf(stderr,"%s: Tables '%s' and '%s' are not identicaln",
  400.   my_progname,names[j],names[j+1]);
  401.  error:
  402.   while (i--)
  403.     mi_close(mrg->file[i]);
  404.   my_free((gptr) mrg->file,MYF(0));
  405.   return 1;
  406. }
  407. static int compress(MRG_INFO *mrg,char *result_table)
  408. {
  409.   int error;
  410.   File new_file,join_isam_file;
  411.   MI_INFO *isam_file;
  412.   MYISAM_SHARE *share;
  413.   char org_name[FN_REFLEN],new_name[FN_REFLEN],temp_name[FN_REFLEN];
  414.   uint i,header_length,fields,trees,used_trees;
  415.   my_off_t old_length,new_length,tot_elements;
  416.   HUFF_COUNTS *huff_counts;
  417.   HUFF_TREE *huff_trees;
  418.   DBUG_ENTER("compress");
  419.   isam_file=mrg->file[0]; /* Take this as an example */
  420.   share=isam_file->s;
  421.   new_file=join_isam_file= -1;
  422.   trees=fields=0;
  423.   huff_trees=0;
  424.   huff_counts=0;
  425.   /* Create temporary or join file */
  426.   if (backup)
  427.     VOID(fn_format(org_name,isam_file->filename,"",MI_NAME_DEXT,2));
  428.   else
  429.     VOID(fn_format(org_name,isam_file->filename,"",MI_NAME_DEXT,2+4+16));
  430.   if (!test_only && result_table)
  431.   {
  432.     /* Make a new indexfile based on first file in list */
  433.     uint length;
  434.     char *buff;
  435.     strmov(org_name,result_table); /* Fix error messages */
  436.     VOID(fn_format(new_name,result_table,"",MI_NAME_IEXT,2));
  437.     if ((join_isam_file=my_create(new_name,0,tmpfile_createflag,MYF(MY_WME)))
  438. < 0)
  439.       goto err;
  440.     length=(uint) share->base.keystart;
  441.     if (!(buff=my_malloc(length,MYF(MY_WME))))
  442.       goto err;
  443.     if (my_pread(share->kfile,buff,length,0L,MYF(MY_WME | MY_NABP)) ||
  444. my_write(join_isam_file,buff,length,
  445.  MYF(MY_WME | MY_NABP | MY_WAIT_IF_FULL)))
  446.     {
  447.       my_free(buff,MYF(0));
  448.       goto err;
  449.     }
  450.     my_free(buff,MYF(0));
  451.     VOID(fn_format(new_name,result_table,"",MI_NAME_DEXT,2));
  452.   }
  453.   else if (!tmp_dir[0])
  454.     VOID(make_new_name(new_name,org_name));
  455.   else
  456.     VOID(fn_format(new_name,org_name,tmp_dir,DATA_TMP_EXT,1+2+4));
  457.   if (!test_only &&
  458.       (new_file=my_create(new_name,0,tmpfile_createflag,MYF(MY_WME))) < 0)
  459.     goto err;
  460.   /* Start calculating statistics */
  461.   mrg->records=0;
  462.   for (i=0 ; i < mrg->count ; i++)
  463.     mrg->records+=mrg->file[i]->s->state.state.records;
  464.   if (write_loop || verbose)
  465.   {
  466.     printf("Compressing %s: (%lu records)n",
  467.    result_table ? new_name : org_name,(ulong) mrg->records);
  468.   }
  469.   trees=fields=share->base.fields;
  470.   huff_counts=init_huff_count(isam_file,mrg->records);
  471.   QUICK_SAFEMALLOC;
  472.   if (write_loop || verbose)
  473.     printf("- Calculating statisticsn");
  474.   if (get_statistic(mrg,huff_counts))
  475.     goto err;
  476.   NORMAL_SAFEMALLOC;
  477.   old_length=0;
  478.   for (i=0; i < mrg->count ; i++)
  479.     old_length+= (mrg->file[i]->s->state.state.data_file_length -
  480.   mrg->file[i]->s->state.state.empty);
  481.   if (init_queue(&queue,256,0,0,compare_huff_elements,0))
  482.     goto err;
  483.   check_counts(huff_counts,fields,mrg->records);
  484.   huff_trees=make_huff_trees(huff_counts,trees);
  485.   if ((int) (used_trees=join_same_trees(huff_counts,trees)) < 0)
  486.     goto err;
  487.   if (make_huff_decode_table(huff_trees,fields))
  488.     goto err;
  489.   init_file_buffer(new_file,0);
  490.   file_buffer.pos_in_file=HEAD_LENGTH;
  491.   if (! test_only)
  492.     VOID(my_seek(new_file,file_buffer.pos_in_file,MY_SEEK_SET,MYF(0)));
  493.   write_field_info(huff_counts,fields,used_trees);
  494.   if (!(tot_elements=write_huff_tree(huff_trees,trees)))
  495.     goto err;
  496.   header_length=(uint) file_buffer.pos_in_file+
  497.     (uint) (file_buffer.pos-file_buffer.buffer);
  498.   /* Compress file */
  499.   if (write_loop || verbose)
  500.     printf("- Compressing filen");
  501.   error=compress_isam_file(mrg,huff_counts);
  502.   new_length=file_buffer.pos_in_file;
  503.   if (!error && !test_only)
  504.   {
  505.     char buff[MEMMAP_EXTRA_MARGIN]; /* End marginal for memmap */
  506.     bzero(buff,sizeof(buff));
  507.     error=my_write(file_buffer.file,buff,sizeof(buff),
  508.    MYF(MY_WME | MY_NABP | MY_WAIT_IF_FULL)) != 0;
  509.   }
  510.   if (!error)
  511.     error=write_header(mrg,header_length,used_trees,tot_elements,
  512.        new_length);
  513.   end_file_buffer();
  514.   if (verbose && mrg->records)
  515.     printf("Min record length: %6d   Max length: %6d   Mean total length: %6ldn",
  516.    mrg->min_pack_length,mrg->max_pack_length,
  517.    (ulong) (new_length/mrg->records));
  518.   if (!test_only)
  519.   {
  520.     error|=my_close(new_file,MYF(MY_WME));
  521.     if (!result_table)
  522.     {
  523.       error|=my_close(isam_file->dfile,MYF(MY_WME));
  524.       isam_file->dfile= -1; /* Tell mi_close file is closed */
  525.     }
  526.   }
  527.   free_counts_and_tree_and_queue(huff_trees,trees,huff_counts,fields);
  528.   if (! test_only && ! error)
  529.   {
  530.     if (result_table)
  531.     {
  532.       error=save_state_mrg(join_isam_file,mrg,new_length,glob_crc);
  533.     }
  534.     else
  535.     {
  536.       if (backup)
  537.       {
  538. if (my_rename(org_name,make_old_name(temp_name,isam_file->filename),
  539.       MYF(MY_WME)))
  540.   error=1;
  541. else
  542. {
  543.   if (tmp_dir[0])
  544.   {
  545.     if (!(error=my_copy(new_name,org_name,MYF(MY_WME))))
  546.       VOID(my_delete(new_name,MYF(MY_WME)));
  547.   }
  548.   else
  549.     error=my_rename(new_name,org_name,MYF(MY_WME));
  550.   if (!error)
  551.     VOID(my_copystat(temp_name,org_name,MYF(MY_COPYTIME)));
  552. }
  553.       }
  554.       else
  555.       {
  556. if (tmp_dir[0])
  557. {
  558.   if (!(error=my_copy(new_name,org_name,
  559.       MYF(MY_WME | MY_HOLD_ORIGINAL_MODES
  560.   | MY_COPYTIME))))
  561.     VOID(my_delete(new_name,MYF(MY_WME)));
  562. }
  563. else
  564.   error=my_redel(org_name,new_name,MYF(MY_WME | MY_COPYTIME));
  565.       }
  566.       if (! error)
  567. error=save_state(isam_file,mrg,new_length,glob_crc);
  568.     }
  569.   }
  570.   error|=mrg_close(mrg);
  571.   if (join_isam_file >= 0)
  572.     error|=my_close(join_isam_file,MYF(MY_WME));
  573.   if (error)
  574.   {
  575.     VOID(fprintf(stderr,"Aborting: %s is not compressedn",org_name));
  576.     DBUG_RETURN(-1);
  577.   }
  578.   if (write_loop || verbose)
  579.   {
  580.     if (old_length)
  581.       printf("%.4g%%     n", (((longlong) (old_length -new_length))*100.0/
  582.        (longlong) old_length));
  583.     else
  584.       puts("Empty file saved in compressed format");
  585.   }
  586.   DBUG_RETURN(0);
  587.  err:
  588.   free_counts_and_tree_and_queue(huff_trees,trees,huff_counts,fields);
  589.   if (new_file >= 0)
  590.     VOID(my_close(new_file,MYF(0)));
  591.   if (join_isam_file >= 0)
  592.     VOID(my_close(join_isam_file,MYF(0)));
  593.   mrg_close(mrg);
  594.   VOID(fprintf(stderr,"Aborted: %s is not compressedn",org_name));
  595.   DBUG_RETURN(-1);
  596. }
  597. /* Init a huff_count-struct for each field and init it */
  598. static HUFF_COUNTS *init_huff_count(MI_INFO *info,my_off_t records)
  599. {
  600.   reg2 uint i;
  601.   reg1 HUFF_COUNTS *count;
  602.   if ((count = (HUFF_COUNTS*) my_malloc(info->s->base.fields*
  603. sizeof(HUFF_COUNTS),
  604. MYF(MY_ZEROFILL | MY_WME))))
  605.   {
  606.     for (i=0 ; i < info->s->base.fields ; i++)
  607.     {
  608.       enum en_fieldtype type;
  609.       count[i].field_length=info->s->rec[i].length;
  610.       type= count[i].field_type= (enum en_fieldtype) info->s->rec[i].type;
  611.       if (type == FIELD_INTERVALL ||
  612.   type == FIELD_CONSTANT ||
  613.   type == FIELD_ZERO)
  614. type = FIELD_NORMAL;
  615.       if (count[i].field_length <= 8 &&
  616.   (type == FIELD_NORMAL ||
  617.    type == FIELD_SKIPP_ZERO))
  618. count[i].max_zero_fill= count[i].field_length;
  619.       init_tree(&count[i].int_tree,0,-1,(qsort_cmp) compare_tree,0,NULL);
  620.       if (records && type != FIELD_BLOB && type != FIELD_VARCHAR)
  621. count[i].tree_pos=count[i].tree_buff =
  622.   my_malloc(count[i].field_length > 1 ? tree_buff_length : 2,
  623.     MYF(MY_WME));
  624.     }
  625.   }
  626.   return count;
  627. }
  628. /* Free memory used by counts and trees */
  629. static void free_counts_and_tree_and_queue(HUFF_TREE *huff_trees, uint trees,
  630.    HUFF_COUNTS *huff_counts,
  631.    uint fields)
  632. {
  633.   register uint i;
  634.   if (huff_trees)
  635.   {
  636.     for (i=0 ; i < trees ; i++)
  637.     {
  638.       if (huff_trees[i].element_buffer)
  639. my_free((gptr) huff_trees[i].element_buffer,MYF(0));
  640.       if (huff_trees[i].code)
  641. my_free((gptr) huff_trees[i].code,MYF(0));
  642.     }
  643.     my_free((gptr) huff_trees,MYF(0));
  644.   }
  645.   if (huff_counts)
  646.   {
  647.     for (i=0 ; i < fields ; i++)
  648.     {
  649.       if (huff_counts[i].tree_buff)
  650.       {
  651. my_free((gptr) huff_counts[i].tree_buff,MYF(0));
  652. delete_tree(&huff_counts[i].int_tree);
  653.       }
  654.     }
  655.     my_free((gptr) huff_counts,MYF(0));
  656.   }
  657.   delete_queue(&queue); /* This is safe to free */
  658.   return;
  659. }
  660. /* Read through old file and gather some statistics */
  661. static int get_statistic(MRG_INFO *mrg,HUFF_COUNTS *huff_counts)
  662. {
  663.   int error;
  664.   uint length;
  665.   ulong reclength,max_blob_length;
  666.   byte *record,*pos,*next_pos,*end_pos,*start_pos;
  667.   ha_rows record_count;
  668.   my_bool static_row_size;
  669.   HUFF_COUNTS *count,*end_count;
  670.   TREE_ELEMENT *element;
  671.   DBUG_ENTER("get_statistic");
  672.   reclength=mrg->file[0]->s->base.reclength;
  673.   record=(byte*) my_alloca(reclength);
  674.   end_count=huff_counts+mrg->file[0]->s->base.fields;
  675.   record_count=0; glob_crc=0;
  676.   max_blob_length=0;
  677.   /* Check how to calculate checksum */
  678.   static_row_size=1;
  679.   for (count=huff_counts ; count < end_count ; count++)
  680.   {
  681.     if (count->field_type == FIELD_BLOB || count->field_type == FIELD_VARCHAR)
  682.     {
  683.       static_row_size=0;
  684.       break;
  685.     }
  686.   }
  687.   mrg_reset(mrg);
  688.   while ((error=mrg_rrnd(mrg,record)) != HA_ERR_END_OF_FILE)
  689.   {
  690.     ulong tot_blob_length=0;
  691.     if (! error)
  692.     {
  693.       if (static_row_size)
  694. glob_crc+=mi_static_checksum(mrg->file[0],record);
  695.       else
  696. glob_crc+=mi_checksum(mrg->file[0],record);
  697.       for (pos=record,count=huff_counts ;
  698.    count < end_count ;
  699.    count++,
  700.    pos=next_pos)
  701.       {
  702. next_pos=end_pos=(start_pos=pos)+count->field_length;
  703. /* Put value in tree if there is room for it */
  704. if (count->tree_buff)
  705. {
  706.   global_count=count;
  707.   if (!(element=tree_insert(&count->int_tree,pos,0)) ||
  708.       (element->count == 1 &&
  709.        count->tree_buff + tree_buff_length <
  710.        count->tree_pos + count->field_length) ||
  711.       (count->field_length == 1 &&
  712.        count->int_tree.elements_in_tree > 1))
  713.   {
  714.     delete_tree(&count->int_tree);
  715.     my_free(count->tree_buff,MYF(0));
  716.     count->tree_buff=0;
  717.   }
  718.   else
  719.   {
  720.     if (element->count == 1)
  721.     { /* New element */
  722.       memcpy(count->tree_pos,pos,(size_t) count->field_length);
  723.       tree_set_pointer(element,count->tree_pos);
  724.       count->tree_pos+=count->field_length;
  725.     }
  726.   }
  727. }
  728. /* Save character counters and space-counts and zero-field-counts */
  729. if (count->field_type == FIELD_NORMAL ||
  730.     count->field_type == FIELD_SKIPP_ENDSPACE)
  731. {
  732.   for ( ; end_pos > pos ; end_pos--)
  733.     if (end_pos[-1] != ' ')
  734.       break;
  735.   if (end_pos == pos)
  736.   {
  737.     count->empty_fields++;
  738.     count->max_zero_fill=0;
  739.     continue;
  740.   }
  741.   length= (uint) (next_pos-end_pos);
  742.   count->tot_end_space+=length;
  743.   if (length < 8)
  744.     count->end_space[length]++;
  745.   if (count->max_end_space < length)
  746.     count->max_end_space = length;
  747. }
  748. if (count->field_type == FIELD_NORMAL ||
  749.     count->field_type == FIELD_SKIPP_PRESPACE)
  750. {
  751.   for (pos=start_pos; pos < end_pos ; pos++)
  752.     if (pos[0] != ' ')
  753.       break;
  754.   if (end_pos == pos)
  755.   {
  756.     count->empty_fields++;
  757.     count->max_zero_fill=0;
  758.     continue;
  759.   }
  760.   length= (uint) (pos-start_pos);
  761.   count->tot_pre_space+=length;
  762.   if (length < 8)
  763.     count->pre_space[length]++;
  764.   if (count->max_pre_space < length)
  765.     count->max_pre_space = length;
  766. }
  767. if (count->field_type == FIELD_BLOB)
  768. {
  769.   uint field_length=count->field_length -mi_portable_sizeof_char_ptr;
  770.   ulong blob_length= _mi_calc_blob_length(field_length, start_pos);
  771.   memcpy_fixed((char*) &pos,  start_pos+field_length,sizeof(char*));
  772.   end_pos=pos+blob_length;
  773.   tot_blob_length+=blob_length;
  774.   set_if_bigger(count->max_length,blob_length);
  775. }
  776. else if (count->field_type == FIELD_VARCHAR)
  777. {
  778.   length=uint2korr(start_pos);
  779.   pos=start_pos+2;
  780.   end_pos=start_pos+length;
  781.   set_if_bigger(count->max_length,length);
  782. }
  783. if (count->field_length <= 8 &&
  784.     (count->field_type == FIELD_NORMAL ||
  785.      count->field_type == FIELD_SKIPP_ZERO))
  786. {
  787.   uint i;
  788.   if (!memcmp((byte*) start_pos,zero_string,count->field_length))
  789.   {
  790.     count->zero_fields++;
  791.     continue;
  792.   }
  793.   for (i =0 ; i < count->max_zero_fill && ! end_pos[-1 - (int) i] ;
  794.        i++) ;
  795.   if (i < count->max_zero_fill)
  796.     count->max_zero_fill=i;
  797. }
  798. if (count->field_type == FIELD_ZERO ||
  799.     count->field_type == FIELD_CHECK)
  800.   continue;
  801. for ( ; pos < end_pos ; pos++)
  802.   count->counts[(uchar) *pos]++;
  803.       }
  804.       if (tot_blob_length > max_blob_length)
  805. max_blob_length=tot_blob_length;
  806.       record_count++;
  807.       if (write_loop && record_count % WRITE_COUNT == 0)
  808.       {
  809. printf("%lur",(ulong) record_count); VOID(fflush(stdout));
  810.       }
  811.     }
  812.     else if (error != HA_ERR_RECORD_DELETED)
  813.     {
  814.       fprintf(stderr,"Got error %d while reading rows",error);
  815.       break;
  816.     }
  817.   }
  818.   if (write_loop)
  819.   {
  820.     printf("            r"); VOID(fflush(stdout));
  821.   }
  822.   mrg->records=record_count;
  823.   mrg->max_blob_length=max_blob_length;
  824.   my_afree((gptr) record);
  825.   DBUG_RETURN(error != HA_ERR_END_OF_FILE);
  826. }
  827. static int compare_huff_elements(void *not_used, byte *a, byte *b)
  828. {
  829.   return *((my_off_t*) a) < *((my_off_t*) b) ? -1 :
  830.     (*((my_off_t*) a) == *((my_off_t*) b)  ? 0 : 1);
  831. }
  832. /* Check each tree if we should use pre-space-compress, end-space-
  833.    compress, empty-field-compress or zero-field-compress */
  834. static void check_counts(HUFF_COUNTS *huff_counts, uint trees,
  835.  my_off_t records)
  836. {
  837.   uint space_fields,fill_zero_fields,field_count[(int) FIELD_VARCHAR+1];
  838.   my_off_t old_length,new_length,length;
  839.   DBUG_ENTER("check_counts");
  840.   bzero((gptr) field_count,sizeof(field_count));
  841.   space_fields=fill_zero_fields=0;
  842.   for (; trees-- ; huff_counts++)
  843.   {
  844.     if (huff_counts->field_type == FIELD_BLOB)
  845.     {
  846.       huff_counts->length_bits=max_bit(huff_counts->max_length);
  847.       goto found_pack;
  848.     }
  849.     else if (huff_counts->field_type == FIELD_VARCHAR)
  850.     {
  851.       huff_counts->length_bits=max_bit(huff_counts->max_length);
  852.       goto found_pack;
  853.     }
  854.     else if (huff_counts->field_type == FIELD_CHECK)
  855.     {
  856.       huff_counts->bytes_packed=0;
  857.       huff_counts->counts[0]=0;
  858.       goto found_pack;
  859.     }
  860.     huff_counts->field_type=FIELD_NORMAL;
  861.     huff_counts->pack_type=0;
  862.     if (huff_counts->zero_fields || ! records)
  863.     {
  864.       my_off_t old_space_count;
  865.       if (huff_counts->zero_fields == records)
  866.       {
  867. huff_counts->field_type= FIELD_ZERO;
  868. huff_counts->bytes_packed=0;
  869. huff_counts->counts[0]=0;
  870. goto found_pack;
  871.       }
  872.       old_space_count=huff_counts->counts[' '];
  873.       huff_counts->counts[' ']+=huff_counts->tot_end_space+
  874. huff_counts->tot_pre_space +
  875.   huff_counts->empty_fields * huff_counts->field_length;
  876.       old_length=calc_packed_length(huff_counts,0)+records/8;
  877.       length=huff_counts->zero_fields*huff_counts->field_length;
  878.       huff_counts->counts[0]+=length;
  879.       new_length=calc_packed_length(huff_counts,0);
  880.       if (old_length < new_length && huff_counts->field_length > 1)
  881.       {
  882. huff_counts->field_type=FIELD_SKIPP_ZERO;
  883. huff_counts->counts[0]-=length;
  884. huff_counts->bytes_packed=old_length- records/8;
  885. goto found_pack;
  886.       }
  887.       huff_counts->counts[' ']=old_space_count;
  888.     }
  889.     huff_counts->bytes_packed=calc_packed_length(huff_counts,0);
  890.     if (huff_counts->empty_fields)
  891.     {
  892.       if (huff_counts->field_length > 2 &&
  893.   huff_counts->empty_fields + (records - huff_counts->empty_fields)*
  894.   (1+max_bit(max(huff_counts->max_pre_space,
  895.  huff_counts->max_end_space))) <
  896.   records * max_bit(huff_counts->field_length))
  897.       {
  898. huff_counts->pack_type |= PACK_TYPE_SPACE_FIELDS;
  899.       }
  900.       else
  901.       {
  902. length=huff_counts->empty_fields*huff_counts->field_length;
  903. if (huff_counts->tot_end_space || ! huff_counts->tot_pre_space)
  904. {
  905.   huff_counts->tot_end_space+=length;
  906.   huff_counts->max_end_space=huff_counts->field_length;
  907.   if (huff_counts->field_length < 8)
  908.     huff_counts->end_space[huff_counts->field_length]+=
  909.       huff_counts->empty_fields;
  910. }
  911. else
  912. {
  913.   huff_counts->tot_pre_space+=length;
  914.   huff_counts->max_pre_space=huff_counts->field_length;
  915.   if (huff_counts->field_length < 8)
  916.     huff_counts->pre_space[huff_counts->field_length]+=
  917.       huff_counts->empty_fields;
  918. }
  919.       }
  920.     }
  921.     if (huff_counts->tot_end_space)
  922.     {
  923.       huff_counts->counts[' ']+=huff_counts->tot_pre_space;
  924.       if (test_space_compress(huff_counts,records,huff_counts->max_end_space,
  925.       huff_counts->end_space,
  926.       huff_counts->tot_end_space,FIELD_SKIPP_ENDSPACE))
  927. goto found_pack;
  928.       huff_counts->counts[' ']-=huff_counts->tot_pre_space;
  929.     }
  930.     if (huff_counts->tot_pre_space)
  931.     {
  932.       if (test_space_compress(huff_counts,records,huff_counts->max_pre_space,
  933.       huff_counts->pre_space,
  934.       huff_counts->tot_pre_space,FIELD_SKIPP_PRESPACE))
  935. goto found_pack;
  936.     }
  937.   found_pack: /* Found field-packing */
  938.     /* Test if we can use zero-fill */
  939.     if (huff_counts->max_zero_fill &&
  940. (huff_counts->field_type == FIELD_NORMAL ||
  941.  huff_counts->field_type == FIELD_SKIPP_ZERO))
  942.     {
  943.       huff_counts->counts[0]-=huff_counts->max_zero_fill*
  944. (huff_counts->field_type == FIELD_SKIPP_ZERO ?
  945.  records - huff_counts->zero_fields : records);
  946.       huff_counts->pack_type|=PACK_TYPE_ZERO_FILL;
  947.       huff_counts->bytes_packed=calc_packed_length(huff_counts,0);
  948.     }
  949.     /* Test if intervall-field is better */
  950.     if (huff_counts->tree_buff)
  951.     {
  952.       HUFF_TREE tree;
  953.       tree.element_buffer=0;
  954.       if (!make_huff_tree(&tree,huff_counts) &&
  955.   tree.bytes_packed+tree.tree_pack_length < huff_counts->bytes_packed)
  956.       {
  957. if (tree.elements == 1)
  958.   huff_counts->field_type=FIELD_CONSTANT;
  959. else
  960.   huff_counts->field_type=FIELD_INTERVALL;
  961. huff_counts->pack_type=0;
  962.       }
  963.       else
  964.       {
  965. my_free((gptr) huff_counts->tree_buff,MYF(0));
  966. delete_tree(&huff_counts->int_tree);
  967. huff_counts->tree_buff=0;
  968.       }
  969.       if (tree.element_buffer)
  970. my_free((gptr) tree.element_buffer,MYF(0));
  971.     }
  972.     if (huff_counts->pack_type & PACK_TYPE_SPACE_FIELDS)
  973.       space_fields++;
  974.     if (huff_counts->pack_type & PACK_TYPE_ZERO_FILL)
  975.       fill_zero_fields++;
  976.     field_count[huff_counts->field_type]++;
  977.   }
  978.   if (verbose)
  979.     printf("nnormal:    %3d  empty-space:     %3d  empty-zero:       %3d  empty-fill: %3dnpre-space: %3d  end-space:       %3d  intervall-fields: %3d  zero:       %3dn",
  980.    field_count[FIELD_NORMAL],space_fields,
  981.    field_count[FIELD_SKIPP_ZERO],fill_zero_fields,
  982.    field_count[FIELD_SKIPP_PRESPACE],
  983.    field_count[FIELD_SKIPP_ENDSPACE],
  984.    field_count[FIELD_INTERVALL],
  985.    field_count[FIELD_ZERO]);
  986.   DBUG_VOID_RETURN;
  987. }
  988. /* Test if we can use space-compression and empty-field-compression */
  989. static int
  990. test_space_compress(HUFF_COUNTS *huff_counts, my_off_t records,
  991.     uint max_space_length, my_off_t *space_counts,
  992.     my_off_t tot_space_count, enum en_fieldtype field_type)
  993. {
  994.   int min_pos;
  995.   uint length_bits,i;
  996.   my_off_t space_count,min_space_count,min_pack,new_length,skipp;
  997.   length_bits=max_bit(max_space_length);
  998. /* Default no end_space-packing */
  999.   space_count=huff_counts->counts[(uint) ' '];
  1000.   min_space_count= (huff_counts->counts[(uint) ' ']+= tot_space_count);
  1001.   min_pack=calc_packed_length(huff_counts,0);
  1002.   min_pos= -2;
  1003.   huff_counts->counts[(uint) ' ']=space_count;
  1004. /* Test with allways space-count */
  1005.   new_length=huff_counts->bytes_packed+length_bits*records/8;
  1006.   if (new_length+1 < min_pack)
  1007.   {
  1008.     min_pos= -1;
  1009.     min_pack=new_length;
  1010.     min_space_count=space_count;
  1011.   }
  1012. /* Test with length-flag */
  1013.   for (skipp=0L, i=0 ; i < 8 ; i++)
  1014.   {
  1015.     if (space_counts[i])
  1016.     {
  1017.       if (i)
  1018. huff_counts->counts[(uint) ' ']+=space_counts[i];
  1019.       skipp+=huff_counts->pre_space[i];
  1020.       new_length=calc_packed_length(huff_counts,0)+
  1021. (records+(records-skipp)*(1+length_bits))/8;
  1022.       if (new_length < min_pack)
  1023.       {
  1024. min_pos=(int) i;
  1025. min_pack=new_length;
  1026. min_space_count=huff_counts->counts[(uint) ' '];
  1027.       }
  1028.     }
  1029.   }
  1030.   huff_counts->counts[(uint) ' ']=min_space_count;
  1031.   huff_counts->bytes_packed=min_pack;
  1032.   switch (min_pos) {
  1033.   case -2:
  1034.     return(0); /* No space-compress */
  1035.   case -1: /* Always space-count */
  1036.     huff_counts->field_type=field_type;
  1037.     huff_counts->min_space=0;
  1038.     huff_counts->length_bits=max_bit(max_space_length);
  1039.     break;
  1040.   default:
  1041.     huff_counts->field_type=field_type;
  1042.     huff_counts->min_space=(uint) min_pos;
  1043.     huff_counts->pack_type|=PACK_TYPE_SELECTED;
  1044.     huff_counts->length_bits=max_bit(max_space_length);
  1045.     break;
  1046.   }
  1047.   return(1); /* Using space-compress */
  1048. }
  1049. /* Make a huff_tree of each huff_count */
  1050. static HUFF_TREE* make_huff_trees(HUFF_COUNTS *huff_counts, uint trees)
  1051. {
  1052.   uint tree;
  1053.   HUFF_TREE *huff_tree;
  1054.   DBUG_ENTER("make_huff_trees");
  1055.   if (!(huff_tree=(HUFF_TREE*) my_malloc(trees*sizeof(HUFF_TREE),
  1056.  MYF(MY_WME | MY_ZEROFILL))))
  1057.     DBUG_RETURN(0);
  1058.   for (tree=0 ; tree < trees ; tree++)
  1059.   {
  1060.     if (make_huff_tree(huff_tree+tree,huff_counts+tree))
  1061.     {
  1062.       while (tree--)
  1063. my_free((gptr) huff_tree[tree].element_buffer,MYF(0));
  1064.       my_free((gptr) huff_tree,MYF(0));
  1065.       DBUG_RETURN(0);
  1066.     }
  1067.   }
  1068.   DBUG_RETURN(huff_tree);
  1069. }
  1070. /* Update huff_tree according to huff_counts->counts or
  1071.    huff_counts->tree_buff */
  1072. static int make_huff_tree(HUFF_TREE *huff_tree, HUFF_COUNTS *huff_counts)
  1073. {
  1074.   uint i,found,bits_packed,first,last;
  1075.   my_off_t bytes_packed;
  1076.   HUFF_ELEMENT *a,*b,*new;
  1077.   first=last=0;
  1078.   if (huff_counts->tree_buff)
  1079.   {
  1080.     found= (uint) (huff_counts->tree_pos - huff_counts->tree_buff) /
  1081.       huff_counts->field_length;
  1082.     first=0; last=found-1;
  1083.   }
  1084.   else
  1085.   {
  1086.     for (i=found=0 ; i < 256 ; i++)
  1087.     {
  1088.       if (huff_counts->counts[i])
  1089.       {
  1090. if (! found++)
  1091.   first=i;
  1092. last=i;
  1093.       }
  1094.     }
  1095.     if (found < 2)
  1096.       found=2;
  1097.   }
  1098.   if (queue.max_elements < found)
  1099.   {
  1100.     delete_queue(&queue);
  1101.     if (init_queue(&queue,found,0,0,compare_huff_elements,0))
  1102.       return -1;
  1103.   }
  1104.   if (!huff_tree->element_buffer)
  1105.   {
  1106.     if (!(huff_tree->element_buffer=
  1107.  (HUFF_ELEMENT*) my_malloc(found*2*sizeof(HUFF_ELEMENT),MYF(MY_WME))))
  1108.       return 1;
  1109.   }
  1110.   else
  1111.   {
  1112.     HUFF_ELEMENT *temp;
  1113.     if (!(temp=
  1114.   (HUFF_ELEMENT*) my_realloc((gptr) huff_tree->element_buffer,
  1115.      found*2*sizeof(HUFF_ELEMENT),
  1116.      MYF(MY_WME))))
  1117.       return 1;
  1118.     huff_tree->element_buffer=temp;
  1119.   }
  1120.   huff_counts->tree=huff_tree;
  1121.   huff_tree->counts=huff_counts;
  1122.   huff_tree->min_chr=first;
  1123.   huff_tree->max_chr=last;
  1124.   huff_tree->char_bits=max_bit(last-first);
  1125.   huff_tree->offset_bits=max_bit(found-1)+1;
  1126.   if (huff_counts->tree_buff)
  1127.   {
  1128.     huff_tree->elements=0;
  1129.     tree_walk(&huff_counts->int_tree,
  1130.       (int (*)(void*, element_count,void*)) save_counts_in_queue,
  1131.       (gptr) huff_tree, left_root_right);
  1132.     huff_tree->tree_pack_length=(1+15+16+5+5+
  1133.  (huff_tree->char_bits+1)*found+
  1134.  (huff_tree->offset_bits+1)*
  1135.  (found-2)+7)/8 +
  1136.    (uint) (huff_tree->counts->tree_pos-
  1137.    huff_tree->counts->tree_buff);
  1138.   }
  1139.   else
  1140.   {
  1141.     huff_tree->elements=found;
  1142.     huff_tree->tree_pack_length=(9+9+5+5+
  1143.  (huff_tree->char_bits+1)*found+
  1144.  (huff_tree->offset_bits+1)*
  1145.  (found-2)+7)/8;
  1146.     for (i=first, found=0 ; i <= last ; i++)
  1147.     {
  1148.       if (huff_counts->counts[i])
  1149.       {
  1150. new=huff_tree->element_buffer+(found++);
  1151. new->count=huff_counts->counts[i];
  1152. new->a.leaf.null=0;
  1153. new->a.leaf.element_nr=i;
  1154. queue.root[found]=(byte*) new;
  1155.       }
  1156.     }
  1157.     while (found < 2)
  1158.     { /* Our huff_trees request at least 2 elements */
  1159.       new=huff_tree->element_buffer+(found++);
  1160.       new->count=0;
  1161.       new->a.leaf.null=0;
  1162.       if (last)
  1163. new->a.leaf.element_nr=huff_tree->min_chr=last-1;
  1164.       else
  1165. new->a.leaf.element_nr=huff_tree->max_chr=last+1;
  1166.       queue.root[found]=(byte*) new;
  1167.     }
  1168.   }
  1169.   queue.elements=found;
  1170.   for (i=found/2 ; i > 0 ; i--)
  1171.     _downheap(&queue,i);
  1172.   bytes_packed=0; bits_packed=0;
  1173.   for (i=1 ; i < found ; i++)
  1174.   {
  1175.     a=(HUFF_ELEMENT*) queue_remove(&queue,0);
  1176.     b=(HUFF_ELEMENT*) queue.root[1];
  1177.     new=huff_tree->element_buffer+found+i;
  1178.     new->count=a->count+b->count;
  1179.     bits_packed+=(uint) (new->count & 7);
  1180.     bytes_packed+=new->count/8;
  1181.     new->a.nod.left=a; /* lesser in left  */
  1182.     new->a.nod.right=b;
  1183.     queue.root[1]=(byte*) new;
  1184.     queue_replaced(&queue);
  1185.   }
  1186.   huff_tree->root=(HUFF_ELEMENT*) queue.root[1];
  1187.   huff_tree->bytes_packed=bytes_packed+(bits_packed+7)/8;
  1188.   return 0;
  1189. }
  1190. static int compare_tree(register const uchar *s, register const uchar *t)
  1191. {
  1192.   uint length;
  1193.   for (length=global_count->field_length; length-- ;)
  1194.     if (*s++ != *t++)
  1195.       return (int) s[-1] - (int) t[-1];
  1196.   return 0;
  1197. }
  1198. /* Used by make_huff_tree to save intervall-counts in queue */
  1199. static int save_counts_in_queue(byte *key, element_count count,
  1200. HUFF_TREE *tree)
  1201. {
  1202.   HUFF_ELEMENT *new;
  1203.   new=tree->element_buffer+(tree->elements++);
  1204.   new->count=count;
  1205.   new->a.leaf.null=0;
  1206.   new->a.leaf.element_nr= (uint) (key- tree->counts->tree_buff) /
  1207.     tree->counts->field_length;
  1208.   queue.root[tree->elements]=(byte*) new;
  1209.   return 0;
  1210. }
  1211. /* Calculate length of file if given counts should be used */
  1212. /* Its actually a faster version of make_huff_tree */
  1213. static my_off_t calc_packed_length(HUFF_COUNTS *huff_counts,
  1214.    uint add_tree_lenght)
  1215. {
  1216.   uint i,found,bits_packed,first,last;
  1217.   my_off_t bytes_packed;
  1218.   HUFF_ELEMENT element_buffer[256];
  1219.   DBUG_ENTER("calc_packed_length");
  1220.   first=last=0;
  1221.   for (i=found=0 ; i < 256 ; i++)
  1222.   {
  1223.     if (huff_counts->counts[i])
  1224.     {
  1225.       if (! found++)
  1226. first=i;
  1227.       last=i;
  1228.       queue.root[found]=(byte*) &huff_counts->counts[i];
  1229.     }
  1230.   }
  1231.   if (!found)
  1232.     DBUG_RETURN(0); /* Empty tree */
  1233.   if (found < 2)
  1234.     queue.root[++found]=(byte*) &huff_counts->counts[last ? 0 : 1];
  1235.   queue.elements=found;
  1236.   bytes_packed=0; bits_packed=0;
  1237.   if (add_tree_lenght)
  1238.     bytes_packed=(8+9+5+5+(max_bit(last-first)+1)*found+
  1239.   (max_bit(found-1)+1+1)*(found-2) +7)/8;
  1240.   for (i=(found+1)/2 ; i > 0 ; i--)
  1241.     _downheap(&queue,i);
  1242.   for (i=0 ; i < found-1 ; i++)
  1243.   {
  1244.     HUFF_ELEMENT *a,*b,*new;
  1245.     a=(HUFF_ELEMENT*) queue_remove(&queue,0);
  1246.     b=(HUFF_ELEMENT*) queue.root[1];
  1247.     new=element_buffer+i;
  1248.     new->count=a->count+b->count;
  1249.     bits_packed+=(uint) (new->count & 7);
  1250.     bytes_packed+=new->count/8;
  1251.     queue.root[1]=(byte*) new;
  1252.     queue_replaced(&queue);
  1253.   }
  1254.   DBUG_RETURN(bytes_packed+(bits_packed+7)/8);
  1255. }
  1256. /* Remove trees that don't give any compression */
  1257. static uint join_same_trees(HUFF_COUNTS *huff_counts, uint trees)
  1258. {
  1259.   uint k,tree_number;
  1260.   HUFF_COUNTS count,*i,*j,*last_count;
  1261.   last_count=huff_counts+trees;
  1262.   for (tree_number=0, i=huff_counts ; i < last_count ; i++)
  1263.   {
  1264.     if (!i->tree->tree_number)
  1265.     {
  1266.       i->tree->tree_number= ++tree_number;
  1267.       if (i->tree_buff)
  1268. continue; /* Don't join intervall */
  1269.       for (j=i+1 ; j < last_count ; j++)
  1270.       {
  1271. if (! j->tree->tree_number && ! j->tree_buff)
  1272. {
  1273.   for (k=0 ; k < 256 ; k++)
  1274.     count.counts[k]=i->counts[k]+j->counts[k];
  1275.   if (calc_packed_length(&count,1) <=
  1276.       i->tree->bytes_packed + j->tree->bytes_packed+
  1277.       i->tree->tree_pack_length+j->tree->tree_pack_length+
  1278.       ALLOWED_JOIN_DIFF)
  1279.   {
  1280.     memcpy_fixed((byte*) i->counts,(byte*) count.counts,
  1281.  sizeof(count.counts[0])*256);
  1282.     my_free((gptr) j->tree->element_buffer,MYF(0));
  1283.     j->tree->element_buffer=0;
  1284.     j->tree=i->tree;
  1285.     bmove((byte*) i->counts,(byte*) count.counts,
  1286.   sizeof(count.counts[0])*256);
  1287.     if (make_huff_tree(i->tree,i))
  1288.       return (uint) -1;
  1289.   }
  1290. }
  1291.       }
  1292.     }
  1293.   }
  1294.   if (verbose)
  1295.     printf("Original trees:  %d  After join: %dn",trees,tree_number);
  1296.   return tree_number; /* Return trees left */
  1297. }
  1298. /* Fill in huff_tree decode tables */
  1299. static int make_huff_decode_table(HUFF_TREE *huff_tree, uint trees)
  1300. {
  1301.   uint elements;
  1302.   for ( ; trees-- ; huff_tree++)
  1303.   {
  1304.     if (huff_tree->tree_number > 0)
  1305.     {
  1306.       elements=huff_tree->counts->tree_buff ? huff_tree->elements : 256;
  1307.       if (!(huff_tree->code =
  1308.     (ulong*) my_malloc(elements*
  1309.        (sizeof(ulong)+sizeof(uchar)),
  1310.        MYF(MY_WME | MY_ZEROFILL))))
  1311. return 1;
  1312.       huff_tree->code_len=(uchar*) (huff_tree->code+elements);
  1313.       make_traverse_code_tree(huff_tree,huff_tree->root,32,0);
  1314.     }
  1315.   }
  1316.   return 0;
  1317. }
  1318. static void make_traverse_code_tree(HUFF_TREE *huff_tree,
  1319.     HUFF_ELEMENT *element,
  1320.     uint size, ulong code)
  1321. {
  1322.   uint chr;
  1323.   if (!element->a.leaf.null)
  1324.   {
  1325.     chr=element->a.leaf.element_nr;
  1326.     huff_tree->code_len[chr]=(uchar) (32-size);
  1327.     huff_tree->code[chr]=    (code >> size);
  1328.     if (huff_tree->height < 32-size)
  1329.       huff_tree->height= 32-size;
  1330.   }
  1331.   else
  1332.   {
  1333.     size--;
  1334.     make_traverse_code_tree(huff_tree,element->a.nod.left,size,code);
  1335.     make_traverse_code_tree(huff_tree,element->a.nod.right,size,
  1336.     code+((ulong) 1L << size));
  1337.   }
  1338.   return;
  1339. }
  1340. /* Write header to new packed data file */
  1341. static int write_header(MRG_INFO *mrg,uint head_length,uint trees,
  1342. my_off_t tot_elements,my_off_t filelength)
  1343. {
  1344.   byte *buff=file_buffer.pos;
  1345.   bzero(buff,HEAD_LENGTH);
  1346.   memcpy_fixed(buff,myisam_pack_file_magic,4);
  1347.   int4store(buff+4,head_length);
  1348.   int4store(buff+8, mrg->min_pack_length);
  1349.   int4store(buff+12,mrg->max_pack_length);
  1350.   int4store(buff+16,tot_elements);
  1351.   int4store(buff+20,intervall_length);
  1352.   int2store(buff+24,trees);
  1353.   buff[26]=(char) mrg->ref_length;
  1354. /* Save record pointer length */
  1355.   buff[27]= (uchar) mi_get_pointer_length((ulonglong) filelength,2);
  1356.   if (test_only)
  1357.     return 0;
  1358.   VOID(my_seek(file_buffer.file,0L,MY_SEEK_SET,MYF(0)));
  1359.   return my_write(file_buffer.file,file_buffer.pos,HEAD_LENGTH,
  1360.   MYF(MY_WME | MY_NABP | MY_WAIT_IF_FULL)) != 0;
  1361. }
  1362. /* Write fieldinfo to new packed file */
  1363. static void write_field_info(HUFF_COUNTS *counts, uint fields, uint trees)
  1364. {
  1365.   reg1 uint i;
  1366.   uint huff_tree_bits;
  1367.   huff_tree_bits=max_bit(trees ? trees-1 : 0);
  1368.   for (i=0 ; i++ < fields ; counts++)
  1369.   {
  1370.     write_bits((ulong) (int) counts->field_type,5);
  1371.     write_bits(counts->pack_type,6);
  1372.     if (counts->pack_type & PACK_TYPE_ZERO_FILL)
  1373.       write_bits(counts->max_zero_fill,5);
  1374.     else
  1375.       write_bits(counts->length_bits,5);
  1376.     write_bits((ulong) counts->tree->tree_number-1,huff_tree_bits);
  1377.   }
  1378.   flush_bits();
  1379.   return;
  1380. }
  1381. /* Write all huff_trees to new datafile. Return tot count of
  1382.    elements in all trees
  1383.    Returns 0 on error */
  1384. static my_off_t write_huff_tree(HUFF_TREE *huff_tree, uint trees)
  1385. {
  1386.   uint i,int_length;
  1387.   uint *packed_tree,*offset,length;
  1388.   my_off_t elements;
  1389.   for (i=length=0 ; i < trees ; i++)
  1390.     if (huff_tree[i].tree_number > 0 && huff_tree[i].elements > length)
  1391.       length=huff_tree[i].elements;
  1392.   if (!(packed_tree=(uint*) my_alloca(sizeof(uint)*length*2)))
  1393.   {
  1394.     my_error(EE_OUTOFMEMORY,MYF(ME_BELL),sizeof(uint)*length*2);
  1395.     return 0;
  1396.   }
  1397.   intervall_length=0;
  1398.   for (elements=0; trees-- ; huff_tree++)
  1399.   {
  1400.     if (huff_tree->tree_number == 0)
  1401.       continue; /* Deleted tree */
  1402.     elements+=huff_tree->elements;
  1403.     huff_tree->max_offset=2;
  1404.     if (huff_tree->elements <= 1)
  1405.       offset=packed_tree;
  1406.     else
  1407.       offset=make_offset_code_tree(huff_tree,huff_tree->root,packed_tree);
  1408.     huff_tree->offset_bits=max_bit(huff_tree->max_offset);
  1409.     if (huff_tree->max_offset >= IS_OFFSET)
  1410.     { /* This should be impossible */
  1411.       VOID(fprintf(stderr,"Tree offset got too big: %d, abortedn",
  1412.       huff_tree->max_offset));
  1413.       my_afree((gptr) packed_tree);
  1414.       return 0;
  1415.     }
  1416. #ifdef EXTRA_DBUG
  1417.     printf("pos: %d  elements: %d  tree-elements: %d  char_bits: %dn",
  1418.    (uint) (file_buffer.pos-file_buffer.buffer),
  1419.    huff_tree->elements,  (offset-packed_tree),huff_tree->char_bits);
  1420. #endif
  1421.     if (!huff_tree->counts->tree_buff)
  1422.     {
  1423.       write_bits(0,1);
  1424.       write_bits(huff_tree->min_chr,8);
  1425.       write_bits(huff_tree->elements,9);
  1426.       write_bits(huff_tree->char_bits,5);
  1427.       write_bits(huff_tree->offset_bits,5);
  1428.       int_length=0;
  1429.     }
  1430.     else
  1431.     {
  1432.       int_length=(uint) (huff_tree->counts->tree_pos -
  1433.  huff_tree->counts->tree_buff);
  1434.       write_bits(1,1);
  1435.       write_bits(huff_tree->elements,15);
  1436.       write_bits(int_length,16);
  1437.       write_bits(huff_tree->char_bits,5);
  1438.       write_bits(huff_tree->offset_bits,5);
  1439.       intervall_length+=int_length;
  1440.     }
  1441.     length=(uint) (offset-packed_tree);
  1442.     if (length != huff_tree->elements*2-2)
  1443.       printf("error: Huff-tree-length: %d != calc_length: %dn",
  1444.      length,huff_tree->elements*2-2);
  1445.     for (i=0 ; i < length ; i++)
  1446.     {
  1447.       if (packed_tree[i] & IS_OFFSET)
  1448. write_bits(packed_tree[i] - IS_OFFSET+ (1 << huff_tree->offset_bits),
  1449.    huff_tree->offset_bits+1);
  1450.       else
  1451. write_bits(packed_tree[i]-huff_tree->min_chr,huff_tree->char_bits+1);
  1452.     }
  1453.     flush_bits();
  1454.     if (huff_tree->counts->tree_buff)
  1455.     {
  1456.       for (i=0 ; i < int_length ; i++)
  1457. write_bits((uint) (uchar) huff_tree->counts->tree_buff[i],8);
  1458.     }
  1459.     flush_bits();
  1460.   }
  1461.   my_afree((gptr) packed_tree);
  1462.   return elements;
  1463. }
  1464. static uint *make_offset_code_tree(HUFF_TREE *huff_tree, HUFF_ELEMENT *element,
  1465.    uint *offset)
  1466. {
  1467.   uint *prev_offset;
  1468.   prev_offset= offset;
  1469.   if (!element->a.nod.left->a.leaf.null)
  1470.   {
  1471.     offset[0] =(uint) element->a.nod.left->a.leaf.element_nr;
  1472.     offset+=2;
  1473.   }
  1474.   else
  1475.   {
  1476.     prev_offset[0]= IS_OFFSET+2;
  1477.     offset=make_offset_code_tree(huff_tree,element->a.nod.left,offset+2);
  1478.   }
  1479.   if (!element->a.nod.right->a.leaf.null)
  1480.   {
  1481.     prev_offset[1]=element->a.nod.right->a.leaf.element_nr;
  1482.     return offset;
  1483.   }
  1484.   else
  1485.   {
  1486.     uint temp=(uint) (offset-prev_offset-1);
  1487.     prev_offset[1]= IS_OFFSET+ temp;
  1488.     if (huff_tree->max_offset < temp)
  1489.       huff_tree->max_offset = temp;
  1490.     return make_offset_code_tree(huff_tree,element->a.nod.right,offset);
  1491.   }
  1492. }
  1493. /* Get number of bits neaded to represent value */
  1494. static uint max_bit(register uint value)
  1495. {
  1496.   reg2 uint power=1;
  1497.   while ((value>>=1))
  1498.     power++;
  1499.   return (power);
  1500. }
  1501. static int compress_isam_file(MRG_INFO *mrg, HUFF_COUNTS *huff_counts)
  1502. {
  1503.   int error;
  1504.   uint i,max_calc_length,pack_ref_length,min_record_length,max_record_length,
  1505.     intervall,field_length,max_pack_length,pack_blob_length;
  1506.   my_off_t record_count;
  1507.   ulong length,pack_length;
  1508.   byte *record,*pos,*end_pos,*record_pos,*start_pos;
  1509.   HUFF_COUNTS *count,*end_count;
  1510.   HUFF_TREE *tree;
  1511.   MI_INFO *isam_file=mrg->file[0];
  1512.   DBUG_ENTER("compress_isam_file");
  1513.   if (!(record=(byte*) my_alloca(isam_file->s->base.reclength)))
  1514.     return -1;
  1515.   end_count=huff_counts+isam_file->s->base.fields;
  1516.   min_record_length= (uint) ~0;
  1517.   max_record_length=0;
  1518.   for (i=max_calc_length=0 ; i < isam_file->s->base.fields ; i++)
  1519.   {
  1520.     if (!(huff_counts[i].pack_type & PACK_TYPE_ZERO_FILL))
  1521.       huff_counts[i].max_zero_fill=0;
  1522.     if (huff_counts[i].field_type == FIELD_CONSTANT ||
  1523. huff_counts[i].field_type == FIELD_ZERO ||
  1524. huff_counts[i].field_type == FIELD_CHECK)
  1525.       continue;
  1526.     if (huff_counts[i].field_type == FIELD_INTERVALL)
  1527.       max_calc_length+=huff_counts[i].tree->height;
  1528.     else if (huff_counts[i].field_type == FIELD_BLOB ||
  1529.      huff_counts[i].field_type == FIELD_VARCHAR)
  1530.       max_calc_length=huff_counts[i].tree->height*huff_counts[i].max_length + huff_counts[i].length_bits +1;
  1531.     else
  1532.       max_calc_length+=
  1533. (huff_counts[i].field_length - huff_counts[i].max_zero_fill)*
  1534.   huff_counts[i].tree->height+huff_counts[i].length_bits;
  1535.   }
  1536.   max_calc_length/=8;
  1537.   if (max_calc_length < 254)
  1538.     pack_ref_length=1;
  1539.   else if (max_calc_length <= 65535)
  1540.     pack_ref_length=3;
  1541.   else
  1542.     pack_ref_length=4;
  1543.   record_count=0;
  1544.   pack_blob_length=0;
  1545.   if (isam_file->s->base.blobs)
  1546.   {
  1547.     if (mrg->max_blob_length < 254)
  1548.       pack_blob_length=1;
  1549.     else if (mrg->max_blob_length <= 65535)
  1550.       pack_blob_length=3;
  1551.     else
  1552.       pack_blob_length=4;
  1553.   }
  1554.   max_pack_length=pack_ref_length+pack_blob_length;
  1555.   mrg_reset(mrg);
  1556.   while ((error=mrg_rrnd(mrg,record)) != HA_ERR_END_OF_FILE)
  1557.   {
  1558.     ulong tot_blob_length=0;
  1559.     if (! error)
  1560.     {
  1561.       if (flush_buffer(max_calc_length+max_pack_length))
  1562. break;
  1563.       record_pos=file_buffer.pos;
  1564.       file_buffer.pos+=max_pack_length;
  1565.       for (start_pos=record, count= huff_counts; count < end_count ; count++)
  1566.       {
  1567. end_pos=start_pos+(field_length=count->field_length);
  1568. tree=count->tree;
  1569. if (count->pack_type & PACK_TYPE_SPACE_FIELDS)
  1570. {
  1571.   for (pos=start_pos ; *pos == ' ' && pos < end_pos; pos++) ;
  1572.   if (pos == end_pos)
  1573.   {
  1574.     write_bits(1,1);
  1575.     start_pos=end_pos;
  1576.     continue;
  1577.   }
  1578.   write_bits(0,1);
  1579. }
  1580. end_pos-=count->max_zero_fill;
  1581. field_length-=count->max_zero_fill;
  1582. switch(count->field_type) {
  1583. case FIELD_SKIPP_ZERO:
  1584.   if (!memcmp((byte*) start_pos,zero_string,field_length))
  1585.   {
  1586.     write_bits(1,1);
  1587.     start_pos=end_pos;
  1588.     break;
  1589.   }
  1590.   write_bits(0,1);
  1591.   /* Fall through */
  1592. case FIELD_NORMAL:
  1593.   for ( ; start_pos < end_pos ; start_pos++)
  1594.     write_bits(tree->code[(uchar) *start_pos],
  1595.        (uint) tree->code_len[(uchar) *start_pos]);
  1596.   break;
  1597. case FIELD_SKIPP_ENDSPACE:
  1598.   for (pos=end_pos ; pos > start_pos && pos[-1] == ' ' ; pos--) ;
  1599.   length=(uint) (end_pos-pos);
  1600.   if (count->pack_type & PACK_TYPE_SELECTED)
  1601.   {
  1602.     if (length > count->min_space)
  1603.     {
  1604.       write_bits(1,1);
  1605.       write_bits(length,count->length_bits);
  1606.     }
  1607.     else
  1608.     {
  1609.       write_bits(0,1);
  1610.       pos=end_pos;
  1611.     }
  1612.   }
  1613.   else
  1614.     write_bits(length,count->length_bits);
  1615.   for ( ; start_pos < pos ; start_pos++)
  1616.     write_bits(tree->code[(uchar) *start_pos],
  1617.        (uint) tree->code_len[(uchar) *start_pos]);
  1618.   start_pos=end_pos;
  1619.   break;
  1620. case FIELD_SKIPP_PRESPACE:
  1621.   for (pos=start_pos ; pos < end_pos && pos[0] == ' ' ; pos++) ;
  1622.   length=(uint) (pos-start_pos);
  1623.   if (count->pack_type & PACK_TYPE_SELECTED)
  1624.   {
  1625.     if (length > count->min_space)
  1626.     {
  1627.       write_bits(1,1);
  1628.       write_bits(length,count->length_bits);
  1629.     }
  1630.     else
  1631.     {
  1632.       pos=start_pos;
  1633.       write_bits(0,1);
  1634.     }
  1635.   }
  1636.   else
  1637.     write_bits(length,count->length_bits);
  1638.   for (start_pos=pos ; start_pos < end_pos ; start_pos++)
  1639.     write_bits(tree->code[(uchar) *start_pos],
  1640.        (uint) tree->code_len[(uchar) *start_pos]);
  1641.   break;
  1642. case FIELD_CONSTANT:
  1643. case FIELD_ZERO:
  1644. case FIELD_CHECK:
  1645.   start_pos=end_pos;
  1646.   break;
  1647. case FIELD_INTERVALL:
  1648.   global_count=count;
  1649.   pos=(byte*) tree_search(&count->int_tree,start_pos);
  1650.   intervall=(uint) (pos - count->tree_buff)/field_length;
  1651.   write_bits(tree->code[intervall],(uint) tree->code_len[intervall]);
  1652.   start_pos=end_pos;
  1653.   break;
  1654. case FIELD_BLOB:
  1655. {
  1656.   ulong blob_length=_mi_calc_blob_length(field_length-
  1657.  mi_portable_sizeof_char_ptr,
  1658.  start_pos);
  1659.   if (!blob_length)
  1660.   {
  1661.     write_bits(1,1); /* Empty blob */
  1662.   }
  1663.   else
  1664.   {
  1665.     byte *blob,*blob_end;
  1666.     write_bits(0,1);
  1667.     write_bits(blob_length,count->length_bits);
  1668.     memcpy_fixed(&blob,end_pos-mi_portable_sizeof_char_ptr,
  1669.  sizeof(char*));
  1670.     blob_end=blob+blob_length;
  1671.     for ( ; blob < blob_end ; blob++)
  1672.       write_bits(tree->code[(uchar) *blob],
  1673.  (uint) tree->code_len[(uchar) *blob]);
  1674.     tot_blob_length+=blob_length;
  1675.   }
  1676.   start_pos= end_pos;
  1677.   break;
  1678. }
  1679. case FIELD_VARCHAR:
  1680. {
  1681.   ulong col_length= uint2korr(start_pos);
  1682.   if (!col_length)
  1683.   {
  1684.     write_bits(1,1); /* Empty varchar */
  1685.   }
  1686.   else
  1687.   {
  1688.     byte *end=start_pos+2+col_length;
  1689.     write_bits(0,1);
  1690.     write_bits(col_length,count->length_bits);
  1691.     for (start_pos+=2 ; start_pos < end ; start_pos++)
  1692.       write_bits(tree->code[(uchar) *start_pos],
  1693.  (uint) tree->code_len[(uchar) *start_pos]);
  1694.   }
  1695.   start_pos= end_pos;
  1696.   break;
  1697. }
  1698. case FIELD_LAST:
  1699.   abort(); /* Impossible */
  1700. }
  1701. start_pos+=count->max_zero_fill;
  1702.       }
  1703.       flush_bits();
  1704.       length=(ulong) (file_buffer.pos-record_pos)-max_pack_length;
  1705.       pack_length=save_pack_length(record_pos,length);
  1706.       if (pack_blob_length)
  1707. pack_length+=save_pack_length(record_pos+pack_length,tot_blob_length);
  1708.       /* Correct file buffer if the header was smaller */
  1709.       if (pack_length != max_pack_length)
  1710.       {
  1711. bmove(record_pos+pack_length,record_pos+max_pack_length,length);
  1712. file_buffer.pos-= (max_pack_length-pack_length);
  1713.       }
  1714.       if (length < (ulong) min_record_length)
  1715. min_record_length=(uint) length;
  1716.       if (length > (ulong) max_record_length)
  1717. max_record_length=(uint) length;
  1718.       if (write_loop && ++record_count % WRITE_COUNT == 0)
  1719.       {
  1720. printf("%lur",(ulong) record_count); VOID(fflush(stdout));
  1721.       }
  1722.     }
  1723.     else if (error != HA_ERR_RECORD_DELETED)
  1724.       break;
  1725.   }
  1726.   if (error == HA_ERR_END_OF_FILE)
  1727.     error=0;
  1728.   else
  1729.   {
  1730.     fprintf(stderr,"%s: Got error %d reading recordsn",my_progname,error);
  1731.   }
  1732.   my_afree((gptr) record);
  1733.   mrg->ref_length=max_pack_length;
  1734.   mrg->min_pack_length=max_record_length ? min_record_length : 0;
  1735.   mrg->max_pack_length=max_record_length;
  1736.   DBUG_RETURN(error || error_on_write || flush_buffer(~(ulong) 0));
  1737. }
  1738. static char *make_new_name(char *new_name, char *old_name)
  1739. {
  1740.   return fn_format(new_name,old_name,"",DATA_TMP_EXT,2+4);
  1741. }
  1742. static char *make_old_name(char *new_name, char *old_name)
  1743. {
  1744.   return fn_format(new_name,old_name,"",OLD_EXT,2+4);
  1745. }
  1746. /* rutines for bit writing buffer */
  1747. static void init_file_buffer(File file, pbool read_buffer)
  1748. {
  1749.   file_buffer.file=file;
  1750.   file_buffer.buffer=my_malloc(ALIGN_SIZE(RECORD_CACHE_SIZE),MYF(MY_WME));
  1751.   file_buffer.end=file_buffer.buffer+ALIGN_SIZE(RECORD_CACHE_SIZE)-8;
  1752.   file_buffer.pos_in_file=0;
  1753.   error_on_write=0;
  1754.   if (read_buffer)
  1755.   {
  1756.     file_buffer.pos=file_buffer.end;
  1757.     file_buffer.bits=0;
  1758.   }
  1759.   else
  1760.   {
  1761.     file_buffer.pos=file_buffer.buffer;
  1762.     file_buffer.bits=BITS_SAVED;
  1763.   }
  1764.   file_buffer.byte=0;
  1765. }
  1766. static int flush_buffer(ulong neaded_length)
  1767. {
  1768.   ulong length;
  1769.   if ((ulong) (file_buffer.end - file_buffer.pos) > neaded_length)
  1770.     return 0;
  1771.   length=(ulong) (file_buffer.pos-file_buffer.buffer);
  1772.   file_buffer.pos=file_buffer.buffer;
  1773.   file_buffer.pos_in_file+=length;
  1774.   if (test_only)
  1775.     return 0;
  1776.   if (error_on_write|| my_write(file_buffer.file,file_buffer.buffer,
  1777. length,
  1778. MYF(MY_WME | MY_NABP | MY_WAIT_IF_FULL)))
  1779.   {
  1780.     error_on_write=1;
  1781.     return 1;
  1782.   }
  1783.   if (neaded_length != ~(ulong) 0 &&
  1784.       (ulong) (file_buffer.end-file_buffer.buffer) < neaded_length)
  1785.   {
  1786.     char *tmp;
  1787.     neaded_length+=256; /* some margin */
  1788.     tmp=my_realloc(file_buffer.buffer, neaded_length,MYF(MY_WME));
  1789.     if (!tmp)
  1790.       return 1;
  1791.     file_buffer.pos= tmp + (ulong) (file_buffer.pos - file_buffer.buffer);
  1792.     file_buffer.buffer=tmp;
  1793.     file_buffer.end=tmp+neaded_length-8;
  1794.   }
  1795.   return 0;
  1796. }
  1797. static void end_file_buffer(void)
  1798. {
  1799.   my_free((gptr) file_buffer.buffer,MYF(0));
  1800. }
  1801. /* output `bits` low bits of `value' */
  1802. static void write_bits (register ulong value, register uint bits)
  1803. {
  1804.   if ((file_buffer.bits-=(int) bits) >= 0)
  1805.   {
  1806.     file_buffer.byte|=value << file_buffer.bits;
  1807.   }
  1808.   else
  1809.   {
  1810.     reg3 uint byte_buff;
  1811.     bits= (uint) -file_buffer.bits;
  1812.     byte_buff=file_buffer.byte | (uint) (value >> bits);
  1813. #if BITS_SAVED == 32
  1814.     *file_buffer.pos++= (byte) (byte_buff >> 24) ;
  1815.     *file_buffer.pos++= (byte) (byte_buff >> 16) ;
  1816. #endif
  1817.     *file_buffer.pos++= (byte) (byte_buff >> 8) ;
  1818.     *file_buffer.pos++= (byte) byte_buff;
  1819.     value&=(1 << bits)-1;
  1820. #if BITS_SAVED == 16
  1821.     if (bits >= sizeof(uint))
  1822.     {
  1823.       bits-=8;
  1824.       *file_buffer.pos++= (uchar) (value >> bits);
  1825.       value&= (1 << bits)-1;
  1826.       if (bits >= sizeof(uint))
  1827.       {
  1828. bits-=8;
  1829. *file_buffer.pos++= (uchar) (value >> bits);
  1830. value&= (1 << bits)-1;
  1831.       }
  1832.     }
  1833. #endif
  1834.     if (file_buffer.pos >= file_buffer.end)
  1835.       VOID(flush_buffer((uint) ~0));
  1836.     file_buffer.bits=(int) (BITS_SAVED - bits);
  1837.     file_buffer.byte=(uint) (value << (BITS_SAVED - bits));
  1838.   }
  1839.   return;
  1840. }
  1841. /* Flush bits in bit_buffer to buffer */
  1842. static void flush_bits (void)
  1843. {
  1844.   uint bits,byte_buff;
  1845.   bits=(file_buffer.bits) & ~7;
  1846.   byte_buff = file_buffer.byte >> bits;
  1847.   bits=BITS_SAVED - bits;
  1848.   while (bits > 0)
  1849.   {
  1850.     bits-=8;
  1851.     *file_buffer.pos++= (byte) (uchar) (byte_buff >> bits) ;
  1852.   }
  1853.   file_buffer.bits=BITS_SAVED;
  1854.   file_buffer.byte=0;
  1855.   return;
  1856. }
  1857. /****************************************************************************
  1858. ** functions to handle the joined files
  1859. ****************************************************************************/
  1860. static int save_state(MI_INFO *isam_file,MRG_INFO *mrg,my_off_t new_length,
  1861.       ha_checksum crc)
  1862. {
  1863.   MYISAM_SHARE *share=isam_file->s;
  1864.   uint options=mi_uint2korr(share->state.header.options);
  1865.   uint key;
  1866.   DBUG_ENTER("save_state");
  1867.   options|= HA_OPTION_COMPRESS_RECORD | HA_OPTION_READ_ONLY_DATA;
  1868.   mi_int2store(share->state.header.options,options);
  1869.   share->state.state.data_file_length=new_length;
  1870.   share->state.state.del=0;
  1871.   share->state.state.empty=0;
  1872.   share->state.dellink= HA_OFFSET_ERROR;
  1873.   share->state.split=(ha_rows) mrg->records;
  1874.   share->state.version=(ulong) time((time_t*) 0);
  1875.   share->state.key_map=0;
  1876.   share->state.state.key_file_length=share->base.keystart;
  1877.   for (key=0 ; key < share->base.keys ; key++)
  1878.     share->state.key_root[key]= HA_OFFSET_ERROR;
  1879.   for (key=0 ; key < share->state.header.max_block_size ; key++)
  1880.     share->state.key_del[key]= HA_OFFSET_ERROR;
  1881.   share->state.checksum=crc; /* Save crc here */
  1882.   share->changed=1; /* Force write of header */
  1883.   share->state.open_count=0;
  1884.   share->global_changed=0;
  1885.   VOID(my_chsize(share->kfile,share->state.state.key_file_length,
  1886.  MYF(0)));
  1887.   if (share->base.keys)
  1888.     isamchk_neaded=1;
  1889.   DBUG_RETURN(mi_state_info_write(share->kfile,&share->state,1+2));
  1890. }
  1891. static int save_state_mrg(File file,MRG_INFO *mrg,my_off_t new_length,
  1892.   ha_checksum crc)
  1893. {
  1894.   MI_STATE_INFO state;
  1895.   MI_INFO *isam_file=mrg->file[0];
  1896.   uint options;
  1897.   DBUG_ENTER("save_state_mrg");
  1898.   state= isam_file->s->state;
  1899.   options= (mi_uint2korr(state.header.options) | HA_OPTION_COMPRESS_RECORD |
  1900.     HA_OPTION_READ_ONLY_DATA);
  1901.   mi_int2store(state.header.options,options);
  1902.   state.state.data_file_length=new_length;
  1903.   state.state.del=0;
  1904.   state.state.empty=0;
  1905.   state.state.records=state.split=(ha_rows) mrg->records;
  1906.   state.state.key_file_length=isam_file->s->base.keystart;
  1907.   state.dellink= HA_OFFSET_ERROR;
  1908.   state.version=(ulong) time((time_t*) 0);
  1909.   state.key_map=0;
  1910.   state.checksum=crc;
  1911.   if (isam_file->s->base.keys)
  1912.     isamchk_neaded=1;
  1913.   state.changed=STATE_CHANGED | STATE_NOT_ANALYZED; /* Force check of table */
  1914.   DBUG_RETURN (mi_state_info_write(file,&state,1+2));
  1915. }
  1916. /* reset for mrg_rrnd */
  1917. static void mrg_reset(MRG_INFO *mrg)
  1918. {
  1919.   if (mrg->current)
  1920.   {
  1921.     mi_extra(*mrg->current,HA_EXTRA_NO_CACHE);
  1922.     mrg->current=0;
  1923.   }
  1924. }
  1925. static int mrg_rrnd(MRG_INFO *info,byte *buf)
  1926. {
  1927.   int error;
  1928.   MI_INFO *isam_info;
  1929.   my_off_t filepos;
  1930.   if (!info->current)
  1931.   {
  1932.     isam_info= *(info->current=info->file);
  1933.     info->end=info->current+info->count;
  1934.     mi_extra(isam_info,HA_EXTRA_RESET);
  1935.     mi_extra(isam_info,HA_EXTRA_CACHE);
  1936.     filepos=isam_info->s->pack.header_length;
  1937.   }
  1938.   else
  1939.   {
  1940.     isam_info= *info->current;
  1941.     filepos= isam_info->nextpos;
  1942.   }
  1943.   for (;;)
  1944.   {
  1945.     isam_info->update&= HA_STATE_CHANGED;
  1946.     if (!(error=(*isam_info->s->read_rnd)(isam_info,(byte*) buf,
  1947.   filepos, 1)) ||
  1948. error != HA_ERR_END_OF_FILE)
  1949.       return (error);
  1950.     mi_extra(isam_info,HA_EXTRA_NO_CACHE);
  1951.     if (info->current+1 == info->end)
  1952.       return(HA_ERR_END_OF_FILE);
  1953.     info->current++;
  1954.     isam_info= *info->current;
  1955.     filepos=isam_info->s->pack.header_length;
  1956.     mi_extra(isam_info,HA_EXTRA_RESET);
  1957.     mi_extra(isam_info,HA_EXTRA_CACHE);
  1958.   }
  1959. }
  1960. static int mrg_close(MRG_INFO *mrg)
  1961. {
  1962.   uint i;
  1963.   int error=0;
  1964.   for (i=0 ; i < mrg->count ; i++)
  1965.     error|=mi_close(mrg->file[i]);
  1966.   if (mrg->free_file)
  1967.     my_free((gptr) mrg->file,MYF(0));
  1968.   return error;
  1969. }