~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to plugin/memory/ha_heap.cc

  • Committer: Brian Aker
  • Date: 2010-09-22 22:25:29 UTC
  • mto: (1791.1.1 drizzle)
  • mto: This revision was merged to the branch mainline in revision 1792.
  • Revision ID: brian@tangent.org-20100922222529-geo4wggmu5ntqa5k
Current boost work (more conversion).

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* Copyright (C) 2000-2006 MySQL AB
2
 
 
3
 
   This program is free software; you can redistribute it and/or modify
4
 
   it under the terms of the GNU General Public License as published by
5
 
   the Free Software Foundation; version 2 of the License.
6
 
 
7
 
   This program is distributed in the hope that it will be useful,
8
 
   but WITHOUT ANY WARRANTY; without even the implied warranty of
9
 
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10
 
   GNU General Public License for more details.
11
 
 
12
 
   You should have received a copy of the GNU General Public License
13
 
   along with this program; if not, write to the Free Software
14
 
   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA */
15
 
 
16
 
#include "heap_priv.h"
17
 
#include <drizzled/error.h>
18
 
#include <drizzled/table.h>
19
 
#include <drizzled/session.h>
20
 
#include <drizzled/field/timestamp.h>
21
 
#include <drizzled/field/varstring.h>
22
 
#include "drizzled/plugin/daemon.h"
23
 
 
24
 
#include <boost/thread/mutex.hpp>
25
 
 
26
 
#include "heap.h"
27
 
#include "ha_heap.h"
28
 
 
29
 
#include <string>
30
 
 
31
 
 
32
 
using namespace drizzled;
33
 
using namespace std;
34
 
 
35
 
static const string engine_name("MEMORY");
36
 
 
37
 
boost::mutex THR_LOCK_heap;
38
 
 
39
 
static const char *ha_heap_exts[] = {
40
 
  NULL
41
 
};
42
 
 
43
 
class HeapEngine : public plugin::StorageEngine
44
 
{
45
 
public:
46
 
  explicit HeapEngine(string name_arg) :
47
 
    plugin::StorageEngine(name_arg,
48
 
                          HTON_STATS_RECORDS_IS_EXACT |
49
 
                          HTON_NULL_IN_KEY |
50
 
                          HTON_FAST_KEY_READ |
51
 
                          HTON_NO_BLOBS |
52
 
                          HTON_HAS_RECORDS |
53
 
                          HTON_SKIP_STORE_LOCK |
54
 
                          HTON_TEMPORARY_ONLY)
55
 
  {
56
 
  }
57
 
 
58
 
  virtual ~HeapEngine()
59
 
  {
60
 
    hp_panic(HA_PANIC_CLOSE);
61
 
  }
62
 
 
63
 
  virtual Cursor *create(Table &table)
64
 
  {
65
 
    return new ha_heap(*this, table);
66
 
  }
67
 
 
68
 
  const char **bas_ext() const {
69
 
    return ha_heap_exts;
70
 
  }
71
 
 
72
 
  int doCreateTable(Session &session,
73
 
                    Table &table_arg,
74
 
                    const TableIdentifier &identifier,
75
 
                    message::Table &create_proto);
76
 
 
77
 
  /* For whatever reason, internal tables can be created by Cursor::open()
78
 
     for MEMORY.
79
 
     Instead of diving down a rat hole, let's just cry ourselves to sleep
80
 
     at night with this odd hackish workaround.
81
 
   */
82
 
  int heap_create_table(Session *session, const char *table_name,
83
 
                        Table *table_arg,
84
 
                        bool internal_table,
85
 
                        message::Table &create_proto,
86
 
                        HP_SHARE **internal_share);
87
 
 
88
 
  int doRenameTable(Session&, const TableIdentifier &from, const TableIdentifier &to);
89
 
 
90
 
  int doDropTable(Session&, const TableIdentifier &identifier);
91
 
 
92
 
  int doGetTableDefinition(Session& session,
93
 
                           const TableIdentifier &identifier,
94
 
                           message::Table &table_message);
95
 
 
96
 
  uint32_t max_supported_keys()          const { return MAX_KEY; }
97
 
  uint32_t max_supported_key_part_length() const { return MAX_KEY_LENGTH; }
98
 
 
99
 
  uint32_t index_flags(enum  ha_key_alg ) const
100
 
  {
101
 
    return ( HA_ONLY_WHOLE_INDEX | HA_KEY_SCAN_NOT_ROR);
102
 
  }
103
 
 
104
 
  bool doDoesTableExist(Session& session, const TableIdentifier &identifier);
105
 
  void doGetTableIdentifiers(CachedDirectory &directory,
106
 
                             const SchemaIdentifier &schema_identifier,
107
 
                             TableIdentifier::vector &set_of_identifiers);
108
 
};
109
 
 
110
 
void HeapEngine::doGetTableIdentifiers(CachedDirectory&,
111
 
                                       const SchemaIdentifier&,
112
 
                                       TableIdentifier::vector&)
113
 
{
114
 
}
115
 
 
116
 
bool HeapEngine::doDoesTableExist(Session& session, const TableIdentifier &identifier)
117
 
{
118
 
  return session.getMessageCache().doesTableMessageExist(identifier);
119
 
}
120
 
 
121
 
int HeapEngine::doGetTableDefinition(Session &session,
122
 
                                     const TableIdentifier &identifier,
123
 
                                     message::Table &table_proto)
124
 
{
125
 
  if (session.getMessageCache().getTableMessage(identifier, table_proto))
126
 
    return EEXIST;
127
 
 
128
 
  return ENOENT;
129
 
}
130
 
/*
131
 
  We have to ignore ENOENT entries as the MEMORY table is created on open and
132
 
  not when doing a CREATE on the table.
133
 
*/
134
 
int HeapEngine::doDropTable(Session &session, const TableIdentifier &identifier)
135
 
{
136
 
  session.getMessageCache().removeTableMessage(identifier);
137
 
 
138
 
  int error= heap_delete_table(identifier.getPath().c_str());
139
 
 
140
 
  if (error == ENOENT)
141
 
    error= 0;
142
 
 
143
 
  return error;
144
 
}
145
 
 
146
 
static HeapEngine *heap_storage_engine= NULL;
147
 
 
148
 
static int heap_init(module::Context &context)
149
 
{
150
 
  heap_storage_engine= new HeapEngine(engine_name);
151
 
  context.add(heap_storage_engine);
152
 
  return 0;
153
 
}
154
 
 
155
 
 
156
 
/*****************************************************************************
157
 
** MEMORY tables
158
 
*****************************************************************************/
159
 
 
160
 
ha_heap::ha_heap(plugin::StorageEngine &engine_arg,
161
 
                 Table &table_arg)
162
 
  :Cursor(engine_arg, table_arg), file(0), records_changed(0), key_stat_version(0),
163
 
  internal_table(0)
164
 
{}
165
 
 
166
 
/*
167
 
  Hash index statistics is updated (copied from HP_KEYDEF::hash_buckets to
168
 
  rec_per_key) after 1/MEMORY_STATS_UPDATE_THRESHOLD fraction of table records
169
 
  have been inserted/updated/deleted. delete_all_rows() and table flush cause
170
 
  immediate update.
171
 
 
172
 
  NOTE
173
 
   hash index statistics must be updated when number of table records changes
174
 
   from 0 to non-zero value and vice versa. Otherwise records_in_range may
175
 
   erroneously return 0 and 'range' may miss records.
176
 
*/
177
 
#define MEMORY_STATS_UPDATE_THRESHOLD 10
178
 
 
179
 
int ha_heap::doOpen(const drizzled::TableIdentifier &identifier, int mode, uint32_t test_if_locked)
180
 
{
181
 
  if ((test_if_locked & HA_OPEN_INTERNAL_TABLE) || (!(file= heap_open(identifier.getPath().c_str(), mode)) && errno == ENOENT))
182
 
  {
183
 
    internal_table= test(test_if_locked & HA_OPEN_INTERNAL_TABLE);
184
 
    file= 0;
185
 
    HP_SHARE *internal_share= NULL;
186
 
    message::Table create_proto;
187
 
 
188
 
    if (not heap_storage_engine->heap_create_table(getTable()->in_use,
189
 
                                                   identifier.getPath().c_str(),
190
 
                                                   getTable(),
191
 
                                                   internal_table,
192
 
                                                   create_proto,
193
 
                                                   &internal_share))
194
 
    {
195
 
        file= internal_table ?
196
 
          heap_open_from_share(internal_share, mode) :
197
 
          heap_open_from_share_and_register(internal_share, mode);
198
 
      if (!file)
199
 
      {
200
 
         /* Couldn't open table; Remove the newly created table */
201
 
        THR_LOCK_heap.lock();
202
 
        hp_free(internal_share);
203
 
        THR_LOCK_heap.unlock();
204
 
      }
205
 
    }
206
 
  }
207
 
  ref_length= sizeof(HEAP_PTR);
208
 
  if (file)
209
 
  {
210
 
    /* Initialize variables for the opened table */
211
 
    set_keys_for_scanning();
212
 
    /*
213
 
      We cannot run update_key_stats() here because we do not have a
214
 
      lock on the table. The 'records' count might just be changed
215
 
      temporarily at this moment and we might get wrong statistics (Bug
216
 
      #10178). Instead we request for update. This will be done in
217
 
      ha_heap::info(), which is always called before key statistics are
218
 
      used.
219
 
    */
220
 
    key_stat_version= file->getShare()->key_stat_version - 1;
221
 
  }
222
 
  return (file ? 0 : 1);
223
 
}
224
 
 
225
 
int ha_heap::close(void)
226
 
{
227
 
  return internal_table ? hp_close(file) : heap_close(file);
228
 
}
229
 
 
230
 
 
231
 
/*
232
 
  Create a copy of this table
233
 
 
234
 
  DESCRIPTION
235
 
    Do same as default implementation but use file->s->name instead of
236
 
    table->getShare()->path. This is needed by Windows where the clone() call sees
237
 
    '/'-delimited path in table->getShare()->path, while ha_peap::open() was called
238
 
    with '\'-delimited path.
239
 
*/
240
 
 
241
 
Cursor *ha_heap::clone(memory::Root *)
242
 
{
243
 
  Cursor *new_handler= getTable()->getMutableShare()->db_type()->getCursor(*getTable());
244
 
  TableIdentifier identifier(getTable()->getShare()->getSchemaName(),
245
 
                             getTable()->getShare()->getTableName(),
246
 
                             getTable()->getShare()->getPath());
247
 
 
248
 
  if (new_handler && !new_handler->ha_open(identifier, getTable()->db_stat,
249
 
                                           HA_OPEN_IGNORE_IF_LOCKED))
250
 
    return new_handler;
251
 
  return NULL;
252
 
}
253
 
 
254
 
 
255
 
const char *ha_heap::index_type(uint32_t )
256
 
{
257
 
  return ("HASH");
258
 
}
259
 
 
260
 
 
261
 
/*
262
 
  Compute which keys to use for scanning
263
 
 
264
 
  SYNOPSIS
265
 
    set_keys_for_scanning()
266
 
    no parameter
267
 
 
268
 
  DESCRIPTION
269
 
    Set the bitmap btree_keys, which is used when the upper layers ask
270
 
    which keys to use for scanning. For each btree index the
271
 
    corresponding bit is set.
272
 
 
273
 
  RETURN
274
 
    void
275
 
*/
276
 
 
277
 
void ha_heap::set_keys_for_scanning(void)
278
 
{
279
 
}
280
 
 
281
 
 
282
 
void ha_heap::update_key_stats()
283
 
{
284
 
  for (uint32_t i= 0; i < getTable()->getShare()->sizeKeys(); i++)
285
 
  {
286
 
    KeyInfo *key= &getTable()->key_info[i];
287
 
 
288
 
    if (!key->rec_per_key)
289
 
      continue;
290
 
 
291
 
    {
292
 
      if (key->flags & HA_NOSAME)
293
 
        key->rec_per_key[key->key_parts-1]= 1;
294
 
      else
295
 
      {
296
 
        ha_rows hash_buckets= file->getShare()->keydef[i].hash_buckets;
297
 
        uint32_t no_records= hash_buckets ? (uint) (file->getShare()->records/hash_buckets) : 2;
298
 
        if (no_records < 2)
299
 
          no_records= 2;
300
 
        key->rec_per_key[key->key_parts-1]= no_records;
301
 
      }
302
 
    }
303
 
  }
304
 
  records_changed= 0;
305
 
  /* At the end of update_key_stats() we can proudly claim they are OK. */
306
 
  key_stat_version= file->getShare()->key_stat_version;
307
 
}
308
 
 
309
 
 
310
 
int ha_heap::doInsertRecord(unsigned char * buf)
311
 
{
312
 
  int res;
313
 
  if (getTable()->next_number_field && buf == getTable()->getInsertRecord())
314
 
  {
315
 
    if ((res= update_auto_increment()))
316
 
      return res;
317
 
  }
318
 
  res= heap_write(file,buf);
319
 
  if (!res && (++records_changed*MEMORY_STATS_UPDATE_THRESHOLD >
320
 
               file->getShare()->records))
321
 
  {
322
 
    /*
323
 
       We can perform this safely since only one writer at the time is
324
 
       allowed on the table.
325
 
    */
326
 
    file->getShare()->key_stat_version++;
327
 
  }
328
 
  return res;
329
 
}
330
 
 
331
 
int ha_heap::doUpdateRecord(const unsigned char * old_data, unsigned char * new_data)
332
 
{
333
 
  int res;
334
 
 
335
 
  res= heap_update(file,old_data,new_data);
336
 
  if (!res && ++records_changed*MEMORY_STATS_UPDATE_THRESHOLD >
337
 
              file->getShare()->records)
338
 
  {
339
 
    /*
340
 
       We can perform this safely since only one writer at the time is
341
 
       allowed on the table.
342
 
    */
343
 
    file->getShare()->key_stat_version++;
344
 
  }
345
 
  return res;
346
 
}
347
 
 
348
 
int ha_heap::doDeleteRecord(const unsigned char * buf)
349
 
{
350
 
  int res;
351
 
 
352
 
  res= heap_delete(file,buf);
353
 
  if (!res && getTable()->getShare()->getType() == message::Table::STANDARD &&
354
 
      ++records_changed*MEMORY_STATS_UPDATE_THRESHOLD > file->getShare()->records)
355
 
  {
356
 
    /*
357
 
       We can perform this safely since only one writer at the time is
358
 
       allowed on the table.
359
 
    */
360
 
    file->getShare()->key_stat_version++;
361
 
  }
362
 
  return res;
363
 
}
364
 
 
365
 
int ha_heap::index_read_map(unsigned char *buf, const unsigned char *key,
366
 
                            key_part_map keypart_map,
367
 
                            enum ha_rkey_function find_flag)
368
 
{
369
 
  assert(inited==INDEX);
370
 
  ha_statistic_increment(&system_status_var::ha_read_key_count);
371
 
  int error = heap_rkey(file,buf,active_index, key, keypart_map, find_flag);
372
 
  getTable()->status = error ? STATUS_NOT_FOUND : 0;
373
 
  return error;
374
 
}
375
 
 
376
 
int ha_heap::index_read_last_map(unsigned char *buf, const unsigned char *key,
377
 
                                 key_part_map keypart_map)
378
 
{
379
 
  assert(inited==INDEX);
380
 
  ha_statistic_increment(&system_status_var::ha_read_key_count);
381
 
  int error= heap_rkey(file, buf, active_index, key, keypart_map,
382
 
                       HA_READ_PREFIX_LAST);
383
 
  getTable()->status= error ? STATUS_NOT_FOUND : 0;
384
 
  return error;
385
 
}
386
 
 
387
 
int ha_heap::index_read_idx_map(unsigned char *buf, uint32_t index, const unsigned char *key,
388
 
                                key_part_map keypart_map,
389
 
                                enum ha_rkey_function find_flag)
390
 
{
391
 
  ha_statistic_increment(&system_status_var::ha_read_key_count);
392
 
  int error = heap_rkey(file, buf, index, key, keypart_map, find_flag);
393
 
  getTable()->status = error ? STATUS_NOT_FOUND : 0;
394
 
  return error;
395
 
}
396
 
 
397
 
int ha_heap::index_next(unsigned char * buf)
398
 
{
399
 
  assert(inited==INDEX);
400
 
  ha_statistic_increment(&system_status_var::ha_read_next_count);
401
 
  int error=heap_rnext(file,buf);
402
 
  getTable()->status=error ? STATUS_NOT_FOUND: 0;
403
 
  return error;
404
 
}
405
 
 
406
 
int ha_heap::index_prev(unsigned char * buf)
407
 
{
408
 
  assert(inited==INDEX);
409
 
  ha_statistic_increment(&system_status_var::ha_read_prev_count);
410
 
  int error=heap_rprev(file,buf);
411
 
  getTable()->status=error ? STATUS_NOT_FOUND: 0;
412
 
  return error;
413
 
}
414
 
 
415
 
int ha_heap::index_first(unsigned char * buf)
416
 
{
417
 
  assert(inited==INDEX);
418
 
  ha_statistic_increment(&system_status_var::ha_read_first_count);
419
 
  int error=heap_rfirst(file, buf, active_index);
420
 
  getTable()->status=error ? STATUS_NOT_FOUND: 0;
421
 
  return error;
422
 
}
423
 
 
424
 
int ha_heap::index_last(unsigned char * buf)
425
 
{
426
 
  assert(inited==INDEX);
427
 
  ha_statistic_increment(&system_status_var::ha_read_last_count);
428
 
  int error=heap_rlast(file, buf, active_index);
429
 
  getTable()->status=error ? STATUS_NOT_FOUND: 0;
430
 
  return error;
431
 
}
432
 
 
433
 
int ha_heap::doStartTableScan(bool scan)
434
 
{
435
 
  return scan ? heap_scan_init(file) : 0;
436
 
}
437
 
 
438
 
int ha_heap::rnd_next(unsigned char *buf)
439
 
{
440
 
  ha_statistic_increment(&system_status_var::ha_read_rnd_next_count);
441
 
  int error=heap_scan(file, buf);
442
 
  getTable()->status=error ? STATUS_NOT_FOUND: 0;
443
 
  return error;
444
 
}
445
 
 
446
 
int ha_heap::rnd_pos(unsigned char * buf, unsigned char *pos)
447
 
{
448
 
  int error;
449
 
  HEAP_PTR heap_position;
450
 
  ha_statistic_increment(&system_status_var::ha_read_rnd_count);
451
 
  memcpy(&heap_position, pos, sizeof(HEAP_PTR));
452
 
  error=heap_rrnd(file, buf, heap_position);
453
 
  getTable()->status=error ? STATUS_NOT_FOUND: 0;
454
 
  return error;
455
 
}
456
 
 
457
 
void ha_heap::position(const unsigned char *)
458
 
{
459
 
  *(HEAP_PTR*) ref= heap_position(file);        // Ref is aligned
460
 
}
461
 
 
462
 
int ha_heap::info(uint32_t flag)
463
 
{
464
 
  HEAPINFO hp_info;
465
 
  (void) heap_info(file,&hp_info,flag);
466
 
 
467
 
  errkey=                     hp_info.errkey;
468
 
  stats.records=              hp_info.records;
469
 
  stats.deleted=              hp_info.deleted;
470
 
  stats.mean_rec_length=      hp_info.reclength;
471
 
  stats.data_file_length=     hp_info.data_length;
472
 
  stats.index_file_length=    hp_info.index_length;
473
 
  stats.max_data_file_length= hp_info.max_records * hp_info.reclength;
474
 
  stats.delete_length=        hp_info.deleted * hp_info.reclength;
475
 
  if (flag & HA_STATUS_AUTO)
476
 
    stats.auto_increment_value= hp_info.auto_increment;
477
 
  /*
478
 
    If info() is called for the first time after open(), we will still
479
 
    have to update the key statistics. Hoping that a table lock is now
480
 
    in place.
481
 
  */
482
 
  if (key_stat_version != file->getShare()->key_stat_version)
483
 
    update_key_stats();
484
 
  return 0;
485
 
}
486
 
 
487
 
int ha_heap::extra(enum ha_extra_function operation)
488
 
{
489
 
  return heap_extra(file,operation);
490
 
}
491
 
 
492
 
 
493
 
int ha_heap::reset()
494
 
{
495
 
  return heap_reset(file);
496
 
}
497
 
 
498
 
 
499
 
int ha_heap::delete_all_rows()
500
 
{
501
 
  heap_clear(file);
502
 
  if (getTable()->getShare()->getType() == message::Table::STANDARD)
503
 
  {
504
 
    /*
505
 
       We can perform this safely since only one writer at the time is
506
 
       allowed on the table.
507
 
    */
508
 
    file->getShare()->key_stat_version++;
509
 
  }
510
 
  return 0;
511
 
}
512
 
 
513
 
/*
514
 
  Disable indexes.
515
 
 
516
 
  SYNOPSIS
517
 
    disable_indexes()
518
 
    mode        mode of operation:
519
 
                HA_KEY_SWITCH_NONUNIQ      disable all non-unique keys
520
 
                HA_KEY_SWITCH_ALL          disable all keys
521
 
                HA_KEY_SWITCH_NONUNIQ_SAVE dis. non-uni. and make persistent
522
 
                HA_KEY_SWITCH_ALL_SAVE     dis. all keys and make persistent
523
 
 
524
 
  DESCRIPTION
525
 
    Disable indexes and clear keys to use for scanning.
526
 
 
527
 
  IMPLEMENTATION
528
 
    HA_KEY_SWITCH_NONUNIQ       is not implemented.
529
 
    HA_KEY_SWITCH_NONUNIQ_SAVE  is not implemented with HEAP.
530
 
    HA_KEY_SWITCH_ALL_SAVE      is not implemented with HEAP.
531
 
 
532
 
  RETURN
533
 
    0  ok
534
 
    HA_ERR_WRONG_COMMAND  mode not implemented.
535
 
*/
536
 
 
537
 
int ha_heap::disable_indexes(uint32_t mode)
538
 
{
539
 
  int error;
540
 
 
541
 
  if (mode == HA_KEY_SWITCH_ALL)
542
 
  {
543
 
    if (!(error= heap_disable_indexes(file)))
544
 
      set_keys_for_scanning();
545
 
  }
546
 
  else
547
 
  {
548
 
    /* mode not implemented */
549
 
    error= HA_ERR_WRONG_COMMAND;
550
 
  }
551
 
  return error;
552
 
}
553
 
 
554
 
 
555
 
/*
556
 
  Enable indexes.
557
 
 
558
 
  SYNOPSIS
559
 
    enable_indexes()
560
 
    mode        mode of operation:
561
 
                HA_KEY_SWITCH_NONUNIQ      enable all non-unique keys
562
 
                HA_KEY_SWITCH_ALL          enable all keys
563
 
                HA_KEY_SWITCH_NONUNIQ_SAVE en. non-uni. and make persistent
564
 
                HA_KEY_SWITCH_ALL_SAVE     en. all keys and make persistent
565
 
 
566
 
  DESCRIPTION
567
 
    Enable indexes and set keys to use for scanning.
568
 
    The indexes might have been disabled by disable_index() before.
569
 
    The function works only if both data and indexes are empty,
570
 
    since the heap storage engine cannot repair the indexes.
571
 
    To be sure, call Cursor::delete_all_rows() before.
572
 
 
573
 
  IMPLEMENTATION
574
 
    HA_KEY_SWITCH_NONUNIQ       is not implemented.
575
 
    HA_KEY_SWITCH_NONUNIQ_SAVE  is not implemented with HEAP.
576
 
    HA_KEY_SWITCH_ALL_SAVE      is not implemented with HEAP.
577
 
 
578
 
  RETURN
579
 
    0  ok
580
 
    HA_ERR_CRASHED  data or index is non-empty. Delete all rows and retry.
581
 
    HA_ERR_WRONG_COMMAND  mode not implemented.
582
 
*/
583
 
 
584
 
int ha_heap::enable_indexes(uint32_t mode)
585
 
{
586
 
  int error;
587
 
 
588
 
  if (mode == HA_KEY_SWITCH_ALL)
589
 
  {
590
 
    if (!(error= heap_enable_indexes(file)))
591
 
      set_keys_for_scanning();
592
 
  }
593
 
  else
594
 
  {
595
 
    /* mode not implemented */
596
 
    error= HA_ERR_WRONG_COMMAND;
597
 
  }
598
 
  return error;
599
 
}
600
 
 
601
 
 
602
 
/*
603
 
  Test if indexes are disabled.
604
 
 
605
 
  SYNOPSIS
606
 
    indexes_are_disabled()
607
 
    no parameters
608
 
 
609
 
  RETURN
610
 
    0  indexes are not disabled
611
 
    1  all indexes are disabled
612
 
   [2  non-unique indexes are disabled - NOT YET IMPLEMENTED]
613
 
*/
614
 
 
615
 
int ha_heap::indexes_are_disabled(void)
616
 
{
617
 
  return heap_indexes_are_disabled(file);
618
 
}
619
 
 
620
 
void ha_heap::drop_table(const char *)
621
 
{
622
 
  file->getShare()->delete_on_close= 1;
623
 
  close();
624
 
}
625
 
 
626
 
 
627
 
int HeapEngine::doRenameTable(Session &session, const TableIdentifier &from, const TableIdentifier &to)
628
 
{
629
 
  session.getMessageCache().renameTableMessage(from, to);
630
 
  return heap_rename(from.getPath().c_str(), to.getPath().c_str());
631
 
}
632
 
 
633
 
 
634
 
ha_rows ha_heap::records_in_range(uint32_t inx, key_range *min_key,
635
 
                                  key_range *max_key)
636
 
{
637
 
  KeyInfo *key= &getTable()->key_info[inx];
638
 
 
639
 
  if (!min_key || !max_key ||
640
 
      min_key->length != max_key->length ||
641
 
      min_key->length != key->key_length ||
642
 
      min_key->flag != HA_READ_KEY_EXACT ||
643
 
      max_key->flag != HA_READ_AFTER_KEY)
644
 
    return HA_POS_ERROR;                        // Can only use exact keys
645
 
 
646
 
  if (stats.records <= 1)
647
 
    return stats.records;
648
 
 
649
 
  /* Assert that info() did run. We need current statistics here. */
650
 
  assert(key_stat_version == file->getShare()->key_stat_version);
651
 
  return key->rec_per_key[key->key_parts-1];
652
 
}
653
 
 
654
 
int HeapEngine::doCreateTable(Session &session,
655
 
                              Table &table_arg,
656
 
                              const TableIdentifier &identifier,
657
 
                              message::Table& create_proto)
658
 
{
659
 
  int error;
660
 
  HP_SHARE *internal_share;
661
 
  const char *table_name= identifier.getPath().c_str();
662
 
 
663
 
  error= heap_create_table(&session, table_name, &table_arg,
664
 
                           false, 
665
 
                           create_proto,
666
 
                           &internal_share);
667
 
 
668
 
  if (error == 0)
669
 
  {
670
 
    session.getMessageCache().storeTableMessage(identifier, create_proto);
671
 
  }
672
 
 
673
 
  return error;
674
 
}
675
 
 
676
 
 
677
 
int HeapEngine::heap_create_table(Session *session, const char *table_name,
678
 
                                  Table *table_arg,
679
 
                                  bool internal_table, 
680
 
                                  message::Table &create_proto,
681
 
                                  HP_SHARE **internal_share)
682
 
{
683
 
  uint32_t key, parts, mem_per_row_keys= 0;
684
 
  uint32_t keys= table_arg->getShare()->sizeKeys();
685
 
  uint32_t auto_key= 0, auto_key_type= 0;
686
 
  uint32_t max_key_fieldnr = 0, key_part_size = 0, next_field_pos = 0;
687
 
  uint32_t column_count= table_arg->getShare()->sizeFields();
688
 
  std::vector<HP_KEYDEF> keydef;
689
 
  int error;
690
 
  bool found_real_auto_increment= 0;
691
 
 
692
 
  /* 
693
 
   * We cannot create tables with more rows than UINT32_MAX.  This is a
694
 
   * limitation of the HEAP engine.  Here, since TableShare::getMaxRows()
695
 
   * can return a number more than that, we trap it here instead of casting
696
 
   * to a truncated integer.
697
 
   */
698
 
  uint64_t num_rows= table_arg->getShare()->getMaxRows();
699
 
  if (num_rows > UINT32_MAX)
700
 
    return -1;
701
 
 
702
 
  for (key= parts= 0; key < keys; key++)
703
 
    parts+= table_arg->key_info[key].key_parts;
704
 
 
705
 
  keydef.resize(keys);
706
 
  std::vector<HA_KEYSEG> seg_buffer;
707
 
  seg_buffer.resize(parts);
708
 
  HA_KEYSEG *seg= &seg_buffer[0];
709
 
 
710
 
  for (key= 0; key < keys; key++)
711
 
  {
712
 
    KeyInfo *pos= &table_arg->key_info[key];
713
 
    KeyPartInfo *key_part=     pos->key_part;
714
 
    KeyPartInfo *key_part_end= key_part + pos->key_parts;
715
 
 
716
 
    keydef[key].keysegs=   (uint) pos->key_parts;
717
 
    keydef[key].flag=      (pos->flags & (HA_NOSAME | HA_NULL_ARE_EQUAL));
718
 
    keydef[key].seg=       seg;
719
 
 
720
 
    mem_per_row_keys+= sizeof(char*) * 2; // = sizeof(HASH_INFO)
721
 
 
722
 
    for (; key_part != key_part_end; key_part++, seg++)
723
 
    {
724
 
      Field *field= key_part->field;
725
 
 
726
 
      {
727
 
        if ((seg->type = field->key_type()) != (int) HA_KEYTYPE_TEXT &&
728
 
            seg->type != HA_KEYTYPE_VARTEXT1 &&
729
 
            seg->type != HA_KEYTYPE_VARTEXT2 &&
730
 
            seg->type != HA_KEYTYPE_VARBINARY1 &&
731
 
            seg->type != HA_KEYTYPE_VARBINARY2)
732
 
          seg->type= HA_KEYTYPE_BINARY;
733
 
      }
734
 
      seg->start=   (uint) key_part->offset;
735
 
      seg->length=  (uint) key_part->length;
736
 
      seg->flag=    key_part->key_part_flag;
737
 
 
738
 
      next_field_pos= seg->start + seg->length;
739
 
      if (field->type() == DRIZZLE_TYPE_VARCHAR)
740
 
      {
741
 
        next_field_pos+= (uint8_t)(((Field_varstring*)field)->pack_length_no_ptr());
742
 
      }
743
 
 
744
 
      if (next_field_pos > key_part_size) {
745
 
        key_part_size= next_field_pos;
746
 
      }
747
 
 
748
 
      if (field->flags & ENUM_FLAG)
749
 
        seg->charset= &my_charset_bin;
750
 
      else
751
 
        seg->charset= field->charset();
752
 
      if (field->null_ptr)
753
 
      {
754
 
        seg->null_bit= field->null_bit;
755
 
        seg->null_pos= (uint) (field->null_ptr - (unsigned char*) table_arg->getInsertRecord());
756
 
      }
757
 
      else
758
 
      {
759
 
        seg->null_bit= 0;
760
 
        seg->null_pos= 0;
761
 
      }
762
 
      if (field->flags & AUTO_INCREMENT_FLAG &&
763
 
          table_arg->found_next_number_field &&
764
 
          key == table_arg->getShare()->next_number_index)
765
 
      {
766
 
        /*
767
 
          Store key number and type for found auto_increment key
768
 
          We have to store type as seg->type can differ from it
769
 
        */
770
 
        auto_key= key+ 1;
771
 
        auto_key_type= field->key_type();
772
 
      }
773
 
      if ((uint)field->position() + 1 > max_key_fieldnr)
774
 
      {
775
 
        /* Do not use seg->fieldnr as it's not reliable in case of temp tables */
776
 
        max_key_fieldnr= field->position() + 1;
777
 
      }
778
 
    }
779
 
  }
780
 
 
781
 
  if (key_part_size < table_arg->getShare()->null_bytes + ((table_arg->getShare()->last_null_bit_pos+7) >> 3))
782
 
  {
783
 
    /* Make sure to include null fields regardless of the presense of keys */
784
 
    key_part_size = table_arg->getShare()->null_bytes + ((table_arg->getShare()->last_null_bit_pos+7) >> 3);
785
 
  }
786
 
 
787
 
 
788
 
 
789
 
  if (table_arg->found_next_number_field)
790
 
  {
791
 
    keydef[table_arg->getShare()->next_number_index].flag|= HA_AUTO_KEY;
792
 
    found_real_auto_increment= table_arg->getShare()->next_number_key_offset == 0;
793
 
  }
794
 
  HP_CREATE_INFO hp_create_info;
795
 
  hp_create_info.auto_key= auto_key;
796
 
  hp_create_info.auto_key_type= auto_key_type;
797
 
  hp_create_info.auto_increment= (create_proto.options().has_auto_increment_value() ?
798
 
                                  create_proto.options().auto_increment_value() - 1 : 0);
799
 
  hp_create_info.max_table_size=session->variables.max_heap_table_size;
800
 
  hp_create_info.with_auto_increment= found_real_auto_increment;
801
 
  hp_create_info.internal_table= internal_table;
802
 
  hp_create_info.max_chunk_size= table_arg->getShare()->block_size;
803
 
 
804
 
  error= heap_create(table_name,
805
 
                     keys, &keydef[0],
806
 
                     column_count,
807
 
                     key_part_size,
808
 
                     table_arg->getShare()->getRecordLength(), mem_per_row_keys,
809
 
                     static_cast<uint32_t>(num_rows), /* We check for overflow above, so cast is fine here. */
810
 
                     0, // Factor out MIN
811
 
                     &hp_create_info, internal_share);
812
 
 
813
 
  return (error);
814
 
}
815
 
 
816
 
 
817
 
void ha_heap::get_auto_increment(uint64_t, uint64_t, uint64_t,
818
 
                                 uint64_t *first_value,
819
 
                                 uint64_t *nb_reserved_values)
820
 
{
821
 
  ha_heap::info(HA_STATUS_AUTO);
822
 
  *first_value= stats.auto_increment_value;
823
 
  /* such table has only table-level locking so reserves up to +inf */
824
 
  *nb_reserved_values= UINT64_MAX;
825
 
}
826
 
 
827
 
 
828
 
int ha_heap::cmp_ref(const unsigned char *ref1, const unsigned char *ref2)
829
 
{
830
 
  return memcmp(ref1, ref2, sizeof(HEAP_PTR));
831
 
}
832
 
 
833
 
 
834
 
DRIZZLE_DECLARE_PLUGIN
835
 
{
836
 
  DRIZZLE_VERSION_ID,
837
 
  "MEMORY",
838
 
  "1.0",
839
 
  "MySQL AB",
840
 
  "Hash based, stored in memory, useful for temporary tables",
841
 
  PLUGIN_LICENSE_GPL,
842
 
  heap_init,
843
 
  NULL,                       /* system variables                */
844
 
  NULL                        /* config options                  */
845
 
}
846
 
DRIZZLE_DECLARE_PLUGIN_END;