~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to sql/records.cc

  • Committer: brian
  • Date: 2008-06-25 05:29:13 UTC
  • Revision ID: brian@localhost.localdomain-20080625052913-6upwo0jsrl4lnapl
clean slate

Show diffs side-by-side

added added

removed removed

Lines of Context:
20
20
  @brief
21
21
  Functions for easy reading of records, possible through a cache
22
22
*/
23
 
#include <drizzled/server_includes.h>
24
 
#include <drizzled/error.h>
25
 
#include <drizzled/table.h>
26
 
#include <drizzled/session.h>
 
23
 
 
24
#include "mysql_priv.h"
27
25
 
28
26
static int rr_quick(READ_RECORD *info);
29
27
int rr_sequential(READ_RECORD *info);
32
30
static int rr_unpack_from_buffer(READ_RECORD *info);
33
31
static int rr_from_pointers(READ_RECORD *info);
34
32
static int rr_from_cache(READ_RECORD *info);
35
 
static int init_rr_cache(Session *session, READ_RECORD *info);
36
 
static int rr_cmp(unsigned char *a,unsigned char *b);
 
33
static int init_rr_cache(THD *thd, READ_RECORD *info);
 
34
static int rr_cmp(uchar *a,uchar *b);
37
35
static int rr_index_first(READ_RECORD *info);
38
36
static int rr_index(READ_RECORD *info);
39
37
 
47
45
    join_read_first/next functions.
48
46
 
49
47
  @param info         READ_RECORD structure to initialize.
50
 
  @param session          Thread handle
 
48
  @param thd          Thread handle
51
49
  @param table        Table to be accessed
52
50
  @param print_error  If true, call table->file->print_error() if an error
53
51
                      occurs (except for end-of-records error)
54
52
  @param idx          index to scan
55
53
*/
56
54
 
57
 
void init_read_record_idx(READ_RECORD *info, Session *, Table *table,
58
 
                          bool print_error, uint32_t idx)
 
55
void init_read_record_idx(READ_RECORD *info, THD *thd, TABLE *table,
 
56
                          bool print_error, uint idx)
59
57
{
60
58
  empty_record(table);
61
 
  memset(info, 0, sizeof(*info));
 
59
  bzero((char*) info,sizeof(*info));
62
60
  info->table= table;
63
61
  info->file=  table->file;
64
62
  info->record= table->record[0];
117
115
    rr_from_tempfile:
118
116
    -----------------
119
117
      Same as rr_from_pointers except that references are fetched from
120
 
      temporary file instead of from
 
118
      temporary file instead of from 
121
119
    rr_from_cache:
122
120
    --------------
123
121
      This is a special variant of rr_from_tempfile that can be used for
140
138
    This is the most basic access method of a table using rnd_init,
141
139
    rnd_next and rnd_end. No indexes are used.
142
140
*/
143
 
void init_read_record(READ_RECORD *info,Session *session, Table *table,
 
141
void init_read_record(READ_RECORD *info,THD *thd, TABLE *table,
144
142
                      SQL_SELECT *select,
145
143
                      int use_record_cache, bool print_error)
146
144
{
147
145
  IO_CACHE *tempfile;
 
146
  DBUG_ENTER("init_read_record");
148
147
 
149
 
  memset(info, 0, sizeof(*info));
150
 
  info->session=session;
 
148
  bzero((char*) info,sizeof(*info));
 
149
  info->thd=thd;
151
150
  info->table=table;
152
151
  info->file= table->file;
153
152
  info->forms= &info->table;            /* Only one table */
154
 
 
 
153
  
155
154
  if (table->s->tmp_table == NON_TRANSACTIONAL_TMP_TABLE &&
156
155
      !table->sort.addon_field)
157
 
    table->file->extra(HA_EXTRA_MMAP);
158
 
 
 
156
    VOID(table->file->extra(HA_EXTRA_MMAP));
 
157
  
159
158
  if (table->sort.addon_field)
160
159
  {
161
160
    info->rec_buf= table->sort.addon_buf;
178
177
    tempfile= table->sort.io_cache;
179
178
  if (tempfile && my_b_inited(tempfile)) // Test if ref-records was used
180
179
  {
 
180
    DBUG_PRINT("info",("using rr_from_tempfile"));
181
181
    info->read_record= (table->sort.addon_field ?
182
182
                        rr_unpack_from_tempfile : rr_from_tempfile);
183
183
    info->io_cache=tempfile;
192
192
      and table->sort.io_cache is read sequentially
193
193
    */
194
194
    if (!table->sort.addon_field &&
195
 
        session->variables.read_rnd_buff_size &&
 
195
        ! (specialflag & SPECIAL_SAFE_MODE) &&
 
196
        thd->variables.read_rnd_buff_size &&
196
197
        !(table->file->ha_table_flags() & HA_FAST_KEY_READ) &&
197
198
        (table->db_stat & HA_READ_ONLY ||
198
199
         table->reginfo.lock_type <= TL_READ_NO_INSERT) &&
199
 
        (uint64_t) table->s->reclength* (table->file->stats.records+
 
200
        (ulonglong) table->s->reclength* (table->file->stats.records+
200
201
                                          table->file->stats.deleted) >
201
 
        (uint64_t) MIN_FILE_LENGTH_TO_USE_ROW_CACHE &&
 
202
        (ulonglong) MIN_FILE_LENGTH_TO_USE_ROW_CACHE &&
202
203
        info->io_cache->end_of_file/info->ref_length * table->s->reclength >
203
204
        (my_off_t) MIN_ROWS_TO_USE_TABLE_CACHE &&
204
205
        !table->s->blob_fields &&
205
206
        info->ref_length <= MAX_REFLENGTH)
206
207
    {
207
 
      if (! init_rr_cache(session, info))
 
208
      if (! init_rr_cache(thd, info))
208
209
      {
 
210
        DBUG_PRINT("info",("using rr_from_cache"));
209
211
        info->read_record=rr_from_cache;
210
212
      }
211
213
    }
212
214
  }
213
215
  else if (select && select->quick)
214
216
  {
 
217
    DBUG_PRINT("info",("using rr_quick"));
215
218
    info->read_record=rr_quick;
216
219
  }
217
220
  else if (table->sort.record_pointers)
218
221
  {
 
222
    DBUG_PRINT("info",("using record_pointers"));
219
223
    table->file->ha_rnd_init(0);
220
224
    info->cache_pos=table->sort.record_pointers;
221
 
    info->cache_end=info->cache_pos+
 
225
    info->cache_end=info->cache_pos+ 
222
226
                    table->sort.found_records*info->ref_length;
223
227
    info->read_record= (table->sort.addon_field ?
224
228
                        rr_unpack_from_buffer : rr_from_pointers);
225
229
  }
226
230
  else
227
231
  {
 
232
    DBUG_PRINT("info",("using rr_sequential"));
228
233
    info->read_record=rr_sequential;
229
234
    table->file->ha_rnd_init(1);
230
235
    /* We can use record cache if we don't update dynamic length tables */
234
239
         !(table->s->db_options_in_use & HA_OPTION_PACK_RECORD) ||
235
240
         (use_record_cache < 0 &&
236
241
          !(table->file->ha_table_flags() & HA_NOT_DELETE_WITH_CACHE))))
237
 
      table->file->extra_opt(HA_EXTRA_CACHE, session->variables.read_buff_size);
 
242
      VOID(table->file->extra_opt(HA_EXTRA_CACHE,
 
243
                                  thd->variables.read_buff_size));
238
244
  }
239
 
  /*
 
245
  /* 
240
246
    Do condition pushdown for UPDATE/DELETE.
241
 
    TODO: Remove this from here as it causes two condition pushdown calls
 
247
    TODO: Remove this from here as it causes two condition pushdown calls 
242
248
    when we're running a SELECT and the condition cannot be pushed down.
243
249
  */
244
 
  if (session->variables.engine_condition_pushdown &&
245
 
      select && select->cond &&
 
250
  if (thd->variables.engine_condition_pushdown && 
 
251
      select && select->cond && 
246
252
      (select->cond->used_tables() & table->map) &&
247
253
      !table->file->pushed_cond)
248
254
    table->file->cond_push(select->cond);
249
255
 
250
 
  return;
 
256
  DBUG_VOID_RETURN;
251
257
} /* init_read_record */
252
258
 
253
259
 
256
262
{                   /* free cache if used */
257
263
  if (info->cache)
258
264
  {
259
 
    free((char*) info->cache);
 
265
    my_free_lock((char*) info->cache,MYF(0));
260
266
    info->cache=0;
261
267
  }
262
268
  if (info->table)
291
297
  int tmp;
292
298
  while ((tmp= info->select->quick->get_next()))
293
299
  {
294
 
    if (info->session->killed)
 
300
    if (info->thd->killed)
295
301
    {
296
302
      my_error(ER_SERVER_SHUTDOWN, MYF(0));
297
303
      return 1;
302
308
      break;
303
309
    }
304
310
  }
305
 
  update_virtual_fields_marked_for_write(info->table);
306
311
  return tmp;
307
312
}
308
313
 
358
363
int rr_sequential(READ_RECORD *info)
359
364
{
360
365
  int tmp;
361
 
  while ((tmp= info->file->rnd_next(info->record)))
 
366
  while ((tmp=info->file->rnd_next(info->record)))
362
367
  {
363
 
    if (info->session->killed)
 
368
    if (info->thd->killed)
364
369
    {
365
 
      info->session->send_kill_message();
 
370
      info->thd->send_kill_message();
366
371
      return 1;
367
372
    }
368
373
    /*
369
 
      TODO> Fix this so that engine knows how to behave on its own.
370
374
      rnd_next can return RECORD_DELETED for MyISAM when one thread is
371
375
      reading and another deleting without locks.
372
376
    */
376
380
      break;
377
381
    }
378
382
  }
379
 
  if (!tmp)
380
 
    update_virtual_fields_marked_for_write(info->table);
381
383
  return tmp;
382
384
}
383
385
 
406
408
  Read a result set record from a temporary file after sorting.
407
409
 
408
410
  The function first reads the next sorted record from the temporary file.
409
 
  into a buffer. If a success it calls a callback function that unpacks
 
411
  into a buffer. If a success it calls a callback function that unpacks 
410
412
  the fields values use in the result set from this buffer into their
411
413
  positions in the regular record buffer.
412
414
 
422
424
{
423
425
  if (my_b_read(info->io_cache, info->rec_buf, info->ref_length))
424
426
    return -1;
425
 
  Table *table= info->table;
 
427
  TABLE *table= info->table;
426
428
  (*table->sort.unpack)(table->sort.addon_field, info->rec_buf);
427
429
 
428
430
  return 0;
431
433
static int rr_from_pointers(READ_RECORD *info)
432
434
{
433
435
  int tmp;
434
 
  unsigned char *cache_pos;
 
436
  uchar *cache_pos;
435
437
 
436
438
  for (;;)
437
439
  {
457
459
  Read a result set record from a buffer after sorting.
458
460
 
459
461
  The function first reads the next sorted record from the sort buffer.
460
 
  If a success it calls a callback function that unpacks
 
462
  If a success it calls a callback function that unpacks 
461
463
  the fields values use in the result set from this buffer into their
462
464
  positions in the regular record buffer.
463
465
 
473
475
{
474
476
  if (info->cache_pos == info->cache_end)
475
477
    return -1;                      /* End of buffer */
476
 
  Table *table= info->table;
 
478
  TABLE *table= info->table;
477
479
  (*table->sort.unpack)(table->sort.addon_field, info->cache_pos);
478
480
  info->cache_pos+= info->ref_length;
479
481
 
481
483
}
482
484
        /* cacheing of records from a database */
483
485
 
484
 
static int init_rr_cache(Session *session, READ_RECORD *info)
 
486
static int init_rr_cache(THD *thd, READ_RECORD *info)
485
487
{
486
 
  uint32_t rec_cache_size;
 
488
  uint rec_cache_size;
 
489
  DBUG_ENTER("init_rr_cache");
487
490
 
488
491
  info->struct_length= 3+MAX_REFLENGTH;
489
492
  info->reclength= ALIGN_SIZE(info->table->s->reclength+1);
491
494
    info->reclength= ALIGN_SIZE(info->struct_length);
492
495
 
493
496
  info->error_offset= info->table->s->reclength;
494
 
  info->cache_records= (session->variables.read_rnd_buff_size /
 
497
  info->cache_records= (thd->variables.read_rnd_buff_size /
495
498
                        (info->reclength+info->struct_length));
496
499
  rec_cache_size= info->cache_records*info->reclength;
497
500
  info->rec_cache_size= info->cache_records*info->ref_length;
498
501
 
499
502
  // We have to allocate one more byte to use uint3korr (see comments for it)
500
503
  if (info->cache_records <= 2 ||
501
 
      !(info->cache=(unsigned char*) malloc(rec_cache_size+info->cache_records*
502
 
                                            info->struct_length+1)))
503
 
    return(1);
 
504
      !(info->cache=(uchar*) my_malloc_lock(rec_cache_size+info->cache_records*
 
505
                                           info->struct_length+1,
 
506
                                           MYF(0))))
 
507
    DBUG_RETURN(1);
504
508
#ifdef HAVE_purify
505
509
  // Avoid warnings in qsort
506
 
  memset(info->cache, 0,
507
 
         rec_cache_size+info->cache_records* info->struct_length+1);
 
510
  bzero(info->cache,rec_cache_size+info->cache_records* info->struct_length+1);
508
511
#endif
 
512
  DBUG_PRINT("info",("Allocated buffert for %d records",info->cache_records));
509
513
  info->read_positions=info->cache+rec_cache_size;
510
514
  info->cache_pos=info->cache_end=info->cache;
511
 
  return(0);
 
515
  DBUG_RETURN(0);
512
516
} /* init_rr_cache */
513
517
 
514
518
 
515
519
static int rr_from_cache(READ_RECORD *info)
516
520
{
517
 
  register uint32_t i;
518
 
  uint32_t length;
 
521
  register uint i;
 
522
  ulong length;
519
523
  my_off_t rest_of_file;
520
 
  int16_t error;
521
 
  unsigned char *position,*ref_position,*record_pos;
522
 
  uint32_t record;
 
524
  int16 error;
 
525
  uchar *position,*ref_position,*record_pos;
 
526
  ulong record;
523
527
 
524
528
  for (;;)
525
529
  {
543
547
    length=info->rec_cache_size;
544
548
    rest_of_file=info->io_cache->end_of_file - my_b_tell(info->io_cache);
545
549
    if ((my_off_t) length > rest_of_file)
546
 
      length= (uint32_t) rest_of_file;
 
550
      length= (ulong) rest_of_file;
547
551
    if (!length || my_b_read(info->io_cache,info->cache,length))
548
552
    {
 
553
      DBUG_PRINT("info",("Found end of file"));
549
554
      return -1;                        /* End of file */
550
555
    }
551
556
 
570
575
      record=uint3korr(position);
571
576
      position+=3;
572
577
      record_pos=info->cache+record*info->reclength;
573
 
      if ((error=(int16_t) info->file->rnd_pos(record_pos,info->ref_pos)))
 
578
      if ((error=(int16) info->file->rnd_pos(record_pos,info->ref_pos)))
574
579
      {
575
580
        record_pos[info->error_offset]=1;
576
581
        shortstore(record_pos,error);
 
582
        DBUG_PRINT("error",("Got error: %d:%d when reading row",
 
583
                            my_errno, error));
577
584
      }
578
585
      else
579
586
        record_pos[info->error_offset]=0;
583
590
} /* rr_from_cache */
584
591
 
585
592
 
586
 
static int rr_cmp(unsigned char *a,unsigned char *b)
 
593
static int rr_cmp(uchar *a,uchar *b)
587
594
{
588
595
  if (a[0] != b[0])
589
596
    return (int) a[0] - (int) b[0];