00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00022 #include <config.h>
00023
00024 #include <drizzled/drizzled.h>
00025 #include <drizzled/error.h>
00026 #include <drizzled/internal/iocache.h>
00027 #include <drizzled/internal/my_sys.h>
00028 #include <drizzled/optimizer/range.h>
00029 #include <drizzled/plugin/storage_engine.h>
00030 #include <drizzled/records.h>
00031 #include <drizzled/session.h>
00032 #include <drizzled/table.h>
00033 #include <drizzled/system_variables.h>
00034
00035 namespace drizzled {
00036
00037 static int rr_sequential(ReadRecord *info);
00038 static int rr_quick(ReadRecord *info);
00039 static int rr_from_tempfile(ReadRecord *info);
00040 static int rr_unpack_from_tempfile(ReadRecord *info);
00041 static int rr_unpack_from_buffer(ReadRecord *info);
00042 static int rr_from_pointers(ReadRecord *info);
00043 static int rr_from_cache(ReadRecord *info);
00044 static int rr_cmp(unsigned char *a,unsigned char *b);
00045 static int rr_index_first(ReadRecord *info);
00046 static int rr_index(ReadRecord *info);
00047
00048 void ReadRecord::init_reard_record_sequential()
00049 {
00050 read_record= rr_sequential;
00051 }
00052
00053 int ReadRecord::init_read_record_idx(Session *,
00054 Table *table_arg,
00055 bool print_error_arg,
00056 uint32_t idx)
00057 {
00058 table_arg->emptyRecord();
00059 table= table_arg;
00060 cursor= table->cursor;
00061 record= table->getInsertRecord();
00062 print_error= print_error_arg;
00063
00064 table->status=0;
00065 if (not table->cursor->inited)
00066 {
00067 int error= table->cursor->startIndexScan(idx, 1);
00068 if (error != 0)
00069 return error;
00070 }
00071
00072 read_record= rr_index_first;
00073
00074 return 0;
00075 }
00076
00077
00078 int ReadRecord::init_read_record(Session *session_arg,
00079 Table *table_arg,
00080 optimizer::SqlSelect *select_arg,
00081 int use_record_cache,
00082 bool print_error_arg)
00083 {
00084 internal::io_cache_st *tempfile;
00085 int error= 0;
00086
00087 session= session_arg;
00088 table= table_arg;
00089 cursor= table->cursor;
00090 forms= &table;
00091
00092 if (table->sort.addon_field)
00093 {
00094 rec_buf= table->sort.addon_buf;
00095 ref_length= table->sort.addon_length;
00096 }
00097 else
00098 {
00099 table->emptyRecord();
00100 record= table->getInsertRecord();
00101 ref_length= table->cursor->ref_length;
00102 }
00103 select= select_arg;
00104 print_error= print_error_arg;
00105 ignore_not_found_rows= 0;
00106 table->status=0;
00107
00108 if (select && select->file->inited())
00109 {
00110 tempfile= select->file;
00111 }
00112 else
00113 {
00114 tempfile= table->sort.io_cache;
00115 }
00116
00117 if (tempfile && tempfile->inited())
00118 {
00119 read_record= table->sort.addon_field ? rr_unpack_from_tempfile : rr_from_tempfile;
00120
00121 io_cache=tempfile;
00122 io_cache->reinit_io_cache(internal::READ_CACHE,0L,0,0);
00123 ref_pos=table->cursor->ref;
00124 if (!table->cursor->inited)
00125 {
00126 error= table->cursor->startTableScan(0);
00127 if (error != 0)
00128 return error;
00129 }
00130
00131
00132
00133
00134
00135
00136 if (!table->sort.addon_field &&
00137 session->variables.read_rnd_buff_size &&
00138 !(table->cursor->getEngine()->check_flag(HTON_BIT_FAST_KEY_READ)) &&
00139 (table->db_stat & HA_READ_ONLY ||
00140 table->reginfo.lock_type <= TL_READ_NO_INSERT) &&
00141 (uint64_t) table->getShare()->getRecordLength() * (table->cursor->stats.records+
00142 table->cursor->stats.deleted) >
00143 (uint64_t) MIN_FILE_LENGTH_TO_USE_ROW_CACHE &&
00144 io_cache->end_of_file/ref_length * table->getShare()->getRecordLength() >
00145 (internal::my_off_t) MIN_ROWS_TO_USE_TABLE_CACHE &&
00146 !table->getShare()->blob_fields &&
00147 ref_length <= MAX_REFLENGTH)
00148 {
00149 if (init_rr_cache())
00150 {
00151 read_record= rr_from_cache;
00152 }
00153 }
00154 }
00155 else if (select && select->quick)
00156 {
00157 read_record= rr_quick;
00158 }
00159 else if (table->sort.record_pointers)
00160 {
00161 error= table->cursor->startTableScan(0);
00162 if (error != 0)
00163 return error;
00164
00165 cache_pos=table->sort.record_pointers;
00166 cache_end= cache_pos+ table->sort.found_records * ref_length;
00167 read_record= (table->sort.addon_field ? rr_unpack_from_buffer : rr_from_pointers);
00168 }
00169 else
00170 {
00171 read_record= rr_sequential;
00172 error= table->cursor->startTableScan(1);
00173 if (error != 0)
00174 return error;
00175
00176
00177 if (!table->no_cache &&
00178 (use_record_cache > 0 ||
00179 (int) table->reginfo.lock_type <= (int) TL_READ_WITH_SHARED_LOCKS ||
00180 !(table->getShare()->db_options_in_use & HA_OPTION_PACK_RECORD)))
00181 {
00182 table->cursor->extra_opt(HA_EXTRA_CACHE, session->variables.read_buff_size);
00183 }
00184 }
00185
00186 return 0;
00187 }
00188
00189
00190 void ReadRecord::end_read_record()
00191 {
00192 if (cache)
00193 {
00194 global_read_rnd_buffer.sub(session->variables.read_rnd_buff_size);
00195 free((char*) cache);
00196 cache= NULL;
00197 }
00198 if (table)
00199 {
00200 table->filesort_free_buffers();
00201 (void) cursor->extra(HA_EXTRA_NO_CACHE);
00202 if (read_record != rr_quick)
00203 (void) cursor->ha_index_or_rnd_end();
00204
00205 table= NULL;
00206 }
00207 }
00208
00209 static int rr_handle_error(ReadRecord *info, int error)
00210 {
00211 if (error == HA_ERR_END_OF_FILE)
00212 error= -1;
00213 else
00214 {
00215 if (info->print_error)
00216 info->table->print_error(error, MYF(0));
00217 if (error < 0)
00218 error= 1;
00219 }
00220 return error;
00221 }
00222
00224 static int rr_quick(ReadRecord *info)
00225 {
00226 int tmp;
00227 while ((tmp= info->select->quick->get_next()))
00228 {
00229 if (info->session->getKilled())
00230 {
00231 my_error(ER_SERVER_SHUTDOWN, MYF(0));
00232 return 1;
00233 }
00234 if (tmp != HA_ERR_RECORD_DELETED)
00235 {
00236 tmp= rr_handle_error(info, tmp);
00237 break;
00238 }
00239 }
00240
00241 return tmp;
00242 }
00243
00256 static int rr_index_first(ReadRecord *info)
00257 {
00258 int tmp= info->cursor->index_first(info->record);
00259 info->read_record= rr_index;
00260 if (tmp)
00261 tmp= rr_handle_error(info, tmp);
00262 return tmp;
00263 }
00264
00280 static int rr_index(ReadRecord *info)
00281 {
00282 int tmp= info->cursor->index_next(info->record);
00283 if (tmp)
00284 tmp= rr_handle_error(info, tmp);
00285 return tmp;
00286 }
00287
00288 int rr_sequential(ReadRecord *info)
00289 {
00290 int tmp;
00291 while ((tmp= info->cursor->rnd_next(info->record)))
00292 {
00293 if (info->session->getKilled())
00294 {
00295 info->session->send_kill_message();
00296 return 1;
00297 }
00298
00299
00300
00301
00302
00303 if (tmp != HA_ERR_RECORD_DELETED)
00304 {
00305 tmp= rr_handle_error(info, tmp);
00306 break;
00307 }
00308 }
00309
00310 return tmp;
00311 }
00312
00313 static int rr_from_tempfile(ReadRecord *info)
00314 {
00315 int tmp;
00316 for (;;)
00317 {
00318 if (info->io_cache->read(info->ref_pos, info->ref_length))
00319 return -1;
00320 if (!(tmp=info->cursor->rnd_pos(info->record,info->ref_pos)))
00321 break;
00322
00323 if (tmp == HA_ERR_RECORD_DELETED ||
00324 (tmp == HA_ERR_KEY_NOT_FOUND && info->ignore_not_found_rows))
00325 continue;
00326 tmp= rr_handle_error(info, tmp);
00327 break;
00328 }
00329 return tmp;
00330 }
00331
00347 static int rr_unpack_from_tempfile(ReadRecord *info)
00348 {
00349 if (info->io_cache->read(info->rec_buf, info->ref_length))
00350 return -1;
00351 Table *table= info->table;
00352 (*table->sort.unpack)(table->sort.addon_field, info->rec_buf);
00353
00354 return 0;
00355 }
00356
00357 static int rr_from_pointers(ReadRecord *info)
00358 {
00359 int tmp;
00360 unsigned char *cache_pos;
00361
00362
00363 for (;;)
00364 {
00365 if (info->cache_pos == info->cache_end)
00366 return -1;
00367 cache_pos= info->cache_pos;
00368 info->cache_pos+= info->ref_length;
00369
00370 if (!(tmp=info->cursor->rnd_pos(info->record,cache_pos)))
00371 break;
00372
00373
00374 if (tmp == HA_ERR_RECORD_DELETED ||
00375 (tmp == HA_ERR_KEY_NOT_FOUND && info->ignore_not_found_rows))
00376 continue;
00377 tmp= rr_handle_error(info, tmp);
00378 break;
00379 }
00380 return tmp;
00381 }
00382
00398 static int rr_unpack_from_buffer(ReadRecord *info)
00399 {
00400 if (info->cache_pos == info->cache_end)
00401 return -1;
00402 Table *table= info->table;
00403 (*table->sort.unpack)(table->sort.addon_field, info->cache_pos);
00404 info->cache_pos+= info->ref_length;
00405
00406 return 0;
00407 }
00408
00409
00410 bool ReadRecord::init_rr_cache()
00411 {
00412 uint32_t local_rec_cache_size;
00413
00414 struct_length= 3 + MAX_REFLENGTH;
00415 reclength= ALIGN_SIZE(table->getShare()->getRecordLength() + 1);
00416 if (reclength < struct_length)
00417 reclength= ALIGN_SIZE(struct_length);
00418
00419 error_offset= table->getShare()->getRecordLength();
00420 cache_records= (session->variables.read_rnd_buff_size /
00421 (reclength + struct_length));
00422 local_rec_cache_size= cache_records * reclength;
00423 rec_cache_size= cache_records * ref_length;
00424
00425 if (not global_read_rnd_buffer.add(session->variables.read_rnd_buff_size))
00426 {
00427 my_error(ER_OUT_OF_GLOBAL_READRNDMEMORY, MYF(ME_ERROR+ME_WAITTANG));
00428 return false;
00429 }
00430
00431
00432 if (cache_records <= 2)
00433 return false;
00434 cache= (unsigned char*) malloc(local_rec_cache_size + cache_records * struct_length + 1);
00435 #ifdef HAVE_VALGRIND
00436
00437 memset(cache, 0, local_rec_cache_size + cache_records * struct_length + 1);
00438 #endif
00439 read_positions= cache + local_rec_cache_size;
00440 cache_pos= cache_end= cache;
00441
00442 return true;
00443 }
00444
00445 static int rr_from_cache(ReadRecord *info)
00446 {
00447 uint32_t length;
00448 internal::my_off_t rest_of_file;
00449 int16_t error;
00450 unsigned char *position,*ref_position,*record_pos;
00451 uint32_t record;
00452
00453 for (;;)
00454 {
00455 if (info->cache_pos != info->cache_end)
00456 {
00457 if (info->cache_pos[info->error_offset])
00458 {
00459 shortget(error,info->cache_pos);
00460 if (info->print_error)
00461 info->table->print_error(error,MYF(0));
00462 }
00463 else
00464 {
00465 error=0;
00466 memcpy(info->record,info->cache_pos, (size_t) info->table->getShare()->getRecordLength());
00467 }
00468 info->cache_pos+= info->reclength;
00469 return ((int) error);
00470 }
00471 length=info->rec_cache_size;
00472 rest_of_file= info->io_cache->end_of_file - info->io_cache->tell();
00473 if ((internal::my_off_t) length > rest_of_file)
00474 {
00475 length= (uint32_t) rest_of_file;
00476 }
00477
00478 if (!length || info->io_cache->read(info->getCache(), length))
00479 {
00480 return -1;
00481 }
00482
00483 length/=info->ref_length;
00484 position=info->getCache();
00485 ref_position=info->read_positions;
00486 for (uint32_t i= 0 ; i < length ; i++,position+=info->ref_length)
00487 {
00488 memcpy(ref_position,position,(size_t) info->ref_length);
00489 ref_position+=MAX_REFLENGTH;
00490 int3store(ref_position,(long) i);
00491 ref_position+=3;
00492 }
00493 internal::my_qsort(info->read_positions, length, info->struct_length,
00494 (qsort_cmp) rr_cmp);
00495
00496 position=info->read_positions;
00497 for (uint32_t i= 0 ; i < length ; i++)
00498 {
00499 memcpy(info->ref_pos, position, (size_t)info->ref_length);
00500 position+=MAX_REFLENGTH;
00501 record=uint3korr(position);
00502 position+=3;
00503 record_pos= info->getCache() + record * info->reclength;
00504 if ((error=(int16_t) info->cursor->rnd_pos(record_pos,info->ref_pos)))
00505 {
00506 record_pos[info->error_offset]=1;
00507 shortstore(record_pos,error);
00508 }
00509 else
00510 record_pos[info->error_offset]=0;
00511 }
00512 info->cache_end= (info->cache_pos= info->getCache())+length*info->reclength;
00513 }
00514 }
00515
00516 static int rr_cmp(unsigned char *a,unsigned char *b)
00517 {
00518 if (a[0] != b[0])
00519 return (int) a[0] - (int) b[0];
00520 if (a[1] != b[1])
00521 return (int) a[1] - (int) b[1];
00522 if (a[2] != b[2])
00523 return (int) a[2] - (int) b[2];
00524 #if MAX_REFLENGTH == 4
00525 return (int) a[3] - (int) b[3];
00526 #else
00527 if (a[3] != b[3])
00528 return (int) a[3] - (int) b[3];
00529 if (a[4] != b[4])
00530 return (int) a[4] - (int) b[4];
00531 if (a[5] != b[5])
00532 return (int) a[1] - (int) b[5];
00533 if (a[6] != b[6])
00534 return (int) a[6] - (int) b[6];
00535 return (int) a[7] - (int) b[7];
00536 #endif
00537 }
00538
00539 }