~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
17
/**
18
  @file
19
20
  @brief
21
  Functions for easy reading of records, possible through a cache
22
*/
23
24
#include "mysql_priv.h"
25
26
static int rr_quick(READ_RECORD *info);
27
int rr_sequential(READ_RECORD *info);
28
static int rr_from_tempfile(READ_RECORD *info);
29
static int rr_unpack_from_tempfile(READ_RECORD *info);
30
static int rr_unpack_from_buffer(READ_RECORD *info);
31
static int rr_from_pointers(READ_RECORD *info);
32
static int rr_from_cache(READ_RECORD *info);
33
static int init_rr_cache(THD *thd, READ_RECORD *info);
34
static int rr_cmp(uchar *a,uchar *b);
35
static int rr_index_first(READ_RECORD *info);
36
static int rr_index(READ_RECORD *info);
37
38
39
/**
40
  Initialize READ_RECORD structure to perform full index scan (in forward
41
  direction) using read_record.read_record() interface.
42
43
    This function has been added at late stage and is used only by
44
    UPDATE/DELETE. Other statements perform index scans using
45
    join_read_first/next functions.
46
47
  @param info         READ_RECORD structure to initialize.
48
  @param thd          Thread handle
49
  @param table        Table to be accessed
50
  @param print_error  If true, call table->file->print_error() if an error
51
                      occurs (except for end-of-records error)
52
  @param idx          index to scan
53
*/
54
77.1.46 by Monty Taylor
Finished the warnings work!
55
void init_read_record_idx(READ_RECORD *info,
56
                          THD *thd __attribute__((__unused__)),
57
                          TABLE *table,
1 by brian
clean slate
58
                          bool print_error, uint idx)
59
{
60
  empty_record(table);
61
  bzero((char*) info,sizeof(*info));
62
  info->table= table;
63
  info->file=  table->file;
64
  info->record= table->record[0];
65
  info->print_error= print_error;
66
67
  table->status=0;			/* And it's always found */
68
  if (!table->file->inited)
69
    table->file->ha_index_init(idx, 1);
70
  /* read_record will be changed to rr_index in rr_index_first */
71
  info->read_record= rr_index_first;
72
}
73
74
75
/*
76
  init_read_record is used to scan by using a number of different methods.
77
  Which method to use is set-up in this call so that later calls to
78
  the info->read_record will call the appropriate method using a function
79
  pointer.
80
81
  There are five methods that relate completely to the sort function
82
  filesort. The result of a filesort is retrieved using read_record
83
  calls. The other two methods are used for normal table access.
84
85
  The filesort will produce references to the records sorted, these
86
  references can be stored in memory or in a temporary file.
87
88
  The temporary file is normally used when the references doesn't fit into
89
  a properly sized memory buffer. For most small queries the references
90
  are stored in the memory buffer.
91
92
  The temporary file is also used when performing an update where a key is
93
  modified.
94
95
  Methods used when ref's are in memory (using rr_from_pointers):
96
    rr_unpack_from_buffer:
97
    ----------------------
98
      This method is used when table->sort.addon_field is allocated.
99
      This is allocated for most SELECT queries not involving any BLOB's.
100
      In this case the records are fetched from a memory buffer.
101
    rr_from_pointers:
102
    -----------------
103
      Used when the above is not true, UPDATE, DELETE and so forth and
104
      SELECT's involving BLOB's. It is also used when the addon_field
105
      buffer is not allocated due to that its size was bigger than the
106
      session variable max_length_for_sort_data.
107
      In this case the record data is fetched from the handler using the
108
      saved reference using the rnd_pos handler call.
109
110
  Methods used when ref's are in a temporary file (using rr_from_tempfile)
111
    rr_unpack_from_tempfile:
112
    ------------------------
113
      Same as rr_unpack_from_buffer except that references are fetched from
114
      temporary file. Should obviously not really happen other than in
115
      strange configurations.
116
117
    rr_from_tempfile:
118
    -----------------
119
      Same as rr_from_pointers except that references are fetched from
120
      temporary file instead of from 
121
    rr_from_cache:
122
    --------------
123
      This is a special variant of rr_from_tempfile that can be used for
124
      handlers that is not using the HA_FAST_KEY_READ table flag. Instead
125
      of reading the references one by one from the temporary file it reads
126
      a set of them, sorts them and reads all of them into a buffer which
127
      is then used for a number of subsequent calls to rr_from_cache.
128
      It is only used for SELECT queries and a number of other conditions
129
      on table size.
130
131
  All other accesses use either index access methods (rr_quick) or a full
132
  table scan (rr_sequential).
133
  rr_quick:
134
  ---------
135
    rr_quick uses one of the QUICK_SELECT classes in opt_range.cc to
136
    perform an index scan. There are loads of functionality hidden
137
    in these quick classes. It handles all index scans of various kinds.
138
  rr_sequential:
139
  --------------
140
    This is the most basic access method of a table using rnd_init,
141
    rnd_next and rnd_end. No indexes are used.
142
*/
143
void init_read_record(READ_RECORD *info,THD *thd, TABLE *table,
144
		      SQL_SELECT *select,
145
		      int use_record_cache, bool print_error)
146
{
147
  IO_CACHE *tempfile;
148
149
  bzero((char*) info,sizeof(*info));
150
  info->thd=thd;
151
  info->table=table;
152
  info->file= table->file;
153
  info->forms= &info->table;		/* Only one table */
154
  
155
  if (table->s->tmp_table == NON_TRANSACTIONAL_TMP_TABLE &&
156
      !table->sort.addon_field)
157
    VOID(table->file->extra(HA_EXTRA_MMAP));
158
  
159
  if (table->sort.addon_field)
160
  {
161
    info->rec_buf= table->sort.addon_buf;
162
    info->ref_length= table->sort.addon_length;
163
  }
164
  else
165
  {
166
    empty_record(table);
167
    info->record= table->record[0];
168
    info->ref_length= table->file->ref_length;
169
  }
170
  info->select=select;
171
  info->print_error=print_error;
172
  info->ignore_not_found_rows= 0;
173
  table->status=0;			/* And it's always found */
174
175
  if (select && my_b_inited(&select->file))
176
    tempfile= &select->file;
177
  else
178
    tempfile= table->sort.io_cache;
179
  if (tempfile && my_b_inited(tempfile)) // Test if ref-records was used
180
  {
181
    info->read_record= (table->sort.addon_field ?
182
                        rr_unpack_from_tempfile : rr_from_tempfile);
183
    info->io_cache=tempfile;
184
    reinit_io_cache(info->io_cache,READ_CACHE,0L,0,0);
185
    info->ref_pos=table->file->ref;
186
    if (!table->file->inited)
187
      table->file->ha_rnd_init(0);
188
189
    /*
190
      table->sort.addon_field is checked because if we use addon fields,
191
      it doesn't make sense to use cache - we don't read from the table
192
      and table->sort.io_cache is read sequentially
193
    */
194
    if (!table->sort.addon_field &&
195
        ! (specialflag & SPECIAL_SAFE_MODE) &&
196
	thd->variables.read_rnd_buff_size &&
197
	!(table->file->ha_table_flags() & HA_FAST_KEY_READ) &&
198
	(table->db_stat & HA_READ_ONLY ||
199
	 table->reginfo.lock_type <= TL_READ_NO_INSERT) &&
151 by Brian Aker
Ulonglong to uint64_t
200
	(uint64_t) table->s->reclength* (table->file->stats.records+
1 by brian
clean slate
201
                                          table->file->stats.deleted) >
151 by Brian Aker
Ulonglong to uint64_t
202
	(uint64_t) MIN_FILE_LENGTH_TO_USE_ROW_CACHE &&
1 by brian
clean slate
203
	info->io_cache->end_of_file/info->ref_length * table->s->reclength >
204
	(my_off_t) MIN_ROWS_TO_USE_TABLE_CACHE &&
205
	!table->s->blob_fields &&
206
        info->ref_length <= MAX_REFLENGTH)
207
    {
208
      if (! init_rr_cache(thd, info))
209
      {
210
	info->read_record=rr_from_cache;
211
      }
212
    }
213
  }
214
  else if (select && select->quick)
215
  {
216
    info->read_record=rr_quick;
217
  }
218
  else if (table->sort.record_pointers)
219
  {
220
    table->file->ha_rnd_init(0);
221
    info->cache_pos=table->sort.record_pointers;
222
    info->cache_end=info->cache_pos+ 
223
                    table->sort.found_records*info->ref_length;
224
    info->read_record= (table->sort.addon_field ?
225
                        rr_unpack_from_buffer : rr_from_pointers);
226
  }
227
  else
228
  {
229
    info->read_record=rr_sequential;
230
    table->file->ha_rnd_init(1);
231
    /* We can use record cache if we don't update dynamic length tables */
232
    if (!table->no_cache &&
233
	(use_record_cache > 0 ||
234
	 (int) table->reginfo.lock_type <= (int) TL_READ_HIGH_PRIORITY ||
235
	 !(table->s->db_options_in_use & HA_OPTION_PACK_RECORD) ||
236
	 (use_record_cache < 0 &&
237
	  !(table->file->ha_table_flags() & HA_NOT_DELETE_WITH_CACHE))))
238
      VOID(table->file->extra_opt(HA_EXTRA_CACHE,
239
				  thd->variables.read_buff_size));
240
  }
241
  /* 
242
    Do condition pushdown for UPDATE/DELETE.
243
    TODO: Remove this from here as it causes two condition pushdown calls 
244
    when we're running a SELECT and the condition cannot be pushed down.
245
  */
246
  if (thd->variables.engine_condition_pushdown && 
247
      select && select->cond && 
248
      (select->cond->used_tables() & table->map) &&
249
      !table->file->pushed_cond)
250
    table->file->cond_push(select->cond);
251
51.1.4 by Jay Pipes
Removed all DBUG_XXX content from records.cc. Builds/tests run fine. On to next file...
252
  return;
1 by brian
clean slate
253
} /* init_read_record */
254
255
256
257
void end_read_record(READ_RECORD *info)
258
{                   /* free cache if used */
259
  if (info->cache)
260
  {
261
    my_free_lock((char*) info->cache,MYF(0));
262
    info->cache=0;
263
  }
264
  if (info->table)
265
  {
266
    filesort_free_buffers(info->table,0);
267
    (void) info->file->extra(HA_EXTRA_NO_CACHE);
268
    if (info->read_record != rr_quick) // otherwise quick_range does it
269
      (void) info->file->ha_index_or_rnd_end();
270
    info->table=0;
271
  }
272
}
273
274
static int rr_handle_error(READ_RECORD *info, int error)
275
{
276
  if (error == HA_ERR_END_OF_FILE)
277
    error= -1;
278
  else
279
  {
280
    if (info->print_error)
281
      info->table->file->print_error(error, MYF(0));
282
    if (error < 0)                            // Fix negative BDB errno
283
      error= 1;
284
  }
285
  return error;
286
}
287
288
289
/** Read a record from head-database. */
290
291
static int rr_quick(READ_RECORD *info)
292
{
293
  int tmp;
294
  while ((tmp= info->select->quick->get_next()))
295
  {
296
    if (info->thd->killed)
297
    {
298
      my_error(ER_SERVER_SHUTDOWN, MYF(0));
299
      return 1;
300
    }
301
    if (tmp != HA_ERR_RECORD_DELETED)
302
    {
303
      tmp= rr_handle_error(info, tmp);
304
      break;
305
    }
306
  }
307
  return tmp;
308
}
309
310
311
/**
312
  Reads first row in an index scan.
313
314
  @param info  	Scan info
315
316
  @retval
317
    0   Ok
318
  @retval
319
    -1   End of records
320
  @retval
321
    1   Error
322
*/
323
324
static int rr_index_first(READ_RECORD *info)
325
{
326
  int tmp= info->file->index_first(info->record);
327
  info->read_record= rr_index;
328
  if (tmp)
329
    tmp= rr_handle_error(info, tmp);
330
  return tmp;
331
}
332
333
334
/**
335
  Reads index sequentially after first row.
336
337
  Read the next index record (in forward direction) and translate return
338
  value.
339
340
  @param info  Scan info
341
342
  @retval
343
    0   Ok
344
  @retval
345
    -1   End of records
346
  @retval
347
    1   Error
348
*/
349
350
static int rr_index(READ_RECORD *info)
351
{
352
  int tmp= info->file->index_next(info->record);
353
  if (tmp)
354
    tmp= rr_handle_error(info, tmp);
355
  return tmp;
356
}
357
358
359
int rr_sequential(READ_RECORD *info)
360
{
361
  int tmp;
362
  while ((tmp=info->file->rnd_next(info->record)))
363
  {
364
    if (info->thd->killed)
365
    {
366
      info->thd->send_kill_message();
367
      return 1;
368
    }
369
    /*
370
      rnd_next can return RECORD_DELETED for MyISAM when one thread is
371
      reading and another deleting without locks.
372
    */
373
    if (tmp != HA_ERR_RECORD_DELETED)
374
    {
375
      tmp= rr_handle_error(info, tmp);
376
      break;
377
    }
378
  }
379
  return tmp;
380
}
381
382
383
static int rr_from_tempfile(READ_RECORD *info)
384
{
385
  int tmp;
386
  for (;;)
387
  {
388
    if (my_b_read(info->io_cache,info->ref_pos,info->ref_length))
389
      return -1;					/* End of file */
390
    if (!(tmp=info->file->rnd_pos(info->record,info->ref_pos)))
391
      break;
392
    /* The following is extremely unlikely to happen */
393
    if (tmp == HA_ERR_RECORD_DELETED ||
394
        (tmp == HA_ERR_KEY_NOT_FOUND && info->ignore_not_found_rows))
395
      continue;
396
    tmp= rr_handle_error(info, tmp);
397
    break;
398
  }
399
  return tmp;
400
} /* rr_from_tempfile */
401
402
403
/**
404
  Read a result set record from a temporary file after sorting.
405
406
  The function first reads the next sorted record from the temporary file.
407
  into a buffer. If a success it calls a callback function that unpacks 
408
  the fields values use in the result set from this buffer into their
409
  positions in the regular record buffer.
410
411
  @param info          Reference to the context including record descriptors
412
413
  @retval
414
    0   Record successfully read.
415
  @retval
416
    -1   There is no record to be read anymore.
417
*/
418
419
static int rr_unpack_from_tempfile(READ_RECORD *info)
420
{
421
  if (my_b_read(info->io_cache, info->rec_buf, info->ref_length))
422
    return -1;
423
  TABLE *table= info->table;
424
  (*table->sort.unpack)(table->sort.addon_field, info->rec_buf);
425
426
  return 0;
427
}
428
429
static int rr_from_pointers(READ_RECORD *info)
430
{
431
  int tmp;
432
  uchar *cache_pos;
433
434
  for (;;)
435
  {
436
    if (info->cache_pos == info->cache_end)
437
      return -1;					/* End of file */
438
    cache_pos= info->cache_pos;
439
    info->cache_pos+= info->ref_length;
440
441
    if (!(tmp=info->file->rnd_pos(info->record,cache_pos)))
442
      break;
443
444
    /* The following is extremely unlikely to happen */
445
    if (tmp == HA_ERR_RECORD_DELETED ||
446
        (tmp == HA_ERR_KEY_NOT_FOUND && info->ignore_not_found_rows))
447
      continue;
448
    tmp= rr_handle_error(info, tmp);
449
    break;
450
  }
451
  return tmp;
452
}
453
454
/**
455
  Read a result set record from a buffer after sorting.
456
457
  The function first reads the next sorted record from the sort buffer.
458
  If a success it calls a callback function that unpacks 
459
  the fields values use in the result set from this buffer into their
460
  positions in the regular record buffer.
461
462
  @param info          Reference to the context including record descriptors
463
464
  @retval
465
    0   Record successfully read.
466
  @retval
467
    -1   There is no record to be read anymore.
468
*/
469
470
static int rr_unpack_from_buffer(READ_RECORD *info)
471
{
472
  if (info->cache_pos == info->cache_end)
473
    return -1;                      /* End of buffer */
474
  TABLE *table= info->table;
475
  (*table->sort.unpack)(table->sort.addon_field, info->cache_pos);
476
  info->cache_pos+= info->ref_length;
477
478
  return 0;
479
}
480
	/* cacheing of records from a database */
481
482
static int init_rr_cache(THD *thd, READ_RECORD *info)
483
{
484
  uint rec_cache_size;
485
486
  info->struct_length= 3+MAX_REFLENGTH;
487
  info->reclength= ALIGN_SIZE(info->table->s->reclength+1);
488
  if (info->reclength < info->struct_length)
489
    info->reclength= ALIGN_SIZE(info->struct_length);
490
491
  info->error_offset= info->table->s->reclength;
492
  info->cache_records= (thd->variables.read_rnd_buff_size /
493
                        (info->reclength+info->struct_length));
494
  rec_cache_size= info->cache_records*info->reclength;
495
  info->rec_cache_size= info->cache_records*info->ref_length;
496
497
  // We have to allocate one more byte to use uint3korr (see comments for it)
498
  if (info->cache_records <= 2 ||
499
      !(info->cache=(uchar*) my_malloc_lock(rec_cache_size+info->cache_records*
500
					   info->struct_length+1,
501
					   MYF(0))))
51.1.4 by Jay Pipes
Removed all DBUG_XXX content from records.cc. Builds/tests run fine. On to next file...
502
    return(1);
1 by brian
clean slate
503
#ifdef HAVE_purify
504
  // Avoid warnings in qsort
505
  bzero(info->cache,rec_cache_size+info->cache_records* info->struct_length+1);
506
#endif
507
  info->read_positions=info->cache+rec_cache_size;
508
  info->cache_pos=info->cache_end=info->cache;
51.1.4 by Jay Pipes
Removed all DBUG_XXX content from records.cc. Builds/tests run fine. On to next file...
509
  return(0);
1 by brian
clean slate
510
} /* init_rr_cache */
511
512
513
static int rr_from_cache(READ_RECORD *info)
514
{
515
  register uint i;
516
  ulong length;
517
  my_off_t rest_of_file;
518
  int16 error;
519
  uchar *position,*ref_position,*record_pos;
520
  ulong record;
521
522
  for (;;)
523
  {
524
    if (info->cache_pos != info->cache_end)
525
    {
526
      if (info->cache_pos[info->error_offset])
527
      {
528
	shortget(error,info->cache_pos);
529
	if (info->print_error)
530
	  info->table->file->print_error(error,MYF(0));
531
      }
532
      else
533
      {
534
	error=0;
535
	memcpy(info->record,info->cache_pos,
536
               (size_t) info->table->s->reclength);
537
      }
538
      info->cache_pos+=info->reclength;
539
      return ((int) error);
540
    }
541
    length=info->rec_cache_size;
542
    rest_of_file=info->io_cache->end_of_file - my_b_tell(info->io_cache);
543
    if ((my_off_t) length > rest_of_file)
544
      length= (ulong) rest_of_file;
545
    if (!length || my_b_read(info->io_cache,info->cache,length))
546
    {
547
      return -1;			/* End of file */
548
    }
549
550
    length/=info->ref_length;
551
    position=info->cache;
552
    ref_position=info->read_positions;
553
    for (i=0 ; i < length ; i++,position+=info->ref_length)
554
    {
555
      memcpy(ref_position,position,(size_t) info->ref_length);
556
      ref_position+=MAX_REFLENGTH;
557
      int3store(ref_position,(long) i);
558
      ref_position+=3;
559
    }
560
    my_qsort(info->read_positions, length, info->struct_length,
561
             (qsort_cmp) rr_cmp);
562
563
    position=info->read_positions;
564
    for (i=0 ; i < length ; i++)
565
    {
566
      memcpy(info->ref_pos,position,(size_t) info->ref_length);
567
      position+=MAX_REFLENGTH;
568
      record=uint3korr(position);
569
      position+=3;
570
      record_pos=info->cache+record*info->reclength;
571
      if ((error=(int16) info->file->rnd_pos(record_pos,info->ref_pos)))
572
      {
573
	record_pos[info->error_offset]=1;
574
	shortstore(record_pos,error);
575
      }
576
      else
577
	record_pos[info->error_offset]=0;
578
    }
579
    info->cache_end=(info->cache_pos=info->cache)+length*info->reclength;
580
  }
581
} /* rr_from_cache */
582
583
584
static int rr_cmp(uchar *a,uchar *b)
585
{
586
  if (a[0] != b[0])
587
    return (int) a[0] - (int) b[0];
588
  if (a[1] != b[1])
589
    return (int) a[1] - (int) b[1];
590
  if (a[2] != b[2])
591
    return (int) a[2] - (int) b[2];
592
#if MAX_REFLENGTH == 4
593
  return (int) a[3] - (int) b[3];
594
#else
595
  if (a[3] != b[3])
596
    return (int) a[3] - (int) b[3];
597
  if (a[4] != b[4])
598
    return (int) a[4] - (int) b[4];
599
  if (a[5] != b[5])
600
    return (int) a[1] - (int) b[5];
601
  if (a[6] != b[6])
602
    return (int) a[6] - (int) b[6];
603
  return (int) a[7] - (int) b[7];
604
#endif
605
}