20
20
Functions for easy reading of records, possible through a cache
23
#include "drizzled/error.h"
24
#include "drizzled/table.h"
25
#include "drizzled/session.h"
26
#include "drizzled/records.h"
27
#include "drizzled/optimizer/range.h"
28
#include "drizzled/internal/my_sys.h"
29
#include "drizzled/internal/iocache.h"
30
#include "drizzled/drizzled.h"
35
static int rr_sequential(ReadRecord *info);
36
static int rr_quick(ReadRecord *info);
37
static int rr_from_tempfile(ReadRecord *info);
38
static int rr_unpack_from_tempfile(ReadRecord *info);
39
static int rr_unpack_from_buffer(ReadRecord *info);
40
static int rr_from_pointers(ReadRecord *info);
41
static int rr_from_cache(ReadRecord *info);
22
#include <drizzled/server_includes.h>
23
#include <drizzled/error.h>
24
#include <drizzled/table.h>
25
#include <drizzled/session.h>
27
int rr_sequential(READ_RECORD *info);
28
static int rr_quick(READ_RECORD *info);
29
static int rr_from_tempfile(READ_RECORD *info);
30
static int rr_unpack_from_tempfile(READ_RECORD *info);
31
static int rr_unpack_from_buffer(READ_RECORD *info);
32
static int rr_from_pointers(READ_RECORD *info);
33
static int rr_from_cache(READ_RECORD *info);
34
static int init_rr_cache(Session *session, READ_RECORD *info);
42
35
static int rr_cmp(unsigned char *a,unsigned char *b);
43
static int rr_index_first(ReadRecord *info);
44
static int rr_index(ReadRecord *info);
46
void ReadRecord::init_reard_record_sequential()
48
read_record= rr_sequential;
51
void ReadRecord::init_read_record_idx(Session *,
56
table_arg->emptyRecord();
58
cursor= table->cursor;
59
record= table->getInsertRecord();
60
print_error= print_error_arg;
36
static int rr_index_first(READ_RECORD *info);
37
static int rr_index(READ_RECORD *info);
40
Initialize READ_RECORD structure to perform full index scan (in forward
41
direction) using read_record.read_record() interface.
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.
47
@param info READ_RECORD structure to initialize.
48
@param session 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
54
void init_read_record_idx(READ_RECORD *info,
61
memset(info, 0, sizeof(*info));
63
info->file= table->file;
64
info->record= table->record[0];
65
info->print_error= print_error;
62
67
table->status=0; /* And it's always found */
63
if (not table->cursor->inited)
64
table->cursor->startIndexScan(idx, 1);
68
if (!table->file->inited)
69
table->file->ha_index_init(idx, 1);
65
70
/* read_record will be changed to rr_index in rr_index_first */
66
read_record= rr_index_first;
71
info->read_record= rr_index_first;
70
void ReadRecord::init_read_record(Session *session_arg,
72
optimizer::SqlSelect *select_arg,
75
init_read_record is used to scan by using a number of different methods.
76
Which method to use is set-up in this call so that later calls to
77
the info->read_record will call the appropriate method using a function
80
There are five methods that relate completely to the sort function
81
filesort. The result of a filesort is retrieved using read_record
82
calls. The other two methods are used for normal table access.
84
The filesort will produce references to the records sorted, these
85
references can be stored in memory or in a temporary file.
87
The temporary file is normally used when the references doesn't fit into
88
a properly sized memory buffer. For most small queries the references
89
are stored in the memory buffer.
91
The temporary file is also used when performing an update where a key is
94
Methods used when ref's are in memory (using rr_from_pointers):
95
rr_unpack_from_buffer:
96
----------------------
97
This method is used when table->sort.addon_field is allocated.
98
This is allocated for most SELECT queries not involving any BLOB's.
99
In this case the records are fetched from a memory buffer.
102
Used when the above is not true, UPDATE, DELETE and so forth and
103
SELECT's involving BLOB's. It is also used when the addon_field
104
buffer is not allocated due to that its size was bigger than the
105
session variable max_length_for_sort_data.
106
In this case the record data is fetched from the handler using the
107
saved reference using the rnd_pos handler call.
109
Methods used when ref's are in a temporary file (using rr_from_tempfile)
110
rr_unpack_from_tempfile:
111
------------------------
112
Same as rr_unpack_from_buffer except that references are fetched from
113
temporary file. Should obviously not really happen other than in
114
strange configurations.
118
Same as rr_from_pointers except that references are fetched from
119
temporary file instead of from
122
This is a special variant of rr_from_tempfile that can be used for
123
handlers that is not using the HA_FAST_KEY_READ table flag. Instead
124
of reading the references one by one from the temporary file it reads
125
a set of them, sorts them and reads all of them into a buffer which
126
is then used for a number of subsequent calls to rr_from_cache.
127
It is only used for SELECT queries and a number of other conditions
130
All other accesses use either index access methods (rr_quick) or a full
131
table scan (rr_sequential).
134
rr_quick uses one of the QUICK_SELECT classes in opt_range.cc to
135
perform an index scan. There are loads of functionality hidden
136
in these quick classes. It handles all index scans of various kinds.
139
This is the most basic access method of a table using rnd_init,
140
rnd_next and rnd_end. No indexes are used.
142
void init_read_record(READ_RECORD *info,
146
int use_record_cache,
76
internal::IO_CACHE *tempfile;
80
cursor= table->cursor;
81
forms= &table; /* Only one table */
151
memset(info, 0, sizeof(*info));
152
info->session=session;
154
info->file= table->file;
155
info->forms= &info->table; /* Only one table */
157
if (table->s->tmp_table == NON_TRANSACTIONAL_TMP_TABLE &&
158
!table->sort.addon_field)
159
table->file->extra(HA_EXTRA_MMAP);
83
161
if (table->sort.addon_field)
85
rec_buf= table->sort.addon_buf;
86
ref_length= table->sort.addon_length;
163
info->rec_buf= table->sort.addon_buf;
164
info->ref_length= table->sort.addon_length;
90
168
table->emptyRecord();
91
record= table->getInsertRecord();
92
ref_length= table->cursor->ref_length;
169
info->record= table->record[0];
170
info->ref_length= table->file->ref_length;
95
print_error= print_error_arg;
96
ignore_not_found_rows= 0;
173
info->print_error=print_error;
174
info->ignore_not_found_rows= 0;
97
175
table->status=0; /* And it's always found */
99
if (select && my_b_inited(select->file))
101
tempfile= select->file;
177
if (select && my_b_inited(&select->file))
178
tempfile= &select->file;
105
180
tempfile= table->sort.io_cache;
108
181
if (tempfile && my_b_inited(tempfile)) // Test if ref-records was used
110
read_record= (table->sort.addon_field ?
111
rr_unpack_from_tempfile : rr_from_tempfile);
114
io_cache->reinit_io_cache(internal::READ_CACHE,0L,0,0);
115
ref_pos=table->cursor->ref;
116
if (!table->cursor->inited)
117
table->cursor->startTableScan(0);
183
info->read_record= (table->sort.addon_field ?
184
rr_unpack_from_tempfile : rr_from_tempfile);
185
info->io_cache=tempfile;
186
reinit_io_cache(info->io_cache,READ_CACHE,0L,0,0);
187
info->ref_pos=table->file->ref;
188
if (!table->file->inited)
189
table->file->ha_rnd_init(0);
120
192
table->sort.addon_field is checked because if we use addon fields,
124
196
if (!table->sort.addon_field &&
125
197
session->variables.read_rnd_buff_size &&
126
!(table->cursor->getEngine()->check_flag(HTON_BIT_FAST_KEY_READ)) &&
198
!(table->file->ha_table_flags() & HA_FAST_KEY_READ) &&
127
199
(table->db_stat & HA_READ_ONLY ||
128
200
table->reginfo.lock_type <= TL_READ_NO_INSERT) &&
129
(uint64_t) table->getShare()->getRecordLength() * (table->cursor->stats.records+
130
table->cursor->stats.deleted) >
201
(uint64_t) table->s->reclength* (table->file->stats.records+
202
table->file->stats.deleted) >
131
203
(uint64_t) MIN_FILE_LENGTH_TO_USE_ROW_CACHE &&
132
io_cache->end_of_file/ref_length * table->getShare()->getRecordLength() >
133
(internal::my_off_t) MIN_ROWS_TO_USE_TABLE_CACHE &&
134
!table->getShare()->blob_fields &&
135
ref_length <= MAX_REFLENGTH)
204
info->io_cache->end_of_file/info->ref_length * table->s->reclength >
205
(my_off_t) MIN_ROWS_TO_USE_TABLE_CACHE &&
206
!table->s->blob_fields &&
207
info->ref_length <= MAX_REFLENGTH)
209
if (! init_rr_cache(session, info))
139
read_record= rr_from_cache;
211
info->read_record=rr_from_cache;
143
215
else if (select && select->quick)
145
read_record= rr_quick;
217
info->read_record=rr_quick;
147
219
else if (table->sort.record_pointers)
149
table->cursor->startTableScan(0);
150
cache_pos=table->sort.record_pointers;
151
cache_end= cache_pos+ table->sort.found_records * ref_length;
152
read_record= (table->sort.addon_field ? rr_unpack_from_buffer : rr_from_pointers);
221
table->file->ha_rnd_init(0);
222
info->cache_pos=table->sort.record_pointers;
223
info->cache_end=info->cache_pos+
224
table->sort.found_records*info->ref_length;
225
info->read_record= (table->sort.addon_field ?
226
rr_unpack_from_buffer : rr_from_pointers);
156
read_record= rr_sequential;
157
table->cursor->startTableScan(1);
230
info->read_record=rr_sequential;
231
table->file->ha_rnd_init(1);
158
232
/* We can use record cache if we don't update dynamic length tables */
159
233
if (!table->no_cache &&
160
234
(use_record_cache > 0 ||
161
235
(int) table->reginfo.lock_type <= (int) TL_READ_WITH_SHARED_LOCKS ||
162
!(table->getShare()->db_options_in_use & HA_OPTION_PACK_RECORD)))
164
table->cursor->extra_opt(HA_EXTRA_CACHE, session->variables.read_buff_size);
236
!(table->s->db_options_in_use & HA_OPTION_PACK_RECORD) ||
237
(use_record_cache < 0 &&
238
!(table->file->ha_table_flags() & HA_NOT_DELETE_WITH_CACHE))))
239
table->file->extra_opt(HA_EXTRA_CACHE, session->variables.read_buff_size);
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.
246
if (session->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);
169
253
} /* init_read_record */
172
void ReadRecord::end_read_record()
255
void end_read_record(READ_RECORD *info)
173
256
{ /* free cache if used */
176
global_read_rnd_buffer.sub(session->variables.read_rnd_buff_size);
259
free((char*) info->cache);
182
table->filesort_free_buffers();
183
(void) cursor->extra(HA_EXTRA_NO_CACHE);
184
if (read_record != rr_quick) // otherwise quick_range does it
185
(void) cursor->ha_index_or_rnd_end();
264
filesort_free_buffers(info->table,0);
265
(void) info->file->extra(HA_EXTRA_NO_CACHE);
266
if (info->read_record != rr_quick) // otherwise quick_range does it
267
(void) info->file->ha_index_or_rnd_end();
191
static int rr_handle_error(ReadRecord *info, int error)
272
static int rr_handle_error(READ_RECORD *info, int error)
193
274
if (error == HA_ERR_END_OF_FILE)
197
278
if (info->print_error)
198
info->table->print_error(error, MYF(0));
279
info->table->file->print_error(error, MYF(0));
199
280
if (error < 0) // Fix negative BDB errno
391
471
/* cacheing of records from a database */
392
bool ReadRecord::init_rr_cache()
472
static int init_rr_cache(Session *session, READ_RECORD *info)
394
uint32_t local_rec_cache_size;
396
struct_length= 3 + MAX_REFLENGTH;
397
reclength= ALIGN_SIZE(table->getShare()->getRecordLength() + 1);
398
if (reclength < struct_length)
399
reclength= ALIGN_SIZE(struct_length);
401
error_offset= table->getShare()->getRecordLength();
402
cache_records= (session->variables.read_rnd_buff_size /
403
(reclength + struct_length));
404
local_rec_cache_size= cache_records * reclength;
405
rec_cache_size= cache_records * ref_length;
407
if (not global_read_rnd_buffer.add(session->variables.read_rnd_buff_size))
409
my_error(ER_OUT_OF_GLOBAL_READRNDMEMORY, MYF(ME_ERROR+ME_WAITTANG));
474
uint32_t rec_cache_size;
476
info->struct_length= 3+MAX_REFLENGTH;
477
info->reclength= ALIGN_SIZE(info->table->s->reclength+1);
478
if (info->reclength < info->struct_length)
479
info->reclength= ALIGN_SIZE(info->struct_length);
481
info->error_offset= info->table->s->reclength;
482
info->cache_records= (session->variables.read_rnd_buff_size /
483
(info->reclength+info->struct_length));
484
rec_cache_size= info->cache_records*info->reclength;
485
info->rec_cache_size= info->cache_records*info->ref_length;
413
487
// We have to allocate one more byte to use uint3korr (see comments for it)
414
if (cache_records <= 2 ||
415
!(cache=(unsigned char*) malloc(local_rec_cache_size + cache_records * struct_length + 1)))
488
if (info->cache_records <= 2 ||
489
!(info->cache=(unsigned char*) malloc(rec_cache_size+info->cache_records*
490
info->struct_length+1)))
420
493
// Avoid warnings in qsort
421
memset(cache, 0, local_rec_cache_size + cache_records * struct_length + 1);
494
memset(info->cache, 0,
495
rec_cache_size+info->cache_records* info->struct_length+1);
423
read_positions= cache + local_rec_cache_size;
424
cache_pos= cache_end= cache;
497
info->read_positions=info->cache+rec_cache_size;
498
info->cache_pos=info->cache_end=info->cache;
427
500
} /* init_rr_cache */
429
static int rr_from_cache(ReadRecord *info)
502
static int rr_from_cache(READ_RECORD *info)
432
internal::my_off_t rest_of_file;
506
my_off_t rest_of_file;
434
508
unsigned char *position,*ref_position,*record_pos;
443
517
shortget(error,info->cache_pos);
444
518
if (info->print_error)
445
info->table->print_error(error,MYF(0));
519
info->table->file->print_error(error,MYF(0));
450
memcpy(info->record,info->cache_pos, (size_t) info->table->getShare()->getRecordLength());
524
memcpy(info->record,info->cache_pos, (size_t) info->table->s->reclength);
452
info->cache_pos+= info->reclength;
526
info->cache_pos+=info->reclength;
453
527
return ((int) error);
455
529
length=info->rec_cache_size;
456
rest_of_file= info->io_cache->end_of_file - my_b_tell(info->io_cache);
457
if ((internal::my_off_t) length > rest_of_file)
530
rest_of_file=info->io_cache->end_of_file - my_b_tell(info->io_cache);
531
if ((my_off_t) length > rest_of_file)
459
532
length= (uint32_t) rest_of_file;
462
if (!length || my_b_read(info->io_cache, info->getCache(), length))
533
if (!length || my_b_read(info->io_cache,info->cache,length))
464
return -1; /* End of cursor */
535
return -1; /* End of file */
467
538
length/=info->ref_length;
468
position=info->getCache();
539
position=info->cache;
469
540
ref_position=info->read_positions;
470
for (uint32_t i= 0 ; i < length ; i++,position+=info->ref_length)
541
for (i=0 ; i < length ; i++,position+=info->ref_length)
472
543
memcpy(ref_position,position,(size_t) info->ref_length);
473
544
ref_position+=MAX_REFLENGTH;
474
545
int3store(ref_position,(long) i);
477
internal::my_qsort(info->read_positions, length, info->struct_length,
548
my_qsort(info->read_positions, length, info->struct_length,
480
551
position=info->read_positions;
481
for (uint32_t i= 0 ; i < length ; i++)
552
for (i=0 ; i < length ; i++)
483
memcpy(info->ref_pos, position, (size_t)info->ref_length);
554
memcpy(info->ref_pos,position,(size_t) info->ref_length);
484
555
position+=MAX_REFLENGTH;
485
556
record=uint3korr(position);
487
record_pos= info->getCache() + record * info->reclength;
488
if ((error=(int16_t) info->cursor->rnd_pos(record_pos,info->ref_pos)))
558
record_pos=info->cache+record*info->reclength;
559
if ((error=(int16_t) info->file->rnd_pos(record_pos,info->ref_pos)))
490
561
record_pos[info->error_offset]=1;
491
562
shortstore(record_pos,error);