~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to plugin/haildb/haildb_engine.cc

  • Committer: Brian Aker
  • Date: 2011-02-22 06:12:02 UTC
  • mfrom: (2190.1.6 drizzle-build)
  • Revision ID: brian@tangent.org-20110222061202-k03czxykqy4x9hjs
List update, header fixes, multiple symbols, and David deletes some code.

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