12
12
You should have received a copy of the GNU General Public License
13
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 */
14
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
16
16
#include "heap_priv.h"
17
17
#include <drizzled/error.h>
18
18
#include <drizzled/table.h>
19
19
#include <drizzled/session.h>
20
#include <drizzled/current_session.h>
21
#include <drizzled/field/timestamp.h>
22
20
#include <drizzled/field/varstring.h>
23
21
#include "drizzled/plugin/daemon.h"
23
#include <boost/thread/mutex.hpp>
26
26
#include "ha_heap.h"
52
52
HTON_SKIP_STORE_LOCK |
53
53
HTON_TEMPORARY_ONLY)
55
pthread_mutex_init(&THR_LOCK_heap, MY_MUTEX_INIT_FAST);
58
57
virtual ~HeapEngine()
60
59
hp_panic(HA_PANIC_CLOSE);
62
pthread_mutex_destroy(&THR_LOCK_heap);
65
virtual Cursor *create(TableShare &table,
66
memory::Root *mem_root)
62
virtual Cursor *create(Table &table)
68
return new (mem_root) ha_heap(*this, table);
64
return new ha_heap(*this, table);
71
67
const char **bas_ext() const {
88
84
message::Table &create_proto,
89
85
HP_SHARE **internal_share);
91
int doRenameTable(Session&, TableIdentifier &from, TableIdentifier &to);
87
int doRenameTable(Session&, const identifier::Table &from, const identifier::Table &to);
93
int doDropTable(Session&, TableIdentifier &identifier);
89
int doDropTable(Session&, const identifier::Table &identifier);
95
91
int doGetTableDefinition(Session& session,
96
TableIdentifier &identifier,
92
const identifier::Table &identifier,
97
93
message::Table &table_message);
99
/* Temp only engine, so do not return values. */
100
void doGetTableNames(CachedDirectory &, SchemaIdentifier& , set<string>&) { };
102
95
uint32_t max_supported_keys() const { return MAX_KEY; }
103
96
uint32_t max_supported_key_part_length() const { return MAX_KEY_LENGTH; }
105
uint32_t index_flags(enum ha_key_alg algorithm) const
98
uint32_t index_flags(enum ha_key_alg ) const
107
return ((algorithm == HA_KEY_ALG_BTREE) ?
112
HA_ONLY_WHOLE_INDEX |
113
HA_KEY_SCAN_NOT_ROR);
100
return ( HA_ONLY_WHOLE_INDEX | HA_KEY_SCAN_NOT_ROR);
116
bool doDoesTableExist(Session& session, TableIdentifier &identifier);
117
void doGetTableIdentifiers(drizzled::CachedDirectory &directory,
118
drizzled::SchemaIdentifier &schema_identifier,
119
drizzled::TableIdentifiers &set_of_identifiers);
103
bool doDoesTableExist(Session& session, const identifier::Table &identifier);
104
void doGetTableIdentifiers(CachedDirectory &directory,
105
const identifier::Schema &schema_identifier,
106
identifier::Table::vector &set_of_identifiers);
122
void HeapEngine::doGetTableIdentifiers(drizzled::CachedDirectory&,
123
drizzled::SchemaIdentifier&,
124
drizzled::TableIdentifiers&)
109
void HeapEngine::doGetTableIdentifiers(CachedDirectory&,
110
const identifier::Schema&,
111
identifier::Table::vector&)
128
bool HeapEngine::doDoesTableExist(Session& session, TableIdentifier &identifier)
115
bool HeapEngine::doDoesTableExist(Session& session, const identifier::Table &identifier)
130
return session.doesTableMessageExist(identifier);
117
return session.getMessageCache().doesTableMessageExist(identifier);
133
120
int HeapEngine::doGetTableDefinition(Session &session,
134
TableIdentifier &identifier,
121
const identifier::Table &identifier,
135
122
message::Table &table_proto)
137
if (session.getTableMessage(identifier, table_proto))
124
if (session.getMessageCache().getTableMessage(identifier, table_proto))
143
130
We have to ignore ENOENT entries as the MEMORY table is created on open and
144
131
not when doing a CREATE on the table.
146
int HeapEngine::doDropTable(Session &session, TableIdentifier &identifier)
133
int HeapEngine::doDropTable(Session &session, const identifier::Table &identifier)
148
session.removeTableMessage(identifier);
135
session.getMessageCache().removeTableMessage(identifier);
150
137
int error= heap_delete_table(identifier.getPath().c_str());
189
176
#define MEMORY_STATS_UPDATE_THRESHOLD 10
191
int ha_heap::open(const char *name, int mode, uint32_t test_if_locked)
178
int ha_heap::doOpen(const drizzled::identifier::Table &identifier, int mode, uint32_t test_if_locked)
193
if ((test_if_locked & HA_OPEN_INTERNAL_TABLE) || (!(file= heap_open(name, mode)) && errno == ENOENT))
180
if ((test_if_locked & HA_OPEN_INTERNAL_TABLE) || (!(file= heap_open(identifier.getPath().c_str(), mode)) && errno == ENOENT))
195
HA_CREATE_INFO create_info;
196
182
internal_table= test(test_if_locked & HA_OPEN_INTERNAL_TABLE);
197
memset(&create_info, 0, sizeof(create_info));
199
184
HP_SHARE *internal_share= NULL;
200
185
message::Table create_proto;
202
if (!heap_storage_engine->heap_create_table(ha_session(), name, table,
187
if (not heap_storage_engine->heap_create_table(getTable()->in_use,
188
identifier.getPath().c_str(),
207
194
file= internal_table ?
208
195
heap_open_from_share(internal_share, mode) :
248
234
Do same as default implementation but use file->s->name instead of
249
table->s->path. This is needed by Windows where the clone() call sees
250
'/'-delimited path in table->s->path, while ha_peap::open() was called
235
table->getShare()->path. This is needed by Windows where the clone() call sees
236
'/'-delimited path in table->getShare()->path, while ha_peap::open() was called
251
237
with '\'-delimited path.
254
Cursor *ha_heap::clone(memory::Root *mem_root)
240
Cursor *ha_heap::clone(memory::Root *)
256
Cursor *new_handler= table->s->db_type()->getCursor(*table->s, mem_root);
242
Cursor *new_handler= getTable()->getMutableShare()->db_type()->getCursor(*getTable());
243
identifier::Table identifier(getTable()->getShare()->getSchemaName(),
244
getTable()->getShare()->getTableName(),
245
getTable()->getShare()->getPath());
258
if (new_handler && !new_handler->ha_open(table, file->s->name, table->db_stat,
247
if (new_handler && !new_handler->ha_open(identifier, getTable()->db_stat,
259
248
HA_OPEN_IGNORE_IF_LOCKED))
260
249
return new_handler;
265
const char *ha_heap::index_type(uint32_t inx)
254
const char *ha_heap::index_type(uint32_t )
267
return ((table_share->key_info[inx].algorithm == HA_KEY_ALG_BTREE) ?
288
276
void ha_heap::set_keys_for_scanning(void)
291
for (uint32_t i= 0 ; i < table->s->keys ; i++)
293
if (table->key_info[i].algorithm == HA_KEY_ALG_BTREE)
299
281
void ha_heap::update_key_stats()
301
for (uint32_t i= 0; i < table->s->keys; i++)
283
for (uint32_t i= 0; i < getTable()->getShare()->sizeKeys(); i++)
303
KEY *key=table->key_info+i;
285
KeyInfo *key= &getTable()->key_info[i];
304
287
if (!key->rec_per_key)
306
if (key->algorithm != HA_KEY_ALG_BTREE)
308
291
if (key->flags & HA_NOSAME)
309
292
key->rec_per_key[key->key_parts-1]= 1;
312
ha_rows hash_buckets= file->s->keydef[i].hash_buckets;
313
uint32_t no_records= hash_buckets ? (uint) (file->s->records/hash_buckets) : 2;
295
ha_rows hash_buckets= file->getShare()->keydef[i].hash_buckets;
296
uint32_t no_records= hash_buckets ? (uint) (file->getShare()->records/hash_buckets) : 2;
314
297
if (no_records < 2)
316
299
key->rec_per_key[key->key_parts-1]= no_records;
320
303
records_changed= 0;
321
304
/* At the end of update_key_stats() we can proudly claim they are OK. */
322
key_stat_version= file->s->key_stat_version;
305
key_stat_version= file->getShare()->key_stat_version;
326
int ha_heap::write_row(unsigned char * buf)
309
int ha_heap::doInsertRecord(unsigned char * buf)
329
ha_statistic_increment(&system_status_var::ha_write_count);
330
if (table->next_number_field && buf == table->record[0])
312
if (getTable()->next_number_field && buf == getTable()->getInsertRecord())
332
314
if ((res= update_auto_increment()))
335
317
res= heap_write(file,buf);
336
318
if (!res && (++records_changed*MEMORY_STATS_UPDATE_THRESHOLD >
319
file->getShare()->records))
340
322
We can perform this safely since only one writer at the time is
341
323
allowed on the table.
343
file->s->key_stat_version++;
325
file->getShare()->key_stat_version++;
348
int ha_heap::update_row(const unsigned char * old_data, unsigned char * new_data)
330
int ha_heap::doUpdateRecord(const unsigned char * old_data, unsigned char * new_data)
351
ha_statistic_increment(&system_status_var::ha_update_count);
352
if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_UPDATE)
353
table->timestamp_field->set_time();
354
334
res= heap_update(file,old_data,new_data);
355
335
if (!res && ++records_changed*MEMORY_STATS_UPDATE_THRESHOLD >
336
file->getShare()->records)
359
339
We can perform this safely since only one writer at the time is
360
340
allowed on the table.
362
file->s->key_stat_version++;
342
file->getShare()->key_stat_version++;
367
int ha_heap::delete_row(const unsigned char * buf)
347
int ha_heap::doDeleteRecord(const unsigned char * buf)
370
ha_statistic_increment(&system_status_var::ha_delete_count);
371
351
res= heap_delete(file,buf);
372
if (!res && table->s->tmp_table == message::Table::STANDARD &&
373
++records_changed*MEMORY_STATS_UPDATE_THRESHOLD > file->s->records)
352
if (!res && getTable()->getShare()->getType() == message::Table::STANDARD &&
353
++records_changed*MEMORY_STATS_UPDATE_THRESHOLD > file->getShare()->records)
376
356
We can perform this safely since only one writer at the time is
377
357
allowed on the table.
379
file->s->key_stat_version++;
359
file->getShare()->key_stat_version++;
648
619
void ha_heap::drop_table(const char *)
650
file->s->delete_on_close= 1;
621
file->getShare()->delete_on_close= 1;
655
int HeapEngine::doRenameTable(Session &session, TableIdentifier &from, TableIdentifier &to)
626
int HeapEngine::doRenameTable(Session &session, const identifier::Table &from, const identifier::Table &to)
657
session.renameTableMessage(from, to);
628
session.getMessageCache().renameTableMessage(from, to);
658
629
return heap_rename(from.getPath().c_str(), to.getPath().c_str());
662
633
ha_rows ha_heap::records_in_range(uint32_t inx, key_range *min_key,
663
634
key_range *max_key)
665
KEY *key=table->key_info+inx;
666
if (key->algorithm == HA_KEY_ALG_BTREE)
667
return hp_rb_records_in_range(file, inx, min_key, max_key);
636
KeyInfo *key= &getTable()->key_info[inx];
669
638
if (!min_key || !max_key ||
670
639
min_key->length != max_key->length ||
677
646
return stats.records;
679
648
/* Assert that info() did run. We need current statistics here. */
680
assert(key_stat_version == file->s->key_stat_version);
649
assert(key_stat_version == file->getShare()->key_stat_version);
681
650
return key->rec_per_key[key->key_parts-1];
684
653
int HeapEngine::doCreateTable(Session &session,
685
654
Table &table_arg,
686
drizzled::TableIdentifier &identifier,
655
const identifier::Table &identifier,
687
656
message::Table& create_proto)
710
679
message::Table &create_proto,
711
680
HP_SHARE **internal_share)
713
uint32_t key, parts, mem_per_row_keys= 0, keys= table_arg->s->keys;
682
uint32_t key, parts, mem_per_row_keys= 0;
683
uint32_t keys= table_arg->getShare()->sizeKeys();
714
684
uint32_t auto_key= 0, auto_key_type= 0;
715
685
uint32_t max_key_fieldnr = 0, key_part_size = 0, next_field_pos = 0;
716
uint32_t column_idx, column_count= table_arg->s->fields;
717
HP_COLUMNDEF *columndef;
720
char buff[FN_REFLEN];
686
uint32_t column_count= table_arg->getShare()->sizeFields();
687
std::vector<HP_KEYDEF> keydef;
722
TableShare *share= table_arg->s;
723
689
bool found_real_auto_increment= 0;
728
694
* can return a number more than that, we trap it here instead of casting
729
695
* to a truncated integer.
731
uint64_t num_rows= share->getMaxRows();
697
uint64_t num_rows= table_arg->getShare()->getMaxRows();
732
698
if (num_rows > UINT32_MAX)
735
if (!(columndef= (HP_COLUMNDEF*) malloc(column_count * sizeof(HP_COLUMNDEF))))
738
for (column_idx= 0; column_idx < column_count; column_idx++)
740
Field* field= *(table_arg->field + column_idx);
741
HP_COLUMNDEF* column= columndef + column_idx;
742
column->type= (uint16_t)field->type();
743
column->length= field->pack_length();
744
column->offset= field->offset(field->table->record[0]);
748
column->null_bit= field->null_bit;
749
column->null_pos= (uint) (field->null_ptr - (unsigned char*) table_arg->record[0]);
757
if (field->type() == DRIZZLE_TYPE_VARCHAR)
759
column->length_bytes= (uint8_t)(((Field_varstring*)field)->length_bytes);
763
column->length_bytes= 0;
767
701
for (key= parts= 0; key < keys; key++)
768
702
parts+= table_arg->key_info[key].key_parts;
770
if (!(keydef= (HP_KEYDEF*) malloc(keys * sizeof(HP_KEYDEF) +
771
parts * sizeof(HA_KEYSEG))))
773
free((void *) columndef);
705
std::vector<HA_KEYSEG> seg_buffer;
706
seg_buffer.resize(parts);
707
HA_KEYSEG *seg= &seg_buffer[0];
777
seg= reinterpret_cast<HA_KEYSEG*> (keydef + keys);
778
709
for (key= 0; key < keys; key++)
780
KEY *pos= table_arg->key_info+key;
781
KEY_PART_INFO *key_part= pos->key_part;
782
KEY_PART_INFO *key_part_end= key_part + pos->key_parts;
711
KeyInfo *pos= &table_arg->key_info[key];
712
KeyPartInfo *key_part= pos->key_part;
713
KeyPartInfo *key_part_end= key_part + pos->key_parts;
784
715
keydef[key].keysegs= (uint) pos->key_parts;
785
716
keydef[key].flag= (pos->flags & (HA_NOSAME | HA_NULL_ARE_EQUAL));
786
717
keydef[key].seg= seg;
788
switch (pos->algorithm) {
789
case HA_KEY_ALG_UNDEF:
790
case HA_KEY_ALG_HASH:
791
keydef[key].algorithm= HA_KEY_ALG_HASH;
792
mem_per_row_keys+= sizeof(char*) * 2; // = sizeof(HASH_INFO)
794
case HA_KEY_ALG_BTREE:
795
keydef[key].algorithm= HA_KEY_ALG_BTREE;
796
mem_per_row_keys+=sizeof(TREE_ELEMENT)+pos->key_length+sizeof(char*);
799
assert(0); // cannot happen
719
mem_per_row_keys+= sizeof(char*) * 2; // = sizeof(HASH_INFO)
802
721
for (; key_part != key_part_end; key_part++, seg++)
804
723
Field *field= key_part->field;
806
if (pos->algorithm == HA_KEY_ALG_BTREE)
807
seg->type= field->key_type();
810
726
if ((seg->type = field->key_type()) != (int) HA_KEYTYPE_TEXT &&
811
727
seg->type != HA_KEYTYPE_VARTEXT1 &&
853
769
auto_key= key+ 1;
854
770
auto_key_type= field->key_type();
856
if ((uint)field->field_index + 1 > max_key_fieldnr)
772
if ((uint)field->position() + 1 > max_key_fieldnr)
858
774
/* Do not use seg->fieldnr as it's not reliable in case of temp tables */
859
max_key_fieldnr= field->field_index + 1;
775
max_key_fieldnr= field->position() + 1;
864
if (key_part_size < share->null_bytes + ((share->last_null_bit_pos+7) >> 3))
780
if (key_part_size < table_arg->getShare()->null_bytes + ((table_arg->getShare()->last_null_bit_pos+7) >> 3))
866
782
/* Make sure to include null fields regardless of the presense of keys */
867
key_part_size = share->null_bytes + ((share->last_null_bit_pos+7) >> 3);
783
key_part_size = table_arg->getShare()->null_bytes + ((table_arg->getShare()->last_null_bit_pos+7) >> 3);
872
788
if (table_arg->found_next_number_field)
874
keydef[share->next_number_index].flag|= HA_AUTO_KEY;
875
found_real_auto_increment= share->next_number_key_offset == 0;
790
keydef[table_arg->getShare()->next_number_index].flag|= HA_AUTO_KEY;
791
found_real_auto_increment= table_arg->getShare()->next_number_key_offset == 0;
877
793
HP_CREATE_INFO hp_create_info;
878
794
hp_create_info.auto_key= auto_key;
882
798
hp_create_info.max_table_size=session->variables.max_heap_table_size;
883
799
hp_create_info.with_auto_increment= found_real_auto_increment;
884
800
hp_create_info.internal_table= internal_table;
885
hp_create_info.max_chunk_size= share->block_size;
886
hp_create_info.is_dynamic= (share->row_type == ROW_TYPE_DYNAMIC);
888
error= heap_create(internal::fn_format(buff,table_name,"","",
889
MY_REPLACE_EXT|MY_UNPACK_FILENAME),
891
column_count, columndef,
892
max_key_fieldnr, key_part_size,
893
share->reclength, mem_per_row_keys,
894
static_cast<uint32_t>(num_rows), /* We check for overflow above, so cast is fine here. */
896
&hp_create_info, internal_share);
898
free((unsigned char*) keydef);
899
free((void *) columndef);
801
hp_create_info.max_chunk_size= table_arg->getShare()->block_size;
803
error= heap_create(table_name,
807
table_arg->getShare()->getRecordLength(), mem_per_row_keys,
808
static_cast<uint32_t>(num_rows), /* We check for overflow above, so cast is fine here. */
810
&hp_create_info, internal_share);