13
13
along with this program; if not, write to the Free Software
14
14
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
16
#include "heap_priv.h"
17
#include <drizzled/error.h>
18
#include <drizzled/table.h>
19
#include <drizzled/session.h>
20
#include <drizzled/current_session.h>
21
#include <drizzled/field/timestamp.h>
22
#include <drizzled/field/varstring.h>
17
#ifdef USE_PRAGMA_IMPLEMENTATION
18
#pragma implementation // gcc: Class implementation
21
#define MYSQL_SERVER 1
22
#include "mysql_priv.h"
23
#include <mysql/plugin.h>
25
24
#include "ha_heap.h"
30
using namespace drizzled;
33
static const string engine_name("MEMORY");
35
pthread_mutex_t THR_LOCK_heap= PTHREAD_MUTEX_INITIALIZER;
37
static const char *ha_heap_exts[] = {
41
class HeapEngine : public drizzled::plugin::StorageEngine
44
HeapEngine(string name_arg)
45
: drizzled::plugin::StorageEngine(name_arg,
46
HTON_STATS_RECORDS_IS_EXACT |
51
HTON_SKIP_STORE_LOCK |
55
virtual Cursor *create(TableShare &table,
56
memory::Root *mem_root)
58
return new (mem_root) ha_heap(*this, table);
61
const char **bas_ext() const {
65
int doCreateTable(Session *session,
66
const char *table_name,
68
drizzled::message::Table &create_proto);
70
/* For whatever reason, internal tables can be created by Cursor::open()
72
Instead of diving down a rat hole, let's just cry ourselves to sleep
73
at night with this odd hackish workaround.
75
int heap_create_table(Session *session, const char *table_name,
78
drizzled::message::Table &create_proto,
79
HP_SHARE **internal_share);
81
int doRenameTable(Session*, const char * from, const char * to);
83
int doDropTable(Session&, const string table_path);
85
int doGetTableDefinition(Session& session,
88
const char *table_name,
90
drizzled::message::Table *table_proto);
92
/* Temp only engine, so do not return values. */
93
void doGetTableNames(drizzled::CachedDirectory &, string& , set<string>&) { };
95
uint32_t max_supported_keys() const { return MAX_KEY; }
96
uint32_t max_supported_key_part_length() const { return MAX_KEY_LENGTH; }
98
uint32_t index_flags(enum ha_key_alg algorithm) const
100
return ((algorithm == HA_KEY_ALG_BTREE) ?
105
HA_ONLY_WHOLE_INDEX |
106
HA_KEY_SCAN_NOT_ROR);
111
int HeapEngine::doGetTableDefinition(Session&,
116
drizzled::message::Table *table_proto)
119
ProtoCache::iterator iter;
121
pthread_mutex_lock(&proto_cache_mutex);
122
iter= proto_cache.find(path);
124
if (iter!= proto_cache.end())
127
table_proto->CopyFrom(((*iter).second));
130
pthread_mutex_unlock(&proto_cache_mutex);
135
We have to ignore ENOENT entries as the MEMORY table is created on open and
136
not when doing a CREATE on the table.
138
int HeapEngine::doDropTable(Session&, const string table_path)
140
ProtoCache::iterator iter;
142
pthread_mutex_lock(&proto_cache_mutex);
143
iter= proto_cache.find(table_path.c_str());
145
if (iter!= proto_cache.end())
146
proto_cache.erase(iter);
147
pthread_mutex_unlock(&proto_cache_mutex);
149
return heap_delete_table(table_path.c_str());
152
static HeapEngine *heap_storage_engine= NULL;
154
static int heap_init(drizzled::plugin::Registry ®istry)
156
heap_storage_engine= new HeapEngine(engine_name);
157
registry.add(heap_storage_engine);
158
pthread_mutex_init(&THR_LOCK_heap, MY_MUTEX_INIT_FAST);
27
static handler *heap_create_handler(handlerton *hton,
31
int heap_panic(handlerton *hton, ha_panic_function flag)
33
return hp_panic(flag);
37
int heap_init(void *p)
39
handlerton *heap_hton;
41
heap_hton= (handlerton *)p;
42
heap_hton->state= SHOW_OPTION_YES;
43
heap_hton->db_type= DB_TYPE_HEAP;
44
heap_hton->create= heap_create_handler;
45
heap_hton->panic= heap_panic;
46
heap_hton->flags= HTON_CAN_RECREATE;
162
static int heap_deinit(drizzled::plugin::Registry ®istry)
51
static handler *heap_create_handler(handlerton *hton,
164
registry.remove(heap_storage_engine);
165
delete heap_storage_engine;
167
int ret= hp_panic(HA_PANIC_CLOSE);
169
pthread_mutex_destroy(&THR_LOCK_heap);
55
return new (mem_root) ha_heap(hton, table);
176
59
/*****************************************************************************
178
61
*****************************************************************************/
180
ha_heap::ha_heap(drizzled::plugin::StorageEngine &engine_arg,
181
TableShare &table_arg)
182
:Cursor(engine_arg, table_arg), file(0), records_changed(0), key_stat_version(0),
63
ha_heap::ha_heap(handlerton *hton, TABLE_SHARE *table_arg)
64
:handler(hton, table_arg), file(0), records_changed(0), key_stat_version(0),
69
static const char *ha_heap_exts[] = {
73
const char **ha_heap::bas_ext() const
187
Hash index statistics is updated (copied from HP_KEYDEF::hash_buckets to
188
rec_per_key) after 1/MEMORY_STATS_UPDATE_THRESHOLD fraction of table records
189
have been inserted/updated/deleted. delete_all_rows() and table flush cause
79
Hash index statistics is updated (copied from HP_KEYDEF::hash_buckets to
80
rec_per_key) after 1/HEAP_STATS_UPDATE_THRESHOLD fraction of table records
81
have been inserted/updated/deleted. delete_all_rows() and table flush cause
193
85
hash index statistics must be updated when number of table records changes
194
from 0 to non-zero value and vice versa. Otherwise records_in_range may
86
from 0 to non-zero value and vice versa. Otherwise records_in_range may
195
87
erroneously return 0 and 'range' may miss records.
197
#define MEMORY_STATS_UPDATE_THRESHOLD 10
89
#define HEAP_STATS_UPDATE_THRESHOLD 10
199
int ha_heap::open(const char *name, int mode, uint32_t test_if_locked)
91
int ha_heap::open(const char *name, int mode, uint test_if_locked)
201
if ((test_if_locked & HA_OPEN_INTERNAL_TABLE) || (!(file= heap_open(name, mode)) && errno == ENOENT))
93
if ((test_if_locked & HA_OPEN_INTERNAL_TABLE) || (!(file= heap_open(name, mode)) && my_errno == ENOENT))
203
95
HA_CREATE_INFO create_info;
204
96
internal_table= test(test_if_locked & HA_OPEN_INTERNAL_TABLE);
205
memset(&create_info, 0, sizeof(create_info));
97
bzero(&create_info, sizeof(create_info));
207
HP_SHARE *internal_share= NULL;
208
drizzled::message::Table create_proto;
210
if (!heap_storage_engine->heap_create_table(ha_session(), name, table,
99
if (!create(name, table, &create_info))
215
101
file= internal_table ?
216
102
heap_open_from_share(internal_share, mode) :
424
int ha_heap::index_next(unsigned char * buf)
304
int ha_heap::index_next(uchar * buf)
426
assert(inited==INDEX);
306
DBUG_ASSERT(inited==INDEX);
427
307
ha_statistic_increment(&SSV::ha_read_next_count);
428
308
int error=heap_rnext(file,buf);
429
309
table->status=error ? STATUS_NOT_FOUND: 0;
433
int ha_heap::index_prev(unsigned char * buf)
313
int ha_heap::index_prev(uchar * buf)
435
assert(inited==INDEX);
315
DBUG_ASSERT(inited==INDEX);
436
316
ha_statistic_increment(&SSV::ha_read_prev_count);
437
317
int error=heap_rprev(file,buf);
438
318
table->status=error ? STATUS_NOT_FOUND: 0;
442
int ha_heap::index_first(unsigned char * buf)
322
int ha_heap::index_first(uchar * buf)
444
assert(inited==INDEX);
324
DBUG_ASSERT(inited==INDEX);
445
325
ha_statistic_increment(&SSV::ha_read_first_count);
446
326
int error=heap_rfirst(file, buf, active_index);
447
327
table->status=error ? STATUS_NOT_FOUND: 0;
451
int ha_heap::index_last(unsigned char * buf)
331
int ha_heap::index_last(uchar * buf)
453
assert(inited==INDEX);
333
DBUG_ASSERT(inited==INDEX);
454
334
ha_statistic_increment(&SSV::ha_read_last_count);
455
335
int error=heap_rlast(file, buf, active_index);
456
336
table->status=error ? STATUS_NOT_FOUND: 0;
685
584
return stats.records;
687
586
/* Assert that info() did run. We need current statistics here. */
688
assert(key_stat_version == file->s->key_stat_version);
587
DBUG_ASSERT(key_stat_version == file->s->key_stat_version);
689
588
return key->rec_per_key[key->key_parts-1];
692
int HeapEngine::doCreateTable(Session *session,
693
const char *table_name,
695
drizzled::message::Table& create_proto)
698
HP_SHARE *internal_share;
700
error= heap_create_table(session, table_name, &table_arg,
707
pthread_mutex_lock(&proto_cache_mutex);
708
proto_cache.insert(make_pair(table_name, create_proto));
709
pthread_mutex_unlock(&proto_cache_mutex);
716
int HeapEngine::heap_create_table(Session *session, const char *table_name,
719
drizzled::message::Table &create_proto,
720
HP_SHARE **internal_share)
722
uint32_t key, parts, mem_per_row_keys= 0, keys= table_arg->s->keys;
723
uint32_t auto_key= 0, auto_key_type= 0;
724
uint32_t max_key_fieldnr = 0, key_part_size = 0, next_field_pos = 0;
725
uint32_t column_idx, column_count= table_arg->s->fields;
726
HP_COLUMNDEF *columndef;
592
int ha_heap::create(const char *name, TABLE *table_arg,
593
HA_CREATE_INFO *create_info)
595
uint key, parts, mem_per_row= 0, keys= table_arg->s->keys;
596
uint auto_key= 0, auto_key_type= 0;
727
598
HP_KEYDEF *keydef;
729
char buff[FN_REFLEN];
731
TableShare *share= table_arg->s;
601
TABLE_SHARE *share= table_arg->s;
732
602
bool found_real_auto_increment= 0;
735
* We cannot create tables with more rows than UINT32_MAX. This is a
736
* limitation of the HEAP engine. Here, since TableShare::getMaxRows()
737
* can return a number more than that, we trap it here instead of casting
738
* to a truncated integer.
740
uint64_t num_rows= share->getMaxRows();
741
if (num_rows > UINT32_MAX)
744
if (!(columndef= (HP_COLUMNDEF*) malloc(column_count * sizeof(HP_COLUMNDEF))))
747
for (column_idx= 0; column_idx < column_count; column_idx++)
749
Field* field= *(table_arg->field + column_idx);
750
HP_COLUMNDEF* column= columndef + column_idx;
751
column->type= (uint16_t)field->type();
752
column->length= field->pack_length();
753
column->offset= field->offset(field->table->record[0]);
757
column->null_bit= field->null_bit;
758
column->null_pos= (uint) (field->null_ptr - (unsigned char*) table_arg->record[0]);
766
if (field->type() == DRIZZLE_TYPE_VARCHAR)
768
column->length_bytes= (uint8_t)(((Field_varstring*)field)->length_bytes);
772
column->length_bytes= 0;
776
604
for (key= parts= 0; key < keys; key++)
777
605
parts+= table_arg->key_info[key].key_parts;
779
if (!(keydef= (HP_KEYDEF*) malloc(keys * sizeof(HP_KEYDEF) +
780
parts * sizeof(HA_KEYSEG))))
782
free((void *) columndef);
786
seg= reinterpret_cast<HA_KEYSEG*> (keydef + keys);
607
if (!(keydef= (HP_KEYDEF*) my_malloc(keys * sizeof(HP_KEYDEF) +
608
parts * sizeof(HA_KEYSEG),
611
seg= my_reinterpret_cast(HA_KEYSEG*) (keydef + keys);
787
612
for (key= 0; key < keys; key++)
789
614
KEY *pos= table_arg->key_info+key;
886
690
HP_CREATE_INFO hp_create_info;
887
691
hp_create_info.auto_key= auto_key;
888
692
hp_create_info.auto_key_type= auto_key_type;
889
hp_create_info.auto_increment= (create_proto.options().has_auto_increment_value() ?
890
create_proto.options().auto_increment_value() - 1 : 0);
891
hp_create_info.max_table_size=session->variables.max_heap_table_size;
693
hp_create_info.auto_increment= (create_info->auto_increment_value ?
694
create_info->auto_increment_value - 1 : 0);
695
hp_create_info.max_table_size=current_thd->variables.max_heap_table_size;
892
696
hp_create_info.with_auto_increment= found_real_auto_increment;
893
697
hp_create_info.internal_table= internal_table;
894
hp_create_info.max_chunk_size= share->block_size;
895
hp_create_info.is_dynamic= (share->row_type == ROW_TYPE_DYNAMIC);
897
error= heap_create(fn_format(buff,table_name,"","",
898
MY_REPLACE_EXT|MY_UNPACK_FILENAME),
900
column_count, columndef,
901
max_key_fieldnr, key_part_size,
902
share->reclength, mem_per_row_keys,
903
static_cast<uint32_t>(num_rows), /* We check for overflow above, so cast is fine here. */
905
&hp_create_info, internal_share);
907
free((unsigned char*) keydef);
908
free((void *) columndef);
698
max_rows = (ha_rows) (hp_create_info.max_table_size / mem_per_row);
699
error= heap_create(name,
700
keys, keydef, share->reclength,
701
(ulong) ((share->max_rows < max_rows &&
703
share->max_rows : max_rows),
704
(ulong) share->min_rows, &hp_create_info, &internal_share);
705
my_free((uchar*) keydef, MYF(0));
706
DBUG_ASSERT(file == 0);
914
void ha_heap::get_auto_increment(uint64_t, uint64_t, uint64_t,
711
void ha_heap::update_create_info(HA_CREATE_INFO *create_info)
713
table->file->info(HA_STATUS_AUTO);
714
if (!(create_info->used_fields & HA_CREATE_USED_AUTO))
715
create_info->auto_increment_value= stats.auto_increment_value;
718
void ha_heap::get_auto_increment(uint64_t offset, uint64_t increment,
719
uint64_t nb_desired_values,
915
720
uint64_t *first_value,
916
721
uint64_t *nb_reserved_values)
918
723
ha_heap::info(HA_STATUS_AUTO);
919
724
*first_value= stats.auto_increment_value;
920
725
/* such table has only table-level locking so reserves up to +inf */
921
*nb_reserved_values= UINT64_MAX;
925
int ha_heap::cmp_ref(const unsigned char *ref1, const unsigned char *ref2)
927
return memcmp(ref1, ref2, sizeof(HEAP_PTR));
931
DRIZZLE_DECLARE_PLUGIN
726
*nb_reserved_values= ULONGLONG_MAX;
730
bool ha_heap::check_if_incompatible_data(HA_CREATE_INFO *info,
733
/* Check that auto_increment value was not changed */
734
if ((info->used_fields & HA_CREATE_USED_AUTO &&
735
info->auto_increment_value != 0) ||
736
table_changes == IS_EQUAL_NO ||
737
table_changes & IS_EQUAL_PACK_LENGTH) // Not implemented yet
738
return COMPATIBLE_DATA_NO;
739
return COMPATIBLE_DATA_YES;
742
struct st_mysql_storage_engine heap_storage_engine=
743
{ MYSQL_HANDLERTON_INTERFACE_VERSION };
745
mysql_declare_plugin(heap)
747
MYSQL_STORAGE_ENGINE_PLUGIN,
748
&heap_storage_engine,
937
751
"Hash based, stored in memory, useful for temporary tables",
938
752
PLUGIN_LICENSE_GPL,
941
756
NULL, /* status variables */
942
757
NULL, /* system variables */
943
758
NULL /* config options */
945
DRIZZLE_DECLARE_PLUGIN_END;
760
mysql_declare_plugin_end;