~ubuntu-branches/ubuntu/trusty/drizzle/trusty

« back to all changes in this revision

Viewing changes to plugin/memory/ha_heap.cc

  • Committer: Bazaar Package Importer
  • Author(s): Monty Taylor
  • Date: 2010-10-02 14:17:48 UTC
  • mfrom: (1.1.1 upstream)
  • mto: (2.1.17 sid)
  • mto: This revision was merged to the branch mainline in revision 3.
  • Revision ID: james.westby@ubuntu.com-20101002141748-m6vbfbfjhrw1153e
Tags: 2010.09.1802-1
* New upstream release.
* Removed pid-file argument hack.
* Updated GPL-2 address to be new address.
* Directly copy in drizzledump.1 since debian doesn't have sphinx 1.0 yet.
* Link to jquery from libjs-jquery. Add it as a depend.
* Add drizzled.8 symlink to the install files.

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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  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(TableShare &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
                             TableIdentifiers &set_of_identifiers);
 
108
};
 
109
 
 
110
void HeapEngine::doGetTableIdentifiers(CachedDirectory&,
 
111
                                       const SchemaIdentifier&,
 
112
                                       TableIdentifiers&)
 
113
{
 
114
}
 
115
 
 
116
bool HeapEngine::doDoesTableExist(Session& session, const TableIdentifier &identifier)
 
117
{
 
118
  return session.doesTableMessageExist(identifier);
 
119
}
 
120
 
 
121
int HeapEngine::doGetTableDefinition(Session &session,
 
122
                                     const TableIdentifier &identifier,
 
123
                                     message::Table &table_proto)
 
124
{
 
125
  if (session.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.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
                 TableShare &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(table->in_use,
 
189
                                                   identifier.getPath().c_str(),
 
190
                                                   table,
 
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= table->getMutableShare()->db_type()->getCursor(*(table->getMutableShare()));
 
244
  TableIdentifier identifier(table->getShare()->getSchemaName(),
 
245
                             table->getShare()->getTableName(),
 
246
                             table->getShare()->getPath());
 
247
 
 
248
  if (new_handler && !new_handler->ha_open(identifier, table, table->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 < table->getShare()->sizeKeys(); i++)
 
285
  {
 
286
    KeyInfo *key= &table->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 (table->next_number_field && buf == table->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 && table->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
  table->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
  table->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
  table->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
  table->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
  table->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
  table->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
  table->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
  table->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
  table->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 (table->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.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= &table->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.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->field_index + 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->field_index + 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;