~drizzle-trunk/drizzle/development

1 by brian
clean slate
1
/* Copyright (C) 2000-2006 MySQL 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; version 2 of the License.
6
7
   This program is distributed in the hope that it will be useful,
8
   but WITHOUT ANY WARRANTY; without even the implied warranty of
9
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10
   GNU General Public License for more details.
11
12
   You should have received a copy of the GNU General Public License
13
   along with this program; if not, write to the Free Software
14
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
15
16
/* Write a row to a MyISAM table */
17
76 by Brian Aker
Next pass on fulltext.
18
#include "myisamdef.h"
612.2.13 by Monty Taylor
Work on removing global.h from headers that should be installed.
19
20
#include <mystrings/m_string.h>
492.1.7 by Monty Taylor
Moved test() to its own file.
21
#include <drizzled/util/test.h>
22
1 by brian
clean slate
23
24
#define MAX_POINTER_LENGTH 8
25
26
	/* Functions declared in this file */
27
28
static int w_search(MI_INFO *info,MI_KEYDEF *keyinfo,
482 by Brian Aker
Remove uint.
29
		    uint32_t comp_flag, unsigned char *key,
30
		    uint32_t key_length, my_off_t pos, unsigned char *father_buff,
481 by Brian Aker
Remove all of uchar.
31
		    unsigned char *father_keypos, my_off_t father_page,
281 by Brian Aker
Converted myisam away from my_bool
32
		    bool insert_last);
481 by Brian Aker
Remove all of uchar.
33
static int _mi_balance_page(MI_INFO *info,MI_KEYDEF *keyinfo,unsigned char *key,
34
			    unsigned char *curr_buff,unsigned char *father_buff,
35
			    unsigned char *father_keypos,my_off_t father_page);
36
static unsigned char *_mi_find_last_pos(MI_KEYDEF *keyinfo, unsigned char *page,
482 by Brian Aker
Remove uint.
37
				unsigned char *key, uint32_t *return_key_length,
481 by Brian Aker
Remove all of uchar.
38
				unsigned char **after_key);
482 by Brian Aker
Remove uint.
39
int _mi_ck_write_tree(register MI_INFO *info, uint32_t keynr,unsigned char *key,
40
		      uint32_t key_length);
41
int _mi_ck_write_btree(register MI_INFO *info, uint32_t keynr,unsigned char *key,
42
		       uint32_t key_length);
1 by brian
clean slate
43
44
	/* Write new record to database */
45
481 by Brian Aker
Remove all of uchar.
46
int mi_write(MI_INFO *info, unsigned char *record)
1 by brian
clean slate
47
{
48
  MYISAM_SHARE *share=info->s;
482 by Brian Aker
Remove uint.
49
  uint32_t i;
1 by brian
clean slate
50
  int save_errno;
51
  my_off_t filepos;
481 by Brian Aker
Remove all of uchar.
52
  unsigned char *buff;
281 by Brian Aker
Converted myisam away from my_bool
53
  bool lock_tree= share->concurrent_insert;
1 by brian
clean slate
54
55
  if (share->options & HA_OPTION_READ_ONLY_DATA)
56
  {
51.1.115 by Jay Pipes
DBUG symbol removal
57
    return(my_errno=EACCES);
1 by brian
clean slate
58
  }
59
  if (_mi_readinfo(info,F_WRLCK,1))
51.1.115 by Jay Pipes
DBUG symbol removal
60
    return(my_errno);
1 by brian
clean slate
61
  filepos= ((share->state.dellink != HA_OFFSET_ERROR &&
62
             !info->append_insert_at_end) ?
63
	    share->state.dellink :
64
	    info->state->data_file_length);
65
66
  if (share->base.reloc == (ha_rows) 1 &&
67
      share->base.records == (ha_rows) 1 &&
68
      info->state->records == (ha_rows) 1)
69
  {						/* System file */
70
    my_errno=HA_ERR_RECORD_FILE_FULL;
71
    goto err2;
72
  }
73
  if (info->state->key_file_length >= share->base.margin_key_file_length)
74
  {
75
    my_errno=HA_ERR_INDEX_FILE_FULL;
76
    goto err2;
77
  }
78
  if (_mi_mark_file_changed(info))
79
    goto err2;
80
81
  /* Calculate and check all unique constraints */
82
  for (i=0 ; i < share->state.header.uniques ; i++)
83
  {
84
    if (mi_check_unique(info,share->uniqueinfo+i,record,
85
		     mi_unique_hash(share->uniqueinfo+i,record),
86
		     HA_OFFSET_ERROR))
87
      goto err2;
88
  }
89
90
	/* Write all keys to indextree */
91
92
  buff=info->lastkey2;
93
  for (i=0 ; i < share->base.keys ; i++)
94
  {
95
    if (mi_is_key_active(share->state.key_map, i))
96
    {
281 by Brian Aker
Converted myisam away from my_bool
97
      bool local_lock_tree= (lock_tree &&
1 by brian
clean slate
98
                                !(info->bulk_insert &&
99
                                  is_tree_inited(&info->bulk_insert[i])));
100
      if (local_lock_tree)
101
      {
658 by Brian Aker
Part removal of my_pthread.h
102
	pthread_rwlock_wrlock(&share->key_root_lock[i]);
1 by brian
clean slate
103
	share->keyinfo[i].version++;
104
      }
105
      {
106
        if (share->keyinfo[i].ck_insert(info,i,buff,
107
			_mi_make_key(info,i,buff,record,filepos)))
108
        {
109
          if (local_lock_tree)
658 by Brian Aker
Part removal of my_pthread.h
110
            pthread_rwlock_unlock(&share->key_root_lock[i]);
1 by brian
clean slate
111
          goto err;
112
        }
113
      }
114
115
      /* The above changed info->lastkey2. Inform mi_rnext_same(). */
116
      info->update&= ~HA_STATE_RNEXT_SAME;
117
118
      if (local_lock_tree)
658 by Brian Aker
Part removal of my_pthread.h
119
        pthread_rwlock_unlock(&share->key_root_lock[i]);
1 by brian
clean slate
120
    }
121
  }
122
  if (share->calc_checksum)
123
    info->checksum=(*share->calc_checksum)(info,record);
124
  if (!(info->opt_flag & OPT_NO_ROWS))
125
  {
126
    if ((*share->write_record)(info,record))
127
      goto err;
128
    info->state->checksum+=info->checksum;
129
  }
130
  if (share->base.auto_key)
131
    set_if_bigger(info->s->state.auto_increment,
132
                  retrieve_auto_increment(info, record));
133
  info->update= (HA_STATE_CHANGED | HA_STATE_AKTIV | HA_STATE_WRITTEN |
134
		 HA_STATE_ROW_CHANGED);
135
  info->state->records++;
136
  info->lastpos=filepos;
398.1.10 by Monty Taylor
Actually removed VOID() this time.
137
  _mi_writeinfo(info, WRITEINFO_UPDATE_KEYFILE);
1 by brian
clean slate
138
139
  /*
140
    Update status of the table. We need to do so after each row write
141
    for the log tables, as we want the new row to become visible to
142
    other threads as soon as possible. We don't lock mutex here
143
    (as it is required by pthread memory visibility rules) as (1) it's
144
    not critical to use outdated share->is_log_table value (2) locking
145
    mutex here for every write is too expensive.
146
  */
147
  if (share->is_log_table)
148
    mi_update_status((void*) info);
149
51.1.115 by Jay Pipes
DBUG symbol removal
150
  return(0);
1 by brian
clean slate
151
152
err:
153
  save_errno=my_errno;
154
  if (my_errno == HA_ERR_FOUND_DUPP_KEY || my_errno == HA_ERR_RECORD_FILE_FULL ||
155
      my_errno == HA_ERR_NULL_IN_SPATIAL || my_errno == HA_ERR_OUT_OF_MEM)
156
  {
157
    if (info->bulk_insert)
158
    {
482 by Brian Aker
Remove uint.
159
      uint32_t j;
1 by brian
clean slate
160
      for (j=0 ; j < share->base.keys ; j++)
161
        mi_flush_bulk_insert(info, j);
162
    }
163
    info->errkey= (int) i;
164
    while ( i-- > 0)
165
    {
166
      if (mi_is_key_active(share->state.key_map, i))
167
      {
281 by Brian Aker
Converted myisam away from my_bool
168
	bool local_lock_tree= (lock_tree &&
1 by brian
clean slate
169
                                  !(info->bulk_insert &&
170
                                    is_tree_inited(&info->bulk_insert[i])));
171
	if (local_lock_tree)
658 by Brian Aker
Part removal of my_pthread.h
172
	  pthread_rwlock_wrlock(&share->key_root_lock[i]);
1 by brian
clean slate
173
	{
482 by Brian Aker
Remove uint.
174
	  uint32_t key_length=_mi_make_key(info,i,buff,record,filepos);
1 by brian
clean slate
175
	  if (_mi_ck_delete(info,i,buff,key_length))
176
	  {
177
	    if (local_lock_tree)
658 by Brian Aker
Part removal of my_pthread.h
178
	      pthread_rwlock_unlock(&share->key_root_lock[i]);
1 by brian
clean slate
179
	    break;
180
	  }
181
	}
182
	if (local_lock_tree)
658 by Brian Aker
Part removal of my_pthread.h
183
	  pthread_rwlock_unlock(&share->key_root_lock[i]);
1 by brian
clean slate
184
      }
185
    }
186
  }
187
  else
188
  {
189
    mi_print_error(info->s, HA_ERR_CRASHED);
190
    mi_mark_crashed(info);
191
  }
192
  info->update= (HA_STATE_CHANGED | HA_STATE_WRITTEN | HA_STATE_ROW_CHANGED);
193
  my_errno=save_errno;
194
err2:
195
  save_errno=my_errno;
398.1.10 by Monty Taylor
Actually removed VOID() this time.
196
  _mi_writeinfo(info,WRITEINFO_UPDATE_KEYFILE);
51.1.115 by Jay Pipes
DBUG symbol removal
197
  return(my_errno=save_errno);
1 by brian
clean slate
198
} /* mi_write */
199
200
201
	/* Write one key to btree */
202
482 by Brian Aker
Remove uint.
203
int _mi_ck_write(MI_INFO *info, uint32_t keynr, unsigned char *key, uint32_t key_length)
1 by brian
clean slate
204
{
205
  if (info->bulk_insert && is_tree_inited(&info->bulk_insert[keynr]))
206
  {
51.1.115 by Jay Pipes
DBUG symbol removal
207
    return(_mi_ck_write_tree(info, keynr, key, key_length));
1 by brian
clean slate
208
  }
209
  else
210
  {
51.1.115 by Jay Pipes
DBUG symbol removal
211
    return(_mi_ck_write_btree(info, keynr, key, key_length));
1 by brian
clean slate
212
  }
213
} /* _mi_ck_write */
214
215
216
/**********************************************************************
217
 *                Normal insert code                                  *
218
 **********************************************************************/
219
482 by Brian Aker
Remove uint.
220
int _mi_ck_write_btree(register MI_INFO *info, uint32_t keynr, unsigned char *key,
221
		       uint32_t key_length)
1 by brian
clean slate
222
{
482 by Brian Aker
Remove uint.
223
  uint32_t error;
224
  uint32_t comp_flag;
1 by brian
clean slate
225
  MI_KEYDEF *keyinfo=info->s->keyinfo+keynr;
226
  my_off_t  *root=&info->s->state.key_root[keynr];
227
228
  if (keyinfo->flag & HA_SORT_ALLOWS_SAME)
229
    comp_flag=SEARCH_BIGGER;			/* Put after same key */
75 by Brian Aker
Another round of cleanup of MyISAM
230
  else if (keyinfo->flag & (HA_NOSAME))
1 by brian
clean slate
231
  {
232
    comp_flag=SEARCH_FIND | SEARCH_UPDATE;	/* No duplicates */
233
    if (keyinfo->flag & HA_NULL_ARE_EQUAL)
234
      comp_flag|= SEARCH_NULL_ARE_EQUAL;
235
  }
236
  else
237
    comp_flag=SEARCH_SAME;			/* Keys in rec-pos order */
238
239
  error=_mi_ck_real_write_btree(info, keyinfo, key, key_length,
240
                                root, comp_flag);
51.1.115 by Jay Pipes
DBUG symbol removal
241
  return(error);
1 by brian
clean slate
242
} /* _mi_ck_write_btree */
243
244
int _mi_ck_real_write_btree(MI_INFO *info, MI_KEYDEF *keyinfo,
482 by Brian Aker
Remove uint.
245
    unsigned char *key, uint32_t key_length, my_off_t *root, uint32_t comp_flag)
1 by brian
clean slate
246
{
247
  int error;
248
  /* key_length parameter is used only if comp_flag is SEARCH_FIND */
249
  if (*root == HA_OFFSET_ERROR ||
250
      (error=w_search(info, keyinfo, comp_flag, key, key_length,
481 by Brian Aker
Remove all of uchar.
251
		      *root, (unsigned char *) 0, (unsigned char*) 0,
1 by brian
clean slate
252
		      (my_off_t) 0, 1)) > 0)
253
    error=_mi_enlarge_root(info,keyinfo,key,root);
51.1.115 by Jay Pipes
DBUG symbol removal
254
  return(error);
1 by brian
clean slate
255
} /* _mi_ck_real_write_btree */
256
257
258
	/* Make a new root with key as only pointer */
259
481 by Brian Aker
Remove all of uchar.
260
int _mi_enlarge_root(MI_INFO *info, MI_KEYDEF *keyinfo, unsigned char *key,
1 by brian
clean slate
261
                     my_off_t *root)
262
{
482 by Brian Aker
Remove uint.
263
  uint32_t t_length,nod_flag;
1 by brian
clean slate
264
  MI_KEY_PARAM s_temp;
265
  MYISAM_SHARE *share=info->s;
266
267
  nod_flag= (*root != HA_OFFSET_ERROR) ?  share->base.key_reflength : 0;
268
  _mi_kpointer(info,info->buff+2,*root); /* if nod */
481 by Brian Aker
Remove all of uchar.
269
  t_length=(*keyinfo->pack_key)(keyinfo,nod_flag,(unsigned char*) 0,
270
				(unsigned char*) 0, (unsigned char*) 0, key,&s_temp);
1 by brian
clean slate
271
  mi_putint(info->buff,t_length+2+nod_flag,nod_flag);
272
  (*keyinfo->store_key)(keyinfo,info->buff+2+nod_flag,&s_temp);
273
  info->buff_used=info->page_changed=1;		/* info->buff is used */
274
  if ((*root= _mi_new(info,keyinfo,DFLT_INIT_HITS)) == HA_OFFSET_ERROR ||
275
      _mi_write_keypage(info,keyinfo,*root,DFLT_INIT_HITS,info->buff))
51.1.115 by Jay Pipes
DBUG symbol removal
276
    return(-1);
277
  return(0);
1 by brian
clean slate
278
} /* _mi_enlarge_root */
279
280
281
	/*
282
	  Search after a position for a key and store it there
283
	  Returns -1 = error
284
		   0  = ok
285
		   1  = key should be stored in higher tree
286
	*/
287
288
static int w_search(register MI_INFO *info, register MI_KEYDEF *keyinfo,
482 by Brian Aker
Remove uint.
289
		    uint32_t comp_flag, unsigned char *key, uint32_t key_length, my_off_t page,
481 by Brian Aker
Remove all of uchar.
290
		    unsigned char *father_buff, unsigned char *father_keypos,
281 by Brian Aker
Converted myisam away from my_bool
291
		    my_off_t father_page, bool insert_last)
1 by brian
clean slate
292
{
293
  int error,flag;
482 by Brian Aker
Remove uint.
294
  uint32_t nod_flag, search_key_length;
481 by Brian Aker
Remove all of uchar.
295
  unsigned char *temp_buff,*keypos;
296
  unsigned char keybuff[MI_MAX_KEY_BUFF];
281 by Brian Aker
Converted myisam away from my_bool
297
  bool was_last_key;
1 by brian
clean slate
298
  my_off_t next_page, dupp_key_pos;
299
300
  search_key_length= (comp_flag & SEARCH_FIND) ? key_length : USE_WHOLE_KEY;
656.1.1 by Monty Taylor
OOOh doggie. Got rid of my_alloca.
301
  if (!(temp_buff= (unsigned char*) malloc(keyinfo->block_length+
302
				           MI_MAX_KEY_BUFF*2)))
51.1.115 by Jay Pipes
DBUG symbol removal
303
    return(-1);
1 by brian
clean slate
304
  if (!_mi_fetch_keypage(info,keyinfo,page,DFLT_INIT_HITS,temp_buff,0))
305
    goto err;
306
307
  flag=(*keyinfo->bin_search)(info,keyinfo,temp_buff,key,search_key_length,
308
			      comp_flag, &keypos, keybuff, &was_last_key);
309
  nod_flag=mi_test_if_nod(temp_buff);
310
  if (flag == 0)
311
  {
482 by Brian Aker
Remove uint.
312
    uint32_t tmp_key_length;
1 by brian
clean slate
313
	/* get position to record with duplicated key */
314
    tmp_key_length=(*keyinfo->get_key)(keyinfo,nod_flag,&keypos,keybuff);
315
    if (tmp_key_length)
316
      dupp_key_pos=_mi_dpos(info,0,keybuff+tmp_key_length);
317
    else
318
      dupp_key_pos= HA_OFFSET_ERROR;
319
320
    {
321
      info->dupp_key_pos= dupp_key_pos;
656.1.1 by Monty Taylor
OOOh doggie. Got rid of my_alloca.
322
      free(temp_buff);
1 by brian
clean slate
323
      my_errno=HA_ERR_FOUND_DUPP_KEY;
51.1.115 by Jay Pipes
DBUG symbol removal
324
      return(-1);
1 by brian
clean slate
325
    }
326
  }
327
  if (flag == MI_FOUND_WRONG_KEY)
51.1.115 by Jay Pipes
DBUG symbol removal
328
    return(-1);
1 by brian
clean slate
329
  if (!was_last_key)
330
    insert_last=0;
331
  next_page=_mi_kpos(nod_flag,keypos);
332
  if (next_page == HA_OFFSET_ERROR ||
333
      (error=w_search(info, keyinfo, comp_flag, key, key_length, next_page,
334
		      temp_buff, keypos, page, insert_last)) >0)
335
  {
336
    error=_mi_insert(info,keyinfo,key,temp_buff,keypos,keybuff,father_buff,
337
		     father_keypos,father_page, insert_last);
338
    if (_mi_write_keypage(info,keyinfo,page,DFLT_INIT_HITS,temp_buff))
339
      goto err;
340
  }
656.1.1 by Monty Taylor
OOOh doggie. Got rid of my_alloca.
341
  free(temp_buff);
51.1.115 by Jay Pipes
DBUG symbol removal
342
  return(error);
1 by brian
clean slate
343
err:
656.1.1 by Monty Taylor
OOOh doggie. Got rid of my_alloca.
344
  free(temp_buff);
51.1.115 by Jay Pipes
DBUG symbol removal
345
  return (-1);
1 by brian
clean slate
346
} /* w_search */
347
348
349
/*
350
  Insert new key.
351
352
  SYNOPSIS
353
    _mi_insert()
354
    info                        Open table information.
355
    keyinfo                     Key definition information.
356
    key                         New key.
357
    anc_buff                    Key page (beginning).
358
    key_pos                     Position in key page where to insert.
359
    key_buff                    Copy of previous key.
360
    father_buff                 parent key page for balancing.
361
    father_key_pos              position in parent key page for balancing.
362
    father_page                 position of parent key page in file.
363
    insert_last                 If to append at end of page.
364
365
  DESCRIPTION
366
    Insert new key at right of key_pos.
367
368
  RETURN
369
    2           if key contains key to upper level.
370
    0           OK.
371
    < 0         Error.
372
*/
373
374
int _mi_insert(register MI_INFO *info, register MI_KEYDEF *keyinfo,
481 by Brian Aker
Remove all of uchar.
375
	       unsigned char *key, unsigned char *anc_buff, unsigned char *key_pos, unsigned char *key_buff,
376
               unsigned char *father_buff, unsigned char *father_key_pos, my_off_t father_page,
281 by Brian Aker
Converted myisam away from my_bool
377
	       bool insert_last)
1 by brian
clean slate
378
{
482 by Brian Aker
Remove uint.
379
  uint32_t a_length,nod_flag;
1 by brian
clean slate
380
  int t_length;
481 by Brian Aker
Remove all of uchar.
381
  unsigned char *endpos, *prev_key;
1 by brian
clean slate
382
  MI_KEY_PARAM s_temp;
383
384
  nod_flag=mi_test_if_nod(anc_buff);
385
  a_length=mi_getint(anc_buff);
386
  endpos= anc_buff+ a_length;
481 by Brian Aker
Remove all of uchar.
387
  prev_key=(key_pos == anc_buff+2+nod_flag ? (unsigned char*) 0 : key_buff);
1 by brian
clean slate
388
  t_length=(*keyinfo->pack_key)(keyinfo,nod_flag,
481 by Brian Aker
Remove all of uchar.
389
				(key_pos == endpos ? (unsigned char*) 0 : key_pos),
1 by brian
clean slate
390
				prev_key, prev_key,
391
				key,&s_temp);
51.1.115 by Jay Pipes
DBUG symbol removal
392
1 by brian
clean slate
393
  if (t_length > 0)
394
  {
395
    if (t_length >= keyinfo->maxlength*2+MAX_POINTER_LENGTH)
396
    {
397
      mi_print_error(info->s, HA_ERR_CRASHED);
398
      my_errno=HA_ERR_CRASHED;
51.1.115 by Jay Pipes
DBUG symbol removal
399
      return(-1);
1 by brian
clean slate
400
    }
481 by Brian Aker
Remove all of uchar.
401
    bmove_upp((unsigned char*) endpos+t_length,(unsigned char*) endpos,(uint) (endpos-key_pos));
1 by brian
clean slate
402
  }
403
  else
404
  {
405
    if (-t_length >= keyinfo->maxlength*2+MAX_POINTER_LENGTH)
406
    {
407
      mi_print_error(info->s, HA_ERR_CRASHED);
408
      my_errno=HA_ERR_CRASHED;
51.1.115 by Jay Pipes
DBUG symbol removal
409
      return(-1);
1 by brian
clean slate
410
    }
629.3.4 by Kristian Nielsen
Take Mats'es changes from bmove()->memcpy(), and fix all of them to be
411
    memmove(key_pos, key_pos - t_length, endpos - key_pos + t_length);
1 by brian
clean slate
412
  }
413
  (*keyinfo->store_key)(keyinfo,key_pos,&s_temp);
414
  a_length+=t_length;
415
  mi_putint(anc_buff,a_length,nod_flag);
416
  if (a_length <= keyinfo->block_length)
417
  {
51.1.115 by Jay Pipes
DBUG symbol removal
418
    return(0);				/* There is room on page */
1 by brian
clean slate
419
  }
420
  /* Page is full */
421
  if (nod_flag)
422
    insert_last=0;
423
  if (!(keyinfo->flag & (HA_VAR_LENGTH_KEY | HA_BINARY_PACK_KEY)) &&
424
      father_buff && !insert_last)
51.1.115 by Jay Pipes
DBUG symbol removal
425
    return(_mi_balance_page(info,keyinfo,key,anc_buff,father_buff,
1 by brian
clean slate
426
				 father_key_pos,father_page));
51.1.115 by Jay Pipes
DBUG symbol removal
427
  return(_mi_split_page(info,keyinfo,key,anc_buff,key_buff, insert_last));
1 by brian
clean slate
428
} /* _mi_insert */
429
430
431
	/* split a full page in two and assign emerging item to key */
432
433
int _mi_split_page(register MI_INFO *info, register MI_KEYDEF *keyinfo,
481 by Brian Aker
Remove all of uchar.
434
		   unsigned char *key, unsigned char *buff, unsigned char *key_buff,
281 by Brian Aker
Converted myisam away from my_bool
435
		   bool insert_last_key)
1 by brian
clean slate
436
{
482 by Brian Aker
Remove uint.
437
  uint32_t length,a_length,key_ref_length,t_length,nod_flag,key_length;
481 by Brian Aker
Remove all of uchar.
438
  unsigned char *key_pos,*pos, *after_key= NULL;
1 by brian
clean slate
439
  my_off_t new_pos;
440
  MI_KEY_PARAM s_temp;
441
442
  if (info->s->keyinfo+info->lastinx == keyinfo)
443
    info->page_changed=1;			/* Info->buff is used */
444
  info->buff_used=1;
445
  nod_flag=mi_test_if_nod(buff);
446
  key_ref_length=2+nod_flag;
447
  if (insert_last_key)
448
    key_pos=_mi_find_last_pos(keyinfo,buff,key_buff, &key_length, &after_key);
449
  else
450
    key_pos=_mi_find_half_pos(nod_flag,keyinfo,buff,key_buff, &key_length,
451
			      &after_key);
452
  if (!key_pos)
51.1.115 by Jay Pipes
DBUG symbol removal
453
    return(-1);
1 by brian
clean slate
454
455
  length=(uint) (key_pos-buff);
456
  a_length=mi_getint(buff);
457
  mi_putint(buff,length,nod_flag);
458
459
  key_pos=after_key;
460
  if (nod_flag)
461
  {
462
    pos=key_pos-nod_flag;
212.6.12 by Mats Kindahl
Removing redundant use of casts in MyISAM storage for memcmp(), memcpy(), memset(), and memmove().
463
    memcpy(info->buff + 2, pos, nod_flag);
1 by brian
clean slate
464
  }
465
466
	/* Move middle item to key and pointer to new page */
467
  if ((new_pos=_mi_new(info,keyinfo,DFLT_INIT_HITS)) == HA_OFFSET_ERROR)
51.1.115 by Jay Pipes
DBUG symbol removal
468
    return(-1);
1 by brian
clean slate
469
  _mi_kpointer(info,_mi_move_key(keyinfo,key,key_buff),new_pos);
470
471
	/* Store new page */
472
  if (!(*keyinfo->get_key)(keyinfo,nod_flag,&key_pos,key_buff))
51.1.115 by Jay Pipes
DBUG symbol removal
473
    return(-1);
1 by brian
clean slate
474
481 by Brian Aker
Remove all of uchar.
475
  t_length=(*keyinfo->pack_key)(keyinfo,nod_flag,(unsigned char *) 0,
476
				(unsigned char*) 0, (unsigned char*) 0,
1 by brian
clean slate
477
				key_buff, &s_temp);
478
  length=(uint) ((buff+a_length)-key_pos);
212.6.12 by Mats Kindahl
Removing redundant use of casts in MyISAM storage for memcmp(), memcpy(), memset(), and memmove().
479
  memcpy(info->buff+key_ref_length+t_length, key_pos, length);
1 by brian
clean slate
480
  (*keyinfo->store_key)(keyinfo,info->buff+key_ref_length,&s_temp);
481
  mi_putint(info->buff,length+t_length+key_ref_length,nod_flag);
482
483
  if (_mi_write_keypage(info,keyinfo,new_pos,DFLT_INIT_HITS,info->buff))
51.1.115 by Jay Pipes
DBUG symbol removal
484
    return(-1);
485
  return(2);				/* Middle key up */
1 by brian
clean slate
486
} /* _mi_split_page */
487
488
489
	/*
490
	  Calculate how to much to move to split a page in two
491
	  Returns pointer to start of key.
492
	  key will contain the key.
493
	  return_key_length will contain the length of key
494
	  after_key will contain the position to where the next key starts
495
	*/
496
482 by Brian Aker
Remove uint.
497
unsigned char *_mi_find_half_pos(uint32_t nod_flag, MI_KEYDEF *keyinfo, unsigned char *page,
498
			 unsigned char *key, uint32_t *return_key_length,
481 by Brian Aker
Remove all of uchar.
499
			 unsigned char **after_key)
1 by brian
clean slate
500
{
482 by Brian Aker
Remove uint.
501
  uint32_t keys,length,key_ref_length;
481 by Brian Aker
Remove all of uchar.
502
  unsigned char *end,*lastpos;
1 by brian
clean slate
503
504
  key_ref_length=2+nod_flag;
505
  length=mi_getint(page)-key_ref_length;
506
  page+=key_ref_length;
507
  if (!(keyinfo->flag &
508
	(HA_PACK_KEY | HA_SPACE_PACK_USED | HA_VAR_LENGTH_KEY |
509
	 HA_BINARY_PACK_KEY)))
510
  {
511
    key_ref_length=keyinfo->keylength+nod_flag;
512
    keys=length/(key_ref_length*2);
513
    *return_key_length=keyinfo->keylength;
514
    end=page+keys*key_ref_length;
515
    *after_key=end+key_ref_length;
516
    memcpy(key,end,key_ref_length);
51.1.115 by Jay Pipes
DBUG symbol removal
517
    return(end);
1 by brian
clean slate
518
  }
519
520
  end=page+length/2-key_ref_length;		/* This is aprox. half */
521
  *key='\0';
522
  do
523
  {
524
    lastpos=page;
525
    if (!(length=(*keyinfo->get_key)(keyinfo,nod_flag,&page,key)))
51.1.115 by Jay Pipes
DBUG symbol removal
526
      return(0);
1 by brian
clean slate
527
  } while (page < end);
528
  *return_key_length=length;
529
  *after_key=page;
51.1.115 by Jay Pipes
DBUG symbol removal
530
  return(lastpos);
1 by brian
clean slate
531
} /* _mi_find_half_pos */
532
533
534
	/*
535
	  Split buffer at last key
536
	  Returns pointer to the start of the key before the last key
537
	  key will contain the last key
538
	*/
539
481 by Brian Aker
Remove all of uchar.
540
static unsigned char *_mi_find_last_pos(MI_KEYDEF *keyinfo, unsigned char *page,
482 by Brian Aker
Remove uint.
541
				unsigned char *key, uint32_t *return_key_length,
481 by Brian Aker
Remove all of uchar.
542
				unsigned char **after_key)
1 by brian
clean slate
543
{
482 by Brian Aker
Remove uint.
544
  uint32_t keys;
545
  uint32_t length;
546
  uint32_t last_length= 0;
547
  uint32_t key_ref_length;
481 by Brian Aker
Remove all of uchar.
548
  unsigned char *end, *lastpos, *prevpos= NULL;
549
  unsigned char key_buff[MI_MAX_KEY_BUFF];
1 by brian
clean slate
550
551
  key_ref_length=2;
552
  length=mi_getint(page)-key_ref_length;
553
  page+=key_ref_length;
554
  if (!(keyinfo->flag &
555
	(HA_PACK_KEY | HA_SPACE_PACK_USED | HA_VAR_LENGTH_KEY |
556
	 HA_BINARY_PACK_KEY)))
557
  {
558
    keys=length/keyinfo->keylength-2;
559
    *return_key_length=length=keyinfo->keylength;
560
    end=page+keys*length;
561
    *after_key=end+length;
562
    memcpy(key,end,length);
51.1.115 by Jay Pipes
DBUG symbol removal
563
    return(end);
1 by brian
clean slate
564
  }
565
566
  end= page + length - key_ref_length;
567
  *key='\0';
568
  length=0;
569
  lastpos=page;
570
  while (page < end)
571
  {
572
    prevpos=lastpos; lastpos=page;
573
    last_length=length;
574
    memcpy(key, key_buff, length);		/* previous key */
575
    if (!(length=(*keyinfo->get_key)(keyinfo,0,&page,key_buff)))
576
    {
577
      mi_print_error(keyinfo->share, HA_ERR_CRASHED);
578
      my_errno=HA_ERR_CRASHED;
51.1.115 by Jay Pipes
DBUG symbol removal
579
      return(0);
1 by brian
clean slate
580
    }
581
  }
582
  *return_key_length=last_length;
583
  *after_key=lastpos;
51.1.115 by Jay Pipes
DBUG symbol removal
584
  return(prevpos);
1 by brian
clean slate
585
} /* _mi_find_last_pos */
586
587
588
	/* Balance page with not packed keys with page on right/left */
589
	/* returns 0 if balance was done */
590
591
static int _mi_balance_page(register MI_INFO *info, MI_KEYDEF *keyinfo,
481 by Brian Aker
Remove all of uchar.
592
			    unsigned char *key, unsigned char *curr_buff, unsigned char *father_buff,
593
			    unsigned char *father_key_pos, my_off_t father_page)
1 by brian
clean slate
594
{
281 by Brian Aker
Converted myisam away from my_bool
595
  bool right;
482 by Brian Aker
Remove uint.
596
  uint32_t k_length,father_length,father_keylength,nod_flag,curr_keylength,
1 by brian
clean slate
597
       right_length,left_length,new_right_length,new_left_length,extra_length,
598
       length,keys;
481 by Brian Aker
Remove all of uchar.
599
  unsigned char *pos,*buff,*extra_buff;
1 by brian
clean slate
600
  my_off_t next_page,new_pos;
481 by Brian Aker
Remove all of uchar.
601
  unsigned char tmp_part_key[MI_MAX_KEY_BUFF];
1 by brian
clean slate
602
603
  k_length=keyinfo->keylength;
604
  father_length=mi_getint(father_buff);
605
  father_keylength=k_length+info->s->base.key_reflength;
606
  nod_flag=mi_test_if_nod(curr_buff);
607
  curr_keylength=k_length+nod_flag;
608
  info->page_changed=1;
609
610
  if ((father_key_pos != father_buff+father_length &&
611
       (info->state->records & 1)) ||
612
      father_key_pos == father_buff+2+info->s->base.key_reflength)
613
  {
614
    right=1;
615
    next_page= _mi_kpos(info->s->base.key_reflength,
616
			father_key_pos+father_keylength);
617
    buff=info->buff;
618
  }
619
  else
620
  {
621
    right=0;
622
    father_key_pos-=father_keylength;
623
    next_page= _mi_kpos(info->s->base.key_reflength,father_key_pos);
624
					/* Fix that curr_buff is to left */
625
    buff=curr_buff; curr_buff=info->buff;
626
  }					/* father_key_pos ptr to parting key */
627
628
  if (!_mi_fetch_keypage(info,keyinfo,next_page,DFLT_INIT_HITS,info->buff,0))
629
    goto err;
630
631
	/* Test if there is room to share keys */
632
633
  left_length=mi_getint(curr_buff);
634
  right_length=mi_getint(buff);
635
  keys=(left_length+right_length-4-nod_flag*2)/curr_keylength;
636
637
  if ((right ? right_length : left_length) + curr_keylength <=
638
      keyinfo->block_length)
639
  {						/* Merge buffs */
640
    new_left_length=2+nod_flag+(keys/2)*curr_keylength;
641
    new_right_length=2+nod_flag+((keys+1)/2)*curr_keylength;
642
    mi_putint(curr_buff,new_left_length,nod_flag);
643
    mi_putint(buff,new_right_length,nod_flag);
644
645
    if (left_length < new_left_length)
646
    {						/* Move keys buff -> leaf */
647
      pos=curr_buff+left_length;
212.6.12 by Mats Kindahl
Removing redundant use of casts in MyISAM storage for memcmp(), memcpy(), memset(), and memmove().
648
      memcpy(pos, father_key_pos, k_length);
649
      length= new_left_length - left_length - k_length;
650
      memcpy(pos+k_length, buff+2, length);
1 by brian
clean slate
651
      pos=buff+2+length;
212.6.12 by Mats Kindahl
Removing redundant use of casts in MyISAM storage for memcmp(), memcpy(), memset(), and memmove().
652
      memcpy(father_key_pos, pos, k_length);
629.3.4 by Kristian Nielsen
Take Mats'es changes from bmove()->memcpy(), and fix all of them to be
653
      memmove(buff+2, pos+k_length, new_right_length);
1 by brian
clean slate
654
    }
655
    else
656
    {						/* Move keys -> buff */
657
481 by Brian Aker
Remove all of uchar.
658
      bmove_upp((unsigned char*) buff+new_right_length,(unsigned char*) buff+right_length,
1 by brian
clean slate
659
		right_length-2);
660
      length=new_right_length-right_length-k_length;
212.6.12 by Mats Kindahl
Removing redundant use of casts in MyISAM storage for memcmp(), memcpy(), memset(), and memmove().
661
      memcpy(buff+2+length,father_key_pos, k_length);
1 by brian
clean slate
662
      pos=curr_buff+new_left_length;
212.6.12 by Mats Kindahl
Removing redundant use of casts in MyISAM storage for memcmp(), memcpy(), memset(), and memmove().
663
      memcpy(father_key_pos, pos, k_length);
664
      memcpy(buff+2, pos+k_length, length);
1 by brian
clean slate
665
    }
666
667
    if (_mi_write_keypage(info,keyinfo,next_page,DFLT_INIT_HITS,info->buff) ||
668
	_mi_write_keypage(info,keyinfo,father_page,DFLT_INIT_HITS,father_buff))
669
      goto err;
51.1.115 by Jay Pipes
DBUG symbol removal
670
    return(0);
1 by brian
clean slate
671
  }
672
673
	/* curr_buff[] and buff[] are full, lets split and make new nod */
674
675
  extra_buff=info->buff+info->s->base.max_key_block_length;
676
  new_left_length=new_right_length=2+nod_flag+(keys+1)/3*curr_keylength;
677
  if (keys == 5)				/* Too few keys to balance */
678
    new_left_length-=curr_keylength;
679
  extra_length=nod_flag+left_length+right_length-
680
    new_left_length-new_right_length-curr_keylength;
681
  mi_putint(curr_buff,new_left_length,nod_flag);
682
  mi_putint(buff,new_right_length,nod_flag);
683
  mi_putint(extra_buff,extra_length+2,nod_flag);
684
685
  /* move first largest keys to new page  */
686
  pos=buff+right_length-extra_length;
212.6.12 by Mats Kindahl
Removing redundant use of casts in MyISAM storage for memcmp(), memcpy(), memset(), and memmove().
687
  memcpy(extra_buff+2, pos, extra_length);
1 by brian
clean slate
688
  /* Save new parting key */
689
  memcpy(tmp_part_key, pos-k_length,k_length);
690
  /* Make place for new keys */
481 by Brian Aker
Remove all of uchar.
691
  bmove_upp((unsigned char*) buff+new_right_length,(unsigned char*) pos-k_length,
1 by brian
clean slate
692
	    right_length-extra_length-k_length-2);
693
  /* Copy keys from left page */
694
  pos= curr_buff+new_left_length;
212.6.12 by Mats Kindahl
Removing redundant use of casts in MyISAM storage for memcmp(), memcpy(), memset(), and memmove().
695
  length= left_length - new_left_length - k_length;
696
  memcpy(buff+2, pos+k_length, length);
1 by brian
clean slate
697
  /* Copy old parting key */
212.6.12 by Mats Kindahl
Removing redundant use of casts in MyISAM storage for memcmp(), memcpy(), memset(), and memmove().
698
  memcpy(buff+2+length, father_key_pos, k_length);
1 by brian
clean slate
699
700
  /* Move new parting keys up to caller */
212.6.12 by Mats Kindahl
Removing redundant use of casts in MyISAM storage for memcmp(), memcpy(), memset(), and memmove().
701
  memcpy((right ? key : father_key_pos), pos, k_length);
702
  memcpy((right ? father_key_pos : key), tmp_part_key, k_length);
1 by brian
clean slate
703
704
  if ((new_pos=_mi_new(info,keyinfo,DFLT_INIT_HITS)) == HA_OFFSET_ERROR)
705
    goto err;
706
  _mi_kpointer(info,key+k_length,new_pos);
707
  if (_mi_write_keypage(info,keyinfo,(right ? new_pos : next_page),
708
			DFLT_INIT_HITS,info->buff) ||
709
      _mi_write_keypage(info,keyinfo,(right ? next_page : new_pos),
710
                        DFLT_INIT_HITS,extra_buff))
711
    goto err;
712
51.1.115 by Jay Pipes
DBUG symbol removal
713
  return(1);				/* Middle key up */
1 by brian
clean slate
714
715
err:
51.1.115 by Jay Pipes
DBUG symbol removal
716
  return(-1);
1 by brian
clean slate
717
} /* _mi_balance_page */
718
719
/**********************************************************************
720
 *                Bulk insert code                                    *
721
 **********************************************************************/
722
723
typedef struct {
724
  MI_INFO *info;
482 by Brian Aker
Remove uint.
725
  uint32_t keynr;
1 by brian
clean slate
726
} bulk_insert_param;
727
482 by Brian Aker
Remove uint.
728
int _mi_ck_write_tree(register MI_INFO *info, uint32_t keynr, unsigned char *key,
729
		      uint32_t key_length)
1 by brian
clean slate
730
{
731
  int error;
732
733
  error= tree_insert(&info->bulk_insert[keynr], key,
734
         key_length + info->s->rec_reflength,
735
         info->bulk_insert[keynr].custom_arg) ? 0 : HA_ERR_OUT_OF_MEM ;
736
51.1.115 by Jay Pipes
DBUG symbol removal
737
  return(error);
1 by brian
clean slate
738
} /* _mi_ck_write_tree */
739
740
741
/* typeof(_mi_keys_compare)=qsort_cmp2 */
742
481 by Brian Aker
Remove all of uchar.
743
static int keys_compare(bulk_insert_param *param, unsigned char *key1, unsigned char *key2)
1 by brian
clean slate
744
{
482 by Brian Aker
Remove uint.
745
  uint32_t not_used[2];
1 by brian
clean slate
746
  return ha_key_cmp(param->info->s->keyinfo[param->keynr].seg,
747
                    key1, key2, USE_WHOLE_KEY, SEARCH_SAME,
748
                    not_used);
749
}
750
751
481 by Brian Aker
Remove all of uchar.
752
static int keys_free(unsigned char *key, TREE_FREE mode, bulk_insert_param *param)
1 by brian
clean slate
753
{
754
  /*
755
    Probably I can use info->lastkey here, but I'm not sure,
756
    and to be safe I'd better use local lastkey.
757
  */
481 by Brian Aker
Remove all of uchar.
758
  unsigned char lastkey[MI_MAX_KEY_BUFF];
482 by Brian Aker
Remove uint.
759
  uint32_t keylen;
1 by brian
clean slate
760
  MI_KEYDEF *keyinfo;
761
762
  switch (mode) {
763
  case free_init:
764
    if (param->info->s->concurrent_insert)
765
    {
658 by Brian Aker
Part removal of my_pthread.h
766
      pthread_rwlock_wrlock(&param->info->s->key_root_lock[param->keynr]);
1 by brian
clean slate
767
      param->info->s->keyinfo[param->keynr].version++;
768
    }
769
    return 0;
770
  case free_free:
771
    keyinfo=param->info->s->keyinfo+param->keynr;
772
    keylen=_mi_keylength(keyinfo, key);
773
    memcpy(lastkey, key, keylen);
774
    return _mi_ck_write_btree(param->info,param->keynr,lastkey,
775
			      keylen - param->info->s->rec_reflength);
776
  case free_end:
777
    if (param->info->s->concurrent_insert)
658 by Brian Aker
Part removal of my_pthread.h
778
      pthread_rwlock_unlock(&param->info->s->key_root_lock[param->keynr]);
1 by brian
clean slate
779
    return 0;
780
  }
781
  return -1;
782
}
783
784
303 by Brian Aker
First pass in removing ulong from MyISAM
785
int mi_init_bulk_insert(MI_INFO *info, uint32_t cache_size, ha_rows rows)
1 by brian
clean slate
786
{
787
  MYISAM_SHARE *share=info->s;
788
  MI_KEYDEF *key=share->keyinfo;
789
  bulk_insert_param *params;
482 by Brian Aker
Remove uint.
790
  uint32_t i, num_keys, total_keylength;
151 by Brian Aker
Ulonglong to uint64_t
791
  uint64_t key_map;
1 by brian
clean slate
792
51.1.115 by Jay Pipes
DBUG symbol removal
793
  assert(!info->bulk_insert &&
1 by brian
clean slate
794
	      (!rows || rows >= MI_MIN_ROWS_TO_USE_BULK_INSERT));
795
796
  mi_clear_all_keys_active(key_map);
797
  for (i=total_keylength=num_keys=0 ; i < share->base.keys ; i++)
798
  {
799
    if (! (key[i].flag & HA_NOSAME) && (share->base.auto_key != i + 1) &&
800
        mi_is_key_active(share->state.key_map, i))
801
    {
802
      num_keys++;
803
      mi_set_key_active(key_map, i);
804
      total_keylength+=key[i].maxlength+TREE_ELEMENT_EXTRA_SIZE;
805
    }
806
  }
807
808
  if (num_keys==0 ||
809
      num_keys * MI_MIN_SIZE_BULK_INSERT_TREE > cache_size)
51.1.115 by Jay Pipes
DBUG symbol removal
810
    return(0);
1 by brian
clean slate
811
812
  if (rows && rows*total_keylength < cache_size)
303 by Brian Aker
First pass in removing ulong from MyISAM
813
    cache_size= (uint32_t)rows;
1 by brian
clean slate
814
  else
815
    cache_size/=total_keylength*16;
816
817
  info->bulk_insert=(TREE *)
656.1.25 by Monty Taylor
Removed my_malloc stuff from storage/
818
    malloc((sizeof(TREE)*share->base.keys+
819
           sizeof(bulk_insert_param)*num_keys));
1 by brian
clean slate
820
821
  if (!info->bulk_insert)
51.1.115 by Jay Pipes
DBUG symbol removal
822
    return(HA_ERR_OUT_OF_MEM);
1 by brian
clean slate
823
824
  params=(bulk_insert_param *)(info->bulk_insert+share->base.keys);
825
  for (i=0 ; i < share->base.keys ; i++)
826
  {
827
    if (mi_is_key_active(key_map, i))
828
    {
829
      params->info=info;
830
      params->keynr=i;
831
      /* Only allocate a 16'th of the buffer at a time */
832
      init_tree(&info->bulk_insert[i],
833
                cache_size * key[i].maxlength,
834
                cache_size * key[i].maxlength, 0,
835
		(qsort_cmp2)keys_compare, 0,
836
		(tree_element_free) keys_free, (void *)params++);
837
    }
838
    else
839
     info->bulk_insert[i].root=0;
840
  }
841
51.1.115 by Jay Pipes
DBUG symbol removal
842
  return(0);
1 by brian
clean slate
843
}
844
482 by Brian Aker
Remove uint.
845
void mi_flush_bulk_insert(MI_INFO *info, uint32_t inx)
1 by brian
clean slate
846
{
847
  if (info->bulk_insert)
848
  {
849
    if (is_tree_inited(&info->bulk_insert[inx]))
850
      reset_tree(&info->bulk_insert[inx]);
851
  }
852
}
853
854
void mi_end_bulk_insert(MI_INFO *info)
855
{
856
  if (info->bulk_insert)
857
  {
482 by Brian Aker
Remove uint.
858
    uint32_t i;
1 by brian
clean slate
859
    for (i=0 ; i < info->s->base.keys ; i++)
860
    {
861
      if (is_tree_inited(& info->bulk_insert[i]))
862
      {
863
        delete_tree(& info->bulk_insert[i]);
864
      }
865
    }
477 by Monty Taylor
Removed my_free(). It turns out that it had been def'd to ignore the flags passed to it in the second arg anyway. Gotta love that.
866
    free((void *)info->bulk_insert);
1 by brian
clean slate
867
    info->bulk_insert=0;
868
  }
869
}