~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to plugin/haildb/haildb_engine.cc

  • Committer: Stewart Smith
  • Date: 2010-02-15 03:55:09 UTC
  • mto: (1273.13.96 build)
  • mto: This revision was merged to the branch mainline in revision 1308.
  • Revision ID: stewart@flamingspork.com-20100215035509-y6sry4q4yymph2by
move SUBSTR, SUBSTRING and SUBSTR_INDEX to plugins. add parser hooks for substr being a plugin now.

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