~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to plugin/haildb/haildb_engine.cc

  • Committer: Brian Aker
  • Date: 2009-02-21 00:18:15 UTC
  • Revision ID: brian@tangent.org-20090221001815-x20e8h71e984lvs1
Completion (?) of uint conversion.

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