mi_write.c 33.1 KB
Newer Older
1
/*
2
   Copyright (c) 2000, 2011, Oracle and/or its affiliates
unknown's avatar
unknown committed
3

unknown's avatar
unknown committed
4 5
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
unknown's avatar
unknown committed
6
   the Free Software Foundation; version 2 of the License.
unknown's avatar
unknown committed
7

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

unknown's avatar
unknown committed
13 14
   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
15
   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA */
unknown's avatar
unknown committed
16 17 18 19

/* Write a row to a MyISAM table */

#include "fulltext.h"
20 21
#include "rt_index.h"

unknown's avatar
unknown committed
22 23 24 25
#define MAX_POINTER_LENGTH 8

	/* Functions declared in this file */

26 27
static int w_search(MI_INFO *info,MI_KEYDEF *keyinfo,
		    uint comp_flag, uchar *key,
unknown's avatar
unknown committed
28 29 30 31 32 33 34 35 36
		    uint key_length, my_off_t pos, uchar *father_buff,
		    uchar *father_keypos, my_off_t father_page,
		    my_bool insert_last);
static int _mi_balance_page(MI_INFO *info,MI_KEYDEF *keyinfo,uchar *key,
			    uchar *curr_buff,uchar *father_buff,
			    uchar *father_keypos,my_off_t father_page);
static uchar *_mi_find_last_pos(MI_KEYDEF *keyinfo, uchar *page,
				uchar *key, uint *return_key_length,
				uchar **after_key);
37
int _mi_ck_write_tree(register MI_INFO *info, uint keynr,uchar *key,
38
		      uint key_length);
39
int _mi_ck_write_btree(register MI_INFO *info, uint keynr,uchar *key,
40
		       uint key_length);
unknown's avatar
unknown committed
41 42 43

	/* Write new record to database */

44
int mi_write(MI_INFO *info, uchar *record)
unknown's avatar
unknown committed
45
{
46
  MYISAM_SHARE *share=info->s;
unknown's avatar
unknown committed
47 48 49 50
  uint i;
  int save_errno;
  my_off_t filepos;
  uchar *buff;
51
  my_bool lock_tree= share->concurrent_insert;
unknown's avatar
unknown committed
52 53 54
  DBUG_ENTER("mi_write");
  DBUG_PRINT("enter",("isam: %d  data: %d",info->s->kfile,info->dfile));

55
  DBUG_EXECUTE_IF("myisam_pretend_crashed_table_on_usage",
unknown's avatar
unknown committed
56
                  mi_print_error(info->s, HA_ERR_CRASHED);
57
                  DBUG_RETURN(my_errno= HA_ERR_CRASHED););
58 59 60 61

  /* it's always a bug to try to write a record with the deleted flag set */
  DBUG_ASSERT(info->s->data_file_type != STATIC_RECORD || *record);

unknown's avatar
unknown committed
62 63 64 65 66 67
  if (share->options & HA_OPTION_READ_ONLY_DATA)
  {
    DBUG_RETURN(my_errno=EACCES);
  }
  if (_mi_readinfo(info,F_WRLCK,1))
    DBUG_RETURN(my_errno);
68

69 70
  filepos= ((share->state.dellink != HA_OFFSET_ERROR &&
             !info->append_insert_at_end) ?
unknown's avatar
unknown committed
71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91
	    share->state.dellink :
	    info->state->data_file_length);

  if (share->base.reloc == (ha_rows) 1 &&
      share->base.records == (ha_rows) 1 &&
      info->state->records == (ha_rows) 1)
  {						/* System file */
    my_errno=HA_ERR_RECORD_FILE_FULL;
    goto err2;
  }
  if (info->state->key_file_length >= share->base.margin_key_file_length)
  {
    my_errno=HA_ERR_INDEX_FILE_FULL;
    goto err2;
  }
  if (_mi_mark_file_changed(info))
    goto err2;

  /* Calculate and check all unique constraints */
  for (i=0 ; i < share->state.header.uniques ; i++)
  {
Sergei Golubchik's avatar
Sergei Golubchik committed
92 93 94 95
    MI_UNIQUEDEF *def= share->uniqueinfo + i;
    if (mi_is_key_active(share->state.key_map, def->key) &&
        mi_check_unique(info, def, record, mi_unique_hash(def, record),
                        HA_OFFSET_ERROR))
unknown's avatar
unknown committed
96 97 98 99 100 101 102 103
      goto err2;
  }

	/* Write all keys to indextree */

  buff=info->lastkey2;
  for (i=0 ; i < share->base.keys ; i++)
  {
104
    if (mi_is_key_active(share->state.key_map, i))
unknown's avatar
unknown committed
105
    {
106 107 108
      my_bool local_lock_tree= (lock_tree &&
                                !(info->bulk_insert &&
                                  is_tree_inited(&info->bulk_insert[i])));
109
      if (local_lock_tree)
unknown's avatar
unknown committed
110
      {
Marc Alff's avatar
Marc Alff committed
111
        mysql_rwlock_wrlock(&share->key_root_lock[i]);
unknown's avatar
unknown committed
112 113
	share->keyinfo[i].version++;
      }
unknown's avatar
unknown committed
114 115
      if (share->keyinfo[i].flag & HA_FULLTEXT )
      {
116
        if (_mi_ft_add(info,i, buff, record, filepos))
unknown's avatar
unknown committed
117
        {
118
	  if (local_lock_tree)
Marc Alff's avatar
Marc Alff committed
119
            mysql_rwlock_unlock(&share->key_root_lock[i]);
unknown's avatar
unknown committed
120 121 122 123 124
          DBUG_PRINT("error",("Got error: %d on write",my_errno));
          goto err;
        }
      }
      else
unknown's avatar
unknown committed
125
      {
126
        if (share->keyinfo[i].ck_insert(info,i,buff,
127
			_mi_make_key(info,i,buff,record,filepos)))
128 129
        {
          if (local_lock_tree)
Marc Alff's avatar
Marc Alff committed
130
            mysql_rwlock_unlock(&share->key_root_lock[i]);
131 132
          DBUG_PRINT("error",("Got error: %d on write",my_errno));
          goto err;
133
        }
unknown's avatar
unknown committed
134
      }
135 136 137 138

      /* The above changed info->lastkey2. Inform mi_rnext_same(). */
      info->update&= ~HA_STATE_RNEXT_SAME;

139
      if (local_lock_tree)
Marc Alff's avatar
Marc Alff committed
140
        mysql_rwlock_unlock(&share->key_root_lock[i]);
unknown's avatar
unknown committed
141 142 143 144 145 146 147 148
    }
  }
  if (share->calc_checksum)
    info->checksum=(*share->calc_checksum)(info,record);
  if (!(info->opt_flag & OPT_NO_ROWS))
  {
    if ((*share->write_record)(info,record))
      goto err;
149
    info->state->checksum+=info->checksum;
unknown's avatar
unknown committed
150 151
  }
  if (share->base.auto_key)
152 153
    set_if_bigger(info->s->state.auto_increment,
                  retrieve_auto_increment(info, record));
unknown's avatar
unknown committed
154 155 156 157 158
  info->update= (HA_STATE_CHANGED | HA_STATE_AKTIV | HA_STATE_WRITTEN |
		 HA_STATE_ROW_CHANGED);
  info->state->records++;
  info->lastpos=filepos;
  myisam_log_record(MI_LOG_WRITE,info,record,filepos,0);
Konstantin Osipov's avatar
Konstantin Osipov committed
159
  (void) _mi_writeinfo(info, WRITEINFO_UPDATE_KEYFILE);
unknown's avatar
unknown committed
160 161 162 163 164 165
  if (info->invalidator != 0)
  {
    DBUG_PRINT("info", ("invalidator... '%s' (update)", info->filename));
    (*info->invalidator)(info->filename);
    info->invalidator=0;
  }
166 167 168 169

  /*
    Update status of the table. We need to do so after each row write
    for the log tables, as we want the new row to become visible to
unknown's avatar
unknown committed
170 171 172 173
    other threads as soon as possible. We don't lock mutex here
    (as it is required by pthread memory visibility rules) as (1) it's
    not critical to use outdated share->is_log_table value (2) locking
    mutex here for every write is too expensive.
174 175 176 177
  */
  if (share->is_log_table)
    mi_update_status((void*) info);

unknown's avatar
unknown committed
178 179 180 181
  DBUG_RETURN(0);

err:
  save_errno=my_errno;
182
  if (my_errno == HA_ERR_FOUND_DUPP_KEY || my_errno == HA_ERR_RECORD_FILE_FULL ||
183
      my_errno == HA_ERR_NULL_IN_SPATIAL || my_errno == HA_ERR_OUT_OF_MEM)
unknown's avatar
unknown committed
184
  {
unknown's avatar
unknown committed
185 186
    if (info->bulk_insert)
    {
unknown's avatar
unknown committed
187
      uint j;
unknown's avatar
unknown committed
188
      for (j=0 ; j < share->base.keys ; j++)
unknown's avatar
unknown committed
189
        mi_flush_bulk_insert(info, j);
unknown's avatar
unknown committed
190
    }
unknown's avatar
unknown committed
191 192 193
    info->errkey= (int) i;
    while ( i-- > 0)
    {
194
      if (mi_is_key_active(share->state.key_map, i))
unknown's avatar
unknown committed
195
      {
196 197 198
	my_bool local_lock_tree= (lock_tree &&
                                  !(info->bulk_insert &&
                                    is_tree_inited(&info->bulk_insert[i])));
199
	if (local_lock_tree)
Marc Alff's avatar
Marc Alff committed
200
          mysql_rwlock_wrlock(&share->key_root_lock[i]);
unknown's avatar
unknown committed
201 202
	if (share->keyinfo[i].flag & HA_FULLTEXT)
        {
203
          if (_mi_ft_del(info,i, buff,record,filepos))
unknown's avatar
unknown committed
204
	  {
205
	    if (local_lock_tree)
Marc Alff's avatar
Marc Alff committed
206
              mysql_rwlock_unlock(&share->key_root_lock[i]);
unknown's avatar
unknown committed
207 208 209 210 211 212
            break;
	  }
        }
        else
	{
	  uint key_length=_mi_make_key(info,i,buff,record,filepos);
213
	  if (share->keyinfo[i].ck_delete(info, i, buff, key_length))
unknown's avatar
unknown committed
214
	  {
215
	    if (local_lock_tree)
Marc Alff's avatar
Marc Alff committed
216
              mysql_rwlock_unlock(&share->key_root_lock[i]);
unknown's avatar
unknown committed
217 218 219
	    break;
	  }
	}
220
	if (local_lock_tree)
Marc Alff's avatar
Marc Alff committed
221
          mysql_rwlock_unlock(&share->key_root_lock[i]);
unknown's avatar
unknown committed
222 223 224 225
      }
    }
  }
  else
226
  {
unknown's avatar
unknown committed
227
    mi_print_error(info->s, HA_ERR_CRASHED);
unknown's avatar
unknown committed
228
    mi_mark_crashed(info);
229
  }
unknown's avatar
unknown committed
230 231 232 233 234
  info->update= (HA_STATE_CHANGED | HA_STATE_WRITTEN | HA_STATE_ROW_CHANGED);
  my_errno=save_errno;
err2:
  save_errno=my_errno;
  myisam_log_record(MI_LOG_WRITE,info,record,filepos,my_errno);
Konstantin Osipov's avatar
Konstantin Osipov committed
235
  (void) _mi_writeinfo(info,WRITEINFO_UPDATE_KEYFILE);
unknown's avatar
unknown committed
236 237 238 239 240 241
  DBUG_RETURN(my_errno=save_errno);
} /* mi_write */


	/* Write one key to btree */

unknown's avatar
unknown committed
242 243 244 245
int _mi_ck_write(MI_INFO *info, uint keynr, uchar *key, uint key_length)
{
  DBUG_ENTER("_mi_ck_write");

246
  if (info->bulk_insert && is_tree_inited(&info->bulk_insert[keynr]))
unknown's avatar
unknown committed
247 248 249 250 251 252 253 254 255
  {
    DBUG_RETURN(_mi_ck_write_tree(info, keynr, key, key_length));
  }
  else
  {
    DBUG_RETURN(_mi_ck_write_btree(info, keynr, key, key_length));
  }
} /* _mi_ck_write */

256

unknown's avatar
unknown committed
257 258 259 260 261
/**********************************************************************
 *                Normal insert code                                  *
 **********************************************************************/

int _mi_ck_write_btree(register MI_INFO *info, uint keynr, uchar *key,
262
		       uint key_length)
unknown's avatar
unknown committed
263 264
{
  int error;
265 266
  uint comp_flag;
  MI_KEYDEF *keyinfo=info->s->keyinfo+keynr;
267
  my_off_t  *root=&info->s->state.key_root[keynr];
unknown's avatar
unknown committed
268
  DBUG_ENTER("_mi_ck_write_btree");
unknown's avatar
unknown committed
269

270 271
  if (keyinfo->flag & HA_SORT_ALLOWS_SAME)
    comp_flag=SEARCH_BIGGER;			/* Put after same key */
272
  else if (keyinfo->flag & (HA_NOSAME|HA_FULLTEXT))
273
  {
274
    comp_flag=SEARCH_FIND | SEARCH_UPDATE | SEARCH_INSERT; /* No duplicates */
275 276 277 278 279 280
    if (keyinfo->flag & HA_NULL_ARE_EQUAL)
      comp_flag|= SEARCH_NULL_ARE_EQUAL;
  }
  else
    comp_flag=SEARCH_SAME;			/* Keys in rec-pos order */

281 282 283 284 285 286 287
  error=_mi_ck_real_write_btree(info, keyinfo, key, key_length,
                                root, comp_flag);
  if (info->ft1_to_ft2)
  {
    if (!error)
      error= _mi_ft_convert_to_ft2(info, keynr, key);
    delete_dynamic(info->ft1_to_ft2);
288
    my_free(info->ft1_to_ft2);
289 290 291 292 293 294 295 296 297 298 299
    info->ft1_to_ft2=0;
  }
  DBUG_RETURN(error);
} /* _mi_ck_write_btree */

int _mi_ck_real_write_btree(MI_INFO *info, MI_KEYDEF *keyinfo,
    uchar *key, uint key_length, my_off_t *root, uint comp_flag)
{
  int error;
  DBUG_ENTER("_mi_ck_real_write_btree");
  /* key_length parameter is used only if comp_flag is SEARCH_FIND */
300
  if (*root == HA_OFFSET_ERROR ||
301
      (error=w_search(info, keyinfo, comp_flag, key, key_length,
302
		      *root, (uchar *) 0, (uchar*) 0,
unknown's avatar
unknown committed
303
		      (my_off_t) 0, 1)) > 0)
304
    error=_mi_enlarge_root(info,keyinfo,key,root);
unknown's avatar
unknown committed
305
  DBUG_RETURN(error);
306
} /* _mi_ck_real_write_btree */
unknown's avatar
unknown committed
307 308 309 310


	/* Make a new root with key as only pointer */

311 312
int _mi_enlarge_root(MI_INFO *info, MI_KEYDEF *keyinfo, uchar *key,
                     my_off_t *root)
unknown's avatar
unknown committed
313 314 315 316 317 318
{
  uint t_length,nod_flag;
  MI_KEY_PARAM s_temp;
  MYISAM_SHARE *share=info->s;
  DBUG_ENTER("_mi_enlarge_root");

319 320
  nod_flag= (*root != HA_OFFSET_ERROR) ?  share->base.key_reflength : 0;
  _mi_kpointer(info,info->buff+2,*root); /* if nod */
unknown's avatar
unknown committed
321 322 323 324 325
  t_length=(*keyinfo->pack_key)(keyinfo,nod_flag,(uchar*) 0,
				(uchar*) 0, (uchar*) 0, key,&s_temp);
  mi_putint(info->buff,t_length+2+nod_flag,nod_flag);
  (*keyinfo->store_key)(keyinfo,info->buff+2+nod_flag,&s_temp);
  info->buff_used=info->page_changed=1;		/* info->buff is used */
326 327
  if ((*root= _mi_new(info,keyinfo,DFLT_INIT_HITS)) == HA_OFFSET_ERROR ||
      _mi_write_keypage(info,keyinfo,*root,DFLT_INIT_HITS,info->buff))
unknown's avatar
unknown committed
328 329 330 331 332 333 334 335 336 337 338 339 340
    DBUG_RETURN(-1);
  DBUG_RETURN(0);
} /* _mi_enlarge_root */


	/*
	  Search after a position for a key and store it there
	  Returns -1 = error
		   0  = ok
		   1  = key should be stored in higher tree
	*/

static int w_search(register MI_INFO *info, register MI_KEYDEF *keyinfo,
341 342 343
		    uint comp_flag, uchar *key, uint key_length, my_off_t page,
		    uchar *father_buff, uchar *father_keypos,
		    my_off_t father_page, my_bool insert_last)
unknown's avatar
unknown committed
344 345
{
  int error,flag;
346
  uint nod_flag, search_key_length;
unknown's avatar
unknown committed
347
  uchar *temp_buff,*keypos;
348
  uchar keybuff[HA_MAX_KEY_BUFF];
unknown's avatar
unknown committed
349
  my_bool was_last_key;
unknown's avatar
unknown committed
350
  my_off_t next_page, dupp_key_pos;
unknown's avatar
unknown committed
351
  DBUG_ENTER("w_search");
unknown's avatar
unknown committed
352
  DBUG_PRINT("enter",("page: %ld", (long) page));
unknown's avatar
unknown committed
353

354
  search_key_length= (comp_flag & SEARCH_FIND) ? key_length : USE_WHOLE_KEY;
unknown's avatar
unknown committed
355
  if (!(temp_buff= (uchar*) my_alloca((uint) keyinfo->block_length+
356
				      HA_MAX_KEY_BUFF*2)))
unknown's avatar
unknown committed
357
    DBUG_RETURN(-1);
358
  if (!_mi_fetch_keypage(info,keyinfo,page,DFLT_INIT_HITS,temp_buff,0))
unknown's avatar
unknown committed
359 360
    goto err;

unknown's avatar
unknown committed
361 362
  flag=(*keyinfo->bin_search)(info,keyinfo,temp_buff,key,search_key_length,
			      comp_flag, &keypos, keybuff, &was_last_key);
unknown's avatar
unknown committed
363 364 365 366 367 368 369
  nod_flag=mi_test_if_nod(temp_buff);
  if (flag == 0)
  {
    uint tmp_key_length;
	/* get position to record with duplicated key */
    tmp_key_length=(*keyinfo->get_key)(keyinfo,nod_flag,&keypos,keybuff);
    if (tmp_key_length)
unknown's avatar
unknown committed
370
      dupp_key_pos=_mi_dpos(info,0,keybuff+tmp_key_length);
unknown's avatar
unknown committed
371
    else
unknown's avatar
unknown committed
372
      dupp_key_pos= HA_OFFSET_ERROR;
unknown's avatar
unknown committed
373

374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391
    if (keyinfo->flag & HA_FULLTEXT)
    {
      uint off;
      int  subkeys;

      get_key_full_length_rdonly(off, keybuff);
      subkeys=ft_sintXkorr(keybuff+off);
      comp_flag=SEARCH_SAME;
      if (subkeys >= 0)
      {
        /* normal word, one-level tree structure */
        flag=(*keyinfo->bin_search)(info, keyinfo, temp_buff, key,
                                    USE_WHOLE_KEY, comp_flag,
                                    &keypos, keybuff, &was_last_key);
      }
      else
      {
        /* popular word. two-level tree. going down */
unknown's avatar
unknown committed
392
        my_off_t root=dupp_key_pos;
393
        keyinfo=&info->s->ft2_keyinfo;
394
        get_key_full_length_rdonly(off, key);
395
        key+=off;
unknown's avatar
unknown committed
396
        keypos-=keyinfo->keylength+nod_flag; /* we'll modify key entry 'in vivo' */
397 398 399
        error=_mi_ck_real_write_btree(info, keyinfo, key, 0,
                                      &root, comp_flag);
        _mi_dpointer(info, keypos+HA_FT_WLEN, root);
400
        subkeys--; /* should there be underflow protection ? */
401
        DBUG_ASSERT(subkeys < 0);
402 403
        ft_intXstore(keypos, subkeys);
        if (!error)
404
          error=_mi_write_keypage(info,keyinfo,page,DFLT_INIT_HITS,temp_buff);
405
        my_afree((uchar*) temp_buff);
406 407 408 409 410
        DBUG_RETURN(error);
      }
    }
    else /* not HA_FULLTEXT, normal HA_NOSAME key */
    {
unknown's avatar
unknown committed
411
      info->dupp_key_pos= dupp_key_pos;
412
      my_afree((uchar*) temp_buff);
413 414 415
      my_errno=HA_ERR_FOUND_DUPP_KEY;
      DBUG_RETURN(-1);
    }
unknown's avatar
unknown committed
416 417 418 419 420 421 422
  }
  if (flag == MI_FOUND_WRONG_KEY)
    DBUG_RETURN(-1);
  if (!was_last_key)
    insert_last=0;
  next_page=_mi_kpos(nod_flag,keypos);
  if (next_page == HA_OFFSET_ERROR ||
423
      (error=w_search(info, keyinfo, comp_flag, key, key_length, next_page,
unknown's avatar
unknown committed
424 425 426 427
		      temp_buff, keypos, page, insert_last)) >0)
  {
    error=_mi_insert(info,keyinfo,key,temp_buff,keypos,keybuff,father_buff,
		     father_keypos,father_page, insert_last);
428
    if (_mi_write_keypage(info,keyinfo,page,DFLT_INIT_HITS,temp_buff))
unknown's avatar
unknown committed
429 430
      goto err;
  }
431
  my_afree((uchar*) temp_buff);
unknown's avatar
unknown committed
432 433
  DBUG_RETURN(error);
err:
434
  my_afree((uchar*) temp_buff);
unknown's avatar
unknown committed
435 436 437 438 439
  DBUG_PRINT("exit",("Error: %d",my_errno));
  DBUG_RETURN (-1);
} /* w_search */


440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463
/*
  Insert new key.

  SYNOPSIS
    _mi_insert()
    info                        Open table information.
    keyinfo                     Key definition information.
    key                         New key.
    anc_buff                    Key page (beginning).
    key_pos                     Position in key page where to insert.
    key_buff                    Copy of previous key.
    father_buff                 parent key page for balancing.
    father_key_pos              position in parent key page for balancing.
    father_page                 position of parent key page in file.
    insert_last                 If to append at end of page.

  DESCRIPTION
    Insert new key at right of key_pos.

  RETURN
    2           if key contains key to upper level.
    0           OK.
    < 0         Error.
*/
unknown's avatar
unknown committed
464 465 466 467 468 469 470 471 472 473 474

int _mi_insert(register MI_INFO *info, register MI_KEYDEF *keyinfo,
	       uchar *key, uchar *anc_buff, uchar *key_pos, uchar *key_buff,
               uchar *father_buff, uchar *father_key_pos, my_off_t father_page,
	       my_bool insert_last)
{
  uint a_length,nod_flag;
  int t_length;
  uchar *endpos, *prev_key;
  MI_KEY_PARAM s_temp;
  DBUG_ENTER("_mi_insert");
unknown's avatar
unknown committed
475
  DBUG_PRINT("enter",("key_pos: 0x%lx", (long) key_pos));
unknown's avatar
unknown committed
476 477 478 479 480 481 482 483 484 485 486 487 488
  DBUG_EXECUTE("key",_mi_print_key(DBUG_FILE,keyinfo->seg,key,USE_WHOLE_KEY););

  nod_flag=mi_test_if_nod(anc_buff);
  a_length=mi_getint(anc_buff);
  endpos= anc_buff+ a_length;
  prev_key=(key_pos == anc_buff+2+nod_flag ? (uchar*) 0 : key_buff);
  t_length=(*keyinfo->pack_key)(keyinfo,nod_flag,
				(key_pos == endpos ? (uchar*) 0 : key_pos),
				prev_key, prev_key,
				key,&s_temp);
#ifndef DBUG_OFF
  if (key_pos != anc_buff+2+nod_flag && (keyinfo->flag &
					 (HA_BINARY_PACK_KEY | HA_PACK_KEY)))
489
  {
490
    DBUG_DUMP("prev_key",(uchar*) key_buff,_mi_keylength(keyinfo,key_buff));
491
  }
unknown's avatar
unknown committed
492 493 494 495
  if (keyinfo->flag & HA_PACK_KEY)
  {
    DBUG_PRINT("test",("t_length: %d  ref_len: %d",
		       t_length,s_temp.ref_length));
unknown's avatar
unknown committed
496 497
    DBUG_PRINT("test",("n_ref_len: %d  n_length: %d  key_pos: 0x%lx",
		       s_temp.n_ref_length,s_temp.n_length, (long) s_temp.key));
unknown's avatar
unknown committed
498 499 500 501 502 503
  }
#endif
  if (t_length > 0)
  {
    if (t_length >= keyinfo->maxlength*2+MAX_POINTER_LENGTH)
    {
unknown's avatar
unknown committed
504
      mi_print_error(info->s, HA_ERR_CRASHED);
unknown's avatar
unknown committed
505 506 507
      my_errno=HA_ERR_CRASHED;
      DBUG_RETURN(-1);
    }
508
    bmove_upp((uchar*) endpos+t_length,(uchar*) endpos,(uint) (endpos-key_pos));
unknown's avatar
unknown committed
509 510 511 512 513
  }
  else
  {
    if (-t_length >= keyinfo->maxlength*2+MAX_POINTER_LENGTH)
    {
unknown's avatar
unknown committed
514
      mi_print_error(info->s, HA_ERR_CRASHED);
unknown's avatar
unknown committed
515 516 517 518 519 520 521 522 523
      my_errno=HA_ERR_CRASHED;
      DBUG_RETURN(-1);
    }
    bmove(key_pos,key_pos-t_length,(uint) (endpos-key_pos)+t_length);
  }
  (*keyinfo->store_key)(keyinfo,key_pos,&s_temp);
  a_length+=t_length;
  mi_putint(anc_buff,a_length,nod_flag);
  if (a_length <= keyinfo->block_length)
524 525 526
  {
    if (keyinfo->block_length - a_length < 32 &&
        keyinfo->flag & HA_FULLTEXT && key_pos == endpos &&
527
        info->s->base.key_reflength <= info->s->rec_reflength &&
528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546
        info->s->options & (HA_OPTION_PACK_RECORD | HA_OPTION_COMPRESS_RECORD))
    {
      /*
        Normal word. One-level tree. Page is almost full.
        Let's consider converting.
        We'll compare 'key' and the first key at anc_buff
       */
      uchar *a=key, *b=anc_buff+2+nod_flag;
      uint alen, blen, ft2len=info->s->ft2_keyinfo.keylength;
      /* the very first key on the page is always unpacked */
      DBUG_ASSERT((*b & 128) == 0);
#if HA_FT_MAXLEN >= 127
      blen= mi_uint2korr(b); b+=2;
#else
      blen= *b++;
#endif
      get_key_length(alen,a);
      DBUG_ASSERT(info->ft1_to_ft2==0);
      if (alen == blen &&
547
          ha_compare_text(keyinfo->seg->charset, a, alen, b, blen, 0, 0)==0)
548 549 550 551
      {
        /* yup. converting */
        info->ft1_to_ft2=(DYNAMIC_ARRAY *)
          my_malloc(sizeof(DYNAMIC_ARRAY), MYF(MY_WME));
552
        my_init_dynamic_array(info->ft1_to_ft2, ft2len, 300, 50, MYF(0));
553 554 555 556 557 558 559 560 561 562 563

        /*
          now, adding all keys from the page to dynarray
          if the page is a leaf (if not keys will be deleted later)
        */
        if (!nod_flag)
        {
          /* let's leave the first key on the page, though, because
             we cannot easily dispatch an empty page here */
          b+=blen+ft2len+2;
          for (a=anc_buff+a_length ; b < a ; b+=ft2len+2)
564
          {
Alexey Botchkov's avatar
Alexey Botchkov committed
565
            if (insert_dynamic(info->ft1_to_ft2, b))
566 567 568 569 570 571
            {
              mi_print_error(info->s, HA_ERR_OUT_OF_MEM);
              my_errno= HA_ERR_OUT_OF_MEM;
              DBUG_RETURN(-1);
            }
          }
572 573 574 575 576 577 578

          /* fixing the page's length - it contains only one key now */
          mi_putint(anc_buff,2+blen+ft2len+2,0);
        }
        /* the rest will be done when we're back from recursion */
      }
    }
unknown's avatar
unknown committed
579
    DBUG_RETURN(0);				/* There is room on page */
580
  }
unknown's avatar
unknown committed
581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602
  /* Page is full */
  if (nod_flag)
    insert_last=0;
  if (!(keyinfo->flag & (HA_VAR_LENGTH_KEY | HA_BINARY_PACK_KEY)) &&
      father_buff && !insert_last)
    DBUG_RETURN(_mi_balance_page(info,keyinfo,key,anc_buff,father_buff,
				 father_key_pos,father_page));
  DBUG_RETURN(_mi_split_page(info,keyinfo,key,anc_buff,key_buff, insert_last));
} /* _mi_insert */


	/* split a full page in two and assign emerging item to key */

int _mi_split_page(register MI_INFO *info, register MI_KEYDEF *keyinfo,
		   uchar *key, uchar *buff, uchar *key_buff,
		   my_bool insert_last_key)
{
  uint length,a_length,key_ref_length,t_length,nod_flag,key_length;
  uchar *key_pos,*pos, *after_key;
  my_off_t new_pos;
  MI_KEY_PARAM s_temp;
  DBUG_ENTER("mi_split_page");
603
  LINT_INIT(after_key);
604
  DBUG_DUMP("buff",(uchar*) buff,mi_getint(buff));
unknown's avatar
unknown committed
605 606 607 608 609 610 611 612 613 614 615 616 617

  if (info->s->keyinfo+info->lastinx == keyinfo)
    info->page_changed=1;			/* Info->buff is used */
  info->buff_used=1;
  nod_flag=mi_test_if_nod(buff);
  key_ref_length=2+nod_flag;
  if (insert_last_key)
    key_pos=_mi_find_last_pos(keyinfo,buff,key_buff, &key_length, &after_key);
  else
    key_pos=_mi_find_half_pos(nod_flag,keyinfo,buff,key_buff, &key_length,
			      &after_key);
  if (!key_pos)
    DBUG_RETURN(-1);
unknown's avatar
unknown committed
618

unknown's avatar
unknown committed
619 620 621 622 623 624 625 626 627
  length=(uint) (key_pos-buff);
  a_length=mi_getint(buff);
  mi_putint(buff,length,nod_flag);

  key_pos=after_key;
  if (nod_flag)
  {
    DBUG_PRINT("test",("Splitting nod"));
    pos=key_pos-nod_flag;
628
    memcpy((uchar*) info->buff+2,(uchar*) pos,(size_t) nod_flag);
unknown's avatar
unknown committed
629 630 631
  }

	/* Move middle item to key and pointer to new page */
632
  if ((new_pos=_mi_new(info,keyinfo,DFLT_INIT_HITS)) == HA_OFFSET_ERROR)
unknown's avatar
unknown committed
633 634 635 636 637 638
    DBUG_RETURN(-1);
  _mi_kpointer(info,_mi_move_key(keyinfo,key,key_buff),new_pos);

	/* Store new page */
  if (!(*keyinfo->get_key)(keyinfo,nod_flag,&key_pos,key_buff))
    DBUG_RETURN(-1);
unknown's avatar
unknown committed
639

unknown's avatar
unknown committed
640 641 642 643
  t_length=(*keyinfo->pack_key)(keyinfo,nod_flag,(uchar *) 0,
				(uchar*) 0, (uchar*) 0,
				key_buff, &s_temp);
  length=(uint) ((buff+a_length)-key_pos);
644
  memcpy((uchar*) info->buff+key_ref_length+t_length,(uchar*) key_pos,
unknown's avatar
unknown committed
645 646 647 648
	 (size_t) length);
  (*keyinfo->store_key)(keyinfo,info->buff+key_ref_length,&s_temp);
  mi_putint(info->buff,length+t_length+key_ref_length,nod_flag);

649
  if (_mi_write_keypage(info,keyinfo,new_pos,DFLT_INIT_HITS,info->buff))
unknown's avatar
unknown committed
650
    DBUG_RETURN(-1);
651
  DBUG_DUMP("key",(uchar*) key,_mi_keylength(keyinfo,key));
unknown's avatar
unknown committed
652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697
  DBUG_RETURN(2);				/* Middle key up */
} /* _mi_split_page */


	/*
	  Calculate how to much to move to split a page in two
	  Returns pointer to start of key.
	  key will contain the key.
	  return_key_length will contain the length of key
	  after_key will contain the position to where the next key starts
	*/

uchar *_mi_find_half_pos(uint nod_flag, MI_KEYDEF *keyinfo, uchar *page,
			 uchar *key, uint *return_key_length,
			 uchar **after_key)
{
  uint keys,length,key_ref_length;
  uchar *end,*lastpos;
  DBUG_ENTER("_mi_find_half_pos");

  key_ref_length=2+nod_flag;
  length=mi_getint(page)-key_ref_length;
  page+=key_ref_length;
  if (!(keyinfo->flag &
	(HA_PACK_KEY | HA_SPACE_PACK_USED | HA_VAR_LENGTH_KEY |
	 HA_BINARY_PACK_KEY)))
  {
    key_ref_length=keyinfo->keylength+nod_flag;
    keys=length/(key_ref_length*2);
    *return_key_length=keyinfo->keylength;
    end=page+keys*key_ref_length;
    *after_key=end+key_ref_length;
    memcpy(key,end,key_ref_length);
    DBUG_RETURN(end);
  }

  end=page+length/2-key_ref_length;		/* This is aprox. half */
  *key='\0';
  do
  {
    lastpos=page;
    if (!(length=(*keyinfo->get_key)(keyinfo,nod_flag,&page,key)))
      DBUG_RETURN(0);
  } while (page < end);
  *return_key_length=length;
  *after_key=page;
unknown's avatar
unknown committed
698 699
  DBUG_PRINT("exit",("returns: 0x%lx  page: 0x%lx  half: 0x%lx",
                     (long) lastpos, (long) page, (long) end));
unknown's avatar
unknown committed
700 701 702 703
  DBUG_RETURN(lastpos);
} /* _mi_find_half_pos */


704 705 706 707 708
/*
  Split buffer at last key
  Returns pointer to the start of the key before the last key
  key will contain the last key
*/
unknown's avatar
unknown committed
709 710 711 712 713 714 715

static uchar *_mi_find_last_pos(MI_KEYDEF *keyinfo, uchar *page,
				uchar *key, uint *return_key_length,
				uchar **after_key)
{
  uint keys,length,last_length,key_ref_length;
  uchar *end,*lastpos,*prevpos;
716
  uchar key_buff[HA_MAX_KEY_BUFF];
unknown's avatar
unknown committed
717 718
  DBUG_ENTER("_mi_find_last_pos");

719 720
  LINT_INIT(last_length);

unknown's avatar
unknown committed
721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736
  key_ref_length=2;
  length=mi_getint(page)-key_ref_length;
  page+=key_ref_length;
  if (!(keyinfo->flag &
	(HA_PACK_KEY | HA_SPACE_PACK_USED | HA_VAR_LENGTH_KEY |
	 HA_BINARY_PACK_KEY)))
  {
    keys=length/keyinfo->keylength-2;
    *return_key_length=length=keyinfo->keylength;
    end=page+keys*length;
    *after_key=end+length;
    memcpy(key,end,length);
    DBUG_RETURN(end);
  }

  end=page+length-key_ref_length;
737
  DBUG_ASSERT(page < end);
unknown's avatar
unknown committed
738 739 740
  *key='\0';
  length=0;
  lastpos=page;
741 742

  do
unknown's avatar
unknown committed
743 744 745 746 747 748
  {
    prevpos=lastpos; lastpos=page;
    last_length=length;
    memcpy(key, key_buff, length);		/* previous key */
    if (!(length=(*keyinfo->get_key)(keyinfo,0,&page,key_buff)))
    {
unknown's avatar
unknown committed
749
      mi_print_error(keyinfo->share, HA_ERR_CRASHED);
unknown's avatar
unknown committed
750 751 752
      my_errno=HA_ERR_CRASHED;
      DBUG_RETURN(0);
    }
753 754
  } while (page < end);

unknown's avatar
unknown committed
755 756
  *return_key_length=last_length;
  *after_key=lastpos;
unknown's avatar
unknown committed
757 758
  DBUG_PRINT("exit",("returns: 0x%lx  page: 0x%lx  end: 0x%lx",
                     (long) prevpos,(long) page,(long) end));
unknown's avatar
unknown committed
759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775
  DBUG_RETURN(prevpos);
} /* _mi_find_last_pos */


	/* Balance page with not packed keys with page on right/left */
	/* returns 0 if balance was done */

static int _mi_balance_page(register MI_INFO *info, MI_KEYDEF *keyinfo,
			    uchar *key, uchar *curr_buff, uchar *father_buff,
			    uchar *father_key_pos, my_off_t father_page)
{
  my_bool right;
  uint k_length,father_length,father_keylength,nod_flag,curr_keylength,
       right_length,left_length,new_right_length,new_left_length,extra_length,
       length,keys;
  uchar *pos,*buff,*extra_buff;
  my_off_t next_page,new_pos;
776
  uchar tmp_part_key[HA_MAX_KEY_BUFF];
unknown's avatar
unknown committed
777 778 779 780 781 782 783 784 785
  DBUG_ENTER("_mi_balance_page");

  k_length=keyinfo->keylength;
  father_length=mi_getint(father_buff);
  father_keylength=k_length+info->s->base.key_reflength;
  nod_flag=mi_test_if_nod(curr_buff);
  curr_keylength=k_length+nod_flag;
  info->page_changed=1;

unknown's avatar
unknown committed
786 787
  if ((father_key_pos != father_buff+father_length &&
       (info->state->records & 1)) ||
unknown's avatar
unknown committed
788 789 790 791 792 793
      father_key_pos == father_buff+2+info->s->base.key_reflength)
  {
    right=1;
    next_page= _mi_kpos(info->s->base.key_reflength,
			father_key_pos+father_keylength);
    buff=info->buff;
unknown's avatar
unknown committed
794
    DBUG_PRINT("test",("use right page: %lu", (ulong) next_page));
unknown's avatar
unknown committed
795 796 797 798 799 800 801 802
  }
  else
  {
    right=0;
    father_key_pos-=father_keylength;
    next_page= _mi_kpos(info->s->base.key_reflength,father_key_pos);
					/* Fix that curr_buff is to left */
    buff=curr_buff; curr_buff=info->buff;
unknown's avatar
unknown committed
803
    DBUG_PRINT("test",("use left page: %lu", (ulong) next_page));
unknown's avatar
unknown committed
804 805
  }					/* father_key_pos ptr to parting key */

806
  if (!_mi_fetch_keypage(info,keyinfo,next_page,DFLT_INIT_HITS,info->buff,0))
unknown's avatar
unknown committed
807
    goto err;
808
  DBUG_DUMP("next",(uchar*) info->buff,mi_getint(info->buff));
unknown's avatar
unknown committed
809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826

	/* Test if there is room to share keys */

  left_length=mi_getint(curr_buff);
  right_length=mi_getint(buff);
  keys=(left_length+right_length-4-nod_flag*2)/curr_keylength;

  if ((right ? right_length : left_length) + curr_keylength <=
      keyinfo->block_length)
  {						/* Merge buffs */
    new_left_length=2+nod_flag+(keys/2)*curr_keylength;
    new_right_length=2+nod_flag+((keys+1)/2)*curr_keylength;
    mi_putint(curr_buff,new_left_length,nod_flag);
    mi_putint(buff,new_right_length,nod_flag);

    if (left_length < new_left_length)
    {						/* Move keys buff -> leaf */
      pos=curr_buff+left_length;
827 828
      memcpy((uchar*) pos,(uchar*) father_key_pos, (size_t) k_length);
      memcpy((uchar*) pos+k_length, (uchar*) buff+2,
unknown's avatar
unknown committed
829 830
	     (size_t) (length=new_left_length - left_length - k_length));
      pos=buff+2+length;
831
      memcpy((uchar*) father_key_pos,(uchar*) pos,(size_t) k_length);
832
      bmove((uchar*) buff + 2, (uchar*) pos + k_length, new_right_length - 2);
unknown's avatar
unknown committed
833 834 835 836
    }
    else
    {						/* Move keys -> buff */

837
      bmove_upp((uchar*) buff+new_right_length,(uchar*) buff+right_length,
unknown's avatar
unknown committed
838 839
		right_length-2);
      length=new_right_length-right_length-k_length;
840
      memcpy((uchar*) buff+2+length,father_key_pos,(size_t) k_length);
unknown's avatar
unknown committed
841
      pos=curr_buff+new_left_length;
842 843
      memcpy((uchar*) father_key_pos,(uchar*) pos,(size_t) k_length);
      memcpy((uchar*) buff+2,(uchar*) pos+k_length,(size_t) length);
unknown's avatar
unknown committed
844 845
    }

846 847
    if (_mi_write_keypage(info,keyinfo,next_page,DFLT_INIT_HITS,info->buff) ||
	_mi_write_keypage(info,keyinfo,father_page,DFLT_INIT_HITS,father_buff))
unknown's avatar
unknown committed
848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869
      goto err;
    DBUG_RETURN(0);
  }

	/* curr_buff[] and buff[] are full, lets split and make new nod */

  extra_buff=info->buff+info->s->base.max_key_block_length;
  new_left_length=new_right_length=2+nod_flag+(keys+1)/3*curr_keylength;
  if (keys == 5)				/* Too few keys to balance */
    new_left_length-=curr_keylength;
  extra_length=nod_flag+left_length+right_length-
    new_left_length-new_right_length-curr_keylength;
  DBUG_PRINT("info",("left_length: %d  right_length: %d  new_left_length: %d  new_right_length: %d  extra_length: %d",
		     left_length, right_length,
		     new_left_length, new_right_length,
		     extra_length));
  mi_putint(curr_buff,new_left_length,nod_flag);
  mi_putint(buff,new_right_length,nod_flag);
  mi_putint(extra_buff,extra_length+2,nod_flag);

  /* move first largest keys to new page  */
  pos=buff+right_length-extra_length;
870
  memcpy((uchar*) extra_buff+2,pos,(size_t) extra_length);
unknown's avatar
unknown committed
871 872 873
  /* Save new parting key */
  memcpy(tmp_part_key, pos-k_length,k_length);
  /* Make place for new keys */
874
  bmove_upp((uchar*) buff+new_right_length,(uchar*) pos-k_length,
unknown's avatar
unknown committed
875 876 877
	    right_length-extra_length-k_length-2);
  /* Copy keys from left page */
  pos= curr_buff+new_left_length;
878
  memcpy((uchar*) buff+2,(uchar*) pos+k_length,
unknown's avatar
unknown committed
879 880
	 (size_t) (length=left_length-new_left_length-k_length));
  /* Copy old parting key */
881
  memcpy((uchar*) buff+2+length,father_key_pos,(size_t) k_length);
unknown's avatar
unknown committed
882 883

  /* Move new parting keys up to caller */
884 885
  memcpy((uchar*) (right ? key : father_key_pos),pos,(size_t) k_length);
  memcpy((uchar*) (right ? father_key_pos : key),tmp_part_key, k_length);
unknown's avatar
unknown committed
886

887
  if ((new_pos=_mi_new(info,keyinfo,DFLT_INIT_HITS)) == HA_OFFSET_ERROR)
unknown's avatar
unknown committed
888 889 890
    goto err;
  _mi_kpointer(info,key+k_length,new_pos);
  if (_mi_write_keypage(info,keyinfo,(right ? new_pos : next_page),
891 892 893
			DFLT_INIT_HITS,info->buff) ||
      _mi_write_keypage(info,keyinfo,(right ? next_page : new_pos),
                        DFLT_INIT_HITS,extra_buff))
unknown's avatar
unknown committed
894 895 896 897 898 899 900
    goto err;

  DBUG_RETURN(1);				/* Middle key up */

err:
  DBUG_RETURN(-1);
} /* _mi_balance_page */
unknown's avatar
unknown committed
901 902 903 904 905 906 907 908 909 910 911

/**********************************************************************
 *                Bulk insert code                                    *
 **********************************************************************/

typedef struct {
  MI_INFO *info;
  uint keynr;
} bulk_insert_param;

int _mi_ck_write_tree(register MI_INFO *info, uint keynr, uchar *key,
912
		      uint key_length)
unknown's avatar
unknown committed
913 914 915 916
{
  int error;
  DBUG_ENTER("_mi_ck_write_tree");

917
  error= tree_insert(&info->bulk_insert[keynr], key,
918
         key_length + info->s->rec_reflength,
919
         info->bulk_insert[keynr].custom_arg) ? 0 : HA_ERR_OUT_OF_MEM ;
unknown's avatar
unknown committed
920 921 922 923

  DBUG_RETURN(error);
} /* _mi_ck_write_tree */

924

unknown's avatar
unknown committed
925
/* typeof(_mi_keys_compare)=qsort_cmp2 */
unknown's avatar
unknown committed
926

unknown's avatar
unknown committed
927 928
static int keys_compare(bulk_insert_param *param, uchar *key1, uchar *key2)
{
929
  uint not_used[2];
unknown's avatar
unknown committed
930
  return ha_key_cmp(param->info->s->keyinfo[param->keynr].seg,
931 932
                    key1, key2, USE_WHOLE_KEY, SEARCH_SAME,
                    not_used);
unknown's avatar
unknown committed
933 934
}

935

unknown's avatar
unknown committed
936 937
static int keys_free(uchar *key, TREE_FREE mode, bulk_insert_param *param)
{
938 939 940 941
  /*
    Probably I can use info->lastkey here, but I'm not sure,
    and to be safe I'd better use local lastkey.
  */
942
  uchar lastkey[HA_MAX_KEY_BUFF];
unknown's avatar
unknown committed
943 944 945 946
  uint keylen;
  MI_KEYDEF *keyinfo;

  switch (mode) {
947 948 949
  case free_init:
    if (param->info->s->concurrent_insert)
    {
Marc Alff's avatar
Marc Alff committed
950
      mysql_rwlock_wrlock(&param->info->s->key_root_lock[param->keynr]);
951 952 953 954 955 956 957 958 959 960 961
      param->info->s->keyinfo[param->keynr].version++;
    }
    return 0;
  case free_free:
    keyinfo=param->info->s->keyinfo+param->keynr;
    keylen=_mi_keylength(keyinfo, key);
    memcpy(lastkey, key, keylen);
    return _mi_ck_write_btree(param->info,param->keynr,lastkey,
			      keylen - param->info->s->rec_reflength);
  case free_end:
    if (param->info->s->concurrent_insert)
Marc Alff's avatar
Marc Alff committed
962
      mysql_rwlock_unlock(&param->info->s->key_root_lock[param->keynr]);
963
    return 0;
unknown's avatar
unknown committed
964 965 966 967
  }
  return -1;
}

968

969
int mi_init_bulk_insert(MI_INFO *info, size_t cache_size, ha_rows rows)
unknown's avatar
unknown committed
970 971 972 973
{
  MYISAM_SHARE *share=info->s;
  MI_KEYDEF *key=share->keyinfo;
  bulk_insert_param *params;
unknown's avatar
unknown committed
974
  uint i, num_keys, total_keylength;
975
  ulonglong key_map;
unknown's avatar
unknown committed
976
  DBUG_ENTER("_mi_init_bulk_insert");
977
  DBUG_PRINT("enter",("cache_size: %lu", (ulong) cache_size));
unknown's avatar
unknown committed
978

979
  DBUG_ASSERT(!info->bulk_insert &&
980
	      (!rows || rows >= MI_MIN_ROWS_TO_USE_BULK_INSERT));
unknown's avatar
unknown committed
981

982
  mi_clear_all_keys_active(key_map);
unknown's avatar
unknown committed
983
  for (i=total_keylength=num_keys=0 ; i < share->base.keys ; i++)
unknown's avatar
unknown committed
984
  {
985 986
    if (! (key[i].flag & HA_NOSAME) && (share->base.auto_key != i + 1) &&
        mi_is_key_active(share->state.key_map, i))
unknown's avatar
unknown committed
987 988
    {
      num_keys++;
989
      mi_set_key_active(key_map, i);
unknown's avatar
unknown committed
990
      total_keylength+=key[i].maxlength+TREE_ELEMENT_EXTRA_SIZE;
unknown's avatar
unknown committed
991 992 993
    }
  }

994
  if (num_keys==0 ||
995
      num_keys * (size_t) MI_MIN_SIZE_BULK_INSERT_TREE > cache_size)
unknown's avatar
unknown committed
996
    DBUG_RETURN(0);
unknown's avatar
unknown committed
997

unknown's avatar
unknown committed
998
  if (rows && rows*total_keylength < cache_size)
999
    cache_size= (size_t) rows;
unknown's avatar
unknown committed
1000 1001 1002
  else
    cache_size/=total_keylength*16;

1003
  info->bulk_insert=(TREE *)
unknown's avatar
unknown committed
1004 1005
    my_malloc((sizeof(TREE)*share->base.keys+
               sizeof(bulk_insert_param)*num_keys),MYF(0));
unknown's avatar
unknown committed
1006 1007

  if (!info->bulk_insert)
unknown's avatar
unknown committed
1008
    DBUG_RETURN(HA_ERR_OUT_OF_MEM);
unknown's avatar
unknown committed
1009

unknown's avatar
unknown committed
1010
  params=(bulk_insert_param *)(info->bulk_insert+share->base.keys);
unknown's avatar
unknown committed
1011
  for (i=0 ; i < share->base.keys ; i++)
unknown's avatar
unknown committed
1012
  {
1013
    if (mi_is_key_active(key_map, i))
unknown's avatar
unknown committed
1014
    {
unknown's avatar
unknown committed
1015 1016
      params->info=info;
      params->keynr=i;
1017
      /* Only allocate a 16'th of the buffer at a time */
unknown's avatar
unknown committed
1018
      init_tree(&info->bulk_insert[i],
unknown's avatar
unknown committed
1019 1020
                cache_size * key[i].maxlength,
                cache_size * key[i].maxlength, 0,
1021
		(qsort_cmp2)keys_compare,
1022
		(tree_element_free) keys_free, (void *)params++, MYF(0));
unknown's avatar
unknown committed
1023 1024
    }
    else
unknown's avatar
unknown committed
1025
     info->bulk_insert[i].root=0;
unknown's avatar
unknown committed
1026
  }
unknown's avatar
unknown committed
1027

unknown's avatar
unknown committed
1028
  DBUG_RETURN(0);
unknown's avatar
unknown committed
1029
}
unknown's avatar
unknown committed
1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051

void mi_flush_bulk_insert(MI_INFO *info, uint inx)
{
  if (info->bulk_insert)
  {
    if (is_tree_inited(&info->bulk_insert[inx]))
      reset_tree(&info->bulk_insert[inx]);
  }
}

void mi_end_bulk_insert(MI_INFO *info)
{
  if (info->bulk_insert)
  {
    uint i;
    for (i=0 ; i < info->s->base.keys ; i++)
    {
      if (is_tree_inited(& info->bulk_insert[i]))
      {
        delete_tree(& info->bulk_insert[i]);
      }
    }
1052
    my_free(info->bulk_insert);
unknown's avatar
unknown committed
1053 1054 1055
    info->bulk_insert=0;
  }
}