~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to plugin/haildb/haildb_engine.cc

  • Committer: Brian Aker
  • Date: 2010-11-19 19:42:44 UTC
  • mto: (1945.2.1 quick)
  • mto: This revision was merged to the branch mainline in revision 1944.
  • Revision ID: brian@tangent.org-20101119194244-7vx6u5vwzvu9uvex
Remove dead getShare() call which should have been a call on the cache
directly.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
  Copyright (C) 2010 Stewart Smith
 
3
 
 
4
  This program is free software; you can redistribute it and/or
 
5
  modify it under the terms of the GNU General Public License
 
6
  as published by the Free Software Foundation; either version 2
 
7
  of the License, or (at your option) any later version.
 
8
 
 
9
  This program is distributed in the hope that it will be useful,
 
10
  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
11
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
12
  GNU General Public License for more details.
 
13
 
 
14
  You should have received a copy of the GNU General Public License
 
15
  along with this program; if not, write to the Free Software
 
16
  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 
17
*/
 
18
 
 
19
/* innobase_get_int_col_max_value() comes from ha_innodb.cc which is under
 
20
   the following license and Copyright */
 
21
 
 
22
/*****************************************************************************
 
23
 
 
24
Copyright (c) 2000, 2009, MySQL AB & Innobase Oy. All Rights Reserved.
 
25
Copyright (c) 2008, 2009 Google Inc.
 
26
 
 
27
Portions of this file contain modifications contributed and copyrighted by
 
28
Google, Inc. Those modifications are gratefully acknowledged and are described
 
29
briefly in the InnoDB documentation. The contributions by Google are
 
30
incorporated with their permission, and subject to the conditions contained in
 
31
the file COPYING.Google.
 
32
 
 
33
This program is free software; you can redistribute it and/or modify it under
 
34
the terms of the GNU General Public License as published by the Free Software
 
35
Foundation; version 2 of the License.
 
36
 
 
37
This program is distributed in the hope that it will be useful, but WITHOUT
 
38
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 
39
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
 
40
 
 
41
You should have received a copy of the GNU General Public License along with
 
42
this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
 
43
St, Fifth Floor, Boston, MA 02110-1301 USA
 
44
 
 
45
*****************************************************************************/
 
46
/***********************************************************************
 
47
 
 
48
Copyright (c) 1995, 2009, Innobase Oy. All Rights Reserved.
 
49
Copyright (c) 2009, Percona Inc.
 
50
 
 
51
Portions of this file contain modifications contributed and copyrighted
 
52
by Percona Inc.. Those modifications are
 
53
gratefully acknowledged and are described briefly in the InnoDB
 
54
documentation. The contributions by Percona Inc. are incorporated with
 
55
their permission, and subject to the conditions contained in the file
 
56
COPYING.Percona.
 
57
 
 
58
This program is free software; you can redistribute it and/or modify it
 
59
under the terms of the GNU General Public License as published by the
 
60
Free Software Foundation; version 2 of the License.
 
61
 
 
62
This program is distributed in the hope that it will be useful, but
 
63
WITHOUT ANY WARRANTY; without even the implied warranty of
 
64
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
 
65
Public License for more details.
 
66
 
 
67
You should have received a copy of the GNU General Public License along
 
68
with this program; if not, write to the Free Software Foundation, Inc.,
 
69
51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
 
70
 
 
71
***********************************************************************/
 
72
 
 
73
 
 
74
#include "config.h"
 
75
#include <drizzled/table.h>
 
76
#include <drizzled/error.h>
 
77
#include "drizzled/internal/my_pthread.h"
 
78
#include <drizzled/plugin/transactional_storage_engine.h>
 
79
 
 
80
#include <fcntl.h>
 
81
 
 
82
#include <string>
 
83
#include <boost/algorithm/string.hpp>
 
84
#include <boost/unordered_set.hpp>
 
85
#include <boost/foreach.hpp>
 
86
#include <map>
 
87
#include <fstream>
 
88
#include <drizzled/message/table.pb.h>
 
89
#include "drizzled/internal/m_string.h"
 
90
 
 
91
#include "drizzled/global_charset_info.h"
 
92
 
 
93
#include "haildb_datadict_dump_func.h"
 
94
#include "config_table_function.h"
 
95
#include "status_table_function.h"
 
96
 
 
97
#include <haildb.h>
 
98
 
 
99
#include "haildb_engine.h"
 
100
 
 
101
#include <drizzled/field.h>
 
102
#include "drizzled/field/timestamp.h" // needed for UPDATE NOW()
 
103
#include "drizzled/field/blob.h"
 
104
#include "drizzled/field/enum.h"
 
105
#include <drizzled/session.h>
 
106
#include <boost/program_options.hpp>
 
107
#include <drizzled/module/option_map.h>
 
108
#include <iostream>
 
109
#include <drizzled/charset.h>
 
110
 
 
111
namespace po= boost::program_options;
 
112
#include <boost/algorithm/string.hpp>
 
113
 
 
114
using namespace std;
 
115
using namespace google;
 
116
using namespace drizzled;
 
117
 
 
118
int read_row_from_haildb(unsigned char* buf, ib_crsr_t cursor, ib_tpl_t tuple, Table* table, bool has_hidden_primary_key, uint64_t *hidden_pkey, drizzled::memory::Root **blobroot= NULL);
 
119
static void fill_ib_search_tpl_from_drizzle_key(ib_tpl_t search_tuple,
 
120
                                                const drizzled::KeyInfo *key_info,
 
121
                                                const unsigned char *key_ptr,
 
122
                                                uint32_t key_len);
 
123
static void store_key_value_from_haildb(KeyInfo *key_info, unsigned char* ref, int ref_len, const unsigned char *record);
 
124
 
 
125
#define HAILDB_EXT ".EID"
 
126
 
 
127
const char HAILDB_TABLE_DEFINITIONS_TABLE[]= "data_dictionary/haildb_table_definitions";
 
128
const string statement_savepoint_name("STATEMENT");
 
129
 
 
130
static boost::unordered_set<std::string> haildb_system_table_names;
 
131
 
 
132
 
 
133
static const char *HailDBCursor_exts[] = {
 
134
  NULL
 
135
};
 
136
 
 
137
class HailDBEngine : public drizzled::plugin::TransactionalStorageEngine
 
138
{
 
139
public:
 
140
  HailDBEngine(const string &name_arg)
 
141
   : drizzled::plugin::TransactionalStorageEngine(name_arg,
 
142
                                                  HTON_NULL_IN_KEY |
 
143
                                                  HTON_CAN_INDEX_BLOBS |
 
144
                                                  HTON_AUTO_PART_KEY |
 
145
                                                  HTON_PARTIAL_COLUMN_READ |
 
146
                                                  HTON_HAS_DOES_TRANSACTIONS)
 
147
  {
 
148
    table_definition_ext= HAILDB_EXT;
 
149
  }
 
150
 
 
151
  ~HailDBEngine();
 
152
 
 
153
  virtual Cursor *create(Table &table)
 
154
  {
 
155
    return new HailDBCursor(*this, table);
 
156
  }
 
157
 
 
158
  const char **bas_ext() const {
 
159
    return HailDBCursor_exts;
 
160
  }
 
161
 
 
162
  bool validateCreateTableOption(const std::string &key,
 
163
                                 const std::string &state);
 
164
 
 
165
  int doCreateTable(Session&,
 
166
                    Table& table_arg,
 
167
                    const drizzled::TableIdentifier &identifier,
 
168
                    drizzled::message::Table& proto);
 
169
 
 
170
  int doDropTable(Session&, const TableIdentifier &identifier);
 
171
 
 
172
  int doRenameTable(drizzled::Session&,
 
173
                    const drizzled::TableIdentifier&,
 
174
                    const drizzled::TableIdentifier&);
 
175
 
 
176
  int doGetTableDefinition(Session& session,
 
177
                           const TableIdentifier &identifier,
 
178
                           drizzled::message::Table &table_proto);
 
179
 
 
180
  bool doDoesTableExist(Session&, const TableIdentifier &identifier);
 
181
 
 
182
private:
 
183
  void getTableNamesInSchemaFromHailDB(const drizzled::SchemaIdentifier &schema,
 
184
                                       drizzled::plugin::TableNameList *set_of_names,
 
185
                                       drizzled::TableIdentifiers *identifiers);
 
186
 
 
187
public:
 
188
  void doGetTableIdentifiers(drizzled::CachedDirectory &,
 
189
                             const drizzled::SchemaIdentifier &schema,
 
190
                             drizzled::TableIdentifiers &identifiers);
 
191
 
 
192
  /* The following defines can be increased if necessary */
 
193
  uint32_t max_supported_keys()          const { return 1000; }
 
194
  uint32_t max_supported_key_length()    const { return 3500; }
 
195
  uint32_t max_supported_key_part_length() const { return 767; }
 
196
 
 
197
  uint32_t index_flags(enum  ha_key_alg) const
 
198
  {
 
199
    return (HA_READ_NEXT |
 
200
            HA_READ_PREV |
 
201
            HA_READ_RANGE |
 
202
            HA_READ_ORDER |
 
203
            HA_KEYREAD_ONLY);
 
204
  }
 
205
  virtual int doStartTransaction(Session *session,
 
206
                                 start_transaction_option_t options);
 
207
  virtual void doStartStatement(Session *session);
 
208
  virtual void doEndStatement(Session *session);
 
209
 
 
210
  virtual int doSetSavepoint(Session* session,
 
211
                                 drizzled::NamedSavepoint &savepoint);
 
212
  virtual int doRollbackToSavepoint(Session* session,
 
213
                                     drizzled::NamedSavepoint &savepoint);
 
214
  virtual int doReleaseSavepoint(Session* session,
 
215
                                     drizzled::NamedSavepoint &savepoint);
 
216
  virtual int doCommit(Session* session, bool all);
 
217
  virtual int doRollback(Session* session, bool all);
 
218
 
 
219
  typedef std::map<std::string, HailDBTableShare*> HailDBMap;
 
220
  HailDBMap haildb_open_tables;
 
221
  HailDBTableShare *findOpenTable(const std::string table_name);
 
222
  void addOpenTable(const std::string &table_name, HailDBTableShare *);
 
223
  void deleteOpenTable(const std::string &table_name);
 
224
 
 
225
  uint64_t getInitialAutoIncrementValue(HailDBCursor *cursor);
 
226
  uint64_t getHiddenPrimaryKeyInitialAutoIncrementValue(HailDBCursor *cursor);
 
227
 
 
228
};
 
229
 
 
230
static drizzled::plugin::StorageEngine *haildb_engine= NULL;
 
231
 
 
232
 
 
233
static ib_trx_t* get_trx(Session* session)
 
234
{
 
235
  return (ib_trx_t*) session->getEngineData(haildb_engine);
 
236
}
 
237
 
 
238
/* This is a superset of the map from innobase plugin.
 
239
   Unlike innobase plugin we don't act on errors here, we just
 
240
   map error codes. */
 
241
static int ib_err_t_to_drizzle_error(ib_err_t err)
 
242
{
 
243
  switch (err)
 
244
  {
 
245
  case DB_SUCCESS:
 
246
    return 0;
 
247
 
 
248
  case DB_ERROR:
 
249
  default:
 
250
    return -1;
 
251
 
 
252
  case DB_INTERRUPTED:
 
253
    return ER_QUERY_INTERRUPTED; // FIXME: is this correct?
 
254
 
 
255
  case DB_OUT_OF_MEMORY:
 
256
    return HA_ERR_OUT_OF_MEM;
 
257
 
 
258
  case DB_DUPLICATE_KEY:
 
259
    return HA_ERR_FOUND_DUPP_KEY;
 
260
 
 
261
  case DB_FOREIGN_DUPLICATE_KEY:
 
262
    return HA_ERR_FOREIGN_DUPLICATE_KEY;
 
263
 
 
264
  case DB_MISSING_HISTORY:
 
265
    return HA_ERR_TABLE_DEF_CHANGED;
 
266
 
 
267
  case DB_RECORD_NOT_FOUND:
 
268
    return HA_ERR_NO_ACTIVE_RECORD;
 
269
 
 
270
  case DB_DEADLOCK:
 
271
    return HA_ERR_LOCK_DEADLOCK;
 
272
 
 
273
  case DB_LOCK_WAIT_TIMEOUT:
 
274
    return HA_ERR_LOCK_WAIT_TIMEOUT;
 
275
 
 
276
  case DB_NO_REFERENCED_ROW:
 
277
    return HA_ERR_NO_REFERENCED_ROW;
 
278
 
 
279
  case DB_ROW_IS_REFERENCED:
 
280
    return HA_ERR_ROW_IS_REFERENCED;
 
281
 
 
282
  case DB_CANNOT_ADD_CONSTRAINT:
 
283
    return HA_ERR_CANNOT_ADD_FOREIGN;
 
284
 
 
285
  case DB_CANNOT_DROP_CONSTRAINT:
 
286
    return HA_ERR_ROW_IS_REFERENCED; /* misleading. should have new err code */
 
287
 
 
288
  case DB_COL_APPEARS_TWICE_IN_INDEX:
 
289
  case DB_CORRUPTION:
 
290
    return HA_ERR_CRASHED;
 
291
 
 
292
  case DB_MUST_GET_MORE_FILE_SPACE:
 
293
  case DB_OUT_OF_FILE_SPACE:
 
294
    return HA_ERR_RECORD_FILE_FULL;
 
295
 
 
296
  case DB_TABLE_IS_BEING_USED:
 
297
    return HA_ERR_WRONG_COMMAND;
 
298
 
 
299
  case DB_TABLE_NOT_FOUND:
 
300
    return HA_ERR_NO_SUCH_TABLE;
 
301
 
 
302
  case DB_TOO_BIG_RECORD:
 
303
    return HA_ERR_TO_BIG_ROW;
 
304
 
 
305
  case DB_NO_SAVEPOINT:
 
306
    return HA_ERR_NO_SAVEPOINT;
 
307
 
 
308
  case DB_LOCK_TABLE_FULL:
 
309
    return HA_ERR_LOCK_TABLE_FULL;
 
310
 
 
311
  case DB_PRIMARY_KEY_IS_NULL:
 
312
    return ER_PRIMARY_CANT_HAVE_NULL;
 
313
 
 
314
  case DB_TOO_MANY_CONCURRENT_TRXS:
 
315
    return HA_ERR_RECORD_FILE_FULL; /* need better error code */
 
316
 
 
317
  case DB_END_OF_INDEX:
 
318
    return HA_ERR_END_OF_FILE;
 
319
 
 
320
  case DB_UNSUPPORTED:
 
321
    return HA_ERR_UNSUPPORTED;
 
322
  }
 
323
}
 
324
 
 
325
static ib_trx_level_t tx_isolation_to_ib_trx_level(enum_tx_isolation level)
 
326
{
 
327
  switch(level)
 
328
  {
 
329
  case ISO_REPEATABLE_READ:
 
330
    return IB_TRX_REPEATABLE_READ;
 
331
  case ISO_READ_COMMITTED:
 
332
    return IB_TRX_READ_COMMITTED;
 
333
  case ISO_SERIALIZABLE:
 
334
    return IB_TRX_SERIALIZABLE;
 
335
  case ISO_READ_UNCOMMITTED:
 
336
    return IB_TRX_READ_UNCOMMITTED;
 
337
  }
 
338
 
 
339
  assert(0);
 
340
  return IB_TRX_REPEATABLE_READ;
 
341
}
 
342
 
 
343
int HailDBEngine::doStartTransaction(Session *session,
 
344
                                             start_transaction_option_t options)
 
345
{
 
346
  ib_trx_t *transaction;
 
347
  ib_trx_level_t isolation_level;
 
348
 
 
349
  (void)options;
 
350
 
 
351
  transaction= get_trx(session);
 
352
  isolation_level= tx_isolation_to_ib_trx_level((enum_tx_isolation)session_tx_isolation(session));
 
353
  *transaction= ib_trx_begin(isolation_level);
 
354
 
 
355
  return 0;
 
356
}
 
357
 
 
358
void HailDBEngine::doStartStatement(Session *session)
 
359
{
 
360
  if(*get_trx(session) == NULL)
 
361
    doStartTransaction(session, START_TRANS_NO_OPTIONS);
 
362
 
 
363
  ib_savepoint_take(*get_trx(session), statement_savepoint_name.c_str(),
 
364
                    statement_savepoint_name.length());
 
365
}
 
366
 
 
367
void HailDBEngine::doEndStatement(Session *)
 
368
{
 
369
}
 
370
 
 
371
int HailDBEngine::doSetSavepoint(Session* session,
 
372
                                         drizzled::NamedSavepoint &savepoint)
 
373
{
 
374
  ib_trx_t *transaction= get_trx(session);
 
375
  ib_savepoint_take(*transaction, savepoint.getName().c_str(),
 
376
                    savepoint.getName().length());
 
377
  return 0;
 
378
}
 
379
 
 
380
int HailDBEngine::doRollbackToSavepoint(Session* session,
 
381
                                                drizzled::NamedSavepoint &savepoint)
 
382
{
 
383
  ib_trx_t *transaction= get_trx(session);
 
384
  ib_err_t err;
 
385
 
 
386
  err= ib_savepoint_rollback(*transaction, savepoint.getName().c_str(),
 
387
                             savepoint.getName().length());
 
388
 
 
389
  return ib_err_t_to_drizzle_error(err);
 
390
}
 
391
 
 
392
int HailDBEngine::doReleaseSavepoint(Session* session,
 
393
                                             drizzled::NamedSavepoint &savepoint)
 
394
{
 
395
  ib_trx_t *transaction= get_trx(session);
 
396
  ib_err_t err;
 
397
 
 
398
  err= ib_savepoint_release(*transaction, savepoint.getName().c_str(),
 
399
                            savepoint.getName().length());
 
400
  if (err != DB_SUCCESS)
 
401
    return ib_err_t_to_drizzle_error(err);
 
402
 
 
403
  return 0;
 
404
}
 
405
 
 
406
int HailDBEngine::doCommit(Session* session, bool all)
 
407
{
 
408
  ib_err_t err;
 
409
  ib_trx_t *transaction= get_trx(session);
 
410
 
 
411
  if (all || (!session_test_options(session, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)))
 
412
  {
 
413
    err= ib_trx_commit(*transaction);
 
414
 
 
415
    if (err != DB_SUCCESS)
 
416
      return ib_err_t_to_drizzle_error(err);
 
417
 
 
418
    *transaction= NULL;
 
419
  }
 
420
 
 
421
  return 0;
 
422
}
 
423
 
 
424
int HailDBEngine::doRollback(Session* session, bool all)
 
425
{
 
426
  ib_err_t err;
 
427
  ib_trx_t *transaction= get_trx(session);
 
428
 
 
429
  if (all || !session_test_options(session, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))
 
430
  {
 
431
    err= ib_trx_rollback(*transaction);
 
432
 
 
433
    if (err != DB_SUCCESS)
 
434
      return ib_err_t_to_drizzle_error(err);
 
435
 
 
436
    *transaction= NULL;
 
437
  }
 
438
  else
 
439
  {
 
440
    err= ib_savepoint_rollback(*transaction, statement_savepoint_name.c_str(),
 
441
                               statement_savepoint_name.length());
 
442
    if (err != DB_SUCCESS)
 
443
      return ib_err_t_to_drizzle_error(err);
 
444
  }
 
445
 
 
446
  return 0;
 
447
}
 
448
 
 
449
HailDBTableShare *HailDBEngine::findOpenTable(const string table_name)
 
450
{
 
451
  HailDBMap::iterator find_iter=
 
452
    haildb_open_tables.find(table_name);
 
453
 
 
454
  if (find_iter != haildb_open_tables.end())
 
455
    return (*find_iter).second;
 
456
  else
 
457
    return NULL;
 
458
}
 
459
 
 
460
void HailDBEngine::addOpenTable(const string &table_name, HailDBTableShare *share)
 
461
{
 
462
  haildb_open_tables[table_name]= share;
 
463
}
 
464
 
 
465
void HailDBEngine::deleteOpenTable(const string &table_name)
 
466
{
 
467
  haildb_open_tables.erase(table_name);
 
468
}
 
469
 
 
470
static pthread_mutex_t haildb_mutex= PTHREAD_MUTEX_INITIALIZER;
 
471
 
 
472
uint64_t HailDBCursor::getHiddenPrimaryKeyInitialAutoIncrementValue()
 
473
{
 
474
  uint64_t nr;
 
475
  ib_err_t err;
 
476
  ib_trx_t transaction= *get_trx(getTable()->in_use);
 
477
  ib_cursor_attach_trx(cursor, transaction);
 
478
  tuple= ib_clust_read_tuple_create(cursor);
 
479
  err= ib_cursor_last(cursor);
 
480
  assert(err == DB_SUCCESS || err == DB_END_OF_INDEX); // Probably a FIXME
 
481
  err= ib_cursor_read_row(cursor, tuple);
 
482
  if (err == DB_RECORD_NOT_FOUND)
 
483
    nr= 1;
 
484
  else
 
485
  {
 
486
    assert (err == DB_SUCCESS);
 
487
    err= ib_tuple_read_u64(tuple, getTable()->getShare()->fields, &nr);
 
488
    nr++;
 
489
  }
 
490
  ib_tuple_delete(tuple);
 
491
  err= ib_cursor_reset(cursor);
 
492
  assert(err == DB_SUCCESS);
 
493
  return nr;
 
494
}
 
495
 
 
496
uint64_t HailDBCursor::getInitialAutoIncrementValue()
 
497
{
 
498
  uint64_t nr;
 
499
  int error;
 
500
 
 
501
  (void) extra(HA_EXTRA_KEYREAD);
 
502
  getTable()->mark_columns_used_by_index_no_reset(getTable()->getShare()->next_number_index);
 
503
  doStartIndexScan(getTable()->getShare()->next_number_index, 1);
 
504
  if (getTable()->getShare()->next_number_keypart == 0)
 
505
  {                                             // Autoincrement at key-start
 
506
    error=index_last(getTable()->getUpdateRecord());
 
507
  }
 
508
  else
 
509
  {
 
510
    unsigned char key[MAX_KEY_LENGTH];
 
511
    key_copy(key, getTable()->getInsertRecord(),
 
512
             getTable()->key_info + getTable()->getShare()->next_number_index,
 
513
             getTable()->getShare()->next_number_key_offset);
 
514
    error= index_read_map(getTable()->getUpdateRecord(), key,
 
515
                          make_prev_keypart_map(getTable()->getShare()->next_number_keypart),
 
516
                          HA_READ_PREFIX_LAST);
 
517
  }
 
518
 
 
519
  if (error)
 
520
    nr=1;
 
521
  else
 
522
    nr= ((uint64_t) getTable()->found_next_number_field->
 
523
         val_int_offset(getTable()->getShare()->rec_buff_length)+1);
 
524
  doEndIndexScan();
 
525
  (void) extra(HA_EXTRA_NO_KEYREAD);
 
526
 
 
527
  if (getTable()->getShare()->getTableProto()->options().auto_increment_value() > nr)
 
528
    nr= getTable()->getShare()->getTableProto()->options().auto_increment_value();
 
529
 
 
530
  return nr;
 
531
}
 
532
 
 
533
HailDBTableShare::HailDBTableShare(const char* name, bool hidden_primary_key)
 
534
  : use_count(0), has_hidden_primary_key(hidden_primary_key)
 
535
{
 
536
  table_name.assign(name);
 
537
}
 
538
 
 
539
uint64_t HailDBEngine::getInitialAutoIncrementValue(HailDBCursor *cursor)
 
540
{
 
541
  doStartTransaction(current_session, START_TRANS_NO_OPTIONS);
 
542
  uint64_t initial_auto_increment_value= cursor->getInitialAutoIncrementValue();
 
543
  doCommit(current_session, true);
 
544
 
 
545
  return initial_auto_increment_value;
 
546
}
 
547
 
 
548
uint64_t HailDBEngine::getHiddenPrimaryKeyInitialAutoIncrementValue(HailDBCursor *cursor)
 
549
{
 
550
  doStartTransaction(current_session, START_TRANS_NO_OPTIONS);
 
551
  uint64_t initial_auto_increment_value= cursor->getHiddenPrimaryKeyInitialAutoIncrementValue();
 
552
  doCommit(current_session, true);
 
553
 
 
554
  return initial_auto_increment_value;
 
555
}
 
556
 
 
557
HailDBTableShare *HailDBCursor::get_share(const char *table_name, bool has_hidden_primary_key, int *rc)
 
558
{
 
559
  pthread_mutex_lock(&haildb_mutex);
 
560
 
 
561
  HailDBEngine *a_engine= static_cast<HailDBEngine *>(getEngine());
 
562
  share= a_engine->findOpenTable(table_name);
 
563
 
 
564
  if (!share)
 
565
  {
 
566
    share= new HailDBTableShare(table_name, has_hidden_primary_key);
 
567
 
 
568
    if (share == NULL)
 
569
    {
 
570
      pthread_mutex_unlock(&haildb_mutex);
 
571
      *rc= HA_ERR_OUT_OF_MEM;
 
572
      return(NULL);
 
573
    }
 
574
 
 
575
    if (getTable()->found_next_number_field)
 
576
    {
 
577
      share->auto_increment_value.fetch_and_store(
 
578
                                  a_engine->getInitialAutoIncrementValue(this));
 
579
 
 
580
    }
 
581
 
 
582
    if (has_hidden_primary_key)
 
583
    {
 
584
      uint64_t hidden_pkey= 0;
 
585
      hidden_pkey= a_engine->getHiddenPrimaryKeyInitialAutoIncrementValue(this);
 
586
      share->hidden_pkey_auto_increment_value.fetch_and_store(hidden_pkey);
 
587
    }
 
588
 
 
589
    a_engine->addOpenTable(share->table_name, share);
 
590
    thr_lock_init(&share->lock);
 
591
  }
 
592
  share->use_count++;
 
593
 
 
594
  pthread_mutex_unlock(&haildb_mutex);
 
595
 
 
596
  return(share);
 
597
}
 
598
 
 
599
int HailDBCursor::free_share()
 
600
{
 
601
  pthread_mutex_lock(&haildb_mutex);
 
602
  if (!--share->use_count)
 
603
  {
 
604
    HailDBEngine *a_engine= static_cast<HailDBEngine *>(getEngine());
 
605
    a_engine->deleteOpenTable(share->table_name);
 
606
    delete share;
 
607
  }
 
608
  pthread_mutex_unlock(&haildb_mutex);
 
609
 
 
610
  return 0;
 
611
}
 
612
 
 
613
 
 
614
THR_LOCK_DATA **HailDBCursor::store_lock(Session *session,
 
615
                                                 THR_LOCK_DATA **to,
 
616
                                                 thr_lock_type lock_type)
 
617
{
 
618
  /* Currently, we can get a transaction start by ::store_lock
 
619
     instead of beginTransaction, startStatement.
 
620
 
 
621
     See https://bugs.launchpad.net/drizzle/+bug/535528
 
622
 
 
623
     all stemming from the transactional engine interface needing
 
624
     a severe amount of immodium.
 
625
   */
 
626
 
 
627
  if(*get_trx(session) == NULL)
 
628
  {
 
629
    static_cast<HailDBEngine*>(getEngine())->
 
630
                    doStartTransaction(session, START_TRANS_NO_OPTIONS);
 
631
  }
 
632
 
 
633
  if (lock_type != TL_UNLOCK)
 
634
  {
 
635
    ib_savepoint_take(*get_trx(session), statement_savepoint_name.c_str(),
 
636
                      statement_savepoint_name.length());
 
637
  }
 
638
 
 
639
  /* the below is adapted from ha_innodb.cc */
 
640
 
 
641
  const uint32_t sql_command = session_sql_command(session);
 
642
 
 
643
  if (sql_command == SQLCOM_DROP_TABLE) {
 
644
 
 
645
    /* MySQL calls this function in DROP Table though this table
 
646
    handle may belong to another session that is running a query.
 
647
    Let us in that case skip any changes to the prebuilt struct. */ 
 
648
 
 
649
  } else if (lock_type == TL_READ_WITH_SHARED_LOCKS
 
650
       || lock_type == TL_READ_NO_INSERT
 
651
       || (lock_type != TL_IGNORE
 
652
           && sql_command != SQLCOM_SELECT)) {
 
653
 
 
654
    /* The OR cases above are in this order:
 
655
    1) MySQL is doing LOCK TABLES ... READ LOCAL, or we
 
656
    are processing a stored procedure or function, or
 
657
    2) (we do not know when TL_READ_HIGH_PRIORITY is used), or
 
658
    3) this is a SELECT ... IN SHARE MODE, or
 
659
    4) we are doing a complex SQL statement like
 
660
    INSERT INTO ... SELECT ... and the logical logging (MySQL
 
661
    binlog) requires the use of a locking read, or
 
662
    MySQL is doing LOCK TABLES ... READ.
 
663
    5) we let InnoDB do locking reads for all SQL statements that
 
664
    are not simple SELECTs; note that select_lock_type in this
 
665
    case may get strengthened in ::external_lock() to LOCK_X.
 
666
    Note that we MUST use a locking read in all data modifying
 
667
    SQL statements, because otherwise the execution would not be
 
668
    serializable, and also the results from the update could be
 
669
    unexpected if an obsolete consistent read view would be
 
670
    used. */
 
671
 
 
672
    enum_tx_isolation isolation_level= session_tx_isolation(session);
 
673
 
 
674
    if (isolation_level != ISO_SERIALIZABLE
 
675
        && (lock_type == TL_READ || lock_type == TL_READ_NO_INSERT)
 
676
        && (sql_command == SQLCOM_INSERT_SELECT
 
677
      || sql_command == SQLCOM_UPDATE
 
678
      || sql_command == SQLCOM_CREATE_TABLE)) {
 
679
 
 
680
      /* If we either have innobase_locks_unsafe_for_binlog
 
681
      option set or this session is using READ COMMITTED
 
682
      isolation level and isolation level of the transaction
 
683
      is not set to serializable and MySQL is doing
 
684
      INSERT INTO...SELECT or UPDATE ... = (SELECT ...) or
 
685
      CREATE  ... SELECT... without FOR UPDATE or
 
686
      IN SHARE MODE in select, then we use consistent
 
687
      read for select. */
 
688
 
 
689
      ib_lock_mode= IB_LOCK_NONE;
 
690
    } else if (sql_command == SQLCOM_CHECKSUM) {
 
691
      /* Use consistent read for checksum table */
 
692
 
 
693
      ib_lock_mode= IB_LOCK_NONE;
 
694
    } else {
 
695
      ib_lock_mode= IB_LOCK_S;
 
696
    }
 
697
 
 
698
  } else if (lock_type != TL_IGNORE) {
 
699
 
 
700
    /* We set possible LOCK_X value in external_lock, not yet
 
701
    here even if this would be SELECT ... FOR UPDATE */
 
702
    ib_lock_mode= IB_LOCK_NONE;
 
703
  }
 
704
 
 
705
  if (lock_type != TL_IGNORE && lock.type == TL_UNLOCK) {
 
706
 
 
707
    /* If we are not doing a LOCK TABLE, DISCARD/IMPORT
 
708
    TABLESPACE or TRUNCATE TABLE then allow multiple
 
709
    writers. Note that ALTER TABLE uses a TL_WRITE_ALLOW_READ
 
710
    < TL_WRITE_CONCURRENT_INSERT.
 
711
    */
 
712
 
 
713
    if ((lock_type >= TL_WRITE_CONCURRENT_INSERT
 
714
         && lock_type <= TL_WRITE)
 
715
        && !session_tablespace_op(session)
 
716
        && sql_command != SQLCOM_TRUNCATE
 
717
        && sql_command != SQLCOM_CREATE_TABLE) {
 
718
 
 
719
      lock_type = TL_WRITE_ALLOW_WRITE;
 
720
    }
 
721
 
 
722
    /* In queries of type INSERT INTO t1 SELECT ... FROM t2 ...
 
723
    MySQL would use the lock TL_READ_NO_INSERT on t2, and that
 
724
    would conflict with TL_WRITE_ALLOW_WRITE, blocking all inserts
 
725
    to t2. Convert the lock to a normal read lock to allow
 
726
    concurrent inserts to t2.
 
727
    */
 
728
 
 
729
    if (lock_type == TL_READ_NO_INSERT) {
 
730
 
 
731
      lock_type = TL_READ;
 
732
    }
 
733
 
 
734
    lock.type = lock_type;
 
735
  }
 
736
 
 
737
  *to++= &lock;
 
738
 
 
739
  return to;
 
740
}
 
741
 
 
742
void HailDBCursor::get_auto_increment(uint64_t, //offset,
 
743
                                              uint64_t, //increment,
 
744
                                              uint64_t, //nb_dis,
 
745
                                              uint64_t *first_value,
 
746
                                              uint64_t *nb_reserved_values)
 
747
{
 
748
fetch:
 
749
  *first_value= share->auto_increment_value.fetch_and_increment();
 
750
  if (*first_value == 0)
 
751
  {
 
752
    /* if it's zero, then we skip it... why? because of ass.
 
753
       set auto-inc to -1 and the sequence is:
 
754
       -1, 1.
 
755
       Zero is still "magic".
 
756
    */
 
757
    share->auto_increment_value.compare_and_swap(1, 0);
 
758
    goto fetch;
 
759
  }
 
760
  *nb_reserved_values= 1;
 
761
}
 
762
 
 
763
static const char* table_path_to_haildb_name(const char* name)
 
764
{
 
765
  size_t l= strlen(name);
 
766
  static string datadict_path("data_dictionary/");
 
767
  static string sys_prefix("data_dictionary/haildb_");
 
768
  static string sys_table_prefix("HAILDB_");
 
769
 
 
770
  if (strncmp(name, sys_prefix.c_str(), sys_prefix.length()) == 0)
 
771
  {
 
772
    string find_name(name+datadict_path.length());
 
773
    std::transform(find_name.begin(), find_name.end(), find_name.begin(), ::toupper);
 
774
    boost::unordered_set<string>::iterator iter= haildb_system_table_names.find(find_name);
 
775
    if (iter != haildb_system_table_names.end())
 
776
      return (*iter).c_str()+sys_table_prefix.length();
 
777
  }
 
778
 
 
779
  int slashes= 2;
 
780
  while(slashes>0 && l > 0)
 
781
  {
 
782
    l--;
 
783
    if (name[l] == '/')
 
784
      slashes--;
 
785
  }
 
786
  if (slashes==0)
 
787
    l++;
 
788
 
 
789
  return &name[l];
 
790
}
 
791
 
 
792
static void TableIdentifier_to_haildb_name(const TableIdentifier &identifier, std::string *str)
 
793
{
 
794
  str->assign(table_path_to_haildb_name(identifier.getPath().c_str()));
 
795
}
 
796
 
 
797
HailDBCursor::HailDBCursor(drizzled::plugin::StorageEngine &engine_arg,
 
798
                           Table &table_arg)
 
799
  :Cursor(engine_arg, table_arg),
 
800
   ib_lock_mode(IB_LOCK_NONE),
 
801
   write_can_replace(false),
 
802
   blobroot(NULL)
 
803
{ }
 
804
 
 
805
static unsigned int get_first_unique_index(drizzled::Table &table)
 
806
{
 
807
  for (uint32_t k= 0; k < table.getShare()->keys; k++)
 
808
  {
 
809
    if (table.key_info[k].flags & HA_NOSAME)
 
810
    {
 
811
      return k;
 
812
    }
 
813
  }
 
814
 
 
815
  return 0;
 
816
}
 
817
 
 
818
int HailDBCursor::open(const char *name, int, uint32_t)
 
819
{
 
820
  const char* haildb_table_name= table_path_to_haildb_name(name);
 
821
  ib_err_t err= ib_cursor_open_table(haildb_table_name, NULL, &cursor);
 
822
  bool has_hidden_primary_key= false;
 
823
  ib_id_t idx_id;
 
824
 
 
825
  if (err != DB_SUCCESS)
 
826
    return ib_err_t_to_drizzle_error(err);
 
827
 
 
828
  err= ib_index_get_id(haildb_table_name, "HIDDEN_PRIMARY", &idx_id);
 
829
 
 
830
  if (err == DB_SUCCESS)
 
831
    has_hidden_primary_key= true;
 
832
 
 
833
  int rc;
 
834
  share= get_share(name, has_hidden_primary_key, &rc);
 
835
  lock.init(&share->lock);
 
836
 
 
837
 
 
838
  if (getTable()->getShare()->getPrimaryKey() != MAX_KEY)
 
839
    ref_length= getTable()->key_info[getTable()->getShare()->getPrimaryKey()].key_length;
 
840
  else if (share->has_hidden_primary_key)
 
841
    ref_length= sizeof(uint64_t);
 
842
  else
 
843
  {
 
844
    unsigned int keynr= get_first_unique_index(*getTable());
 
845
    ref_length= getTable()->key_info[keynr].key_length;
 
846
  }
 
847
 
 
848
  in_table_scan= false;
 
849
 
 
850
  return(0);
 
851
}
 
852
 
 
853
int HailDBCursor::close(void)
 
854
{
 
855
  ib_err_t err= ib_cursor_close(cursor);
 
856
  if (err != DB_SUCCESS)
 
857
    return ib_err_t_to_drizzle_error(err);
 
858
 
 
859
  free_share();
 
860
 
 
861
  delete blobroot;
 
862
  blobroot= NULL;
 
863
 
 
864
  return 0;
 
865
}
 
866
 
 
867
int HailDBCursor::external_lock(Session* session, int lock_type)
 
868
{
 
869
  ib_cursor_stmt_begin(cursor);
 
870
 
 
871
  (void)session;
 
872
 
 
873
  if (lock_type == F_WRLCK)
 
874
  {
 
875
    /* SELECT ... FOR UPDATE or UPDATE TABLE */
 
876
    ib_lock_mode= IB_LOCK_X;
 
877
  }
 
878
  else
 
879
    ib_lock_mode= IB_LOCK_NONE;
 
880
 
 
881
  return 0;
 
882
}
 
883
 
 
884
static int create_table_add_field(ib_tbl_sch_t schema,
 
885
                                  const message::Table::Field &field,
 
886
                                  ib_err_t *err)
 
887
{
 
888
  ib_col_attr_t column_attr= IB_COL_NONE;
 
889
 
 
890
  if (field.has_constraints() && ! field.constraints().is_nullable())
 
891
    column_attr= IB_COL_NOT_NULL;
 
892
 
 
893
  switch (field.type())
 
894
  {
 
895
  case message::Table::Field::VARCHAR:
 
896
    *err= ib_table_schema_add_col(schema, field.name().c_str(), IB_VARCHAR,
 
897
                                  column_attr, 0,
 
898
                                  field.string_options().length());
 
899
    break;
 
900
  case message::Table::Field::INTEGER:
 
901
    *err= ib_table_schema_add_col(schema, field.name().c_str(), IB_INT,
 
902
                                  column_attr, 0, 4);
 
903
    break;
 
904
  case message::Table::Field::BIGINT:
 
905
    *err= ib_table_schema_add_col(schema, field.name().c_str(), IB_INT,
 
906
                                  column_attr, 0, 8);
 
907
    break;
 
908
  case message::Table::Field::DOUBLE:
 
909
  case message::Table::Field::DATETIME:
 
910
    *err= ib_table_schema_add_col(schema, field.name().c_str(), IB_DOUBLE,
 
911
                                  column_attr, 0, sizeof(double));
 
912
    break;
 
913
  case message::Table::Field::ENUM:
 
914
    *err= ib_table_schema_add_col(schema, field.name().c_str(), IB_INT,
 
915
                                  column_attr, 0, 4);
 
916
    break;
 
917
  case message::Table::Field::DATE:
 
918
    *err= ib_table_schema_add_col(schema, field.name().c_str(), IB_INT,
 
919
                                  column_attr, 0, 4);
 
920
    break;
 
921
  case message::Table::Field::TIMESTAMP:
 
922
    *err= ib_table_schema_add_col(schema, field.name().c_str(), IB_INT,
 
923
                                  column_attr, 0, 8);
 
924
    break;
 
925
  case message::Table::Field::BLOB:
 
926
    *err= ib_table_schema_add_col(schema, field.name().c_str(), IB_BLOB,
 
927
                                  column_attr, 0, 0);
 
928
    break;
 
929
  case message::Table::Field::DECIMAL:
 
930
    *err= ib_table_schema_add_col(schema, field.name().c_str(), IB_DECIMAL,
 
931
                                  column_attr, 0, 0);
 
932
    break;
 
933
  default:
 
934
    my_error(ER_CHECK_NOT_IMPLEMENTED, MYF(0), "Column Type");
 
935
    return(HA_ERR_UNSUPPORTED);
 
936
  }
 
937
 
 
938
  return 0;
 
939
}
 
940
 
 
941
static ib_err_t store_table_message(ib_trx_t transaction, const char* table_name, drizzled::message::Table& table_message)
 
942
{
 
943
  ib_crsr_t cursor;
 
944
  ib_tpl_t message_tuple;
 
945
  ib_err_t err;
 
946
  string serialized_message;
 
947
 
 
948
  err= ib_cursor_open_table(HAILDB_TABLE_DEFINITIONS_TABLE, transaction, &cursor);
 
949
  if (err != DB_SUCCESS)
 
950
    return err;
 
951
 
 
952
  message_tuple= ib_clust_read_tuple_create(cursor);
 
953
 
 
954
  err= ib_col_set_value(message_tuple, 0, table_name, strlen(table_name));
 
955
  if (err != DB_SUCCESS)
 
956
    goto cleanup;
 
957
 
 
958
  try {
 
959
    table_message.SerializeToString(&serialized_message);
 
960
  }
 
961
  catch (...)
 
962
  {
 
963
    goto cleanup;
 
964
  }
 
965
 
 
966
  err= ib_col_set_value(message_tuple, 1, serialized_message.c_str(),
 
967
                        serialized_message.length());
 
968
  if (err != DB_SUCCESS)
 
969
    goto cleanup;
 
970
 
 
971
  err= ib_cursor_insert_row(cursor, message_tuple);
 
972
 
 
973
cleanup:
 
974
  ib_tuple_delete(message_tuple);
 
975
 
 
976
  ib_err_t cleanup_err= ib_cursor_close(cursor);
 
977
  if (err == DB_SUCCESS)
 
978
    err= cleanup_err;
 
979
 
 
980
  return err;
 
981
}
 
982
 
 
983
bool HailDBEngine::validateCreateTableOption(const std::string &key,
 
984
                                                     const std::string &state)
 
985
{
 
986
  if (boost::iequals(key, "ROW_FORMAT"))
 
987
  {
 
988
    if (boost::iequals(state, "COMPRESSED"))
 
989
      return true;
 
990
 
 
991
    if (boost::iequals(state, "COMPACT"))
 
992
      return true;
 
993
 
 
994
    if (boost::iequals(state, "DYNAMIC"))
 
995
      return true;
 
996
 
 
997
    if (boost::iequals(state, "REDUNDANT"))
 
998
      return true;
 
999
  }
 
1000
 
 
1001
  return false;
 
1002
}
 
1003
 
 
1004
static ib_tbl_fmt_t parse_ib_table_format(const std::string &value)
 
1005
{
 
1006
  if (boost::iequals(value, "REDUNDANT"))
 
1007
    return IB_TBL_REDUNDANT;
 
1008
  else if (boost::iequals(value, "COMPACT"))
 
1009
    return IB_TBL_COMPACT;
 
1010
  else if (boost::iequals(value, "DYNAMIC"))
 
1011
    return IB_TBL_DYNAMIC;
 
1012
  else if (boost::iequals(value, "COMPRESSED"))
 
1013
    return IB_TBL_COMPRESSED;
 
1014
 
 
1015
  assert(false); /* You need to add possible table formats here */
 
1016
  return IB_TBL_COMPACT;
 
1017
}
 
1018
 
 
1019
int HailDBEngine::doCreateTable(Session &session,
 
1020
                                        Table& table_obj,
 
1021
                                        const drizzled::TableIdentifier &identifier,
 
1022
                                        drizzled::message::Table& table_message)
 
1023
{
 
1024
  ib_tbl_sch_t haildb_table_schema= NULL;
 
1025
//  ib_idx_sch_t haildb_pkey= NULL;
 
1026
  ib_trx_t haildb_schema_transaction;
 
1027
  ib_id_t haildb_table_id;
 
1028
  ib_err_t haildb_err= DB_SUCCESS;
 
1029
  string haildb_table_name;
 
1030
  bool has_explicit_pkey= false;
 
1031
 
 
1032
  (void)table_obj;
 
1033
 
 
1034
  if (table_message.type() == message::Table::TEMPORARY)
 
1035
  {
 
1036
    ib_bool_t create_db_err= ib_database_create(GLOBAL_TEMPORARY_EXT);
 
1037
    if (create_db_err != IB_TRUE)
 
1038
      return -1;
 
1039
  }
 
1040
 
 
1041
  TableIdentifier_to_haildb_name(identifier, &haildb_table_name);
 
1042
 
 
1043
  ib_tbl_fmt_t haildb_table_format= IB_TBL_COMPACT;
 
1044
 
 
1045
  const size_t num_engine_options= table_message.engine().options_size();
 
1046
  for (size_t x= 0; x < num_engine_options; x++)
 
1047
  {
 
1048
    const message::Engine::Option &engine_option= table_message.engine().options(x);
 
1049
    if (boost::iequals(engine_option.name(), "ROW_FORMAT"))
 
1050
    {
 
1051
      haildb_table_format= parse_ib_table_format(engine_option.state());
 
1052
    }
 
1053
  }
 
1054
 
 
1055
  haildb_err= ib_table_schema_create(haildb_table_name.c_str(),
 
1056
                                     &haildb_table_schema,
 
1057
                                     haildb_table_format, 0);
 
1058
 
 
1059
  if (haildb_err != DB_SUCCESS)
 
1060
  {
 
1061
    push_warning_printf(&session, DRIZZLE_ERROR::WARN_LEVEL_ERROR,
 
1062
                        ER_CANT_CREATE_TABLE,
 
1063
                        _("Cannot create table %s. HailDB Error %d (%s)\n"),
 
1064
                        haildb_table_name.c_str(), haildb_err, ib_strerror(haildb_err));
 
1065
    return ib_err_t_to_drizzle_error(haildb_err);
 
1066
  }
 
1067
 
 
1068
  for (int colnr= 0; colnr < table_message.field_size() ; colnr++)
 
1069
  {
 
1070
    const message::Table::Field field = table_message.field(colnr);
 
1071
 
 
1072
    int field_err= create_table_add_field(haildb_table_schema, field,
 
1073
                                          &haildb_err);
 
1074
 
 
1075
    if (haildb_err != DB_SUCCESS || field_err != 0)
 
1076
      ib_table_schema_delete(haildb_table_schema); /* cleanup */
 
1077
 
 
1078
    if (haildb_err != DB_SUCCESS)
 
1079
    {
 
1080
      push_warning_printf(&session, DRIZZLE_ERROR::WARN_LEVEL_ERROR,
 
1081
                          ER_CANT_CREATE_TABLE,
 
1082
                          _("Cannot create field %s on table %s."
 
1083
                            " HailDB Error %d (%s)\n"),
 
1084
                          field.name().c_str(), haildb_table_name.c_str(),
 
1085
                          haildb_err, ib_strerror(haildb_err));
 
1086
      return ib_err_t_to_drizzle_error(haildb_err);
 
1087
    }
 
1088
    if (field_err != 0)
 
1089
      return field_err;
 
1090
  }
 
1091
 
 
1092
  bool has_primary= false;
 
1093
  for (int indexnr= 0; indexnr < table_message.indexes_size() ; indexnr++)
 
1094
  {
 
1095
    message::Table::Index *index = table_message.mutable_indexes(indexnr);
 
1096
 
 
1097
    ib_idx_sch_t haildb_index;
 
1098
 
 
1099
    haildb_err= ib_table_schema_add_index(haildb_table_schema, index->name().c_str(),
 
1100
                                   &haildb_index);
 
1101
    if (haildb_err != DB_SUCCESS)
 
1102
      goto schema_error;
 
1103
 
 
1104
    if (index->is_primary())
 
1105
    {
 
1106
      has_primary= true;
 
1107
      haildb_err= ib_index_schema_set_clustered(haildb_index);
 
1108
      has_explicit_pkey= true;
 
1109
      if (haildb_err != DB_SUCCESS)
 
1110
        goto schema_error;
 
1111
    }
 
1112
 
 
1113
    if (index->is_unique())
 
1114
    {
 
1115
      haildb_err= ib_index_schema_set_unique(haildb_index);
 
1116
      if (haildb_err != DB_SUCCESS)
 
1117
        goto schema_error;
 
1118
    }
 
1119
 
 
1120
    if (index->type() == message::Table::Index::UNKNOWN_INDEX)
 
1121
      index->set_type(message::Table::Index::BTREE);
 
1122
 
 
1123
    for (int partnr= 0; partnr < index->index_part_size(); partnr++)
 
1124
    {
 
1125
      const message::Table::Index::IndexPart part= index->index_part(partnr);
 
1126
      const message::Table::Field::FieldType part_type= table_message.field(part.fieldnr()).type();
 
1127
      uint64_t compare_length= 0;
 
1128
 
 
1129
      if (part_type == message::Table::Field::BLOB
 
1130
          || part_type == message::Table::Field::VARCHAR)
 
1131
        compare_length= part.compare_length();
 
1132
 
 
1133
      haildb_err= ib_index_schema_add_col(haildb_index,
 
1134
                            table_message.field(part.fieldnr()).name().c_str(),
 
1135
                                          compare_length);
 
1136
      if (haildb_err != DB_SUCCESS)
 
1137
        goto schema_error;
 
1138
    }
 
1139
 
 
1140
    if (! has_primary && index->is_unique())
 
1141
    {
 
1142
      haildb_err= ib_index_schema_set_clustered(haildb_index);
 
1143
      has_explicit_pkey= true;
 
1144
      if (haildb_err != DB_SUCCESS)
 
1145
        goto schema_error;
 
1146
    }
 
1147
 
 
1148
  }
 
1149
 
 
1150
  if (! has_explicit_pkey)
 
1151
  {
 
1152
    ib_idx_sch_t haildb_index;
 
1153
 
 
1154
    haildb_err= ib_table_schema_add_col(haildb_table_schema, "hidden_primary_key_col",
 
1155
                                        IB_INT, IB_COL_NOT_NULL, 0, 8);
 
1156
 
 
1157
    haildb_err= ib_table_schema_add_index(haildb_table_schema, "HIDDEN_PRIMARY",
 
1158
                                          &haildb_index);
 
1159
    if (haildb_err != DB_SUCCESS)
 
1160
      goto schema_error;
 
1161
 
 
1162
    haildb_err= ib_index_schema_set_clustered(haildb_index);
 
1163
    if (haildb_err != DB_SUCCESS)
 
1164
      goto schema_error;
 
1165
 
 
1166
    haildb_err= ib_index_schema_add_col(haildb_index, "hidden_primary_key_col", 0);
 
1167
    if (haildb_err != DB_SUCCESS)
 
1168
      goto schema_error;
 
1169
  }
 
1170
 
 
1171
  haildb_schema_transaction= ib_trx_begin(IB_TRX_REPEATABLE_READ);
 
1172
  haildb_err= ib_schema_lock_exclusive(haildb_schema_transaction);
 
1173
  if (haildb_err != DB_SUCCESS)
 
1174
  {
 
1175
    ib_err_t rollback_err= ib_trx_rollback(haildb_schema_transaction);
 
1176
    ib_table_schema_delete(haildb_table_schema);
 
1177
 
 
1178
    push_warning_printf(&session, DRIZZLE_ERROR::WARN_LEVEL_ERROR,
 
1179
                        ER_CANT_CREATE_TABLE,
 
1180
                        _("Cannot Lock HailDB Data Dictionary. HailDB Error %d (%s)\n"),
 
1181
                        haildb_err, ib_strerror(haildb_err));
 
1182
 
 
1183
    assert (rollback_err == DB_SUCCESS);
 
1184
 
 
1185
    return HA_ERR_GENERIC;
 
1186
  }
 
1187
 
 
1188
  haildb_err= ib_table_create(haildb_schema_transaction, haildb_table_schema,
 
1189
                              &haildb_table_id);
 
1190
 
 
1191
  if (haildb_err != DB_SUCCESS)
 
1192
  {
 
1193
    ib_err_t rollback_err= ib_trx_rollback(haildb_schema_transaction);
 
1194
    ib_table_schema_delete(haildb_table_schema);
 
1195
 
 
1196
    if (haildb_err == DB_TABLE_IS_BEING_USED)
 
1197
      return EEXIST;
 
1198
 
 
1199
    push_warning_printf(&session, DRIZZLE_ERROR::WARN_LEVEL_ERROR,
 
1200
                        ER_CANT_CREATE_TABLE,
 
1201
                        _("Cannot create table %s. HailDB Error %d (%s)\n"),
 
1202
                        haildb_table_name.c_str(),
 
1203
                        haildb_err, ib_strerror(haildb_err));
 
1204
 
 
1205
    assert (rollback_err == DB_SUCCESS);
 
1206
    return HA_ERR_GENERIC;
 
1207
  }
 
1208
 
 
1209
  if (table_message.type() == message::Table::TEMPORARY)
 
1210
  {
 
1211
    session.getMessageCache().storeTableMessage(identifier, table_message);
 
1212
    haildb_err= DB_SUCCESS;
 
1213
  }
 
1214
  else
 
1215
    haildb_err= store_table_message(haildb_schema_transaction,
 
1216
                                    haildb_table_name.c_str(),
 
1217
                                    table_message);
 
1218
 
 
1219
  if (haildb_err == DB_SUCCESS)
 
1220
    haildb_err= ib_trx_commit(haildb_schema_transaction);
 
1221
  else
 
1222
    haildb_err= ib_trx_rollback(haildb_schema_transaction);
 
1223
 
 
1224
schema_error:
 
1225
  ib_table_schema_delete(haildb_table_schema);
 
1226
 
 
1227
  if (haildb_err != DB_SUCCESS)
 
1228
  {
 
1229
    push_warning_printf(&session, DRIZZLE_ERROR::WARN_LEVEL_ERROR,
 
1230
                        ER_CANT_CREATE_TABLE,
 
1231
                        _("Cannot create table %s. HailDB Error %d (%s)\n"),
 
1232
                        haildb_table_name.c_str(),
 
1233
                        haildb_err, ib_strerror(haildb_err));
 
1234
    return ib_err_t_to_drizzle_error(haildb_err);
 
1235
  }
 
1236
 
 
1237
  return 0;
 
1238
}
 
1239
 
 
1240
static int delete_table_message_from_haildb(ib_trx_t transaction, const char* table_name)
 
1241
{
 
1242
  ib_crsr_t cursor;
 
1243
  ib_tpl_t search_tuple;
 
1244
  int res;
 
1245
  ib_err_t err;
 
1246
 
 
1247
  err= ib_cursor_open_table(HAILDB_TABLE_DEFINITIONS_TABLE, transaction, &cursor);
 
1248
  if (err != DB_SUCCESS)
 
1249
    return err;
 
1250
 
 
1251
  search_tuple= ib_clust_search_tuple_create(cursor);
 
1252
 
 
1253
  err= ib_col_set_value(search_tuple, 0, table_name, strlen(table_name));
 
1254
  if (err != DB_SUCCESS)
 
1255
    goto rollback;
 
1256
 
 
1257
//  ib_cursor_set_match_mode(cursor, IB_EXACT_MATCH);
 
1258
 
 
1259
  err= ib_cursor_moveto(cursor, search_tuple, IB_CUR_GE, &res);
 
1260
  if (err == DB_RECORD_NOT_FOUND || res != 0)
 
1261
    goto rollback;
 
1262
 
 
1263
  err= ib_cursor_delete_row(cursor);
 
1264
  assert (err == DB_SUCCESS);
 
1265
 
 
1266
rollback:
 
1267
  ib_err_t rollback_err= ib_cursor_close(cursor);
 
1268
  if (err == DB_SUCCESS)
 
1269
    err= rollback_err;
 
1270
 
 
1271
  ib_tuple_delete(search_tuple);
 
1272
 
 
1273
  return err;
 
1274
}
 
1275
 
 
1276
int HailDBEngine::doDropTable(Session &session,
 
1277
                                      const TableIdentifier &identifier)
 
1278
{
 
1279
  ib_trx_t haildb_schema_transaction;
 
1280
  ib_err_t haildb_err;
 
1281
  string haildb_table_name;
 
1282
 
 
1283
  TableIdentifier_to_haildb_name(identifier, &haildb_table_name);
 
1284
 
 
1285
  haildb_schema_transaction= ib_trx_begin(IB_TRX_REPEATABLE_READ);
 
1286
  haildb_err= ib_schema_lock_exclusive(haildb_schema_transaction);
 
1287
  if (haildb_err != DB_SUCCESS)
 
1288
  {
 
1289
    ib_err_t rollback_err= ib_trx_rollback(haildb_schema_transaction);
 
1290
 
 
1291
    push_warning_printf(&session, DRIZZLE_ERROR::WARN_LEVEL_ERROR,
 
1292
                        ER_CANT_DELETE_FILE,
 
1293
                        _("Cannot Lock HailDB Data Dictionary. HailDB Error %d (%s)\n"),
 
1294
                        haildb_err, ib_strerror(haildb_err));
 
1295
 
 
1296
    assert (rollback_err == DB_SUCCESS);
 
1297
 
 
1298
    return HA_ERR_GENERIC;
 
1299
  }
 
1300
 
 
1301
  if (identifier.getType() == message::Table::TEMPORARY)
 
1302
  {
 
1303
      session.getMessageCache().removeTableMessage(identifier);
 
1304
      delete_table_message_from_haildb(haildb_schema_transaction,
 
1305
                                       haildb_table_name.c_str());
 
1306
  }
 
1307
  else
 
1308
  {
 
1309
    if (delete_table_message_from_haildb(haildb_schema_transaction, haildb_table_name.c_str()) != DB_SUCCESS)
 
1310
    {
 
1311
      ib_schema_unlock(haildb_schema_transaction);
 
1312
      ib_err_t rollback_err= ib_trx_rollback(haildb_schema_transaction);
 
1313
      assert(rollback_err == DB_SUCCESS);
 
1314
      return HA_ERR_GENERIC;
 
1315
    }
 
1316
  }
 
1317
 
 
1318
  haildb_err= ib_table_drop(haildb_schema_transaction, haildb_table_name.c_str());
 
1319
 
 
1320
  if (haildb_err == DB_TABLE_NOT_FOUND)
 
1321
  {
 
1322
    haildb_err= ib_trx_rollback(haildb_schema_transaction);
 
1323
    assert(haildb_err == DB_SUCCESS);
 
1324
    return ENOENT;
 
1325
  }
 
1326
  else if (haildb_err != DB_SUCCESS)
 
1327
  {
 
1328
    ib_err_t rollback_err= ib_trx_rollback(haildb_schema_transaction);
 
1329
 
 
1330
    push_warning_printf(&session, DRIZZLE_ERROR::WARN_LEVEL_ERROR,
 
1331
                        ER_CANT_DELETE_FILE,
 
1332
                        _("Cannot DROP table %s. HailDB Error %d (%s)\n"),
 
1333
                        haildb_table_name.c_str(),
 
1334
                        haildb_err, ib_strerror(haildb_err));
 
1335
 
 
1336
    assert(rollback_err == DB_SUCCESS);
 
1337
 
 
1338
    return HA_ERR_GENERIC;
 
1339
  }
 
1340
 
 
1341
  haildb_err= ib_trx_commit(haildb_schema_transaction);
 
1342
  if (haildb_err != DB_SUCCESS)
 
1343
  {
 
1344
    ib_err_t rollback_err= ib_trx_rollback(haildb_schema_transaction);
 
1345
 
 
1346
    push_warning_printf(&session, DRIZZLE_ERROR::WARN_LEVEL_ERROR,
 
1347
                        ER_CANT_DELETE_FILE,
 
1348
                        _("Cannot DROP table %s. HailDB Error %d (%s)\n"),
 
1349
                        haildb_table_name.c_str(),
 
1350
                        haildb_err, ib_strerror(haildb_err));
 
1351
 
 
1352
    assert(rollback_err == DB_SUCCESS);
 
1353
    return HA_ERR_GENERIC;
 
1354
  }
 
1355
 
 
1356
  return 0;
 
1357
}
 
1358
 
 
1359
static ib_err_t rename_table_message(ib_trx_t transaction, const TableIdentifier &from_identifier, const TableIdentifier &to_identifier)
 
1360
{
 
1361
  ib_crsr_t cursor;
 
1362
  ib_tpl_t search_tuple;
 
1363
  ib_tpl_t read_tuple;
 
1364
  ib_tpl_t update_tuple;
 
1365
  int res;
 
1366
  ib_err_t err;
 
1367
  ib_err_t rollback_err;
 
1368
  const char *message;
 
1369
  ib_ulint_t message_len;
 
1370
  drizzled::message::Table table_message;
 
1371
  string from_haildb_table_name;
 
1372
  string to_haildb_table_name;
 
1373
  const char *from;
 
1374
  const char *to;
 
1375
  string serialized_message;
 
1376
  ib_col_meta_t col_meta;
 
1377
 
 
1378
  TableIdentifier_to_haildb_name(from_identifier, &from_haildb_table_name);
 
1379
  TableIdentifier_to_haildb_name(to_identifier, &to_haildb_table_name);
 
1380
 
 
1381
  from= from_haildb_table_name.c_str();
 
1382
  to= to_haildb_table_name.c_str();
 
1383
 
 
1384
  err= ib_cursor_open_table(HAILDB_TABLE_DEFINITIONS_TABLE, transaction, &cursor);
 
1385
  if (err != DB_SUCCESS)
 
1386
  {
 
1387
    rollback_err= ib_trx_rollback(transaction);
 
1388
    assert(rollback_err == DB_SUCCESS);
 
1389
    return err;
 
1390
  }
 
1391
 
 
1392
  search_tuple= ib_clust_search_tuple_create(cursor);
 
1393
  read_tuple= ib_clust_read_tuple_create(cursor);
 
1394
 
 
1395
  err= ib_col_set_value(search_tuple, 0, from, strlen(from));
 
1396
  if (err != DB_SUCCESS)
 
1397
    goto rollback;
 
1398
 
 
1399
//  ib_cursor_set_match_mode(cursor, IB_EXACT_MATCH);
 
1400
 
 
1401
  err= ib_cursor_moveto(cursor, search_tuple, IB_CUR_GE, &res);
 
1402
  if (err == DB_RECORD_NOT_FOUND || res != 0)
 
1403
    goto rollback;
 
1404
 
 
1405
  err= ib_cursor_read_row(cursor, read_tuple);
 
1406
  if (err == DB_RECORD_NOT_FOUND || res != 0)
 
1407
    goto rollback;
 
1408
 
 
1409
  message= (const char*)ib_col_get_value(read_tuple, 1);
 
1410
  message_len= ib_col_get_meta(read_tuple, 1, &col_meta);
 
1411
 
 
1412
  if (table_message.ParseFromArray(message, message_len) == false)
 
1413
    goto rollback;
 
1414
 
 
1415
  table_message.set_name(to_identifier.getTableName());
 
1416
  table_message.set_schema(to_identifier.getSchemaName());
 
1417
 
 
1418
  update_tuple= ib_clust_read_tuple_create(cursor);
 
1419
 
 
1420
  err= ib_tuple_copy(update_tuple, read_tuple);
 
1421
  assert(err == DB_SUCCESS);
 
1422
 
 
1423
  err= ib_col_set_value(update_tuple, 0, to, strlen(to));
 
1424
 
 
1425
  try {
 
1426
    table_message.SerializeToString(&serialized_message);
 
1427
  }
 
1428
  catch (...)
 
1429
  {
 
1430
    goto rollback;
 
1431
  }
 
1432
 
 
1433
  err= ib_col_set_value(update_tuple, 1, serialized_message.c_str(),
 
1434
                        serialized_message.length());
 
1435
 
 
1436
  err= ib_cursor_update_row(cursor, read_tuple, update_tuple);
 
1437
 
 
1438
 
 
1439
  ib_tuple_delete(update_tuple);
 
1440
  ib_tuple_delete(read_tuple);
 
1441
  ib_tuple_delete(search_tuple);
 
1442
 
 
1443
  err= ib_cursor_close(cursor);
 
1444
 
 
1445
rollback:
 
1446
  return err;
 
1447
}
 
1448
 
 
1449
int HailDBEngine::doRenameTable(drizzled::Session &session,
 
1450
                                        const drizzled::TableIdentifier &from,
 
1451
                                        const drizzled::TableIdentifier &to)
 
1452
{
 
1453
  ib_trx_t haildb_schema_transaction;
 
1454
  ib_err_t err;
 
1455
  string from_haildb_table_name;
 
1456
  string to_haildb_table_name;
 
1457
 
 
1458
  if (to.getType() == message::Table::TEMPORARY
 
1459
      && from.getType() == message::Table::TEMPORARY)
 
1460
  {
 
1461
    session.getMessageCache().renameTableMessage(from, to);
 
1462
    return 0;
 
1463
  }
 
1464
 
 
1465
  TableIdentifier_to_haildb_name(from, &from_haildb_table_name);
 
1466
  TableIdentifier_to_haildb_name(to, &to_haildb_table_name);
 
1467
 
 
1468
  haildb_schema_transaction= ib_trx_begin(IB_TRX_REPEATABLE_READ);
 
1469
  err= ib_schema_lock_exclusive(haildb_schema_transaction);
 
1470
  if (err != DB_SUCCESS)
 
1471
  {
 
1472
    push_warning_printf(&session, DRIZZLE_ERROR::WARN_LEVEL_ERROR,
 
1473
                        ER_CANT_DELETE_FILE,
 
1474
                        _("Cannot Lock HailDB Data Dictionary. HailDB Error %d (%s)\n"),
 
1475
                        err, ib_strerror(err));
 
1476
 
 
1477
    goto rollback;
 
1478
  }
 
1479
 
 
1480
  err= ib_table_rename(haildb_schema_transaction,
 
1481
                       from_haildb_table_name.c_str(),
 
1482
                       to_haildb_table_name.c_str());
 
1483
  if (err != DB_SUCCESS)
 
1484
    goto rollback;
 
1485
 
 
1486
  err= rename_table_message(haildb_schema_transaction, from, to);
 
1487
 
 
1488
  if (err != DB_SUCCESS)
 
1489
    goto rollback;
 
1490
 
 
1491
  err= ib_trx_commit(haildb_schema_transaction);
 
1492
  if (err != DB_SUCCESS)
 
1493
    goto rollback;
 
1494
 
 
1495
  return 0;
 
1496
rollback:
 
1497
  ib_err_t rollback_err= ib_schema_unlock(haildb_schema_transaction);
 
1498
  assert(rollback_err == DB_SUCCESS);
 
1499
  rollback_err= ib_trx_rollback(haildb_schema_transaction);
 
1500
  assert(rollback_err == DB_SUCCESS);
 
1501
  return ib_err_t_to_drizzle_error(err);
 
1502
}
 
1503
 
 
1504
void HailDBEngine::getTableNamesInSchemaFromHailDB(
 
1505
                                 const drizzled::SchemaIdentifier &schema,
 
1506
                                 drizzled::plugin::TableNameList *set_of_names,
 
1507
                                 drizzled::TableIdentifiers *identifiers)
 
1508
{
 
1509
  ib_trx_t   transaction;
 
1510
  ib_crsr_t  cursor;
 
1511
  /*
 
1512
    Why not use getPath()?
 
1513
  */
 
1514
  string search_string(schema.getSchemaName());
 
1515
 
 
1516
  boost::algorithm::to_lower(search_string);
 
1517
 
 
1518
  search_string.append("/");
 
1519
 
 
1520
  transaction = ib_trx_begin(IB_TRX_REPEATABLE_READ);
 
1521
  ib_err_t haildb_err= ib_schema_lock_exclusive(transaction);
 
1522
  assert(haildb_err == DB_SUCCESS); /* FIXME: doGetTableNames needs to be able to return error */
 
1523
 
 
1524
  if (search_string.compare("data_dictionary/") == 0)
 
1525
  {
 
1526
    if (set_of_names)
 
1527
    {
 
1528
      BOOST_FOREACH(std::string table_name, haildb_system_table_names)
 
1529
      {
 
1530
        set_of_names->insert(table_name);
 
1531
      }
 
1532
    }
 
1533
    if (identifiers)
 
1534
    {
 
1535
      BOOST_FOREACH(std::string table_name, haildb_system_table_names)
 
1536
      {
 
1537
        identifiers->push_back(TableIdentifier(schema.getSchemaName(),
 
1538
                                               table_name));
 
1539
      }
 
1540
    }
 
1541
  }
 
1542
 
 
1543
  haildb_err= ib_cursor_open_table("SYS_TABLES", transaction, &cursor);
 
1544
  assert(haildb_err == DB_SUCCESS); /* FIXME */
 
1545
 
 
1546
  ib_tpl_t read_tuple;
 
1547
  ib_tpl_t search_tuple;
 
1548
 
 
1549
  read_tuple= ib_clust_read_tuple_create(cursor);
 
1550
  search_tuple= ib_clust_search_tuple_create(cursor);
 
1551
 
 
1552
  haildb_err= ib_col_set_value(search_tuple, 0, search_string.c_str(),
 
1553
                               search_string.length());
 
1554
  assert (haildb_err == DB_SUCCESS); // FIXME
 
1555
 
 
1556
  int res;
 
1557
  haildb_err = ib_cursor_moveto(cursor, search_tuple, IB_CUR_GE, &res);
 
1558
  // fixme: check error above
 
1559
 
 
1560
  while (haildb_err == DB_SUCCESS)
 
1561
  {
 
1562
    haildb_err= ib_cursor_read_row(cursor, read_tuple);
 
1563
 
 
1564
    const char *table_name;
 
1565
    int table_name_len;
 
1566
    ib_col_meta_t column_metadata;
 
1567
 
 
1568
    table_name= (const char*)ib_col_get_value(read_tuple, 0);
 
1569
    table_name_len=  ib_col_get_meta(read_tuple, 0, &column_metadata);
 
1570
 
 
1571
    if (search_string.compare(0, search_string.length(),
 
1572
                              table_name, search_string.length()) == 0)
 
1573
    {
 
1574
      const char *just_table_name= strchr(table_name, '/');
 
1575
      assert(just_table_name);
 
1576
      just_table_name++; /* skip over '/' */
 
1577
      if (set_of_names)
 
1578
        set_of_names->insert(just_table_name);
 
1579
      if (identifiers)
 
1580
        identifiers->push_back(TableIdentifier(schema.getSchemaName(), just_table_name));
 
1581
    }
 
1582
 
 
1583
 
 
1584
    haildb_err= ib_cursor_next(cursor);
 
1585
    read_tuple= ib_tuple_clear(read_tuple);
 
1586
  }
 
1587
 
 
1588
  ib_tuple_delete(read_tuple);
 
1589
  ib_tuple_delete(search_tuple);
 
1590
 
 
1591
  haildb_err= ib_cursor_close(cursor);
 
1592
  assert(haildb_err == DB_SUCCESS); // FIXME
 
1593
 
 
1594
  haildb_err= ib_trx_commit(transaction);
 
1595
  assert(haildb_err == DB_SUCCESS); // FIXME
 
1596
}
 
1597
 
 
1598
void HailDBEngine::doGetTableIdentifiers(drizzled::CachedDirectory &,
 
1599
                                                 const drizzled::SchemaIdentifier &schema,
 
1600
                                                 drizzled::TableIdentifiers &identifiers)
 
1601
{
 
1602
  getTableNamesInSchemaFromHailDB(schema, NULL, &identifiers);
 
1603
}
 
1604
 
 
1605
static int read_table_message_from_haildb(const char* table_name, drizzled::message::Table *table_message)
 
1606
{
 
1607
  ib_trx_t transaction;
 
1608
  ib_tpl_t search_tuple;
 
1609
  ib_tpl_t read_tuple;
 
1610
  ib_crsr_t cursor;
 
1611
  const char *message;
 
1612
  ib_ulint_t message_len;
 
1613
  ib_col_meta_t col_meta;
 
1614
  int res;
 
1615
  ib_err_t err;
 
1616
  ib_err_t rollback_err;
 
1617
 
 
1618
  transaction= ib_trx_begin(IB_TRX_REPEATABLE_READ);
 
1619
  err= ib_schema_lock_exclusive(transaction);
 
1620
  if (err != DB_SUCCESS)
 
1621
  {
 
1622
    rollback_err= ib_trx_rollback(transaction);
 
1623
    assert(rollback_err == DB_SUCCESS);
 
1624
    return err;
 
1625
  }
 
1626
 
 
1627
  err= ib_cursor_open_table(HAILDB_TABLE_DEFINITIONS_TABLE, transaction, &cursor);
 
1628
  if (err != DB_SUCCESS)
 
1629
  {
 
1630
    rollback_err= ib_trx_rollback(transaction);
 
1631
    assert(rollback_err == DB_SUCCESS);
 
1632
    return err;
 
1633
  }
 
1634
 
 
1635
  search_tuple= ib_clust_search_tuple_create(cursor);
 
1636
  read_tuple= ib_clust_read_tuple_create(cursor);
 
1637
 
 
1638
  err= ib_col_set_value(search_tuple, 0, table_name, strlen(table_name));
 
1639
  if (err != DB_SUCCESS)
 
1640
    goto rollback;
 
1641
 
 
1642
//  ib_cursor_set_match_mode(cursor, IB_EXACT_MATCH);
 
1643
 
 
1644
  err= ib_cursor_moveto(cursor, search_tuple, IB_CUR_GE, &res);
 
1645
  if (err == DB_RECORD_NOT_FOUND || res != 0)
 
1646
    goto rollback;
 
1647
 
 
1648
  err= ib_cursor_read_row(cursor, read_tuple);
 
1649
  if (err == DB_RECORD_NOT_FOUND || res != 0)
 
1650
    goto rollback;
 
1651
 
 
1652
  message= (const char*)ib_col_get_value(read_tuple, 1);
 
1653
  message_len= ib_col_get_meta(read_tuple, 1, &col_meta);
 
1654
 
 
1655
  if (table_message->ParseFromArray(message, message_len) == false)
 
1656
    goto rollback;
 
1657
 
 
1658
  ib_tuple_delete(search_tuple);
 
1659
  ib_tuple_delete(read_tuple);
 
1660
  err= ib_cursor_close(cursor);
 
1661
  if (err != DB_SUCCESS)
 
1662
    goto rollback_close_err;
 
1663
  err= ib_trx_commit(transaction);
 
1664
  if (err != DB_SUCCESS)
 
1665
    goto rollback_close_err;
 
1666
 
 
1667
  return 0;
 
1668
 
 
1669
rollback:
 
1670
  ib_tuple_delete(search_tuple);
 
1671
  ib_tuple_delete(read_tuple);
 
1672
  rollback_err= ib_cursor_close(cursor);
 
1673
  assert(rollback_err == DB_SUCCESS);
 
1674
rollback_close_err:
 
1675
  ib_schema_unlock(transaction);
 
1676
  rollback_err= ib_trx_rollback(transaction);
 
1677
  assert(rollback_err == DB_SUCCESS);
 
1678
 
 
1679
  if (strcmp(table_name, HAILDB_TABLE_DEFINITIONS_TABLE) == 0)
 
1680
  {
 
1681
    message::Engine *engine= table_message->mutable_engine();
 
1682
    engine->set_name("InnoDB");
 
1683
    table_message->set_name("haildb_table_definitions");
 
1684
    table_message->set_schema("data_dictionary");
 
1685
    table_message->set_type(message::Table::STANDARD);
 
1686
    table_message->set_creation_timestamp(0);
 
1687
    table_message->set_update_timestamp(0);
 
1688
 
 
1689
    message::Table::TableOptions *options= table_message->mutable_options();
 
1690
    options->set_collation_id(my_charset_bin.number);
 
1691
    options->set_collation(my_charset_bin.name);
 
1692
 
 
1693
    message::Table::Field *field= table_message->add_field();
 
1694
    field->set_name("table_name");
 
1695
    field->set_type(message::Table::Field::VARCHAR);
 
1696
    message::Table::Field::StringFieldOptions *stropt= field->mutable_string_options();
 
1697
    stropt->set_length(IB_MAX_TABLE_NAME_LEN);
 
1698
    stropt->set_collation_id(my_charset_bin.number);
 
1699
    stropt->set_collation(my_charset_bin.name);
 
1700
 
 
1701
    field= table_message->add_field();
 
1702
    field->set_name("message");
 
1703
    field->set_type(message::Table::Field::BLOB);
 
1704
    stropt= field->mutable_string_options();
 
1705
    stropt->set_collation_id(my_charset_bin.number);
 
1706
    stropt->set_collation(my_charset_bin.name);
 
1707
 
 
1708
    message::Table::Index *index= table_message->add_indexes();
 
1709
    index->set_name("PRIMARY");
 
1710
    index->set_is_primary(true);
 
1711
    index->set_is_unique(true);
 
1712
    index->set_type(message::Table::Index::BTREE);
 
1713
    index->set_key_length(IB_MAX_TABLE_NAME_LEN);
 
1714
    message::Table::Index::IndexPart *part= index->add_index_part();
 
1715
    part->set_fieldnr(0);
 
1716
    part->set_compare_length(IB_MAX_TABLE_NAME_LEN);
 
1717
 
 
1718
    return 0;
 
1719
  }
 
1720
 
 
1721
  return -1;
 
1722
}
 
1723
 
 
1724
int HailDBEngine::doGetTableDefinition(Session &session,
 
1725
                                               const TableIdentifier &identifier,
 
1726
                                               drizzled::message::Table &table)
 
1727
{
 
1728
  ib_crsr_t haildb_cursor= NULL;
 
1729
  string haildb_table_name;
 
1730
 
 
1731
  /* Check temporary tables!? */
 
1732
  if (session.getMessageCache().getTableMessage(identifier, table))
 
1733
    return EEXIST;
 
1734
 
 
1735
  TableIdentifier_to_haildb_name(identifier, &haildb_table_name);
 
1736
 
 
1737
  if (ib_cursor_open_table(haildb_table_name.c_str(), NULL, &haildb_cursor) != DB_SUCCESS)
 
1738
    return ENOENT;
 
1739
 
 
1740
  ib_err_t err= ib_cursor_close(haildb_cursor);
 
1741
 
 
1742
  assert (err == DB_SUCCESS);
 
1743
 
 
1744
  if (read_table_message_from_haildb(haildb_table_name.c_str(), &table) != 0)
 
1745
  {
 
1746
    if (get_haildb_system_table_message(haildb_table_name.c_str(), &table) == 0)
 
1747
      return EEXIST;
 
1748
  }
 
1749
 
 
1750
  return EEXIST;
 
1751
}
 
1752
 
 
1753
bool HailDBEngine::doDoesTableExist(Session &,
 
1754
                                    const TableIdentifier& identifier)
 
1755
{
 
1756
  ib_crsr_t haildb_cursor;
 
1757
  string haildb_table_name;
 
1758
 
 
1759
  TableIdentifier_to_haildb_name(identifier, &haildb_table_name);
 
1760
 
 
1761
  boost::unordered_set<string>::iterator iter= haildb_system_table_names.find(identifier.getTableName());
 
1762
  if (iter != haildb_system_table_names.end())
 
1763
    return true;
 
1764
 
 
1765
  if (ib_cursor_open_table(haildb_table_name.c_str(), NULL, &haildb_cursor) != DB_SUCCESS)
 
1766
    return false;
 
1767
 
 
1768
  ib_err_t err= ib_cursor_close(haildb_cursor);
 
1769
  assert(err == DB_SUCCESS);
 
1770
 
 
1771
  return true;
 
1772
}
 
1773
 
 
1774
const char *HailDBCursor::index_type(uint32_t)
 
1775
{
 
1776
  return("BTREE");
 
1777
}
 
1778
 
 
1779
static ib_err_t write_row_to_haildb_tuple(Field **fields, ib_tpl_t tuple)
 
1780
{
 
1781
  int colnr= 0;
 
1782
  ib_err_t err= DB_ERROR;
 
1783
 
 
1784
  for (Field **field= fields; *field; field++, colnr++)
 
1785
  {
 
1786
    if (! (**field).isWriteSet() && (**field).is_null())
 
1787
      continue;
 
1788
 
 
1789
    if ((**field).is_null())
 
1790
    {
 
1791
      err= ib_col_set_value(tuple, colnr, NULL, IB_SQL_NULL);
 
1792
      assert(err == DB_SUCCESS);
 
1793
      continue;
 
1794
    }
 
1795
 
 
1796
    if ((**field).type() == DRIZZLE_TYPE_VARCHAR)
 
1797
    {
 
1798
      /* To get around the length bytes (1 or 2) at (**field).ptr
 
1799
         we can use Field_varstring::val_str to a String
 
1800
         to get a pointer to the real string without copying it.
 
1801
      */
 
1802
      String str;
 
1803
      (**field).setReadSet();
 
1804
      (**field).val_str(&str);
 
1805
      err= ib_col_set_value(tuple, colnr, str.ptr(), str.length());
 
1806
    }
 
1807
    else if ((**field).type() == DRIZZLE_TYPE_ENUM)
 
1808
    {
 
1809
      err= ib_tuple_write_u32(tuple, colnr, *((ib_u32_t*)(*field)->ptr));
 
1810
    }
 
1811
    else if ((**field).type() == DRIZZLE_TYPE_DATE)
 
1812
    {
 
1813
      (**field).setReadSet();
 
1814
      err= ib_tuple_write_u32(tuple, colnr, (*field)->val_int());
 
1815
    }
 
1816
    else if ((**field).type() == DRIZZLE_TYPE_BLOB)
 
1817
    {
 
1818
      Field_blob *blob= reinterpret_cast<Field_blob*>(*field);
 
1819
      unsigned char* blob_ptr;
 
1820
      uint32_t blob_length= blob->get_length();
 
1821
      blob->get_ptr(&blob_ptr);
 
1822
      err= ib_col_set_value(tuple, colnr, blob_ptr, blob_length);
 
1823
    }
 
1824
    else
 
1825
    {
 
1826
      err= ib_col_set_value(tuple, colnr, (*field)->ptr, (*field)->data_length());
 
1827
    }
 
1828
 
 
1829
    assert (err == DB_SUCCESS);
 
1830
  }
 
1831
 
 
1832
  return err;
 
1833
}
 
1834
 
 
1835
static uint64_t innobase_get_int_col_max_value(const Field* field)
 
1836
{
 
1837
  uint64_t      max_value = 0;
 
1838
 
 
1839
  switch(field->key_type()) {
 
1840
    /* TINY */
 
1841
  case HA_KEYTYPE_BINARY:
 
1842
    max_value = 0xFFULL;
 
1843
    break;
 
1844
    /* LONG */
 
1845
  case HA_KEYTYPE_ULONG_INT:
 
1846
    max_value = 0xFFFFFFFFULL;
 
1847
    break;
 
1848
  case HA_KEYTYPE_LONG_INT:
 
1849
    max_value = 0x7FFFFFFFULL;
 
1850
    break;
 
1851
    /* BIG */
 
1852
  case HA_KEYTYPE_ULONGLONG:
 
1853
    max_value = 0xFFFFFFFFFFFFFFFFULL;
 
1854
    break;
 
1855
  case HA_KEYTYPE_LONGLONG:
 
1856
    max_value = 0x7FFFFFFFFFFFFFFFULL;
 
1857
    break;
 
1858
  case HA_KEYTYPE_DOUBLE:
 
1859
    /* We use the maximum as per IEEE754-2008 standard, 2^53 */
 
1860
    max_value = 0x20000000000000ULL;
 
1861
    break;
 
1862
  default:
 
1863
    assert(false);
 
1864
  }
 
1865
 
 
1866
  return(max_value);
 
1867
}
 
1868
 
 
1869
int HailDBCursor::doInsertRecord(unsigned char *record)
 
1870
{
 
1871
  ib_err_t err;
 
1872
  int ret= 0;
 
1873
 
 
1874
  ib_trx_t transaction= *get_trx(getTable()->in_use);
 
1875
 
 
1876
  tuple= ib_clust_read_tuple_create(cursor);
 
1877
 
 
1878
  ib_cursor_attach_trx(cursor, transaction);
 
1879
 
 
1880
  err= ib_cursor_first(cursor);
 
1881
  if (current_session->lex->sql_command == SQLCOM_CREATE_TABLE
 
1882
      && err == DB_MISSING_HISTORY)
 
1883
  {
 
1884
    /* See https://bugs.launchpad.net/drizzle/+bug/556978
 
1885
     *
 
1886
     * In CREATE SELECT, transaction is started in ::store_lock
 
1887
     * at the start of the statement, before the table is created.
 
1888
     * This means the table doesn't exist in our snapshot,
 
1889
     * and we get a DB_MISSING_HISTORY error on ib_cursor_first().
 
1890
     * The way to get around this is to here, restart the transaction
 
1891
     * and continue.
 
1892
     *
 
1893
     * yuck.
 
1894
     */
 
1895
 
 
1896
    HailDBEngine *storage_engine= static_cast<HailDBEngine*>(getEngine());
 
1897
    err= ib_cursor_reset(cursor);
 
1898
    storage_engine->doCommit(current_session, true);
 
1899
    storage_engine->doStartTransaction(current_session, START_TRANS_NO_OPTIONS);
 
1900
    transaction= *get_trx(getTable()->in_use);
 
1901
    assert(err == DB_SUCCESS);
 
1902
    ib_cursor_attach_trx(cursor, transaction);
 
1903
    err= ib_cursor_first(cursor);
 
1904
  }
 
1905
 
 
1906
  assert(err == DB_SUCCESS || err == DB_END_OF_INDEX);
 
1907
 
 
1908
 
 
1909
  if (getTable()->next_number_field)
 
1910
  {
 
1911
    update_auto_increment();
 
1912
 
 
1913
    uint64_t temp_auto= getTable()->next_number_field->val_int();
 
1914
 
 
1915
    if (temp_auto <= innobase_get_int_col_max_value(getTable()->next_number_field))
 
1916
    {
 
1917
      while (true)
 
1918
      {
 
1919
        uint64_t fetched_auto= share->auto_increment_value;
 
1920
 
 
1921
        if (temp_auto >= fetched_auto)
 
1922
        {
 
1923
          uint64_t store_value= temp_auto+1;
 
1924
          if (store_value == 0)
 
1925
            store_value++;
 
1926
 
 
1927
          if (share->auto_increment_value.compare_and_swap(store_value, fetched_auto) == fetched_auto)
 
1928
            break;
 
1929
        }
 
1930
        else
 
1931
          break;
 
1932
      }
 
1933
    }
 
1934
 
 
1935
  }
 
1936
 
 
1937
  write_row_to_haildb_tuple(getTable()->getFields(), tuple);
 
1938
 
 
1939
  if (share->has_hidden_primary_key)
 
1940
  {
 
1941
    err= ib_tuple_write_u64(tuple, getTable()->getShare()->fields, share->hidden_pkey_auto_increment_value.fetch_and_increment());
 
1942
  }
 
1943
 
 
1944
  err= ib_cursor_insert_row(cursor, tuple);
 
1945
 
 
1946
  if (err == DB_DUPLICATE_KEY)
 
1947
  {
 
1948
    if (write_can_replace)
 
1949
    {
 
1950
      store_key_value_from_haildb(getTable()->key_info + getTable()->getShare()->getPrimaryKey(),
 
1951
                                  ref, ref_length, record);
 
1952
 
 
1953
      ib_tpl_t search_tuple= ib_clust_search_tuple_create(cursor);
 
1954
 
 
1955
      fill_ib_search_tpl_from_drizzle_key(search_tuple,
 
1956
                                          getTable()->key_info + 0,
 
1957
                                          ref, ref_length);
 
1958
 
 
1959
      int res;
 
1960
      err= ib_cursor_moveto(cursor, search_tuple, IB_CUR_GE, &res);
 
1961
      assert(err == DB_SUCCESS);
 
1962
      ib_tuple_delete(search_tuple);
 
1963
 
 
1964
      tuple= ib_tuple_clear(tuple);
 
1965
      err= ib_cursor_delete_row(cursor);
 
1966
 
 
1967
      err= ib_cursor_first(cursor);
 
1968
      assert(err == DB_SUCCESS || err == DB_END_OF_INDEX);
 
1969
 
 
1970
      write_row_to_haildb_tuple(getTable()->getFields(), tuple);
 
1971
 
 
1972
      err= ib_cursor_insert_row(cursor, tuple);
 
1973
      assert(err==DB_SUCCESS); // probably be nice and process errors
 
1974
    }
 
1975
    else
 
1976
      ret= HA_ERR_FOUND_DUPP_KEY;
 
1977
  }
 
1978
  else if (err != DB_SUCCESS)
 
1979
    ret= ib_err_t_to_drizzle_error(err);
 
1980
 
 
1981
  tuple= ib_tuple_clear(tuple);
 
1982
  ib_tuple_delete(tuple);
 
1983
  err= ib_cursor_reset(cursor);
 
1984
 
 
1985
  return ret;
 
1986
}
 
1987
 
 
1988
int HailDBCursor::doUpdateRecord(const unsigned char *,
 
1989
                                         unsigned char *)
 
1990
{
 
1991
  ib_tpl_t update_tuple;
 
1992
  ib_err_t err;
 
1993
 
 
1994
  update_tuple= ib_clust_read_tuple_create(cursor);
 
1995
 
 
1996
  err= ib_tuple_copy(update_tuple, tuple);
 
1997
  assert(err == DB_SUCCESS);
 
1998
 
 
1999
  write_row_to_haildb_tuple(getTable()->getFields(), update_tuple);
 
2000
 
 
2001
  err= ib_cursor_update_row(cursor, tuple, update_tuple);
 
2002
 
 
2003
  ib_tuple_delete(update_tuple);
 
2004
 
 
2005
  advance_cursor= true;
 
2006
 
 
2007
  if (err == DB_SUCCESS)
 
2008
    return 0;
 
2009
  else if (err == DB_DUPLICATE_KEY)
 
2010
    return HA_ERR_FOUND_DUPP_KEY;
 
2011
  else
 
2012
    return -1;
 
2013
}
 
2014
 
 
2015
int HailDBCursor::doDeleteRecord(const unsigned char *)
 
2016
{
 
2017
  ib_err_t err;
 
2018
 
 
2019
  err= ib_cursor_delete_row(cursor);
 
2020
  if (err != DB_SUCCESS)
 
2021
    return -1; // FIXME
 
2022
 
 
2023
  advance_cursor= true;
 
2024
  return 0;
 
2025
}
 
2026
 
 
2027
int HailDBCursor::delete_all_rows(void)
 
2028
{
 
2029
  /* I *think* ib_truncate is non-transactional....
 
2030
     so only support TRUNCATE and not DELETE FROM t;
 
2031
     (this is what ha_haildb does)
 
2032
  */
 
2033
  if (session_sql_command(getTable()->in_use) != SQLCOM_TRUNCATE)
 
2034
    return HA_ERR_WRONG_COMMAND;
 
2035
 
 
2036
  ib_id_t id;
 
2037
  ib_err_t err;
 
2038
 
 
2039
  ib_trx_t transaction= ib_trx_begin(IB_TRX_REPEATABLE_READ);
 
2040
 
 
2041
  ib_cursor_attach_trx(cursor, transaction);
 
2042
 
 
2043
  err= ib_schema_lock_exclusive(transaction);
 
2044
  if (err != DB_SUCCESS)
 
2045
  {
 
2046
    ib_err_t rollback_err= ib_trx_rollback(transaction);
 
2047
 
 
2048
    push_warning_printf(getTable()->in_use, DRIZZLE_ERROR::WARN_LEVEL_ERROR,
 
2049
                        ER_CANT_DELETE_FILE,
 
2050
                        _("Cannot Lock HailDB Data Dictionary. HailDB Error %d (%s)\n"),
 
2051
                        err, ib_strerror(err));
 
2052
 
 
2053
    assert (rollback_err == DB_SUCCESS);
 
2054
 
 
2055
    return HA_ERR_GENERIC;
 
2056
  }
 
2057
 
 
2058
  share->auto_increment_value.fetch_and_store(1);
 
2059
 
 
2060
  err= ib_cursor_truncate(&cursor, &id);
 
2061
  if (err != DB_SUCCESS)
 
2062
    goto err;
 
2063
 
 
2064
  ib_schema_unlock(transaction);
 
2065
  /* ib_cursor_truncate commits on success */
 
2066
 
 
2067
  err= ib_cursor_open_table_using_id(id, NULL, &cursor);
 
2068
  if (err != DB_SUCCESS)
 
2069
    goto err;
 
2070
 
 
2071
  return 0;
 
2072
 
 
2073
err:
 
2074
  ib_schema_unlock(transaction);
 
2075
  ib_err_t rollback_err= ib_trx_rollback(transaction);
 
2076
  assert(rollback_err == DB_SUCCESS);
 
2077
  return err;
 
2078
}
 
2079
 
 
2080
int HailDBCursor::doStartTableScan(bool)
 
2081
{
 
2082
  ib_err_t err;
 
2083
  ib_trx_t transaction;
 
2084
 
 
2085
  if (in_table_scan)
 
2086
    doEndTableScan();
 
2087
  in_table_scan= true;
 
2088
 
 
2089
  transaction= *get_trx(getTable()->in_use);
 
2090
 
 
2091
  assert(transaction != NULL);
 
2092
 
 
2093
  ib_cursor_attach_trx(cursor, transaction);
 
2094
 
 
2095
  err= ib_cursor_set_lock_mode(cursor, ib_lock_mode);
 
2096
  assert(err == DB_SUCCESS); // FIXME
 
2097
 
 
2098
  tuple= ib_clust_read_tuple_create(cursor);
 
2099
 
 
2100
  err= ib_cursor_first(cursor);
 
2101
  if (err != DB_SUCCESS && err != DB_END_OF_INDEX)
 
2102
  {
 
2103
    previous_error= ib_err_t_to_drizzle_error(err);
 
2104
    err= ib_cursor_reset(cursor);
 
2105
    return previous_error;
 
2106
  }
 
2107
 
 
2108
  advance_cursor= false;
 
2109
 
 
2110
  previous_error= 0;
 
2111
  return(0);
 
2112
}
 
2113
 
 
2114
int read_row_from_haildb(unsigned char* buf, ib_crsr_t cursor, ib_tpl_t tuple, Table* table, bool has_hidden_primary_key, uint64_t *hidden_pkey, drizzled::memory::Root **blobroot)
 
2115
{
 
2116
  ib_err_t err;
 
2117
  ptrdiff_t row_offset= buf - table->getInsertRecord();
 
2118
 
 
2119
  err= ib_cursor_read_row(cursor, tuple);
 
2120
 
 
2121
  if (err != DB_SUCCESS) // FIXME
 
2122
    return HA_ERR_END_OF_FILE;
 
2123
 
 
2124
  int colnr= 0;
 
2125
 
 
2126
  /* We need the primary key for ::position() to work */
 
2127
  if (table->getShare()->getPrimaryKey() != MAX_KEY)
 
2128
    table->mark_columns_used_by_index_no_reset(table->getShare()->getPrimaryKey());
 
2129
 
 
2130
  for (Field **field= table->getFields() ; *field ; field++, colnr++)
 
2131
  {
 
2132
    if (! (**field).isReadSet())
 
2133
      continue;
 
2134
 
 
2135
    (**field).move_field_offset(row_offset);
 
2136
 
 
2137
    (**field).setWriteSet();
 
2138
 
 
2139
    uint32_t length= ib_col_get_len(tuple, colnr);
 
2140
    if (length == IB_SQL_NULL)
 
2141
    {
 
2142
      (**field).set_null();
 
2143
      continue;
 
2144
    }
 
2145
    else
 
2146
      (**field).set_notnull();
 
2147
 
 
2148
    if ((**field).type() == DRIZZLE_TYPE_VARCHAR)
 
2149
    {
 
2150
      (*field)->store((const char*)ib_col_get_value(tuple, colnr),
 
2151
                      length,
 
2152
                      &my_charset_bin);
 
2153
    }
 
2154
    else if ((**field).type() == DRIZZLE_TYPE_DATE)
 
2155
    {
 
2156
      uint32_t date_read;
 
2157
      err= ib_tuple_read_u32(tuple, colnr, &date_read);
 
2158
      (*field)->store(date_read);
 
2159
    }
 
2160
    else if ((**field).type() == DRIZZLE_TYPE_BLOB)
 
2161
    {
 
2162
      if (blobroot == NULL)
 
2163
        (reinterpret_cast<Field_blob*>(*field))->set_ptr(length,
 
2164
                                      (unsigned char*)ib_col_get_value(tuple,
 
2165
                                                                       colnr));
 
2166
      else
 
2167
      {
 
2168
        if (*blobroot == NULL)
 
2169
        {
 
2170
          *blobroot= new drizzled::memory::Root();
 
2171
          (**blobroot).init_alloc_root();
 
2172
        }
 
2173
 
 
2174
        unsigned char *blob_ptr= (unsigned char*)(**blobroot).alloc_root(length);
 
2175
        memcpy(blob_ptr, ib_col_get_value(tuple, colnr), length);
 
2176
        (reinterpret_cast<Field_blob*>(*field))->set_ptr(length, blob_ptr);
 
2177
      }
 
2178
    }
 
2179
    else
 
2180
    {
 
2181
      ib_col_copy_value(tuple, colnr, (*field)->ptr, (*field)->data_length());
 
2182
    }
 
2183
 
 
2184
    (**field).move_field_offset(-row_offset);
 
2185
 
 
2186
  }
 
2187
 
 
2188
  if (has_hidden_primary_key)
 
2189
  {
 
2190
    err= ib_tuple_read_u64(tuple, colnr, hidden_pkey);
 
2191
  }
 
2192
 
 
2193
  return 0;
 
2194
}
 
2195
 
 
2196
int HailDBCursor::rnd_next(unsigned char *buf)
 
2197
{
 
2198
  ib_err_t err;
 
2199
  int ret;
 
2200
 
 
2201
  if (previous_error)
 
2202
    return previous_error;
 
2203
 
 
2204
  if (advance_cursor)
 
2205
    err= ib_cursor_next(cursor);
 
2206
 
 
2207
  tuple= ib_tuple_clear(tuple);
 
2208
  ret= read_row_from_haildb(buf, cursor, tuple, getTable(),
 
2209
                            share->has_hidden_primary_key,
 
2210
                            &hidden_autoinc_pkey_position);
 
2211
 
 
2212
  advance_cursor= true;
 
2213
  return ret;
 
2214
}
 
2215
 
 
2216
int HailDBCursor::doEndTableScan()
 
2217
{
 
2218
  ib_err_t err;
 
2219
 
 
2220
  ib_tuple_delete(tuple);
 
2221
  err= ib_cursor_reset(cursor);
 
2222
  assert(err == DB_SUCCESS);
 
2223
  in_table_scan= false;
 
2224
  previous_error= 0;
 
2225
  return 0;
 
2226
}
 
2227
 
 
2228
int HailDBCursor::rnd_pos(unsigned char *buf, unsigned char *pos)
 
2229
{
 
2230
  ib_err_t err;
 
2231
  int res;
 
2232
  int ret= 0;
 
2233
  ib_tpl_t search_tuple= ib_clust_search_tuple_create(cursor);
 
2234
 
 
2235
  if (share->has_hidden_primary_key)
 
2236
  {
 
2237
    err= ib_col_set_value(search_tuple, 0,
 
2238
                          ((uint64_t*)(pos)), sizeof(uint64_t));
 
2239
  }
 
2240
  else
 
2241
  {
 
2242
    unsigned int keynr;
 
2243
    if (getTable()->getShare()->getPrimaryKey() != MAX_KEY)
 
2244
      keynr= getTable()->getShare()->getPrimaryKey();
 
2245
    else
 
2246
      keynr= get_first_unique_index(*getTable());
 
2247
 
 
2248
    fill_ib_search_tpl_from_drizzle_key(search_tuple,
 
2249
                                        getTable()->key_info + keynr,
 
2250
                                        pos, ref_length);
 
2251
  }
 
2252
 
 
2253
  err= ib_cursor_moveto(cursor, search_tuple, IB_CUR_GE, &res);
 
2254
  assert(err == DB_SUCCESS);
 
2255
 
 
2256
  assert(res==0);
 
2257
  if (res != 0)
 
2258
    ret= -1;
 
2259
 
 
2260
  ib_tuple_delete(search_tuple);
 
2261
 
 
2262
  tuple= ib_tuple_clear(tuple);
 
2263
 
 
2264
  if (ret == 0)
 
2265
    ret= read_row_from_haildb(buf, cursor, tuple, getTable(),
 
2266
                              share->has_hidden_primary_key,
 
2267
                              &hidden_autoinc_pkey_position);
 
2268
 
 
2269
  advance_cursor= true;
 
2270
 
 
2271
  return(ret);
 
2272
}
 
2273
 
 
2274
static void store_key_value_from_haildb(KeyInfo *key_info, unsigned char* ref, int ref_len, const unsigned char *record)
 
2275
{
 
2276
  KeyPartInfo* key_part= key_info->key_part;
 
2277
  KeyPartInfo* end= key_info->key_part + key_info->key_parts;
 
2278
  unsigned char* ref_start= ref;
 
2279
 
 
2280
  memset(ref, 0, ref_len);
 
2281
 
 
2282
  for (; key_part != end; key_part++)
 
2283
  {
 
2284
    char is_null= 0;
 
2285
 
 
2286
    if(key_part->null_bit)
 
2287
    {
 
2288
      *ref= is_null= record[key_part->null_offset] & key_part->null_bit;
 
2289
      ref++;
 
2290
    }
 
2291
 
 
2292
    Field *field= key_part->field;
 
2293
 
 
2294
    if (field->type() == DRIZZLE_TYPE_VARCHAR)
 
2295
    {
 
2296
      if (is_null)
 
2297
      {
 
2298
        ref+= key_part->length + 2; /* 2 bytes for length */
 
2299
        continue;
 
2300
      }
 
2301
 
 
2302
      String str;
 
2303
      field->val_str(&str);
 
2304
 
 
2305
      *ref++= (char)(str.length() & 0x000000ff);
 
2306
      *ref++= (char)((str.length()>>8) & 0x000000ff);
 
2307
 
 
2308
      memcpy(ref, str.ptr(), str.length());
 
2309
      ref+= key_part->length;
 
2310
    }
 
2311
    // FIXME: blobs.
 
2312
    else
 
2313
    {
 
2314
      if (is_null)
 
2315
      {
 
2316
        ref+= key_part->length;
 
2317
        continue;
 
2318
      }
 
2319
 
 
2320
      memcpy(ref, record+key_part->offset, key_part->length);
 
2321
      ref+= key_part->length;
 
2322
    }
 
2323
 
 
2324
  }
 
2325
 
 
2326
  assert(ref == ref_start + ref_len);
 
2327
}
 
2328
 
 
2329
void HailDBCursor::position(const unsigned char *record)
 
2330
{
 
2331
  if (share->has_hidden_primary_key)
 
2332
    *((uint64_t*) ref)= hidden_autoinc_pkey_position;
 
2333
  else
 
2334
  {
 
2335
    unsigned int keynr;
 
2336
    if (getTable()->getShare()->getPrimaryKey() != MAX_KEY)
 
2337
      keynr= getTable()->getShare()->getPrimaryKey();
 
2338
    else
 
2339
      keynr= get_first_unique_index(*getTable());
 
2340
 
 
2341
    store_key_value_from_haildb(getTable()->key_info + keynr,
 
2342
                                ref, ref_length, record);
 
2343
  }
 
2344
 
 
2345
  return;
 
2346
}
 
2347
 
 
2348
double HailDBCursor::scan_time()
 
2349
{
 
2350
  ib_table_stats_t table_stats;
 
2351
  ib_err_t err;
 
2352
 
 
2353
  err= ib_get_table_statistics(cursor, &table_stats, sizeof(table_stats));
 
2354
 
 
2355
  /* Approximate I/O seeks for full table scan */
 
2356
  return (double) (table_stats.stat_clustered_index_size / 16384);
 
2357
}
 
2358
 
 
2359
int HailDBCursor::info(uint32_t flag)
 
2360
{
 
2361
  ib_table_stats_t table_stats;
 
2362
  ib_err_t err;
 
2363
 
 
2364
  if (flag & HA_STATUS_VARIABLE)
 
2365
  {
 
2366
    err= ib_get_table_statistics(cursor, &table_stats, sizeof(table_stats));
 
2367
 
 
2368
    stats.records= table_stats.stat_n_rows;
 
2369
 
 
2370
    if (table_stats.stat_n_rows < 2)
 
2371
      stats.records= 2;
 
2372
 
 
2373
    stats.deleted= 0;
 
2374
    stats.data_file_length= table_stats.stat_clustered_index_size;
 
2375
    stats.index_file_length= table_stats.stat_sum_of_other_index_sizes;
 
2376
 
 
2377
    stats.mean_rec_length= stats.data_file_length / stats.records;
 
2378
  }
 
2379
 
 
2380
  if (flag & HA_STATUS_AUTO)
 
2381
    stats.auto_increment_value= 1;
 
2382
  return(0);
 
2383
}
 
2384
 
 
2385
int HailDBCursor::doStartIndexScan(uint32_t keynr, bool)
 
2386
{
 
2387
  ib_trx_t transaction= *get_trx(getTable()->in_use);
 
2388
 
 
2389
  active_index= keynr;
 
2390
 
 
2391
  ib_cursor_attach_trx(cursor, transaction);
 
2392
 
 
2393
  if (active_index == 0 && ! share->has_hidden_primary_key)
 
2394
  {
 
2395
    tuple= ib_clust_read_tuple_create(cursor);
 
2396
  }
 
2397
  else
 
2398
  {
 
2399
    ib_err_t err;
 
2400
    ib_id_t index_id;
 
2401
    err= ib_index_get_id(table_path_to_haildb_name(getShare()->getPath()),
 
2402
                         getShare()->getKeyInfo(keynr).name,
 
2403
                         &index_id);
 
2404
    if (err != DB_SUCCESS)
 
2405
      return -1;
 
2406
 
 
2407
    err= ib_cursor_close(cursor);
 
2408
    assert(err == DB_SUCCESS);
 
2409
    err= ib_cursor_open_index_using_id(index_id, transaction, &cursor);
 
2410
 
 
2411
    if (err != DB_SUCCESS)
 
2412
      return -1;
 
2413
 
 
2414
    tuple= ib_clust_read_tuple_create(cursor);
 
2415
    ib_cursor_set_cluster_access(cursor);
 
2416
  }
 
2417
 
 
2418
  ib_err_t err= ib_cursor_set_lock_mode(cursor, ib_lock_mode);
 
2419
  assert(err == DB_SUCCESS);
 
2420
 
 
2421
  advance_cursor= false;
 
2422
  return 0;
 
2423
}
 
2424
 
 
2425
static ib_srch_mode_t ha_rkey_function_to_ib_srch_mode(drizzled::ha_rkey_function find_flag)
 
2426
{
 
2427
  switch (find_flag)
 
2428
  {
 
2429
  case HA_READ_KEY_EXACT:
 
2430
    return IB_CUR_GE;
 
2431
  case HA_READ_KEY_OR_NEXT:
 
2432
    return IB_CUR_GE;
 
2433
  case HA_READ_KEY_OR_PREV:
 
2434
    return IB_CUR_LE;
 
2435
  case HA_READ_AFTER_KEY:
 
2436
    return IB_CUR_G;
 
2437
  case HA_READ_BEFORE_KEY:
 
2438
    return IB_CUR_L;
 
2439
  case HA_READ_PREFIX:
 
2440
    return IB_CUR_GE;
 
2441
  case HA_READ_PREFIX_LAST:
 
2442
    return IB_CUR_LE;
 
2443
  case HA_READ_PREFIX_LAST_OR_PREV:
 
2444
    return IB_CUR_LE;
 
2445
  case HA_READ_MBR_CONTAIN:
 
2446
  case HA_READ_MBR_INTERSECT:
 
2447
  case HA_READ_MBR_WITHIN:
 
2448
  case HA_READ_MBR_DISJOINT:
 
2449
  case HA_READ_MBR_EQUAL:
 
2450
    assert(false); /* these just exist in the enum, not used. */
 
2451
  }
 
2452
 
 
2453
  assert(false);
 
2454
  /* Must return or compiler complains about reaching end of function */
 
2455
  return (ib_srch_mode_t)0;
 
2456
}
 
2457
 
 
2458
static void fill_ib_search_tpl_from_drizzle_key(ib_tpl_t search_tuple,
 
2459
                                                const drizzled::KeyInfo *key_info,
 
2460
                                                const unsigned char *key_ptr,
 
2461
                                                uint32_t key_len)
 
2462
{
 
2463
  KeyPartInfo *key_part= key_info->key_part;
 
2464
  KeyPartInfo *end= key_part + key_info->key_parts;
 
2465
  const unsigned char *buff= key_ptr;
 
2466
  ib_err_t err;
 
2467
 
 
2468
  int fieldnr= 0;
 
2469
 
 
2470
  for(; key_part != end && buff < key_ptr + key_len; key_part++)
 
2471
  {
 
2472
    Field *field= key_part->field;
 
2473
    bool is_null= false;
 
2474
 
 
2475
    if (key_part->null_bit)
 
2476
    {
 
2477
      is_null= *buff;
 
2478
      if (is_null)
 
2479
      {
 
2480
        err= ib_col_set_value(search_tuple, fieldnr, NULL, IB_SQL_NULL);
 
2481
        assert(err == DB_SUCCESS);
 
2482
      }
 
2483
      buff++;
 
2484
    }
 
2485
 
 
2486
    if (field->type() == DRIZZLE_TYPE_VARCHAR)
 
2487
    {
 
2488
      if (is_null)
 
2489
      {
 
2490
        buff+= key_part->length + 2; /* 2 bytes length */
 
2491
        continue;
 
2492
      }
 
2493
 
 
2494
      int length= *buff + (*(buff + 1) << 8);
 
2495
      buff+=2;
 
2496
      err= ib_col_set_value(search_tuple, fieldnr, buff, length);
 
2497
      assert(err == DB_SUCCESS);
 
2498
 
 
2499
      buff+= key_part->length;
 
2500
    }
 
2501
    else if (field->type() == DRIZZLE_TYPE_DATE)
 
2502
    {
 
2503
      uint32_t date_int= static_cast<uint32_t>(field->val_int());
 
2504
      err= ib_col_set_value(search_tuple, fieldnr, &date_int, 4);
 
2505
      buff+= key_part->length;
 
2506
    }
 
2507
    // FIXME: BLOBs
 
2508
    else
 
2509
    {
 
2510
      if (is_null)
 
2511
      {
 
2512
        buff+= key_part->length;
 
2513
        continue;
 
2514
      }
 
2515
 
 
2516
      err= ib_col_set_value(search_tuple, fieldnr,
 
2517
                            buff, key_part->length);
 
2518
      assert(err == DB_SUCCESS);
 
2519
 
 
2520
      buff+= key_part->length;
 
2521
    }
 
2522
 
 
2523
    fieldnr++;
 
2524
  }
 
2525
 
 
2526
  assert(buff == key_ptr + key_len);
 
2527
}
 
2528
 
 
2529
int HailDBCursor::haildb_index_read(unsigned char *buf,
 
2530
                                            const unsigned char *key_ptr,
 
2531
                                            uint32_t key_len,
 
2532
                                            drizzled::ha_rkey_function find_flag,
 
2533
                                            bool allocate_blobs)
 
2534
{
 
2535
  ib_tpl_t search_tuple;
 
2536
  int res;
 
2537
  ib_err_t err;
 
2538
  int ret;
 
2539
  ib_srch_mode_t search_mode;
 
2540
 
 
2541
  search_mode= ha_rkey_function_to_ib_srch_mode(find_flag);
 
2542
 
 
2543
  if (active_index == 0 && ! share->has_hidden_primary_key)
 
2544
    search_tuple= ib_clust_search_tuple_create(cursor);
 
2545
  else
 
2546
    search_tuple= ib_sec_search_tuple_create(cursor);
 
2547
 
 
2548
  fill_ib_search_tpl_from_drizzle_key(search_tuple,
 
2549
                                      getTable()->key_info + active_index,
 
2550
                                      key_ptr, key_len);
 
2551
 
 
2552
  err= ib_cursor_moveto(cursor, search_tuple, search_mode, &res);
 
2553
  ib_tuple_delete(search_tuple);
 
2554
 
 
2555
  if ((err == DB_RECORD_NOT_FOUND || err == DB_END_OF_INDEX))
 
2556
  {
 
2557
    getTable()->status= STATUS_NOT_FOUND;
 
2558
    return HA_ERR_KEY_NOT_FOUND;
 
2559
  }
 
2560
 
 
2561
  if (err != DB_SUCCESS)
 
2562
  {
 
2563
    return ib_err_t_to_drizzle_error(err);
 
2564
  }
 
2565
 
 
2566
  tuple= ib_tuple_clear(tuple);
 
2567
  ret= read_row_from_haildb(buf, cursor, tuple, getTable(),
 
2568
                            share->has_hidden_primary_key,
 
2569
                            &hidden_autoinc_pkey_position,
 
2570
                            (allocate_blobs)? &blobroot : NULL);
 
2571
  if (ret == 0)
 
2572
    getTable()->status= 0;
 
2573
  else
 
2574
    getTable()->status= STATUS_NOT_FOUND;
 
2575
 
 
2576
  advance_cursor= true;
 
2577
 
 
2578
  return ret;
 
2579
}
 
2580
 
 
2581
int HailDBCursor::index_read(unsigned char *buf,
 
2582
                                     const unsigned char *key_ptr,
 
2583
                                     uint32_t key_len,
 
2584
                                     drizzled::ha_rkey_function find_flag)
 
2585
{
 
2586
  return haildb_index_read(buf, key_ptr, key_len, find_flag, false);
 
2587
}
 
2588
 
 
2589
/* This is straight from cursor.cc, but it's private there :( */
 
2590
uint32_t HailDBCursor::calculate_key_len(uint32_t key_position,
 
2591
                                                 key_part_map keypart_map_arg)
 
2592
{
 
2593
  /* works only with key prefixes */
 
2594
  assert(((keypart_map_arg + 1) & keypart_map_arg) == 0);
 
2595
 
 
2596
  KeyPartInfo *key_part_found= getTable()->getShare()->getKeyInfo(key_position).key_part;
 
2597
  KeyPartInfo *end_key_part_found= key_part_found + getTable()->getShare()->getKeyInfo(key_position).key_parts;
 
2598
  uint32_t length= 0;
 
2599
 
 
2600
  while (key_part_found < end_key_part_found && keypart_map_arg)
 
2601
  {
 
2602
    length+= key_part_found->store_length;
 
2603
    keypart_map_arg >>= 1;
 
2604
    key_part_found++;
 
2605
  }
 
2606
  return length;
 
2607
}
 
2608
 
 
2609
 
 
2610
int HailDBCursor::haildb_index_read_map(unsigned char * buf,
 
2611
                                                const unsigned char *key,
 
2612
                                                key_part_map keypart_map,
 
2613
                                                enum ha_rkey_function find_flag,
 
2614
                                                bool allocate_blobs)
 
2615
{
 
2616
  uint32_t key_len= calculate_key_len(active_index, keypart_map);
 
2617
  return  haildb_index_read(buf, key, key_len, find_flag, allocate_blobs);
 
2618
}
 
2619
 
 
2620
int HailDBCursor::index_read_idx_map(unsigned char * buf,
 
2621
                                             uint32_t index,
 
2622
                                             const unsigned char * key,
 
2623
                                             key_part_map keypart_map,
 
2624
                                             enum ha_rkey_function find_flag)
 
2625
{
 
2626
  int error, error1;
 
2627
  error= doStartIndexScan(index, 0);
 
2628
  if (!error)
 
2629
  {
 
2630
    error= haildb_index_read_map(buf, key, keypart_map, find_flag, true);
 
2631
    error1= doEndIndexScan();
 
2632
  }
 
2633
  return error ?  error : error1;
 
2634
}
 
2635
 
 
2636
int HailDBCursor::reset()
 
2637
{
 
2638
  if (blobroot)
 
2639
    blobroot->free_root(MYF(0));
 
2640
 
 
2641
  return 0;
 
2642
}
 
2643
 
 
2644
int HailDBCursor::index_next(unsigned char *buf)
 
2645
{
 
2646
  int ret= HA_ERR_END_OF_FILE;
 
2647
 
 
2648
  if (advance_cursor)
 
2649
  {
 
2650
    ib_err_t err= ib_cursor_next(cursor);
 
2651
    if (err == DB_END_OF_INDEX)
 
2652
      return HA_ERR_END_OF_FILE;
 
2653
  }
 
2654
 
 
2655
  tuple= ib_tuple_clear(tuple);
 
2656
  ret= read_row_from_haildb(buf, cursor, tuple, getTable(),
 
2657
                            share->has_hidden_primary_key,
 
2658
                            &hidden_autoinc_pkey_position);
 
2659
 
 
2660
  advance_cursor= true;
 
2661
  return ret;
 
2662
}
 
2663
 
 
2664
int HailDBCursor::doEndIndexScan()
 
2665
{
 
2666
  active_index= MAX_KEY;
 
2667
 
 
2668
  return doEndTableScan();
 
2669
}
 
2670
 
 
2671
int HailDBCursor::index_prev(unsigned char *buf)
 
2672
{
 
2673
  int ret= HA_ERR_END_OF_FILE;
 
2674
  ib_err_t err;
 
2675
 
 
2676
  if (advance_cursor)
 
2677
  {
 
2678
    err= ib_cursor_prev(cursor);
 
2679
    if (err != DB_SUCCESS)
 
2680
    {
 
2681
      if (err == DB_END_OF_INDEX)
 
2682
        return HA_ERR_END_OF_FILE;
 
2683
      else
 
2684
        return -1; // FIXME
 
2685
    }
 
2686
  }
 
2687
 
 
2688
  tuple= ib_tuple_clear(tuple);
 
2689
  ret= read_row_from_haildb(buf, cursor, tuple, getTable(),
 
2690
                            share->has_hidden_primary_key,
 
2691
                            &hidden_autoinc_pkey_position);
 
2692
 
 
2693
  advance_cursor= true;
 
2694
 
 
2695
  return ret;
 
2696
}
 
2697
 
 
2698
 
 
2699
int HailDBCursor::index_first(unsigned char *buf)
 
2700
{
 
2701
  int ret= HA_ERR_END_OF_FILE;
 
2702
  ib_err_t err;
 
2703
 
 
2704
  err= ib_cursor_first(cursor);
 
2705
  if (err != DB_SUCCESS)
 
2706
    return ib_err_t_to_drizzle_error(err);
 
2707
 
 
2708
  tuple= ib_tuple_clear(tuple);
 
2709
  ret= read_row_from_haildb(buf, cursor, tuple, getTable(),
 
2710
                            share->has_hidden_primary_key,
 
2711
                            &hidden_autoinc_pkey_position);
 
2712
 
 
2713
  advance_cursor= true;
 
2714
 
 
2715
  return ret;
 
2716
}
 
2717
 
 
2718
 
 
2719
int HailDBCursor::index_last(unsigned char *buf)
 
2720
{
 
2721
  int ret= HA_ERR_END_OF_FILE;
 
2722
  ib_err_t err;
 
2723
 
 
2724
  err= ib_cursor_last(cursor);
 
2725
  if (err != DB_SUCCESS)
 
2726
    return ib_err_t_to_drizzle_error(err);
 
2727
 
 
2728
  tuple= ib_tuple_clear(tuple);
 
2729
  ret= read_row_from_haildb(buf, cursor, tuple, getTable(),
 
2730
                            share->has_hidden_primary_key,
 
2731
                            &hidden_autoinc_pkey_position);
 
2732
  advance_cursor= true;
 
2733
 
 
2734
  return ret;
 
2735
}
 
2736
 
 
2737
int HailDBCursor::extra(enum ha_extra_function operation)
 
2738
{
 
2739
  switch (operation)
 
2740
  {
 
2741
  case HA_EXTRA_FLUSH:
 
2742
    if (blobroot)
 
2743
      blobroot->free_root(MYF(0));
 
2744
    break;
 
2745
  case HA_EXTRA_WRITE_CAN_REPLACE:
 
2746
    write_can_replace= true;
 
2747
    break;
 
2748
  case HA_EXTRA_WRITE_CANNOT_REPLACE:
 
2749
    write_can_replace= false;
 
2750
    break;
 
2751
  default:
 
2752
    break;
 
2753
  }
 
2754
 
 
2755
  return 0;
 
2756
}
 
2757
 
 
2758
static int create_table_message_table()
 
2759
{
 
2760
  ib_tbl_sch_t schema;
 
2761
  ib_idx_sch_t index_schema;
 
2762
  ib_trx_t transaction;
 
2763
  ib_id_t table_id;
 
2764
  ib_err_t err, rollback_err;
 
2765
  ib_bool_t create_db_err;
 
2766
 
 
2767
  create_db_err= ib_database_create("data_dictionary");
 
2768
  if (create_db_err != IB_TRUE)
 
2769
    return -1;
 
2770
 
 
2771
  err= ib_table_schema_create(HAILDB_TABLE_DEFINITIONS_TABLE, &schema,
 
2772
                              IB_TBL_COMPACT, 0);
 
2773
  if (err != DB_SUCCESS)
 
2774
    return err;
 
2775
 
 
2776
  err= ib_table_schema_add_col(schema, "table_name", IB_VARCHAR, IB_COL_NONE, 0,
 
2777
                               IB_MAX_TABLE_NAME_LEN);
 
2778
  if (err != DB_SUCCESS)
 
2779
    goto free_err;
 
2780
 
 
2781
  err= ib_table_schema_add_col(schema, "message", IB_BLOB, IB_COL_NONE, 0, 0);
 
2782
  if (err != DB_SUCCESS)
 
2783
    goto free_err;
 
2784
 
 
2785
  err= ib_table_schema_add_index(schema, "PRIMARY_KEY", &index_schema);
 
2786
  if (err != DB_SUCCESS)
 
2787
    goto free_err;
 
2788
 
 
2789
  err= ib_index_schema_add_col(index_schema, "table_name", 0);
 
2790
  if (err != DB_SUCCESS)
 
2791
    goto free_err;
 
2792
  err= ib_index_schema_set_clustered(index_schema);
 
2793
  if (err != DB_SUCCESS)
 
2794
    goto free_err;
 
2795
 
 
2796
  transaction= ib_trx_begin(IB_TRX_REPEATABLE_READ);
 
2797
  err= ib_schema_lock_exclusive(transaction);
 
2798
  if (err != DB_SUCCESS)
 
2799
    goto rollback;
 
2800
 
 
2801
  err= ib_table_create(transaction, schema, &table_id);
 
2802
  if (err != DB_SUCCESS)
 
2803
    goto rollback;
 
2804
 
 
2805
  err= ib_trx_commit(transaction);
 
2806
  if (err != DB_SUCCESS)
 
2807
    goto rollback;
 
2808
 
 
2809
  ib_table_schema_delete(schema);
 
2810
 
 
2811
  return 0;
 
2812
rollback:
 
2813
  ib_schema_unlock(transaction);
 
2814
  rollback_err= ib_trx_rollback(transaction);
 
2815
  assert(rollback_err == DB_SUCCESS);
 
2816
free_err:
 
2817
  ib_table_schema_delete(schema);
 
2818
  return err;
 
2819
}
 
2820
 
 
2821
static char*  innobase_log_group_home_dir   = NULL;
 
2822
static bool innobase_use_doublewrite= true;
 
2823
static unsigned long innobase_fast_shutdown= 1;
 
2824
static bool srv_file_per_table= false;
 
2825
static bool innobase_adaptive_hash_index;
 
2826
static bool srv_adaptive_flushing;
 
2827
static bool innobase_print_verbose_log;
 
2828
static bool innobase_rollback_on_timeout;
 
2829
static bool innobase_create_status_file;
 
2830
static bool srv_use_sys_malloc;
 
2831
static char*  innobase_file_format_name   = const_cast<char *>("Barracuda");
 
2832
static char*  innobase_unix_file_flush_method   = NULL;
 
2833
static unsigned long srv_flush_log_at_trx_commit;
 
2834
static unsigned long srv_max_buf_pool_modified_pct;
 
2835
static unsigned long srv_max_purge_lag;
 
2836
static unsigned long innobase_lru_old_blocks_pct;
 
2837
static unsigned long innobase_lru_block_access_recency;
 
2838
static unsigned long innobase_read_io_threads;
 
2839
static unsigned long innobase_write_io_threads;
 
2840
typedef constrained_check<unsigned int, 1000, 1> autoextend_constraint;
 
2841
static autoextend_constraint srv_auto_extend_increment;
 
2842
static unsigned long innobase_lock_wait_timeout;
 
2843
static unsigned long srv_n_spin_wait_rounds;
 
2844
typedef constrained_check<size_t, SIZE_MAX, 5242880, 1048576> buffer_pool_constraint;
 
2845
static buffer_pool_constraint innobase_buffer_pool_size;
 
2846
typedef constrained_check<size_t, SIZE_MAX, 512, 1024> additional_mem_pool_constraint;
 
2847
static additional_mem_pool_constraint innobase_additional_mem_pool_size;
 
2848
static bool  innobase_use_checksums= true;
 
2849
typedef constrained_check<unsigned int, UINT_MAX, 100> io_capacity_constraint;
 
2850
static io_capacity_constraint srv_io_capacity;
 
2851
 
 
2852
static long innobase_open_files;
 
2853
static long innobase_force_recovery;
 
2854
static long innobase_log_buffer_size;
 
2855
static char  default_haildb_data_file_path[]= "ibdata1:10M:autoextend";
 
2856
static char* haildb_data_file_path= NULL;
 
2857
 
 
2858
static int64_t haildb_log_file_size;
 
2859
static int64_t haildb_log_files_in_group;
 
2860
 
 
2861
static int haildb_init(drizzled::module::Context &context)
 
2862
{
 
2863
  haildb_system_table_names.insert(std::string("HAILDB_SYS_TABLES"));
 
2864
  haildb_system_table_names.insert(std::string("HAILDB_SYS_COLUMNS"));
 
2865
  haildb_system_table_names.insert(std::string("HAILDB_SYS_INDEXES"));
 
2866
  haildb_system_table_names.insert(std::string("HAILDB_SYS_FIELDS"));
 
2867
  haildb_system_table_names.insert(std::string("HAILDB_SYS_FOREIGN"));
 
2868
  haildb_system_table_names.insert(std::string("HAILDB_SYS_FOREIGN_COLS"));
 
2869
 
 
2870
  const module::option_map &vm= context.getOptions();
 
2871
 
 
2872
  /* Inverted Booleans */
 
2873
 
 
2874
  innobase_adaptive_hash_index= (vm.count("disable-adaptive-hash-index")) ? false : true;
 
2875
  srv_adaptive_flushing= (vm.count("disable-adaptive-flushing")) ? false : true;
 
2876
  innobase_use_checksums= (vm.count("disable-checksums")) ? false : true;
 
2877
  innobase_use_doublewrite= (vm.count("disable-doublewrite")) ? false : true;
 
2878
  innobase_print_verbose_log= (vm.count("disable-print-verbose-log")) ? false : true;
 
2879
  srv_use_sys_malloc= (vm.count("use-internal-malloc")) ? false : true;
 
2880
 
 
2881
  if (vm.count("fast-shutdown"))
 
2882
  {
 
2883
    if (innobase_fast_shutdown > 2)
 
2884
    {
 
2885
      errmsg_printf(ERRMSG_LVL_ERROR, _("Invalid value of fast-shutdown"));
 
2886
      return 1;
 
2887
    }
 
2888
  }
 
2889
 
 
2890
  if (vm.count("flush-log-at-trx-commit"))
 
2891
  {
 
2892
    if (srv_flush_log_at_trx_commit > 2)
 
2893
    {
 
2894
      errmsg_printf(ERRMSG_LVL_ERROR, _("Invalid value of flush-log-at-trx-commit"));
 
2895
      return 1;
 
2896
    }
 
2897
  }
 
2898
 
 
2899
  if (vm.count("force-recovery"))
 
2900
  {
 
2901
    if (innobase_force_recovery > 6)
 
2902
    {
 
2903
      errmsg_printf(ERRMSG_LVL_ERROR, _("Invalid value of force-recovery"));
 
2904
      return 1;
 
2905
    }
 
2906
  }
 
2907
 
 
2908
  if (vm.count("log-file-size"))
 
2909
  {
 
2910
    if (haildb_log_file_size > INT64_MAX || haildb_log_file_size < 1*1024*1024L)
 
2911
    {
 
2912
      errmsg_printf(ERRMSG_LVL_ERROR, _("Invalid value of log-file-size"));
 
2913
      return 1;
 
2914
    }
 
2915
    haildb_log_file_size/= 1024*1024L;
 
2916
    haildb_log_file_size*= 1024*1024L;
 
2917
  }
 
2918
 
 
2919
  if (vm.count("log-files-in-group"))
 
2920
  {
 
2921
    if (haildb_log_files_in_group > 100 || haildb_log_files_in_group < 2)
 
2922
    {
 
2923
      errmsg_printf(ERRMSG_LVL_ERROR, _("Invalid value of log-files-in-group"));
 
2924
      return 1;
 
2925
    }
 
2926
  }
 
2927
 
 
2928
  if (vm.count("lock-wait-timeout"))
 
2929
  {
 
2930
    if (innobase_lock_wait_timeout > 1024*1024*1024 || innobase_lock_wait_timeout < 1)
 
2931
    {
 
2932
      errmsg_printf(ERRMSG_LVL_ERROR, _("Invalid value of lock-wait-timeout"));
 
2933
      return 1;
 
2934
    }
 
2935
  }
 
2936
 
 
2937
  if (vm.count("log-buffer-size"))
 
2938
  {
 
2939
    if (innobase_log_buffer_size > LONG_MAX || innobase_log_buffer_size < 256*1024L)
 
2940
    {
 
2941
      errmsg_printf(ERRMSG_LVL_ERROR, _("Invalid value of log-buffer-size"));
 
2942
      return 1;
 
2943
    }
 
2944
    innobase_log_buffer_size/= 1024;
 
2945
    innobase_log_buffer_size*= 1024;
 
2946
  }
 
2947
 
 
2948
  if (vm.count("lru-old-blocks-pct"))
 
2949
  {
 
2950
    if (innobase_lru_old_blocks_pct > 95 || innobase_lru_old_blocks_pct < 5)
 
2951
    {
 
2952
      errmsg_printf(ERRMSG_LVL_ERROR, _("Invalid value of lru-old-blocks-pct"));
 
2953
      return 1;
 
2954
    }
 
2955
  }
 
2956
 
 
2957
  if (vm.count("lru-block-access-recency"))
 
2958
  {
 
2959
    if (innobase_lru_block_access_recency > ULONG_MAX)
 
2960
    {
 
2961
      errmsg_printf(ERRMSG_LVL_ERROR, _("Invalid value of lru-block-access-recency"));
 
2962
      return 1;
 
2963
    }
 
2964
  }
 
2965
 
 
2966
  if (vm.count("max-dirty-pages-pct"))
 
2967
  {
 
2968
    if (srv_max_buf_pool_modified_pct > 99)
 
2969
    {
 
2970
      errmsg_printf(ERRMSG_LVL_ERROR, _("Invalid value of max-dirty-pages-pct"));
 
2971
      return 1;
 
2972
    }
 
2973
  }
 
2974
 
 
2975
  if (vm.count("max-purge-lag"))
 
2976
  {
 
2977
    if (srv_max_purge_lag > (unsigned long)~0L)
 
2978
    {
 
2979
      errmsg_printf(ERRMSG_LVL_ERROR, _("Invalid value of max-purge-lag"));
 
2980
      return 1;
 
2981
    }
 
2982
  }
 
2983
 
 
2984
  if (vm.count("open-files"))
 
2985
  {
 
2986
    if (innobase_open_files > LONG_MAX || innobase_open_files < 10L)
 
2987
    {
 
2988
      errmsg_printf(ERRMSG_LVL_ERROR, _("Invalid value of open-files"));
 
2989
      return 1;
 
2990
    }
 
2991
  }
 
2992
 
 
2993
  if (vm.count("read-io-threads"))
 
2994
  {
 
2995
    if (innobase_read_io_threads > 64 || innobase_read_io_threads < 1)
 
2996
    {
 
2997
      errmsg_printf(ERRMSG_LVL_ERROR, _("Invalid value of read-io-threads"));
 
2998
      return 1;
 
2999
    }
 
3000
  }
 
3001
 
 
3002
  if (vm.count("sync-spin-loops"))
 
3003
  {
 
3004
    if (srv_n_spin_wait_rounds > (unsigned long)~0L)
 
3005
    {
 
3006
      errmsg_printf(ERRMSG_LVL_ERROR, _("Invalid value of sync_spin_loops"));
 
3007
      return 1;
 
3008
    }
 
3009
  }
 
3010
 
 
3011
  if (vm.count("file-format"))
 
3012
  {
 
3013
    innobase_file_format_name= const_cast<char *>(vm["file-format"].as<string>().c_str());
 
3014
  }
 
3015
 
 
3016
  if (vm.count("log-group-home-dir"))
 
3017
  {
 
3018
    innobase_log_group_home_dir= const_cast<char *>(vm["log-group-home-dir"].as<string>().c_str());
 
3019
  }
 
3020
 
 
3021
  if (vm.count("flush-method"))
 
3022
  {
 
3023
    innobase_unix_file_flush_method= const_cast<char *>(vm["flush-method"].as<string>().c_str());
 
3024
  }
 
3025
 
 
3026
  if (vm.count("data-file-path"))
 
3027
  {
 
3028
    haildb_data_file_path= const_cast<char *>(vm["data-file-path"].as<string>().c_str());
 
3029
  }
 
3030
 
 
3031
  ib_err_t err;
 
3032
 
 
3033
  err= ib_init();
 
3034
  if (err != DB_SUCCESS)
 
3035
    goto haildb_error;
 
3036
 
 
3037
 
 
3038
  if (vm.count("data-home-dir"))
 
3039
  {
 
3040
    err= ib_cfg_set_text("data_home_dir", vm["data-home-dir"].as<string>().c_str());
 
3041
    if (err != DB_SUCCESS)
 
3042
      goto haildb_error;
 
3043
  }
 
3044
 
 
3045
  if (innobase_log_group_home_dir)
 
3046
  {
 
3047
    err= ib_cfg_set_text("log_group_home_dir", innobase_log_group_home_dir);
 
3048
    if (err != DB_SUCCESS)
 
3049
      goto haildb_error;
 
3050
  }
 
3051
 
 
3052
  if (haildb_data_file_path == NULL)
 
3053
    haildb_data_file_path= default_haildb_data_file_path;
 
3054
 
 
3055
  if (innobase_print_verbose_log)
 
3056
    err= ib_cfg_set_bool_on("print_verbose_log");
 
3057
  else
 
3058
    err= ib_cfg_set_bool_off("print_verbose_log");
 
3059
 
 
3060
  if (err != DB_SUCCESS)
 
3061
    goto haildb_error;
 
3062
 
 
3063
  if (innobase_rollback_on_timeout)
 
3064
    err= ib_cfg_set_bool_on("rollback_on_timeout");
 
3065
  else
 
3066
    err= ib_cfg_set_bool_off("rollback_on_timeout");
 
3067
 
 
3068
  if (err != DB_SUCCESS)
 
3069
    goto haildb_error;
 
3070
 
 
3071
  if (innobase_use_doublewrite)
 
3072
    err= ib_cfg_set_bool_on("doublewrite");
 
3073
  else
 
3074
    err= ib_cfg_set_bool_off("doublewrite");
 
3075
 
 
3076
  if (err != DB_SUCCESS)
 
3077
    goto haildb_error;
 
3078
 
 
3079
  if (innobase_adaptive_hash_index)
 
3080
    err= ib_cfg_set_bool_on("adaptive_hash_index");
 
3081
  else
 
3082
    err= ib_cfg_set_bool_off("adaptive_hash_index");
 
3083
 
 
3084
  if (err != DB_SUCCESS)
 
3085
    goto haildb_error;
 
3086
 
 
3087
  if (srv_adaptive_flushing)
 
3088
    err= ib_cfg_set_bool_on("adaptive_flushing");
 
3089
  else
 
3090
    err= ib_cfg_set_bool_off("adaptive_flushing");
 
3091
 
 
3092
  if (err != DB_SUCCESS)
 
3093
    goto haildb_error;
 
3094
 
 
3095
  err= ib_cfg_set_int("additional_mem_pool_size", static_cast<size_t>(innobase_additional_mem_pool_size));
 
3096
  if (err != DB_SUCCESS)
 
3097
    goto haildb_error;
 
3098
 
 
3099
  err= ib_cfg_set_int("autoextend_increment", static_cast<unsigned int>(srv_auto_extend_increment));
 
3100
  if (err != DB_SUCCESS)
 
3101
    goto haildb_error;
 
3102
 
 
3103
  err= ib_cfg_set_int("buffer_pool_size", static_cast<size_t>(innobase_buffer_pool_size));
 
3104
  if (err != DB_SUCCESS)
 
3105
    goto haildb_error;
 
3106
 
 
3107
  err= ib_cfg_set_int("io_capacity", static_cast<unsigned int>(srv_io_capacity));
 
3108
  if (err != DB_SUCCESS)
 
3109
    goto haildb_error;
 
3110
 
 
3111
  if (srv_file_per_table)
 
3112
    err= ib_cfg_set_bool_on("file_per_table");
 
3113
  else
 
3114
    err= ib_cfg_set_bool_off("file_per_table");
 
3115
 
 
3116
  if (err != DB_SUCCESS)
 
3117
    goto haildb_error;
 
3118
 
 
3119
  err= ib_cfg_set_int("flush_log_at_trx_commit", srv_flush_log_at_trx_commit);
 
3120
  if (err != DB_SUCCESS)
 
3121
    goto haildb_error;
 
3122
 
 
3123
  if (innobase_unix_file_flush_method)
 
3124
  {
 
3125
    err= ib_cfg_set_text("flush_method", innobase_unix_file_flush_method);
 
3126
    if (err != DB_SUCCESS)
 
3127
      goto haildb_error;
 
3128
  }
 
3129
 
 
3130
  err= ib_cfg_set_int("force_recovery", innobase_force_recovery);
 
3131
  if (err != DB_SUCCESS)
 
3132
    goto haildb_error;
 
3133
 
 
3134
  err= ib_cfg_set_text("data_file_path", haildb_data_file_path);
 
3135
  if (err != DB_SUCCESS)
 
3136
    goto haildb_error;
 
3137
 
 
3138
  err= ib_cfg_set_int("log_file_size", haildb_log_file_size);
 
3139
  if (err != DB_SUCCESS)
 
3140
    goto haildb_error;
 
3141
 
 
3142
  err= ib_cfg_set_int("log_buffer_size", innobase_log_buffer_size);
 
3143
  if (err != DB_SUCCESS)
 
3144
    goto haildb_error;
 
3145
 
 
3146
  err= ib_cfg_set_int("log_files_in_group", haildb_log_files_in_group);
 
3147
  if (err != DB_SUCCESS)
 
3148
    goto haildb_error;
 
3149
 
 
3150
  err= ib_cfg_set_int("checksums", innobase_use_checksums);
 
3151
  if (err != DB_SUCCESS)
 
3152
    goto haildb_error;
 
3153
 
 
3154
  err= ib_cfg_set_int("lock_wait_timeout", innobase_lock_wait_timeout);
 
3155
  if (err != DB_SUCCESS)
 
3156
    goto haildb_error;
 
3157
 
 
3158
  err= ib_cfg_set_int("max_dirty_pages_pct", srv_max_buf_pool_modified_pct);
 
3159
  if (err != DB_SUCCESS)
 
3160
    goto haildb_error;
 
3161
 
 
3162
  err= ib_cfg_set_int("max_purge_lag", srv_max_purge_lag);
 
3163
  if (err != DB_SUCCESS)
 
3164
    goto haildb_error;
 
3165
 
 
3166
  err= ib_cfg_set_int("open_files", innobase_open_files);
 
3167
  if (err != DB_SUCCESS)
 
3168
    goto haildb_error;
 
3169
 
 
3170
  err= ib_cfg_set_int("read_io_threads", innobase_read_io_threads);
 
3171
  if (err != DB_SUCCESS)
 
3172
    goto haildb_error;
 
3173
 
 
3174
  err= ib_cfg_set_int("write_io_threads", innobase_write_io_threads);
 
3175
  if (err != DB_SUCCESS)
 
3176
    goto haildb_error;
 
3177
 
 
3178
  err= ib_cfg_set_int("sync_spin_loops", srv_n_spin_wait_rounds);
 
3179
  if (err != DB_SUCCESS)
 
3180
    goto haildb_error;
 
3181
 
 
3182
  if (srv_use_sys_malloc)
 
3183
    err= ib_cfg_set_bool_on("use_sys_malloc");
 
3184
  else
 
3185
    err= ib_cfg_set_bool_off("use_sys_malloc");
 
3186
 
 
3187
  if (err != DB_SUCCESS)
 
3188
    goto haildb_error;
 
3189
 
 
3190
  err= ib_startup(innobase_file_format_name);
 
3191
  if (err != DB_SUCCESS)
 
3192
    goto haildb_error;
 
3193
 
 
3194
  create_table_message_table();
 
3195
 
 
3196
  haildb_engine= new HailDBEngine("InnoDB");
 
3197
  context.add(haildb_engine);
 
3198
  context.registerVariable(new sys_var_bool_ptr_readonly("adaptive_hash_index",
 
3199
                                                         &innobase_adaptive_hash_index));
 
3200
  context.registerVariable(new sys_var_bool_ptr_readonly("adaptive_flushing",
 
3201
                                                         &srv_adaptive_flushing));
 
3202
  context.registerVariable(new sys_var_constrained_value_readonly<size_t>("additional_mem_pool_size",innobase_additional_mem_pool_size));
 
3203
  context.registerVariable(new sys_var_constrained_value_readonly<unsigned int>("autoextend_increment", srv_auto_extend_increment));
 
3204
  context.registerVariable(new sys_var_constrained_value_readonly<size_t>("buffer_pool_size", innobase_buffer_pool_size));
 
3205
  context.registerVariable(new sys_var_bool_ptr_readonly("checksums",
 
3206
                                                         &innobase_use_checksums));
 
3207
  context.registerVariable(new sys_var_bool_ptr_readonly("doublewrite",
 
3208
                                                         &innobase_use_doublewrite));
 
3209
  context.registerVariable(new sys_var_const_string_val("data_home_dir",
 
3210
                                                vm.count("data-home-dir") ?  vm["data-home-dir"].as<string>() : ""));
 
3211
  context.registerVariable(new sys_var_constrained_value_readonly<unsigned int>("io_capacity", srv_io_capacity));
 
3212
 
 
3213
  haildb_datadict_dump_func_initialize(context);
 
3214
  config_table_function_initialize(context);
 
3215
  status_table_function_initialize(context);
 
3216
 
 
3217
  return 0;
 
3218
haildb_error:
 
3219
  fprintf(stderr, _("Error starting HailDB %d (%s)\n"),
 
3220
          err, ib_strerror(err));
 
3221
  return -1;
 
3222
}
 
3223
 
 
3224
 
 
3225
HailDBEngine::~HailDBEngine()
 
3226
{
 
3227
  ib_err_t err;
 
3228
  ib_shutdown_t shutdown_flag= IB_SHUTDOWN_NORMAL;
 
3229
 
 
3230
  if (innobase_fast_shutdown == 1)
 
3231
    shutdown_flag= IB_SHUTDOWN_NO_IBUFMERGE_PURGE;
 
3232
  else if (innobase_fast_shutdown == 2)
 
3233
    shutdown_flag= IB_SHUTDOWN_NO_BUFPOOL_FLUSH;
 
3234
 
 
3235
  err= ib_shutdown(shutdown_flag);
 
3236
 
 
3237
  if (err != DB_SUCCESS)
 
3238
  {
 
3239
    fprintf(stderr,"Error %d shutting down HailDB!\n", err);
 
3240
  }
 
3241
 
 
3242
}
 
3243
 
 
3244
static char haildb_file_format_name_storage[100];
 
3245
 
 
3246
static int haildb_file_format_name_validate(Session*, drizzle_sys_var*,
 
3247
                                            void *save,
 
3248
                                            drizzle_value *value)
 
3249
{
 
3250
  ib_err_t err;
 
3251
  char buff[100];
 
3252
  int len= sizeof(buff);
 
3253
  const char *format= value->val_str(value, buff, &len);
 
3254
 
 
3255
  *static_cast<const char**>(save)= NULL;
 
3256
 
 
3257
  if (format == NULL)
 
3258
    return 1;
 
3259
 
 
3260
  err= ib_cfg_set_text("file_format", format);
 
3261
 
 
3262
  if (err == DB_SUCCESS)
 
3263
  {
 
3264
    strncpy(haildb_file_format_name_storage, format, sizeof(haildb_file_format_name_storage));;
 
3265
    haildb_file_format_name_storage[sizeof(haildb_file_format_name_storage)-1]= 0;
 
3266
 
 
3267
    *static_cast<const char**>(save)= haildb_file_format_name_storage;
 
3268
    return 0;
 
3269
  }
 
3270
  else
 
3271
    return 1;
 
3272
}
 
3273
 
 
3274
static void haildb_file_format_name_update(Session*, drizzle_sys_var*,
 
3275
                                           void *var_ptr,
 
3276
                                           const void *save)
 
3277
 
 
3278
{
 
3279
  const char* format;
 
3280
 
 
3281
  assert(var_ptr != NULL);
 
3282
  assert(save != NULL);
 
3283
 
 
3284
  format= *static_cast<const char*const*>(save);
 
3285
 
 
3286
  /* Format is already set in validate */
 
3287
  memmove(haildb_file_format_name_storage, format, sizeof(haildb_file_format_name_storage));;
 
3288
  haildb_file_format_name_storage[sizeof(haildb_file_format_name_storage)-1]= 0;
 
3289
 
 
3290
  *static_cast<const char**>(var_ptr)= haildb_file_format_name_storage;
 
3291
}
 
3292
 
 
3293
static void haildb_lru_old_blocks_pct_update(Session*, drizzle_sys_var*,
 
3294
                                             void *,
 
3295
                                             const void *save)
 
3296
 
 
3297
{
 
3298
  unsigned long pct;
 
3299
 
 
3300
  pct= *static_cast<const unsigned long*>(save);
 
3301
 
 
3302
  ib_err_t err= ib_cfg_set_int("lru_old_blocks_pct", pct);
 
3303
  if (err == DB_SUCCESS)
 
3304
    innobase_lru_old_blocks_pct= pct;
 
3305
}
 
3306
 
 
3307
static void haildb_lru_block_access_recency_update(Session*, drizzle_sys_var*,
 
3308
                                                   void *,
 
3309
                                                   const void *save)
 
3310
 
 
3311
{
 
3312
  unsigned long ms;
 
3313
 
 
3314
  ms= *static_cast<const unsigned long*>(save);
 
3315
 
 
3316
  ib_err_t err= ib_cfg_set_int("lru_block_access_recency", ms);
 
3317
 
 
3318
  if (err == DB_SUCCESS)
 
3319
    innobase_lru_block_access_recency= ms;
 
3320
}
 
3321
 
 
3322
static void haildb_status_file_update(Session*, drizzle_sys_var*,
 
3323
                                      void *,
 
3324
                                      const void *save)
 
3325
 
 
3326
{
 
3327
  bool status_file_enabled;
 
3328
  ib_err_t err;
 
3329
 
 
3330
  status_file_enabled= *static_cast<const bool*>(save);
 
3331
 
 
3332
 
 
3333
  if (status_file_enabled)
 
3334
    err= ib_cfg_set_bool_on("status_file");
 
3335
  else
 
3336
    err= ib_cfg_set_bool_off("status_file");
 
3337
 
 
3338
  if (err == DB_SUCCESS)
 
3339
    innobase_create_status_file= status_file_enabled;
 
3340
}
 
3341
 
 
3342
static DRIZZLE_SYSVAR_ULONG(fast_shutdown, innobase_fast_shutdown,
 
3343
  PLUGIN_VAR_OPCMDARG,
 
3344
  "Speeds up the shutdown process of the HailDB storage engine. Possible "
 
3345
  "values are 0, 1 (faster)"
 
3346
  " or 2 (fastest - crash-like)"
 
3347
  ".",
 
3348
  NULL, NULL, 1, 0, 2, 0);
 
3349
 
 
3350
static DRIZZLE_SYSVAR_BOOL(file_per_table, srv_file_per_table,
 
3351
  PLUGIN_VAR_NOCMDARG,
 
3352
  "Stores each HailDB table to an .ibd file in the database dir.",
 
3353
  NULL, NULL, false);
 
3354
 
 
3355
static DRIZZLE_SYSVAR_STR(file_format, innobase_file_format_name,
 
3356
  PLUGIN_VAR_RQCMDARG,
 
3357
  "File format to use for new tables in .ibd files.",
 
3358
  haildb_file_format_name_validate,
 
3359
  haildb_file_format_name_update, "Barracuda");
 
3360
 
 
3361
static DRIZZLE_SYSVAR_ULONG(flush_log_at_trx_commit, srv_flush_log_at_trx_commit,
 
3362
  PLUGIN_VAR_OPCMDARG,
 
3363
  "Set to 0 (write and flush once per second),"
 
3364
  " 1 (write and flush at each commit)"
 
3365
  " or 2 (write at commit, flush once per second).",
 
3366
  NULL, NULL, 1, 0, 2, 0);
 
3367
 
 
3368
static DRIZZLE_SYSVAR_STR(flush_method, innobase_unix_file_flush_method,
 
3369
  PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
 
3370
  "With which method to flush data.", NULL, NULL, NULL);
 
3371
 
 
3372
static DRIZZLE_SYSVAR_LONG(force_recovery, innobase_force_recovery,
 
3373
  PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
 
3374
  "Helps to save your data in case the disk image of the database becomes corrupt.",
 
3375
  NULL, NULL, 0, 0, 6, 0);
 
3376
 
 
3377
static DRIZZLE_SYSVAR_STR(data_file_path, haildb_data_file_path,
 
3378
  PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
 
3379
  "Path to individual files and their sizes.",
 
3380
  NULL, NULL, NULL);
 
3381
 
 
3382
static DRIZZLE_SYSVAR_STR(log_group_home_dir, innobase_log_group_home_dir,
 
3383
  PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
 
3384
  "Path to HailDB log files.", NULL, NULL, NULL);
 
3385
 
 
3386
static DRIZZLE_SYSVAR_LONGLONG(log_file_size, haildb_log_file_size,
 
3387
  PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
 
3388
  "Size of each log file in a log group.",
 
3389
  NULL, NULL, 20*1024*1024L, 1*1024*1024L, INT64_MAX, 1024*1024L);
 
3390
 
 
3391
static DRIZZLE_SYSVAR_LONGLONG(log_files_in_group, haildb_log_files_in_group,
 
3392
  PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
 
3393
  "Number of log files in the log group. HailDB writes to the files in a circular fashion. Value 3 is recommended here.",
 
3394
  NULL, NULL, 2, 2, 100, 0);
 
3395
 
 
3396
static DRIZZLE_SYSVAR_ULONG(lock_wait_timeout, innobase_lock_wait_timeout,
 
3397
  PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
 
3398
  "Timeout in seconds an HailDB transaction may wait for a lock before being rolled back. Values above 100000000 disable the timeout.",
 
3399
  NULL, NULL, 5, 1, 1024 * 1024 * 1024, 0);
 
3400
 
 
3401
static DRIZZLE_SYSVAR_LONG(log_buffer_size, innobase_log_buffer_size,
 
3402
  PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
 
3403
  "The size of the buffer which HailDB uses to write log to the log files on disk.",
 
3404
  NULL, NULL, 8*1024*1024L, 256*1024L, LONG_MAX, 1024);
 
3405
 
 
3406
static DRIZZLE_SYSVAR_ULONG(lru_old_blocks_pct, innobase_lru_old_blocks_pct,
 
3407
  PLUGIN_VAR_RQCMDARG,
 
3408
  "Sets the point in the LRU list from where all pages are classified as "
 
3409
  "old (Advanced users)",
 
3410
  NULL,
 
3411
  haildb_lru_old_blocks_pct_update, 37, 5, 95, 0);
 
3412
 
 
3413
static DRIZZLE_SYSVAR_ULONG(lru_block_access_recency, innobase_lru_block_access_recency,
 
3414
  PLUGIN_VAR_RQCMDARG,
 
3415
  "Milliseconds between accesses to a block at which it is made young. "
 
3416
  "0=disabled (Advanced users)",
 
3417
  NULL,
 
3418
  haildb_lru_block_access_recency_update, 0, 0, ULONG_MAX, 0);
 
3419
 
 
3420
 
 
3421
static DRIZZLE_SYSVAR_ULONG(max_dirty_pages_pct, srv_max_buf_pool_modified_pct,
 
3422
  PLUGIN_VAR_RQCMDARG,
 
3423
  "Percentage of dirty pages allowed in bufferpool.",
 
3424
  NULL, NULL, 75, 0, 99, 0);
 
3425
 
 
3426
static DRIZZLE_SYSVAR_ULONG(max_purge_lag, srv_max_purge_lag,
 
3427
  PLUGIN_VAR_RQCMDARG,
 
3428
  "Desired maximum length of the purge queue (0 = no limit)",
 
3429
  NULL, NULL, 0, 0, ~0L, 0);
 
3430
 
 
3431
static DRIZZLE_SYSVAR_BOOL(rollback_on_timeout, innobase_rollback_on_timeout,
 
3432
  PLUGIN_VAR_OPCMDARG | PLUGIN_VAR_READONLY,
 
3433
  "Roll back the complete transaction on lock wait timeout, for 4.x compatibility (disabled by default)",
 
3434
  NULL, NULL, false);
 
3435
 
 
3436
static DRIZZLE_SYSVAR_LONG(open_files, innobase_open_files,
 
3437
  PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
 
3438
  "How many files at the maximum HailDB keeps open at the same time.",
 
3439
  NULL, NULL, 300L, 10L, LONG_MAX, 0);
 
3440
 
 
3441
static DRIZZLE_SYSVAR_ULONG(read_io_threads, innobase_read_io_threads,
 
3442
  PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
 
3443
  "Number of background read I/O threads in HailDB.",
 
3444
  NULL, NULL, 4, 1, 64, 0);
 
3445
 
 
3446
static DRIZZLE_SYSVAR_ULONG(write_io_threads, innobase_write_io_threads,
 
3447
  PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
 
3448
  "Number of background write I/O threads in HailDB.",
 
3449
  NULL, NULL, 4, 1, 64, 0);
 
3450
 
 
3451
static DRIZZLE_SYSVAR_BOOL(print_verbose_log, innobase_print_verbose_log,
 
3452
  PLUGIN_VAR_NOCMDARG,
 
3453
  "Disable if you want to reduce the number of messages written to the log (default: enabled).",
 
3454
  NULL, NULL, true);
 
3455
 
 
3456
static DRIZZLE_SYSVAR_BOOL(status_file, innobase_create_status_file,
 
3457
  PLUGIN_VAR_OPCMDARG,
 
3458
  "Enable SHOW HAILDB STATUS output in the log",
 
3459
  NULL, haildb_status_file_update, false);
 
3460
 
 
3461
static DRIZZLE_SYSVAR_ULONG(sync_spin_loops, srv_n_spin_wait_rounds,
 
3462
  PLUGIN_VAR_RQCMDARG,
 
3463
  "Count of spin-loop rounds in HailDB mutexes (30 by default)",
 
3464
  NULL, NULL, 30L, 0L, ~0L, 0);
 
3465
 
 
3466
static DRIZZLE_SYSVAR_BOOL(use_sys_malloc, srv_use_sys_malloc,
 
3467
  PLUGIN_VAR_NOCMDARG | PLUGIN_VAR_READONLY,
 
3468
  "Use OS memory allocator instead of HailDB's internal memory allocator",
 
3469
  NULL, NULL, true);
 
3470
 
 
3471
static void init_options(drizzled::module::option_context &context)
 
3472
{
 
3473
  context("disable-adaptive-hash-index",
 
3474
          N_("Disable HailDB adaptive hash index (enabled by default)."));
 
3475
  context("disable-adaptive-flushing",
 
3476
          N_("Do not attempt to flush dirty pages to avoid IO bursts at checkpoints."));
 
3477
  context("additional-mem-pool-size",
 
3478
          po::value<additional_mem_pool_constraint>(&innobase_additional_mem_pool_size)->default_value(8*1024*1024L),
 
3479
          N_("Size of a memory pool HailDB uses to store data dictionary information and other internal data structures."));
 
3480
  context("autoextend-increment",
 
3481
          po::value<autoextend_constraint>(&srv_auto_extend_increment)->default_value(8),
 
3482
          N_("Data file autoextend increment in megabytes"));
 
3483
  context("buffer-pool-size",
 
3484
          po::value<buffer_pool_constraint>(&innobase_buffer_pool_size)->default_value(128*1024*1024L),
 
3485
          N_("The size of the memory buffer HailDB uses to cache data and indexes of its tables."));
 
3486
  context("data-home-dir",
 
3487
          po::value<string>(),
 
3488
          N_("The common part for HailDB table spaces."));
 
3489
  context("disable-checksums",
 
3490
          N_("Disable HailDB checksums validation (enabled by default)."));
 
3491
  context("disable-doublewrite",
 
3492
          N_("Disable HailDB doublewrite buffer (enabled by default)."));
 
3493
  context("io-capacity",
 
3494
          po::value<io_capacity_constraint>(&srv_io_capacity)->default_value(200),
 
3495
          N_("Number of IOPs the server can do. Tunes the background IO rate"));
 
3496
  context("fast-shutdown",
 
3497
          po::value<unsigned long>(&innobase_fast_shutdown)->default_value(1),
 
3498
          N_("Speeds up the shutdown process of the HailDB storage engine. Possible values are 0, 1 (faster) or 2 (fastest - crash-like)."));
 
3499
  context("file-per-table",
 
3500
          po::value<bool>(&srv_file_per_table)->default_value(false)->zero_tokens(),
 
3501
          N_("Stores each HailDB table to an .ibd file in the database dir."));
 
3502
  context("file-format",
 
3503
          po::value<string>(),
 
3504
          N_("File format to use for new tables in .ibd files."));
 
3505
  context("flush-log-at-trx-commit",
 
3506
          po::value<unsigned long>(&srv_flush_log_at_trx_commit)->default_value(1),
 
3507
          N_("Set to 0 (write and flush once per second),1 (write and flush at each commit) or 2 (write at commit, flush once per second)."));
 
3508
  context("flush-method",
 
3509
          po::value<string>(),
 
3510
          N_("With which method to flush data."));
 
3511
  context("force-recovery",
 
3512
          po::value<long>(&innobase_force_recovery)->default_value(0),
 
3513
          N_("Helps to save your data in case the disk image of the database becomes corrupt."));
 
3514
  context("data-file-path",
 
3515
          po::value<string>(),
 
3516
          N_("Path to individual files and their sizes."));
 
3517
  context("log-group-home-dir",
 
3518
          po::value<string>(),
 
3519
          N_("Path to individual files and their sizes."));
 
3520
  context("log-group-home-dir",
 
3521
          po::value<string>(),
 
3522
          N_("Path to HailDB log files."));
 
3523
  context("log-file-size",
 
3524
          po::value<int64_t>(&haildb_log_file_size)->default_value(20*1024*1024L),
 
3525
          N_("Size of each log file in a log group."));
 
3526
  context("haildb-log-files-in-group",
 
3527
          po::value<int64_t>(&haildb_log_files_in_group)->default_value(2),
 
3528
          N_("Number of log files in the log group. HailDB writes to the files in a circular fashion. Value 3 is recommended here."));
 
3529
  context("lock-wait-timeout",
 
3530
          po::value<unsigned long>(&innobase_lock_wait_timeout)->default_value(5),
 
3531
          N_("Timeout in seconds an HailDB transaction may wait for a lock before being rolled back. Values above 100000000 disable the timeout."));
 
3532
  context("log-buffer-size",
 
3533
        po::value<long>(&innobase_log_buffer_size)->default_value(8*1024*1024L),
 
3534
        N_("The size of the buffer which HailDB uses to write log to the log files on disk."));
 
3535
  context("lru-old-blocks-pct",
 
3536
          po::value<unsigned long>(&innobase_lru_old_blocks_pct)->default_value(37),
 
3537
          N_("Sets the point in the LRU list from where all pages are classified as old (Advanced users)"));
 
3538
  context("lru-block-access-recency",
 
3539
          po::value<unsigned long>(&innobase_lru_block_access_recency)->default_value(0),
 
3540
          N_("Milliseconds between accesses to a block at which it is made young. 0=disabled (Advanced users)"));
 
3541
  context("max-dirty-pages-pct",
 
3542
          po::value<unsigned long>(&srv_max_buf_pool_modified_pct)->default_value(75),
 
3543
          N_("Percentage of dirty pages allowed in bufferpool."));
 
3544
  context("max-purge-lag",
 
3545
          po::value<unsigned long>(&srv_max_purge_lag)->default_value(0),
 
3546
          N_("Desired maximum length of the purge queue (0 = no limit)"));
 
3547
  context("rollback-on-timeout",
 
3548
          po::value<bool>(&innobase_rollback_on_timeout)->default_value(false)->zero_tokens(),
 
3549
          N_("Roll back the complete transaction on lock wait timeout, for 4.x compatibility (disabled by default)"));
 
3550
  context("open-files",
 
3551
          po::value<long>(&innobase_open_files)->default_value(300),
 
3552
          N_("How many files at the maximum HailDB keeps open at the same time."));
 
3553
  context("read-io-threads",
 
3554
          po::value<unsigned long>(&innobase_read_io_threads)->default_value(4),
 
3555
          N_("Number of background read I/O threads in HailDB."));
 
3556
  context("write-io-threads",
 
3557
          po::value<unsigned long>(&innobase_write_io_threads)->default_value(4),
 
3558
          N_("Number of background write I/O threads in HailDB."));
 
3559
  context("disable-print-verbose-log",
 
3560
          N_("Disable if you want to reduce the number of messages written to the log (default: enabled)."));
 
3561
  context("status-file",
 
3562
          po::value<bool>(&innobase_create_status_file)->default_value(false)->zero_tokens(),
 
3563
          N_("Enable SHOW HAILDB STATUS output in the log"));
 
3564
  context("sync-spin-loops",
 
3565
          po::value<unsigned long>(&srv_n_spin_wait_rounds)->default_value(30L),
 
3566
          N_("Count of spin-loop rounds in HailDB mutexes (30 by default)"));
 
3567
  context("use-internal-malloc",
 
3568
          N_("Use HailDB's internal memory allocator instead of the OS memory allocator"));
 
3569
}
 
3570
 
 
3571
static drizzle_sys_var* innobase_system_variables[]= {
 
3572
  DRIZZLE_SYSVAR(fast_shutdown),
 
3573
  DRIZZLE_SYSVAR(file_per_table),
 
3574
  DRIZZLE_SYSVAR(file_format),
 
3575
  DRIZZLE_SYSVAR(flush_log_at_trx_commit),
 
3576
  DRIZZLE_SYSVAR(flush_method),
 
3577
  DRIZZLE_SYSVAR(force_recovery),
 
3578
  DRIZZLE_SYSVAR(log_group_home_dir),
 
3579
  DRIZZLE_SYSVAR(data_file_path),
 
3580
  DRIZZLE_SYSVAR(lock_wait_timeout),
 
3581
  DRIZZLE_SYSVAR(log_file_size),
 
3582
  DRIZZLE_SYSVAR(log_files_in_group),
 
3583
  DRIZZLE_SYSVAR(log_buffer_size),
 
3584
  DRIZZLE_SYSVAR(lru_old_blocks_pct),
 
3585
  DRIZZLE_SYSVAR(lru_block_access_recency),
 
3586
  DRIZZLE_SYSVAR(max_dirty_pages_pct),
 
3587
  DRIZZLE_SYSVAR(max_purge_lag),
 
3588
  DRIZZLE_SYSVAR(open_files),
 
3589
  DRIZZLE_SYSVAR(read_io_threads),
 
3590
  DRIZZLE_SYSVAR(rollback_on_timeout),
 
3591
  DRIZZLE_SYSVAR(write_io_threads),
 
3592
  DRIZZLE_SYSVAR(print_verbose_log),
 
3593
  DRIZZLE_SYSVAR(status_file),
 
3594
  DRIZZLE_SYSVAR(sync_spin_loops),
 
3595
  DRIZZLE_SYSVAR(use_sys_malloc),
 
3596
  NULL
 
3597
};
 
3598
 
 
3599
DRIZZLE_DECLARE_PLUGIN
 
3600
{
 
3601
  DRIZZLE_VERSION_ID,
 
3602
  "INNODB",
 
3603
  "1.0",
 
3604
  "Stewart Smith",
 
3605
  "Transactional Storage Engine using the HailDB Library",
 
3606
  PLUGIN_LICENSE_GPL,
 
3607
  haildb_init,     /* Plugin Init */
 
3608
  innobase_system_variables, /* system variables */
 
3609
  init_options                /* config options   */
 
3610
}
 
3611
DRIZZLE_DECLARE_PLUGIN_END;