2
Copyright (C) 2010 Stewart Smith
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.
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.
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.
19
/* innobase_get_int_col_max_value() comes from ha_innodb.cc which is under
20
the following license and Copyright */
22
/*****************************************************************************
24
Copyright (C) 2000, 2009, MySQL AB & Innobase Oy. All Rights Reserved.
25
Copyright (C) 2008, 2009 Google Inc.
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.
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.
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.
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
45
*****************************************************************************/
46
/***********************************************************************
48
Copyright (C) 1995, 2009, Innobase Oy. All Rights Reserved.
49
Copyright (C) 2009, Percona Inc.
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
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.
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.
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
71
***********************************************************************/
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>
85
#include <boost/algorithm/string.hpp>
86
#include <boost/unordered_set.hpp>
87
#include <boost/foreach.hpp>
90
#include <drizzled/message/table.pb.h>
91
#include <drizzled/internal/m_string.h>
93
#include <drizzled/global_charset_info.h>
95
#include "haildb_datadict_dump_func.h"
96
#include "config_table_function.h"
97
#include "status_table_function.h"
101
#include "haildb_engine.h"
103
#include <drizzled/field.h>
104
#include <drizzled/field/blob.h>
105
#include <drizzled/field/enum.h>
106
#include <drizzled/session.h>
107
#include <drizzled/module/option_map.h>
108
#include <drizzled/charset.h>
109
#include <drizzled/current_session.h>
113
namespace po= boost::program_options;
114
#include <boost/program_options.hpp>
115
#include <boost/algorithm/string.hpp>
118
using namespace google;
119
using namespace drizzled;
121
int read_row_from_haildb(Session *session, unsigned char* buf, ib_crsr_t cursor, ib_tpl_t tuple, Table* table, bool has_hidden_primary_key, uint64_t *hidden_pkey, drizzled::memory::Root **blobroot= NULL);
122
static void fill_ib_search_tpl_from_drizzle_key(ib_tpl_t search_tuple,
123
const drizzled::KeyInfo *key_info,
124
const unsigned char *key_ptr,
126
static void store_key_value_from_haildb(KeyInfo *key_info, unsigned char* ref, int ref_len, const unsigned char *record);
128
#define HAILDB_EXT ".EID"
130
const char HAILDB_TABLE_DEFINITIONS_TABLE[]= "data_dictionary/haildb_table_definitions";
131
const string statement_savepoint_name("STATEMENT");
133
static boost::unordered_set<std::string> haildb_system_table_names;
136
static const char *HailDBCursor_exts[] = {
140
class HailDBEngine : public drizzled::plugin::TransactionalStorageEngine
143
HailDBEngine(const string &name_arg)
144
: drizzled::plugin::TransactionalStorageEngine(name_arg,
146
HTON_CAN_INDEX_BLOBS |
148
HTON_PARTIAL_COLUMN_READ |
149
HTON_HAS_DOES_TRANSACTIONS)
151
table_definition_ext= HAILDB_EXT;
156
virtual Cursor *create(Table &table)
158
return new HailDBCursor(*this, table);
161
const char **bas_ext() const {
162
return HailDBCursor_exts;
165
bool validateCreateTableOption(const std::string &key,
166
const std::string &state);
168
int doCreateTable(Session&,
170
const drizzled::identifier::Table &identifier,
171
drizzled::message::Table& proto);
173
int doDropTable(Session&, const identifier::Table &identifier);
175
int doRenameTable(drizzled::Session&,
176
const drizzled::identifier::Table&,
177
const drizzled::identifier::Table&);
179
int doGetTableDefinition(Session& session,
180
const identifier::Table &identifier,
181
drizzled::message::Table &table_proto);
183
bool doDoesTableExist(Session&, const identifier::Table &identifier);
186
void getTableNamesInSchemaFromHailDB(const drizzled::identifier::Schema &schema,
187
drizzled::plugin::TableNameList *set_of_names,
188
drizzled::identifier::Table::vector *identifiers);
191
void doGetTableIdentifiers(drizzled::CachedDirectory &,
192
const drizzled::identifier::Schema &schema,
193
drizzled::identifier::Table::vector &identifiers);
195
/* The following defines can be increased if necessary */
196
uint32_t max_supported_keys() const { return 1000; }
197
uint32_t max_supported_key_length() const { return 3500; }
198
uint32_t max_supported_key_part_length() const { return 767; }
200
uint32_t index_flags(enum ha_key_alg) const
202
return (HA_READ_NEXT |
208
virtual int doStartTransaction(Session *session,
209
start_transaction_option_t options);
210
virtual void doStartStatement(Session *session);
211
virtual void doEndStatement(Session *session);
213
virtual int doSetSavepoint(Session* session,
214
drizzled::NamedSavepoint &savepoint);
215
virtual int doRollbackToSavepoint(Session* session,
216
drizzled::NamedSavepoint &savepoint);
217
virtual int doReleaseSavepoint(Session* session,
218
drizzled::NamedSavepoint &savepoint);
219
virtual int doCommit(Session* session, bool all);
220
virtual int doRollback(Session* session, bool all);
222
typedef std::map<std::string, HailDBTableShare*> HailDBMap;
223
HailDBMap haildb_open_tables;
224
HailDBTableShare *findOpenTable(const std::string table_name);
225
void addOpenTable(const std::string &table_name, HailDBTableShare *);
226
void deleteOpenTable(const std::string &table_name);
228
uint64_t getInitialAutoIncrementValue(HailDBCursor *cursor);
229
uint64_t getHiddenPrimaryKeyInitialAutoIncrementValue(HailDBCursor *cursor);
233
static drizzled::plugin::StorageEngine *haildb_engine= NULL;
236
static ib_trx_t* get_trx(Session* session)
238
return (ib_trx_t*) session->getEngineData(haildb_engine);
241
/* This is a superset of the map from innobase plugin.
242
Unlike innobase plugin we don't act on errors here, we just
244
static int ib_err_t_to_drizzle_error(Session* session, ib_err_t err)
256
return ER_QUERY_INTERRUPTED; // FIXME: is this correct?
258
case DB_OUT_OF_MEMORY:
259
return HA_ERR_OUT_OF_MEM;
261
case DB_DUPLICATE_KEY:
262
return HA_ERR_FOUND_DUPP_KEY;
264
case DB_FOREIGN_DUPLICATE_KEY:
265
return HA_ERR_FOREIGN_DUPLICATE_KEY;
267
case DB_MISSING_HISTORY:
268
return HA_ERR_TABLE_DEF_CHANGED;
270
case DB_RECORD_NOT_FOUND:
271
return HA_ERR_NO_ACTIVE_RECORD;
274
/* HailDB will roll back a transaction itself due to DB_DEADLOCK.
275
This means we have to tell Drizzle about it */
276
session->markTransactionForRollback(true);
277
return HA_ERR_LOCK_DEADLOCK;
279
case DB_LOCK_WAIT_TIMEOUT:
280
session->markTransactionForRollback(false);
281
return HA_ERR_LOCK_WAIT_TIMEOUT;
283
case DB_NO_REFERENCED_ROW:
284
return HA_ERR_NO_REFERENCED_ROW;
286
case DB_ROW_IS_REFERENCED:
287
return HA_ERR_ROW_IS_REFERENCED;
289
case DB_CANNOT_ADD_CONSTRAINT:
290
return HA_ERR_CANNOT_ADD_FOREIGN;
292
case DB_CANNOT_DROP_CONSTRAINT:
293
return HA_ERR_ROW_IS_REFERENCED; /* misleading. should have new err code */
295
case DB_COL_APPEARS_TWICE_IN_INDEX:
297
return HA_ERR_CRASHED;
299
case DB_MUST_GET_MORE_FILE_SPACE:
300
case DB_OUT_OF_FILE_SPACE:
301
return HA_ERR_RECORD_FILE_FULL;
303
case DB_TABLE_IS_BEING_USED:
304
return HA_ERR_WRONG_COMMAND;
306
case DB_TABLE_NOT_FOUND:
307
return HA_ERR_NO_SUCH_TABLE;
309
case DB_TOO_BIG_RECORD:
310
return HA_ERR_TO_BIG_ROW;
312
case DB_NO_SAVEPOINT:
313
return HA_ERR_NO_SAVEPOINT;
315
case DB_LOCK_TABLE_FULL:
316
return HA_ERR_LOCK_TABLE_FULL;
318
case DB_PRIMARY_KEY_IS_NULL:
319
return ER_PRIMARY_CANT_HAVE_NULL;
321
case DB_TOO_MANY_CONCURRENT_TRXS:
322
return HA_ERR_RECORD_FILE_FULL; /* need better error code */
324
case DB_END_OF_INDEX:
325
return HA_ERR_END_OF_FILE;
328
return HA_ERR_UNSUPPORTED;
332
static ib_trx_level_t tx_isolation_to_ib_trx_level(enum_tx_isolation level)
336
case ISO_REPEATABLE_READ:
337
return IB_TRX_REPEATABLE_READ;
338
case ISO_READ_COMMITTED:
339
return IB_TRX_READ_COMMITTED;
340
case ISO_SERIALIZABLE:
341
return IB_TRX_SERIALIZABLE;
342
case ISO_READ_UNCOMMITTED:
343
return IB_TRX_READ_UNCOMMITTED;
347
return IB_TRX_REPEATABLE_READ;
350
int HailDBEngine::doStartTransaction(Session *session,
351
start_transaction_option_t options)
353
ib_trx_t *transaction;
354
ib_trx_level_t isolation_level;
358
transaction= get_trx(session);
359
isolation_level= tx_isolation_to_ib_trx_level(session->getTxIsolation());
360
*transaction= ib_trx_begin(isolation_level);
362
return *transaction == NULL;
365
void HailDBEngine::doStartStatement(Session *session)
367
if(*get_trx(session) == NULL)
368
doStartTransaction(session, START_TRANS_NO_OPTIONS);
370
ib_savepoint_take(*get_trx(session), statement_savepoint_name.c_str(),
371
statement_savepoint_name.length());
374
void HailDBEngine::doEndStatement(Session *)
378
int HailDBEngine::doSetSavepoint(Session* session,
379
drizzled::NamedSavepoint &savepoint)
381
ib_trx_t *transaction= get_trx(session);
382
ib_savepoint_take(*transaction, savepoint.getName().c_str(),
383
savepoint.getName().length());
387
int HailDBEngine::doRollbackToSavepoint(Session* session,
388
drizzled::NamedSavepoint &savepoint)
390
ib_trx_t *transaction= get_trx(session);
393
err= ib_savepoint_rollback(*transaction, savepoint.getName().c_str(),
394
savepoint.getName().length());
396
return ib_err_t_to_drizzle_error(session, err);
399
int HailDBEngine::doReleaseSavepoint(Session* session,
400
drizzled::NamedSavepoint &savepoint)
402
ib_trx_t *transaction= get_trx(session);
405
err= ib_savepoint_release(*transaction, savepoint.getName().c_str(),
406
savepoint.getName().length());
407
if (err != DB_SUCCESS)
408
return ib_err_t_to_drizzle_error(session, err);
413
int HailDBEngine::doCommit(Session* session, bool all)
416
ib_trx_t *transaction= get_trx(session);
420
err= ib_trx_commit(*transaction);
422
if (err != DB_SUCCESS)
423
return ib_err_t_to_drizzle_error(session, err);
431
int HailDBEngine::doRollback(Session* session, bool all)
434
ib_trx_t *transaction= get_trx(session);
438
if (ib_trx_state(*transaction) == IB_TRX_NOT_STARTED)
439
err= ib_trx_release(*transaction);
441
err= ib_trx_rollback(*transaction);
443
if (err != DB_SUCCESS)
444
return ib_err_t_to_drizzle_error(session, err);
450
if (ib_trx_state(*transaction) == IB_TRX_NOT_STARTED)
453
err= ib_savepoint_rollback(*transaction, statement_savepoint_name.c_str(),
454
statement_savepoint_name.length());
455
if (err != DB_SUCCESS)
456
return ib_err_t_to_drizzle_error(session, err);
462
HailDBTableShare *HailDBEngine::findOpenTable(const string table_name)
464
HailDBMap::iterator find_iter=
465
haildb_open_tables.find(table_name);
467
if (find_iter != haildb_open_tables.end())
468
return (*find_iter).second;
473
void HailDBEngine::addOpenTable(const string &table_name, HailDBTableShare *share)
475
haildb_open_tables[table_name]= share;
478
void HailDBEngine::deleteOpenTable(const string &table_name)
480
haildb_open_tables.erase(table_name);
483
static pthread_mutex_t haildb_mutex= PTHREAD_MUTEX_INITIALIZER;
485
uint64_t HailDBCursor::getHiddenPrimaryKeyInitialAutoIncrementValue()
489
ib_trx_t transaction= *get_trx(getTable()->in_use);
490
ib_cursor_attach_trx(cursor, transaction);
491
tuple= ib_clust_read_tuple_create(cursor);
492
err= ib_cursor_last(cursor);
493
assert(err == DB_SUCCESS || err == DB_END_OF_INDEX); // Probably a FIXME
494
err= ib_cursor_read_row(cursor, tuple);
495
if (err == DB_RECORD_NOT_FOUND)
499
assert (err == DB_SUCCESS);
500
err= ib_tuple_read_u64(tuple, getTable()->getShare()->sizeFields(), &nr);
503
ib_tuple_delete(tuple);
505
err= ib_cursor_reset(cursor);
506
assert(err == DB_SUCCESS);
510
uint64_t HailDBCursor::getInitialAutoIncrementValue()
515
(void) extra(HA_EXTRA_KEYREAD);
516
getTable()->mark_columns_used_by_index_no_reset(getTable()->getShare()->next_number_index);
517
doStartIndexScan(getTable()->getShare()->next_number_index, 1);
518
if (getTable()->getShare()->next_number_keypart == 0)
519
{ // Autoincrement at key-start
520
error=index_last(getTable()->getUpdateRecord());
524
unsigned char key[MAX_KEY_LENGTH];
525
key_copy(key, getTable()->getInsertRecord(),
526
getTable()->key_info + getTable()->getShare()->next_number_index,
527
getTable()->getShare()->next_number_key_offset);
528
error= index_read_map(getTable()->getUpdateRecord(), key,
529
make_prev_keypart_map(getTable()->getShare()->next_number_keypart),
530
HA_READ_PREFIX_LAST);
536
nr= ((uint64_t) getTable()->found_next_number_field->
537
val_int_offset(getTable()->getShare()->rec_buff_length)+1);
539
(void) extra(HA_EXTRA_NO_KEYREAD);
541
if (getTable()->getShare()->getTableMessage()->options().auto_increment_value() > nr)
542
nr= getTable()->getShare()->getTableMessage()->options().auto_increment_value();
547
HailDBTableShare::HailDBTableShare(const char* name, bool hidden_primary_key)
548
: use_count(0), has_hidden_primary_key(hidden_primary_key)
550
table_name.assign(name);
553
uint64_t HailDBEngine::getInitialAutoIncrementValue(HailDBCursor *cursor)
555
doStartTransaction(current_session, START_TRANS_NO_OPTIONS);
556
uint64_t initial_auto_increment_value= cursor->getInitialAutoIncrementValue();
557
doCommit(current_session, true);
559
return initial_auto_increment_value;
562
uint64_t HailDBEngine::getHiddenPrimaryKeyInitialAutoIncrementValue(HailDBCursor *cursor)
564
doStartTransaction(current_session, START_TRANS_NO_OPTIONS);
565
uint64_t initial_auto_increment_value= cursor->getHiddenPrimaryKeyInitialAutoIncrementValue();
566
doCommit(current_session, true);
568
return initial_auto_increment_value;
571
HailDBTableShare *HailDBCursor::get_share(const char *table_name, bool has_hidden_primary_key, int *rc)
573
pthread_mutex_lock(&haildb_mutex);
575
HailDBEngine *a_engine= static_cast<HailDBEngine *>(getEngine());
576
share= a_engine->findOpenTable(table_name);
580
share= new HailDBTableShare(table_name, has_hidden_primary_key);
584
pthread_mutex_unlock(&haildb_mutex);
585
*rc= HA_ERR_OUT_OF_MEM;
589
if (getTable()->found_next_number_field)
591
share->auto_increment_value.fetch_and_store(
592
a_engine->getInitialAutoIncrementValue(this));
596
if (has_hidden_primary_key)
598
uint64_t hidden_pkey= 0;
599
hidden_pkey= a_engine->getHiddenPrimaryKeyInitialAutoIncrementValue(this);
600
share->hidden_pkey_auto_increment_value.fetch_and_store(hidden_pkey);
603
a_engine->addOpenTable(share->table_name, share);
604
thr_lock_init(&share->lock);
608
pthread_mutex_unlock(&haildb_mutex);
613
int HailDBCursor::free_share()
615
pthread_mutex_lock(&haildb_mutex);
616
if (!--share->use_count)
618
HailDBEngine *a_engine= static_cast<HailDBEngine *>(getEngine());
619
a_engine->deleteOpenTable(share->table_name);
622
pthread_mutex_unlock(&haildb_mutex);
628
THR_LOCK_DATA **HailDBCursor::store_lock(Session *session,
630
thr_lock_type lock_type)
632
/* Currently, we can get a transaction start by ::store_lock
633
instead of beginTransaction, startStatement.
635
See https://bugs.launchpad.net/drizzle/+bug/535528
637
all stemming from the transactional engine interface needing
638
a severe amount of immodium.
641
if(*get_trx(session) == NULL)
643
static_cast<HailDBEngine*>(getEngine())->
644
doStartTransaction(session, START_TRANS_NO_OPTIONS);
647
if (lock_type != TL_UNLOCK)
649
ib_savepoint_take(*get_trx(session), statement_savepoint_name.c_str(),
650
statement_savepoint_name.length());
653
/* the below is adapted from ha_innodb.cc */
655
const uint32_t sql_command = session->getSqlCommand();
657
if (sql_command == SQLCOM_DROP_TABLE) {
659
/* MySQL calls this function in DROP Table though this table
660
handle may belong to another session that is running a query.
661
Let us in that case skip any changes to the prebuilt struct. */
663
} else if (lock_type == TL_READ_WITH_SHARED_LOCKS
664
|| lock_type == TL_READ_NO_INSERT
665
|| (lock_type != TL_IGNORE
666
&& sql_command != SQLCOM_SELECT)) {
668
/* The OR cases above are in this order:
669
1) MySQL is doing LOCK TABLES ... READ LOCAL, or we
670
are processing a stored procedure or function, or
671
2) (we do not know when TL_READ_HIGH_PRIORITY is used), or
672
3) this is a SELECT ... IN SHARE MODE, or
673
4) we are doing a complex SQL statement like
674
INSERT INTO ... SELECT ... and the logical logging (MySQL
675
binlog) requires the use of a locking read, or
676
MySQL is doing LOCK TABLES ... READ.
677
5) we let InnoDB do locking reads for all SQL statements that
678
are not simple SELECTs; note that select_lock_type in this
679
case may get strengthened in ::external_lock() to LOCK_X.
680
Note that we MUST use a locking read in all data modifying
681
SQL statements, because otherwise the execution would not be
682
serializable, and also the results from the update could be
683
unexpected if an obsolete consistent read view would be
686
enum_tx_isolation isolation_level= session->getTxIsolation();
688
if (isolation_level != ISO_SERIALIZABLE
689
&& (lock_type == TL_READ || lock_type == TL_READ_NO_INSERT)
690
&& (sql_command == SQLCOM_INSERT_SELECT
691
|| sql_command == SQLCOM_UPDATE
692
|| sql_command == SQLCOM_CREATE_TABLE)) {
694
/* If we either have innobase_locks_unsafe_for_binlog
695
option set or this session is using READ COMMITTED
696
isolation level and isolation level of the transaction
697
is not set to serializable and MySQL is doing
698
INSERT INTO...SELECT or UPDATE ... = (SELECT ...) or
699
CREATE ... SELECT... without FOR UPDATE or
700
IN SHARE MODE in select, then we use consistent
703
ib_lock_mode= IB_LOCK_NONE;
704
} else if (sql_command == SQLCOM_CHECKSUM) {
705
/* Use consistent read for checksum table */
707
ib_lock_mode= IB_LOCK_NONE;
709
ib_lock_mode= IB_LOCK_S;
712
} else if (lock_type != TL_IGNORE) {
714
/* We set possible LOCK_X value in external_lock, not yet
715
here even if this would be SELECT ... FOR UPDATE */
716
ib_lock_mode= IB_LOCK_NONE;
719
if (lock_type != TL_IGNORE && lock.type == TL_UNLOCK) {
721
/* If we are not doing a LOCK TABLE, DISCARD/IMPORT
722
TABLESPACE or TRUNCATE TABLE then allow multiple
723
writers. Note that ALTER TABLE uses a TL_WRITE_ALLOW_READ
724
< TL_WRITE_CONCURRENT_INSERT.
727
if ((lock_type >= TL_WRITE_CONCURRENT_INSERT
728
&& lock_type <= TL_WRITE)
729
&& ! session->doing_tablespace_operation()
730
&& sql_command != SQLCOM_TRUNCATE
731
&& sql_command != SQLCOM_CREATE_TABLE) {
733
lock_type = TL_WRITE_ALLOW_WRITE;
736
/* In queries of type INSERT INTO t1 SELECT ... FROM t2 ...
737
MySQL would use the lock TL_READ_NO_INSERT on t2, and that
738
would conflict with TL_WRITE_ALLOW_WRITE, blocking all inserts
739
to t2. Convert the lock to a normal read lock to allow
740
concurrent inserts to t2.
743
if (lock_type == TL_READ_NO_INSERT) {
748
lock.type = lock_type;
756
void HailDBCursor::get_auto_increment(uint64_t, //offset,
757
uint64_t, //increment,
759
uint64_t *first_value,
760
uint64_t *nb_reserved_values)
763
*first_value= share->auto_increment_value.fetch_and_increment();
764
if (*first_value == 0)
766
/* if it's zero, then we skip it... why? because of ass.
767
set auto-inc to -1 and the sequence is:
769
Zero is still "magic".
771
share->auto_increment_value.compare_and_swap(1, 0);
774
*nb_reserved_values= 1;
777
static const char* table_path_to_haildb_name(const char* name)
779
size_t l= strlen(name);
780
static string datadict_path("data_dictionary/");
781
static string sys_prefix("data_dictionary/haildb_");
782
static string sys_table_prefix("HAILDB_");
784
if (strncmp(name, sys_prefix.c_str(), sys_prefix.length()) == 0)
786
string find_name(name+datadict_path.length());
787
std::transform(find_name.begin(), find_name.end(), find_name.begin(), ::toupper);
788
boost::unordered_set<string>::iterator iter= haildb_system_table_names.find(find_name);
789
if (iter != haildb_system_table_names.end())
790
return (*iter).c_str()+sys_table_prefix.length();
794
while(slashes>0 && l > 0)
806
static void TableIdentifier_to_haildb_name(const identifier::Table &identifier, std::string *str)
808
str->assign(table_path_to_haildb_name(identifier.getPath().c_str()));
811
HailDBCursor::HailDBCursor(drizzled::plugin::StorageEngine &engine_arg,
813
:Cursor(engine_arg, table_arg),
814
ib_lock_mode(IB_LOCK_NONE),
815
write_can_replace(false),
819
static unsigned int get_first_unique_index(drizzled::Table &table)
821
for (uint32_t k= 0; k < table.getShare()->keys; k++)
823
if (table.key_info[k].flags & HA_NOSAME)
832
int HailDBCursor::open(const char *name, int, uint32_t)
834
const char* haildb_table_name= table_path_to_haildb_name(name);
835
ib_err_t err= ib_table_get_id(haildb_table_name, &table_id);
836
bool has_hidden_primary_key= false;
839
if (err != DB_SUCCESS)
840
return ib_err_t_to_drizzle_error(getTable()->getSession(), err);
842
err= ib_cursor_open_table_using_id(table_id, NULL, &cursor);
843
cursor_is_sec_index= false;
845
if (err != DB_SUCCESS)
846
return ib_err_t_to_drizzle_error(getTable()->getSession(), err);
848
err= ib_index_get_id(haildb_table_name, "HIDDEN_PRIMARY", &idx_id);
850
if (err == DB_SUCCESS)
851
has_hidden_primary_key= true;
854
share= get_share(name, has_hidden_primary_key, &rc);
855
lock.init(&share->lock);
858
if (getTable()->getShare()->getPrimaryKey() != MAX_KEY)
859
ref_length= getTable()->key_info[getTable()->getShare()->getPrimaryKey()].key_length;
860
else if (share->has_hidden_primary_key)
861
ref_length= sizeof(uint64_t);
864
unsigned int keynr= get_first_unique_index(*getTable());
865
ref_length= getTable()->key_info[keynr].key_length;
868
in_table_scan= false;
873
int HailDBCursor::close(void)
875
ib_err_t err= ib_cursor_close(cursor);
876
if (err != DB_SUCCESS)
877
return ib_err_t_to_drizzle_error(getTable()->getSession(), err);
887
int HailDBCursor::external_lock(Session* session, int lock_type)
889
ib_cursor_stmt_begin(cursor);
893
if (lock_type == F_WRLCK)
895
/* SELECT ... FOR UPDATE or UPDATE TABLE */
896
ib_lock_mode= IB_LOCK_X;
899
ib_lock_mode= IB_LOCK_NONE;
904
static int create_table_add_field(ib_tbl_sch_t schema,
905
const message::Table::Field &field,
908
ib_col_attr_t column_attr= IB_COL_NONE;
910
if (field.has_constraints() && field.constraints().is_notnull())
911
column_attr= IB_COL_NOT_NULL;
913
switch (field.type())
915
case message::Table::Field::VARCHAR:
916
*err= ib_table_schema_add_col(schema, field.name().c_str(), IB_VARCHAR,
918
field.string_options().length());
920
case message::Table::Field::INTEGER:
921
*err= ib_table_schema_add_col(schema, field.name().c_str(), IB_INT,
924
case message::Table::Field::BIGINT:
925
*err= ib_table_schema_add_col(schema, field.name().c_str(), IB_INT,
928
case message::Table::Field::DOUBLE:
929
case message::Table::Field::DATETIME:
930
*err= ib_table_schema_add_col(schema, field.name().c_str(), IB_DOUBLE,
931
column_attr, 0, sizeof(double));
933
case message::Table::Field::ENUM:
934
*err= ib_table_schema_add_col(schema, field.name().c_str(), IB_INT,
937
case message::Table::Field::DATE:
938
*err= ib_table_schema_add_col(schema, field.name().c_str(), IB_INT,
941
case message::Table::Field::EPOCH:
942
*err= ib_table_schema_add_col(schema, field.name().c_str(), IB_INT,
945
case message::Table::Field::BLOB:
946
*err= ib_table_schema_add_col(schema, field.name().c_str(), IB_BLOB,
949
case message::Table::Field::DECIMAL:
950
*err= ib_table_schema_add_col(schema, field.name().c_str(), IB_DECIMAL,
954
my_error(ER_CHECK_NOT_IMPLEMENTED, MYF(0), "Column Type");
955
return(HA_ERR_UNSUPPORTED);
961
static ib_err_t store_table_message(ib_trx_t transaction, const char* table_name, drizzled::message::Table& table_message)
964
ib_tpl_t message_tuple;
966
string serialized_message;
968
err= ib_cursor_open_table(HAILDB_TABLE_DEFINITIONS_TABLE, transaction, &cursor);
969
if (err != DB_SUCCESS)
972
message_tuple= ib_clust_read_tuple_create(cursor);
974
err= ib_col_set_value(message_tuple, 0, table_name, strlen(table_name));
975
if (err != DB_SUCCESS)
979
table_message.SerializeToString(&serialized_message);
986
err= ib_col_set_value(message_tuple, 1, serialized_message.c_str(),
987
serialized_message.length());
988
if (err != DB_SUCCESS)
991
err= ib_cursor_insert_row(cursor, message_tuple);
994
ib_tuple_delete(message_tuple);
996
ib_err_t cleanup_err= ib_cursor_close(cursor);
997
if (err == DB_SUCCESS)
1003
bool HailDBEngine::validateCreateTableOption(const std::string &key,
1004
const std::string &state)
1006
if (boost::iequals(key, "ROW_FORMAT"))
1008
if (boost::iequals(state, "COMPRESSED"))
1011
if (boost::iequals(state, "COMPACT"))
1014
if (boost::iequals(state, "DYNAMIC"))
1017
if (boost::iequals(state, "REDUNDANT"))
1024
static ib_tbl_fmt_t parse_ib_table_format(const std::string &value)
1026
if (boost::iequals(value, "REDUNDANT"))
1027
return IB_TBL_REDUNDANT;
1028
else if (boost::iequals(value, "COMPACT"))
1029
return IB_TBL_COMPACT;
1030
else if (boost::iequals(value, "DYNAMIC"))
1031
return IB_TBL_DYNAMIC;
1032
else if (boost::iequals(value, "COMPRESSED"))
1033
return IB_TBL_COMPRESSED;
1035
assert(false); /* You need to add possible table formats here */
1036
return IB_TBL_COMPACT;
1039
int HailDBEngine::doCreateTable(Session &session,
1041
const drizzled::identifier::Table &identifier,
1042
drizzled::message::Table& table_message)
1044
ib_tbl_sch_t haildb_table_schema= NULL;
1045
// ib_idx_sch_t haildb_pkey= NULL;
1046
ib_trx_t haildb_schema_transaction;
1047
ib_id_t haildb_table_id;
1048
ib_err_t haildb_err= DB_SUCCESS;
1049
string haildb_table_name;
1050
bool has_explicit_pkey= false;
1054
if (table_message.type() == message::Table::TEMPORARY)
1056
ib_bool_t create_db_err= ib_database_create(GLOBAL_TEMPORARY_EXT);
1057
if (create_db_err != IB_TRUE)
1061
TableIdentifier_to_haildb_name(identifier, &haildb_table_name);
1063
ib_tbl_fmt_t haildb_table_format= IB_TBL_COMPACT;
1065
const size_t num_engine_options= table_message.engine().options_size();
1066
for (size_t x= 0; x < num_engine_options; x++)
1068
const message::Engine::Option &engine_option= table_message.engine().options(x);
1069
if (boost::iequals(engine_option.name(), "ROW_FORMAT"))
1071
haildb_table_format= parse_ib_table_format(engine_option.state());
1075
haildb_err= ib_table_schema_create(haildb_table_name.c_str(),
1076
&haildb_table_schema,
1077
haildb_table_format, 0);
1079
if (haildb_err != DB_SUCCESS)
1081
push_warning_printf(&session, DRIZZLE_ERROR::WARN_LEVEL_ERROR,
1082
ER_CANT_CREATE_TABLE,
1083
_("Cannot create table %s. HailDB Error %d (%s)\n"),
1084
haildb_table_name.c_str(), haildb_err, ib_strerror(haildb_err));
1085
return ib_err_t_to_drizzle_error(&session, haildb_err);
1088
for (int colnr= 0; colnr < table_message.field_size() ; colnr++)
1090
const message::Table::Field field = table_message.field(colnr);
1092
int field_err= create_table_add_field(haildb_table_schema, field,
1095
if (haildb_err != DB_SUCCESS || field_err != 0)
1096
ib_table_schema_delete(haildb_table_schema); /* cleanup */
1098
if (haildb_err != DB_SUCCESS)
1100
push_warning_printf(&session, DRIZZLE_ERROR::WARN_LEVEL_ERROR,
1101
ER_CANT_CREATE_TABLE,
1102
_("Cannot create field %s on table %s."
1103
" HailDB Error %d (%s)\n"),
1104
field.name().c_str(), haildb_table_name.c_str(),
1105
haildb_err, ib_strerror(haildb_err));
1106
return ib_err_t_to_drizzle_error(&session, haildb_err);
1112
bool has_primary= false;
1113
for (int indexnr= 0; indexnr < table_message.indexes_size() ; indexnr++)
1115
message::Table::Index *index = table_message.mutable_indexes(indexnr);
1117
ib_idx_sch_t haildb_index;
1119
haildb_err= ib_table_schema_add_index(haildb_table_schema, index->name().c_str(),
1121
if (haildb_err != DB_SUCCESS)
1124
if (index->is_primary())
1127
haildb_err= ib_index_schema_set_clustered(haildb_index);
1128
has_explicit_pkey= true;
1129
if (haildb_err != DB_SUCCESS)
1133
if (index->is_unique())
1135
haildb_err= ib_index_schema_set_unique(haildb_index);
1136
if (haildb_err != DB_SUCCESS)
1140
if (index->type() == message::Table::Index::UNKNOWN_INDEX)
1141
index->set_type(message::Table::Index::BTREE);
1143
for (int partnr= 0; partnr < index->index_part_size(); partnr++)
1145
const message::Table::Index::IndexPart part= index->index_part(partnr);
1146
const message::Table::Field::FieldType part_type= table_message.field(part.fieldnr()).type();
1147
uint64_t compare_length= 0;
1149
if (part_type == message::Table::Field::BLOB
1150
|| part_type == message::Table::Field::VARCHAR)
1151
compare_length= part.compare_length();
1153
haildb_err= ib_index_schema_add_col(haildb_index,
1154
table_message.field(part.fieldnr()).name().c_str(),
1156
if (haildb_err != DB_SUCCESS)
1160
if (! has_primary && index->is_unique())
1162
haildb_err= ib_index_schema_set_clustered(haildb_index);
1163
has_explicit_pkey= true;
1164
if (haildb_err != DB_SUCCESS)
1170
if (! has_explicit_pkey)
1172
ib_idx_sch_t haildb_index;
1174
haildb_err= ib_table_schema_add_col(haildb_table_schema, "hidden_primary_key_col",
1175
IB_INT, IB_COL_NOT_NULL, 0, 8);
1177
haildb_err= ib_table_schema_add_index(haildb_table_schema, "HIDDEN_PRIMARY",
1179
if (haildb_err != DB_SUCCESS)
1182
haildb_err= ib_index_schema_set_clustered(haildb_index);
1183
if (haildb_err != DB_SUCCESS)
1186
haildb_err= ib_index_schema_add_col(haildb_index, "hidden_primary_key_col", 0);
1187
if (haildb_err != DB_SUCCESS)
1191
haildb_schema_transaction= ib_trx_begin(IB_TRX_REPEATABLE_READ);
1192
haildb_err= ib_schema_lock_exclusive(haildb_schema_transaction);
1193
if (haildb_err != DB_SUCCESS)
1195
ib_err_t rollback_err= ib_trx_rollback(haildb_schema_transaction);
1196
ib_table_schema_delete(haildb_table_schema);
1198
push_warning_printf(&session, DRIZZLE_ERROR::WARN_LEVEL_ERROR,
1199
ER_CANT_CREATE_TABLE,
1200
_("Cannot Lock HailDB Data Dictionary. HailDB Error %d (%s)\n"),
1201
haildb_err, ib_strerror(haildb_err));
1203
assert (rollback_err == DB_SUCCESS);
1205
return HA_ERR_GENERIC;
1208
haildb_err= ib_table_create(haildb_schema_transaction, haildb_table_schema,
1211
if (haildb_err != DB_SUCCESS)
1213
ib_err_t rollback_err= ib_trx_rollback(haildb_schema_transaction);
1214
ib_table_schema_delete(haildb_table_schema);
1216
if (haildb_err == DB_TABLE_IS_BEING_USED)
1219
push_warning_printf(&session, DRIZZLE_ERROR::WARN_LEVEL_ERROR,
1220
ER_CANT_CREATE_TABLE,
1221
_("Cannot create table %s. HailDB Error %d (%s)\n"),
1222
haildb_table_name.c_str(),
1223
haildb_err, ib_strerror(haildb_err));
1225
assert (rollback_err == DB_SUCCESS);
1226
return HA_ERR_GENERIC;
1229
if (table_message.type() == message::Table::TEMPORARY)
1231
session.getMessageCache().storeTableMessage(identifier, table_message);
1232
haildb_err= DB_SUCCESS;
1235
haildb_err= store_table_message(haildb_schema_transaction,
1236
haildb_table_name.c_str(),
1239
if (haildb_err == DB_SUCCESS)
1240
haildb_err= ib_trx_commit(haildb_schema_transaction);
1242
haildb_err= ib_trx_rollback(haildb_schema_transaction);
1245
ib_table_schema_delete(haildb_table_schema);
1247
if (haildb_err != DB_SUCCESS)
1249
push_warning_printf(&session, DRIZZLE_ERROR::WARN_LEVEL_ERROR,
1250
ER_CANT_CREATE_TABLE,
1251
_("Cannot create table %s. HailDB Error %d (%s)\n"),
1252
haildb_table_name.c_str(),
1253
haildb_err, ib_strerror(haildb_err));
1254
return ib_err_t_to_drizzle_error(&session, haildb_err);
1260
static int delete_table_message_from_haildb(ib_trx_t transaction, const char* table_name)
1263
ib_tpl_t search_tuple;
1267
err= ib_cursor_open_table(HAILDB_TABLE_DEFINITIONS_TABLE, transaction, &cursor);
1268
if (err != DB_SUCCESS)
1271
search_tuple= ib_clust_search_tuple_create(cursor);
1273
err= ib_col_set_value(search_tuple, 0, table_name, strlen(table_name));
1274
if (err != DB_SUCCESS)
1277
// ib_cursor_set_match_mode(cursor, IB_EXACT_MATCH);
1279
err= ib_cursor_moveto(cursor, search_tuple, IB_CUR_GE, &res);
1280
if (err == DB_RECORD_NOT_FOUND || res != 0)
1283
err= ib_cursor_delete_row(cursor);
1284
assert (err == DB_SUCCESS);
1287
ib_err_t rollback_err= ib_cursor_close(cursor);
1288
if (err == DB_SUCCESS)
1291
ib_tuple_delete(search_tuple);
1296
int HailDBEngine::doDropTable(Session &session,
1297
const identifier::Table &identifier)
1299
ib_trx_t haildb_schema_transaction;
1300
ib_err_t haildb_err;
1301
string haildb_table_name;
1303
TableIdentifier_to_haildb_name(identifier, &haildb_table_name);
1305
haildb_schema_transaction= ib_trx_begin(IB_TRX_REPEATABLE_READ);
1306
haildb_err= ib_schema_lock_exclusive(haildb_schema_transaction);
1307
if (haildb_err != DB_SUCCESS)
1309
ib_err_t rollback_err= ib_trx_rollback(haildb_schema_transaction);
1311
push_warning_printf(&session, DRIZZLE_ERROR::WARN_LEVEL_ERROR,
1312
ER_CANT_DELETE_FILE,
1313
_("Cannot Lock HailDB Data Dictionary. HailDB Error %d (%s)\n"),
1314
haildb_err, ib_strerror(haildb_err));
1316
assert (rollback_err == DB_SUCCESS);
1318
return HA_ERR_GENERIC;
1321
if (identifier.getType() == message::Table::TEMPORARY)
1323
session.getMessageCache().removeTableMessage(identifier);
1324
delete_table_message_from_haildb(haildb_schema_transaction,
1325
haildb_table_name.c_str());
1329
if (delete_table_message_from_haildb(haildb_schema_transaction, haildb_table_name.c_str()) != DB_SUCCESS)
1331
ib_schema_unlock(haildb_schema_transaction);
1332
ib_err_t rollback_err= ib_trx_rollback(haildb_schema_transaction);
1333
assert(rollback_err == DB_SUCCESS);
1334
return HA_ERR_GENERIC;
1338
haildb_err= ib_table_drop(haildb_schema_transaction, haildb_table_name.c_str());
1340
if (haildb_err == DB_TABLE_NOT_FOUND)
1342
haildb_err= ib_trx_rollback(haildb_schema_transaction);
1343
assert(haildb_err == DB_SUCCESS);
1346
else if (haildb_err != DB_SUCCESS)
1348
ib_err_t rollback_err= ib_trx_rollback(haildb_schema_transaction);
1350
push_warning_printf(&session, DRIZZLE_ERROR::WARN_LEVEL_ERROR,
1351
ER_CANT_DELETE_FILE,
1352
_("Cannot DROP table %s. HailDB Error %d (%s)\n"),
1353
haildb_table_name.c_str(),
1354
haildb_err, ib_strerror(haildb_err));
1356
assert(rollback_err == DB_SUCCESS);
1358
return HA_ERR_GENERIC;
1361
haildb_err= ib_trx_commit(haildb_schema_transaction);
1362
if (haildb_err != DB_SUCCESS)
1364
ib_err_t rollback_err= ib_trx_rollback(haildb_schema_transaction);
1366
push_warning_printf(&session, DRIZZLE_ERROR::WARN_LEVEL_ERROR,
1367
ER_CANT_DELETE_FILE,
1368
_("Cannot DROP table %s. HailDB Error %d (%s)\n"),
1369
haildb_table_name.c_str(),
1370
haildb_err, ib_strerror(haildb_err));
1372
assert(rollback_err == DB_SUCCESS);
1373
return HA_ERR_GENERIC;
1379
static ib_err_t rename_table_message(ib_trx_t transaction, const identifier::Table &from_identifier, const identifier::Table &to_identifier)
1382
ib_tpl_t search_tuple;
1383
ib_tpl_t read_tuple;
1384
ib_tpl_t update_tuple;
1387
ib_err_t rollback_err;
1388
const char *message;
1389
ib_ulint_t message_len;
1390
drizzled::message::Table table_message;
1391
string from_haildb_table_name;
1392
string to_haildb_table_name;
1395
string serialized_message;
1396
ib_col_meta_t col_meta;
1398
TableIdentifier_to_haildb_name(from_identifier, &from_haildb_table_name);
1399
TableIdentifier_to_haildb_name(to_identifier, &to_haildb_table_name);
1401
from= from_haildb_table_name.c_str();
1402
to= to_haildb_table_name.c_str();
1404
err= ib_cursor_open_table(HAILDB_TABLE_DEFINITIONS_TABLE, transaction, &cursor);
1405
if (err != DB_SUCCESS)
1407
rollback_err= ib_trx_rollback(transaction);
1408
assert(rollback_err == DB_SUCCESS);
1412
search_tuple= ib_clust_search_tuple_create(cursor);
1413
read_tuple= ib_clust_read_tuple_create(cursor);
1415
err= ib_col_set_value(search_tuple, 0, from, strlen(from));
1416
if (err != DB_SUCCESS)
1419
// ib_cursor_set_match_mode(cursor, IB_EXACT_MATCH);
1421
err= ib_cursor_moveto(cursor, search_tuple, IB_CUR_GE, &res);
1422
if (err == DB_RECORD_NOT_FOUND || res != 0)
1425
err= ib_cursor_read_row(cursor, read_tuple);
1426
if (err == DB_RECORD_NOT_FOUND || res != 0)
1429
message= (const char*)ib_col_get_value(read_tuple, 1);
1430
message_len= ib_col_get_meta(read_tuple, 1, &col_meta);
1432
if (table_message.ParseFromArray(message, message_len) == false)
1435
table_message.set_name(to_identifier.getTableName());
1436
table_message.set_schema(to_identifier.getSchemaName());
1438
update_tuple= ib_clust_read_tuple_create(cursor);
1440
err= ib_tuple_copy(update_tuple, read_tuple);
1441
assert(err == DB_SUCCESS);
1443
err= ib_col_set_value(update_tuple, 0, to, strlen(to));
1446
table_message.SerializeToString(&serialized_message);
1453
err= ib_col_set_value(update_tuple, 1, serialized_message.c_str(),
1454
serialized_message.length());
1456
err= ib_cursor_update_row(cursor, read_tuple, update_tuple);
1459
ib_tuple_delete(update_tuple);
1460
ib_tuple_delete(read_tuple);
1461
ib_tuple_delete(search_tuple);
1463
err= ib_cursor_close(cursor);
1469
int HailDBEngine::doRenameTable(drizzled::Session &session,
1470
const drizzled::identifier::Table &from,
1471
const drizzled::identifier::Table &to)
1473
ib_trx_t haildb_schema_transaction;
1475
string from_haildb_table_name;
1476
string to_haildb_table_name;
1478
if (to.getType() == message::Table::TEMPORARY
1479
&& from.getType() == message::Table::TEMPORARY)
1481
session.getMessageCache().renameTableMessage(from, to);
1485
TableIdentifier_to_haildb_name(from, &from_haildb_table_name);
1486
TableIdentifier_to_haildb_name(to, &to_haildb_table_name);
1488
haildb_schema_transaction= ib_trx_begin(IB_TRX_REPEATABLE_READ);
1489
err= ib_schema_lock_exclusive(haildb_schema_transaction);
1490
if (err != DB_SUCCESS)
1492
push_warning_printf(&session, DRIZZLE_ERROR::WARN_LEVEL_ERROR,
1493
ER_CANT_DELETE_FILE,
1494
_("Cannot Lock HailDB Data Dictionary. HailDB Error %d (%s)\n"),
1495
err, ib_strerror(err));
1500
err= ib_table_rename(haildb_schema_transaction,
1501
from_haildb_table_name.c_str(),
1502
to_haildb_table_name.c_str());
1503
if (err != DB_SUCCESS)
1506
err= rename_table_message(haildb_schema_transaction, from, to);
1508
if (err != DB_SUCCESS)
1511
err= ib_trx_commit(haildb_schema_transaction);
1512
if (err != DB_SUCCESS)
1517
ib_err_t rollback_err= ib_schema_unlock(haildb_schema_transaction);
1518
assert(rollback_err == DB_SUCCESS);
1519
rollback_err= ib_trx_rollback(haildb_schema_transaction);
1520
assert(rollback_err == DB_SUCCESS);
1521
return ib_err_t_to_drizzle_error(&session, err);
1524
void HailDBEngine::getTableNamesInSchemaFromHailDB(
1525
const drizzled::identifier::Schema &schema,
1526
drizzled::plugin::TableNameList *set_of_names,
1527
drizzled::identifier::Table::vector *identifiers)
1529
ib_trx_t transaction;
1532
Why not use getPath()?
1534
string search_string(schema.getSchemaName());
1536
boost::algorithm::to_lower(search_string);
1538
search_string.append("/");
1540
transaction = ib_trx_begin(IB_TRX_REPEATABLE_READ);
1541
ib_err_t haildb_err= ib_schema_lock_exclusive(transaction);
1542
assert(haildb_err == DB_SUCCESS); /* FIXME: doGetTableNames needs to be able to return error */
1544
if (search_string.compare("data_dictionary/") == 0)
1548
BOOST_FOREACH(std::string table_name, haildb_system_table_names)
1550
set_of_names->insert(table_name);
1555
BOOST_FOREACH(std::string table_name, haildb_system_table_names)
1557
identifiers->push_back(identifier::Table(schema.getSchemaName(),
1563
haildb_err= ib_cursor_open_table("SYS_TABLES", transaction, &cursor);
1564
assert(haildb_err == DB_SUCCESS); /* FIXME */
1566
ib_tpl_t read_tuple;
1567
ib_tpl_t search_tuple;
1569
read_tuple= ib_clust_read_tuple_create(cursor);
1570
search_tuple= ib_clust_search_tuple_create(cursor);
1572
haildb_err= ib_col_set_value(search_tuple, 0, search_string.c_str(),
1573
search_string.length());
1574
assert (haildb_err == DB_SUCCESS); // FIXME
1577
haildb_err = ib_cursor_moveto(cursor, search_tuple, IB_CUR_GE, &res);
1578
// fixme: check error above
1580
while (haildb_err == DB_SUCCESS)
1582
haildb_err= ib_cursor_read_row(cursor, read_tuple);
1584
const char *table_name;
1586
ib_col_meta_t column_metadata;
1588
table_name= (const char*)ib_col_get_value(read_tuple, 0);
1589
table_name_len= ib_col_get_meta(read_tuple, 0, &column_metadata);
1591
if (search_string.compare(0, search_string.length(),
1592
table_name, search_string.length()) == 0)
1594
const char *just_table_name= strchr(table_name, '/');
1595
assert(just_table_name);
1596
just_table_name++; /* skip over '/' */
1598
set_of_names->insert(just_table_name);
1600
identifiers->push_back(identifier::Table(schema.getSchemaName(), just_table_name));
1604
haildb_err= ib_cursor_next(cursor);
1605
read_tuple= ib_tuple_clear(read_tuple);
1608
ib_tuple_delete(read_tuple);
1609
ib_tuple_delete(search_tuple);
1611
haildb_err= ib_cursor_close(cursor);
1612
assert(haildb_err == DB_SUCCESS); // FIXME
1614
haildb_err= ib_trx_commit(transaction);
1615
assert(haildb_err == DB_SUCCESS); // FIXME
1618
void HailDBEngine::doGetTableIdentifiers(drizzled::CachedDirectory &,
1619
const drizzled::identifier::Schema &schema,
1620
drizzled::identifier::Table::vector &identifiers)
1622
getTableNamesInSchemaFromHailDB(schema, NULL, &identifiers);
1625
static int read_table_message_from_haildb(const char* table_name, drizzled::message::Table *table_message)
1627
ib_trx_t transaction;
1628
ib_tpl_t search_tuple;
1629
ib_tpl_t read_tuple;
1631
const char *message;
1632
ib_ulint_t message_len;
1633
ib_col_meta_t col_meta;
1636
ib_err_t rollback_err;
1638
transaction= ib_trx_begin(IB_TRX_REPEATABLE_READ);
1639
err= ib_schema_lock_exclusive(transaction);
1640
if (err != DB_SUCCESS)
1642
rollback_err= ib_trx_rollback(transaction);
1643
assert(rollback_err == DB_SUCCESS);
1647
err= ib_cursor_open_table(HAILDB_TABLE_DEFINITIONS_TABLE, transaction, &cursor);
1648
if (err != DB_SUCCESS)
1650
rollback_err= ib_trx_rollback(transaction);
1651
assert(rollback_err == DB_SUCCESS);
1655
search_tuple= ib_clust_search_tuple_create(cursor);
1656
read_tuple= ib_clust_read_tuple_create(cursor);
1658
err= ib_col_set_value(search_tuple, 0, table_name, strlen(table_name));
1659
if (err != DB_SUCCESS)
1662
// ib_cursor_set_match_mode(cursor, IB_EXACT_MATCH);
1664
err= ib_cursor_moveto(cursor, search_tuple, IB_CUR_GE, &res);
1665
if (err == DB_RECORD_NOT_FOUND || res != 0)
1668
err= ib_cursor_read_row(cursor, read_tuple);
1669
if (err == DB_RECORD_NOT_FOUND || res != 0)
1672
message= (const char*)ib_col_get_value(read_tuple, 1);
1673
message_len= ib_col_get_meta(read_tuple, 1, &col_meta);
1675
if (table_message->ParseFromArray(message, message_len) == false)
1678
ib_tuple_delete(search_tuple);
1679
ib_tuple_delete(read_tuple);
1680
err= ib_cursor_close(cursor);
1681
if (err != DB_SUCCESS)
1682
goto rollback_close_err;
1683
err= ib_trx_commit(transaction);
1684
if (err != DB_SUCCESS)
1685
goto rollback_close_err;
1690
ib_tuple_delete(search_tuple);
1691
ib_tuple_delete(read_tuple);
1692
rollback_err= ib_cursor_close(cursor);
1693
assert(rollback_err == DB_SUCCESS);
1695
ib_schema_unlock(transaction);
1696
rollback_err= ib_trx_rollback(transaction);
1697
assert(rollback_err == DB_SUCCESS);
1699
if (strcmp(table_name, HAILDB_TABLE_DEFINITIONS_TABLE) == 0)
1701
message::Engine *engine= table_message->mutable_engine();
1702
engine->set_name("InnoDB");
1703
table_message->set_name("haildb_table_definitions");
1704
table_message->set_schema("data_dictionary");
1705
table_message->set_type(message::Table::STANDARD);
1706
table_message->set_creation_timestamp(0);
1707
table_message->set_update_timestamp(0);
1709
message::Table::TableOptions *options= table_message->mutable_options();
1710
options->set_collation_id(my_charset_bin.number);
1711
options->set_collation(my_charset_bin.name);
1713
message::Table::Field *field= table_message->add_field();
1714
field->set_name("table_name");
1715
field->set_type(message::Table::Field::VARCHAR);
1716
message::Table::Field::StringFieldOptions *stropt= field->mutable_string_options();
1717
stropt->set_length(IB_MAX_TABLE_NAME_LEN);
1718
stropt->set_collation_id(my_charset_bin.number);
1719
stropt->set_collation(my_charset_bin.name);
1721
field= table_message->add_field();
1722
field->set_name("message");
1723
field->set_type(message::Table::Field::BLOB);
1724
stropt= field->mutable_string_options();
1725
stropt->set_collation_id(my_charset_bin.number);
1726
stropt->set_collation(my_charset_bin.name);
1728
message::Table::Index *index= table_message->add_indexes();
1729
index->set_name("PRIMARY");
1730
index->set_is_primary(true);
1731
index->set_is_unique(true);
1732
index->set_type(message::Table::Index::BTREE);
1733
index->set_key_length(IB_MAX_TABLE_NAME_LEN);
1734
message::Table::Index::IndexPart *part= index->add_index_part();
1735
part->set_fieldnr(0);
1736
part->set_compare_length(IB_MAX_TABLE_NAME_LEN);
1744
int HailDBEngine::doGetTableDefinition(Session &session,
1745
const identifier::Table &identifier,
1746
drizzled::message::Table &table)
1748
ib_crsr_t haildb_cursor= NULL;
1749
string haildb_table_name;
1751
/* Check temporary tables!? */
1752
if (session.getMessageCache().getTableMessage(identifier, table))
1755
TableIdentifier_to_haildb_name(identifier, &haildb_table_name);
1757
if (ib_cursor_open_table(haildb_table_name.c_str(), NULL, &haildb_cursor) != DB_SUCCESS)
1760
ib_err_t err= ib_cursor_close(haildb_cursor);
1762
assert (err == DB_SUCCESS);
1764
if (read_table_message_from_haildb(haildb_table_name.c_str(), &table) != 0)
1766
if (get_haildb_system_table_message(haildb_table_name.c_str(), &table) == 0)
1773
bool HailDBEngine::doDoesTableExist(Session &,
1774
const identifier::Table& identifier)
1776
ib_crsr_t haildb_cursor;
1777
string haildb_table_name;
1779
TableIdentifier_to_haildb_name(identifier, &haildb_table_name);
1781
boost::unordered_set<string>::iterator iter= haildb_system_table_names.find(identifier.getTableName());
1782
if (iter != haildb_system_table_names.end())
1785
if (ib_cursor_open_table(haildb_table_name.c_str(), NULL, &haildb_cursor) != DB_SUCCESS)
1788
ib_err_t err= ib_cursor_close(haildb_cursor);
1789
assert(err == DB_SUCCESS);
1794
const char *HailDBCursor::index_type(uint32_t)
1799
static ib_err_t write_row_to_haildb_tuple(const unsigned char* buf,
1800
Field **fields, ib_tpl_t tuple)
1803
ib_err_t err= DB_ERROR;
1804
ptrdiff_t row_offset= buf - (*fields)->getTable()->getInsertRecord();
1806
for (Field **field= fields; *field; field++, colnr++)
1808
(**field).move_field_offset(row_offset);
1810
if (! (**field).isWriteSet() && (**field).is_null())
1812
(**field).move_field_offset(-row_offset);
1816
if ((**field).is_null())
1818
err= ib_col_set_value(tuple, colnr, NULL, IB_SQL_NULL);
1819
assert(err == DB_SUCCESS);
1820
(**field).move_field_offset(-row_offset);
1824
if ((**field).type() == DRIZZLE_TYPE_VARCHAR)
1826
/* To get around the length bytes (1 or 2) at (**field).ptr
1827
we can use Field_varstring::val_str to a String
1828
to get a pointer to the real string without copying it.
1831
(**field).setReadSet();
1832
(**field).val_str_internal(&str);
1833
err= ib_col_set_value(tuple, colnr, str.ptr(), str.length());
1835
else if ((**field).type() == DRIZZLE_TYPE_ENUM)
1837
err= ib_tuple_write_u32(tuple, colnr, *((ib_u32_t*)(*field)->ptr));
1839
else if ((**field).type() == DRIZZLE_TYPE_DATE)
1841
(**field).setReadSet();
1842
err= ib_tuple_write_u32(tuple, colnr, (*field)->val_int());
1844
else if ((**field).type() == DRIZZLE_TYPE_BLOB)
1846
Field_blob *blob= reinterpret_cast<Field_blob*>(*field);
1847
unsigned char* blob_ptr;
1848
uint32_t blob_length= blob->get_length();
1849
blob->get_ptr(&blob_ptr);
1850
err= ib_col_set_value(tuple, colnr, blob_ptr, blob_length);
1854
err= ib_col_set_value(tuple, colnr, (*field)->ptr, (*field)->data_length());
1857
assert (err == DB_SUCCESS);
1859
(**field).move_field_offset(-row_offset);
1865
static uint64_t innobase_get_int_col_max_value(const Field* field)
1867
uint64_t max_value = 0;
1869
switch(field->key_type()) {
1871
case HA_KEYTYPE_BINARY:
1872
max_value = 0xFFULL;
1875
case HA_KEYTYPE_ULONG_INT:
1876
max_value = 0xFFFFFFFFULL;
1878
case HA_KEYTYPE_LONG_INT:
1879
max_value = 0x7FFFFFFFULL;
1882
case HA_KEYTYPE_ULONGLONG:
1883
max_value = 0xFFFFFFFFFFFFFFFFULL;
1885
case HA_KEYTYPE_LONGLONG:
1886
max_value = 0x7FFFFFFFFFFFFFFFULL;
1888
case HA_KEYTYPE_DOUBLE:
1889
/* We use the maximum as per IEEE754-2008 standard, 2^53 */
1890
max_value = 0x20000000000000ULL;
1899
int HailDBCursor::doInsertRecord(unsigned char *record)
1904
ib_trx_t transaction= *get_trx(getTable()->in_use);
1906
tuple= ib_clust_read_tuple_create(cursor);
1908
if (cursor_is_sec_index)
1910
err= ib_cursor_close(cursor);
1911
assert(err == DB_SUCCESS);
1913
err= ib_cursor_open_table_using_id(table_id, transaction, &cursor);
1915
if (err != DB_SUCCESS)
1916
return ib_err_t_to_drizzle_error(getTable()->getSession(), err);
1918
cursor_is_sec_index= false;
1922
ib_cursor_attach_trx(cursor, transaction);
1925
err= ib_cursor_first(cursor);
1926
if (current_session->getLex()->sql_command == SQLCOM_CREATE_TABLE
1927
&& err == DB_MISSING_HISTORY)
1929
/* See https://bugs.launchpad.net/drizzle/+bug/556978
1931
* In CREATE SELECT, transaction is started in ::store_lock
1932
* at the start of the statement, before the table is created.
1933
* This means the table doesn't exist in our snapshot,
1934
* and we get a DB_MISSING_HISTORY error on ib_cursor_first().
1935
* The way to get around this is to here, restart the transaction
1941
HailDBEngine *storage_engine= static_cast<HailDBEngine*>(getEngine());
1942
err= ib_cursor_reset(cursor);
1943
storage_engine->doCommit(current_session, true);
1944
storage_engine->doStartTransaction(current_session, START_TRANS_NO_OPTIONS);
1945
transaction= *get_trx(getTable()->in_use);
1946
assert(err == DB_SUCCESS);
1947
ib_cursor_attach_trx(cursor, transaction);
1948
err= ib_cursor_first(cursor);
1951
assert(err == DB_SUCCESS || err == DB_END_OF_INDEX);
1954
if (getTable()->next_number_field)
1956
update_auto_increment();
1958
uint64_t temp_auto= getTable()->next_number_field->val_int();
1960
if (temp_auto <= innobase_get_int_col_max_value(getTable()->next_number_field))
1964
uint64_t fetched_auto= share->auto_increment_value;
1966
if (temp_auto >= fetched_auto)
1968
uint64_t store_value= temp_auto+1;
1969
if (store_value == 0)
1972
if (share->auto_increment_value.compare_and_swap(store_value, fetched_auto) == fetched_auto)
1982
write_row_to_haildb_tuple(record, getTable()->getFields(), tuple);
1984
if (share->has_hidden_primary_key)
1986
err= ib_tuple_write_u64(tuple, getTable()->getShare()->sizeFields(),
1987
share->hidden_pkey_auto_increment_value.fetch_and_increment());
1990
err= ib_cursor_insert_row(cursor, tuple);
1992
if (err == DB_DUPLICATE_KEY)
1994
if (write_can_replace)
1996
store_key_value_from_haildb(getTable()->key_info + getTable()->getShare()->getPrimaryKey(),
1997
ref, ref_length, record);
1999
ib_tpl_t search_tuple= ib_clust_search_tuple_create(cursor);
2001
fill_ib_search_tpl_from_drizzle_key(search_tuple,
2002
getTable()->key_info + 0,
2006
err= ib_cursor_moveto(cursor, search_tuple, IB_CUR_GE, &res);
2007
assert(err == DB_SUCCESS);
2008
ib_tuple_delete(search_tuple);
2010
tuple= ib_tuple_clear(tuple);
2011
err= ib_cursor_delete_row(cursor);
2013
err= ib_cursor_first(cursor);
2014
assert(err == DB_SUCCESS || err == DB_END_OF_INDEX);
2016
write_row_to_haildb_tuple(record, getTable()->getFields(), tuple);
2018
err= ib_cursor_insert_row(cursor, tuple);
2019
assert(err==DB_SUCCESS); // probably be nice and process errors
2022
ret= HA_ERR_FOUND_DUPP_KEY;
2024
else if (err != DB_SUCCESS)
2025
ret= ib_err_t_to_drizzle_error(getTable()->getSession(), err);
2027
tuple= ib_tuple_clear(tuple);
2028
ib_tuple_delete(tuple);
2030
err= ib_cursor_reset(cursor);
2035
int HailDBCursor::doUpdateRecord(const unsigned char *old_data,
2036
unsigned char *new_data)
2038
ib_tpl_t update_tuple;
2040
bool created_tuple= false;
2042
update_tuple= ib_clust_read_tuple_create(cursor);
2046
ib_trx_t transaction= *get_trx(getTable()->in_use);
2048
if (cursor_is_sec_index)
2050
err= ib_cursor_close(cursor);
2051
assert(err == DB_SUCCESS);
2053
err= ib_cursor_open_table_using_id(table_id, transaction, &cursor);
2055
if (err != DB_SUCCESS)
2056
return ib_err_t_to_drizzle_error(getTable()->getSession(), err);
2057
cursor_is_sec_index= false;
2061
ib_cursor_attach_trx(cursor, transaction);
2064
store_key_value_from_haildb(getTable()->key_info + getTable()->getShare()->getPrimaryKey(),
2065
ref, ref_length, old_data);
2067
ib_tpl_t search_tuple= ib_clust_search_tuple_create(cursor);
2069
fill_ib_search_tpl_from_drizzle_key(search_tuple,
2070
getTable()->key_info + 0,
2073
err= ib_cursor_set_lock_mode(cursor, IB_LOCK_X);
2074
assert(err == DB_SUCCESS);
2077
err= ib_cursor_moveto(cursor, search_tuple, IB_CUR_GE, &res);
2078
assert(err == DB_SUCCESS);
2080
tuple= ib_clust_read_tuple_create(cursor);
2082
err= ib_cursor_read_row(cursor, tuple);
2083
assert(err == DB_SUCCESS);// FIXME
2085
created_tuple= true;
2088
err= ib_tuple_copy(update_tuple, tuple);
2089
assert(err == DB_SUCCESS);
2091
write_row_to_haildb_tuple(new_data, getTable()->getFields(), update_tuple);
2093
err= ib_cursor_update_row(cursor, tuple, update_tuple);
2095
ib_tuple_delete(update_tuple);
2099
ib_err_t ib_err= ib_cursor_reset(cursor); //fixme check error
2100
assert(ib_err == DB_SUCCESS);
2101
tuple= ib_tuple_clear(tuple);
2102
ib_tuple_delete(tuple);
2106
advance_cursor= true;
2108
return ib_err_t_to_drizzle_error(getTable()->getSession(), err);
2111
int HailDBCursor::doDeleteRecord(const unsigned char *)
2115
assert(ib_cursor_is_positioned(cursor) == IB_TRUE);
2116
err= ib_cursor_delete_row(cursor);
2118
advance_cursor= true;
2120
return ib_err_t_to_drizzle_error(getTable()->getSession(), err);
2123
int HailDBCursor::delete_all_rows(void)
2125
/* I *think* ib_truncate is non-transactional....
2126
so only support TRUNCATE and not DELETE FROM t;
2127
(this is what ha_innodb does)
2129
if (getTable()->in_use->getSqlCommand() != SQLCOM_TRUNCATE)
2130
return HA_ERR_WRONG_COMMAND;
2135
ib_trx_t transaction= ib_trx_begin(IB_TRX_REPEATABLE_READ);
2137
if (cursor_is_sec_index)
2139
err= ib_cursor_close(cursor);
2140
assert(err == DB_SUCCESS);
2142
err= ib_cursor_open_table_using_id(table_id, transaction, &cursor);
2144
if (err != DB_SUCCESS)
2145
return ib_err_t_to_drizzle_error(getTable()->getSession(), err);
2146
cursor_is_sec_index= false;
2150
ib_cursor_attach_trx(cursor, transaction);
2153
err= ib_schema_lock_exclusive(transaction);
2154
if (err != DB_SUCCESS)
2156
ib_err_t rollback_err= ib_trx_rollback(transaction);
2158
push_warning_printf(getTable()->in_use, DRIZZLE_ERROR::WARN_LEVEL_ERROR,
2159
ER_CANT_DELETE_FILE,
2160
_("Cannot Lock HailDB Data Dictionary. HailDB Error %d (%s)\n"),
2161
err, ib_strerror(err));
2163
assert (rollback_err == DB_SUCCESS);
2165
return HA_ERR_GENERIC;
2168
share->auto_increment_value.fetch_and_store(1);
2170
err= ib_cursor_truncate(&cursor, &id);
2171
if (err != DB_SUCCESS)
2174
ib_schema_unlock(transaction);
2175
/* ib_cursor_truncate commits on success */
2177
err= ib_cursor_open_table_using_id(id, NULL, &cursor);
2178
if (err != DB_SUCCESS)
2184
ib_schema_unlock(transaction);
2185
ib_err_t rollback_err= ib_trx_rollback(transaction);
2186
assert(rollback_err == DB_SUCCESS);
2187
return ib_err_t_to_drizzle_error(getTable()->getSession(), err);
2190
int HailDBCursor::doStartTableScan(bool)
2192
ib_err_t err= DB_SUCCESS;
2193
ib_trx_t transaction;
2197
in_table_scan= true;
2199
transaction= *get_trx(getTable()->in_use);
2201
assert(transaction != NULL);
2203
if (cursor_is_sec_index)
2205
err= ib_cursor_close(cursor);
2206
assert(err == DB_SUCCESS);
2208
err= ib_cursor_open_table_using_id(table_id, transaction, &cursor);
2209
cursor_is_sec_index= false;
2213
ib_cursor_attach_trx(cursor, transaction);
2216
if (err != DB_SUCCESS)
2217
return ib_err_t_to_drizzle_error(getTable()->getSession(), err);
2219
err= ib_cursor_set_lock_mode(cursor, ib_lock_mode);
2220
assert(err == DB_SUCCESS); // FIXME
2222
tuple= ib_clust_read_tuple_create(cursor);
2224
err= ib_cursor_first(cursor);
2225
if (err != DB_SUCCESS && err != DB_END_OF_INDEX)
2227
int reset_err= ib_cursor_reset(cursor);
2228
assert(reset_err == DB_SUCCESS);
2229
return ib_err_t_to_drizzle_error(getTable()->getSession(), err);
2232
advance_cursor= false;
2237
int read_row_from_haildb(Session *session, unsigned char* buf, ib_crsr_t cursor, ib_tpl_t tuple, Table* table, bool has_hidden_primary_key, uint64_t *hidden_pkey, drizzled::memory::Root **blobroot)
2240
ptrdiff_t row_offset= buf - table->getInsertRecord();
2242
err= ib_cursor_read_row(cursor, tuple);
2244
if (err == DB_RECORD_NOT_FOUND)
2245
return HA_ERR_END_OF_FILE;
2246
if (err != DB_SUCCESS)
2247
return ib_err_t_to_drizzle_error(session, err);
2251
/* We need the primary key for ::position() to work */
2252
if (table->getShare()->getPrimaryKey() != MAX_KEY)
2253
table->mark_columns_used_by_index_no_reset(table->getShare()->getPrimaryKey());
2255
for (Field **field= table->getFields() ; *field ; field++, colnr++)
2257
if (! (**field).isReadSet())
2258
(**field).setReadSet(); /* Fucking broken API screws us royally. */
2260
(**field).move_field_offset(row_offset);
2262
(**field).setWriteSet();
2264
uint32_t length= ib_col_get_len(tuple, colnr);
2265
if (length == IB_SQL_NULL)
2267
(**field).set_null();
2268
(**field).move_field_offset(-row_offset);
2272
(**field).set_notnull();
2274
if ((**field).type() == DRIZZLE_TYPE_VARCHAR)
2276
(*field)->store((const char*)ib_col_get_value(tuple, colnr),
2280
else if ((**field).type() == DRIZZLE_TYPE_DATE)
2283
err= ib_tuple_read_u32(tuple, colnr, &date_read);
2284
(*field)->store(date_read);
2286
else if ((**field).type() == DRIZZLE_TYPE_BLOB)
2288
if (blobroot == NULL)
2289
(reinterpret_cast<Field_blob*>(*field))->set_ptr(length,
2290
(unsigned char*)ib_col_get_value(tuple,
2294
if (*blobroot == NULL)
2296
*blobroot= new drizzled::memory::Root();
2297
(**blobroot).init_alloc_root();
2300
unsigned char *blob_ptr= (unsigned char*)(**blobroot).alloc_root(length);
2301
memcpy(blob_ptr, ib_col_get_value(tuple, colnr), length);
2302
(reinterpret_cast<Field_blob*>(*field))->set_ptr(length, blob_ptr);
2307
ib_col_copy_value(tuple, colnr, (*field)->ptr, (*field)->data_length());
2310
(**field).move_field_offset(-row_offset);
2312
if (err != DB_SUCCESS)
2313
return ib_err_t_to_drizzle_error(session, err);
2316
if (has_hidden_primary_key)
2318
err= ib_tuple_read_u64(tuple, colnr, hidden_pkey);
2321
return ib_err_t_to_drizzle_error(session, err);
2324
int HailDBCursor::rnd_next(unsigned char *buf)
2331
err= ib_cursor_next(cursor);
2332
if (err != DB_SUCCESS)
2333
return ib_err_t_to_drizzle_error(getTable()->getSession(), err);
2336
tuple= ib_tuple_clear(tuple);
2337
ret= read_row_from_haildb(getTable()->getSession(), buf, cursor, tuple,
2339
share->has_hidden_primary_key,
2340
&hidden_autoinc_pkey_position);
2342
advance_cursor= true;
2346
int HailDBCursor::doEndTableScan()
2350
ib_tuple_delete(tuple);
2352
err= ib_cursor_reset(cursor);
2353
assert(err == DB_SUCCESS);
2354
in_table_scan= false;
2355
return ib_err_t_to_drizzle_error(getTable()->getSession(), err);
2358
int HailDBCursor::rnd_pos(unsigned char *buf, unsigned char *pos)
2363
ib_tpl_t search_tuple= ib_clust_search_tuple_create(cursor);
2365
if (share->has_hidden_primary_key)
2367
err= ib_col_set_value(search_tuple, 0,
2368
((uint64_t*)(pos)), sizeof(uint64_t));
2369
if (err != DB_SUCCESS)
2370
return ib_err_t_to_drizzle_error(getTable()->getSession(), err);
2375
if (getTable()->getShare()->getPrimaryKey() != MAX_KEY)
2376
keynr= getTable()->getShare()->getPrimaryKey();
2378
keynr= get_first_unique_index(*getTable());
2380
fill_ib_search_tpl_from_drizzle_key(search_tuple,
2381
getTable()->key_info + keynr,
2385
err= ib_cursor_moveto(cursor, search_tuple, IB_CUR_GE, &res);
2386
if (err != DB_SUCCESS)
2387
return ib_err_t_to_drizzle_error(getTable()->getSession(), err);
2393
ib_tuple_delete(search_tuple);
2395
tuple= ib_tuple_clear(tuple);
2398
ret= read_row_from_haildb(getTable()->getSession(), buf, cursor, tuple,
2400
share->has_hidden_primary_key,
2401
&hidden_autoinc_pkey_position);
2403
advance_cursor= true;
2408
static void store_key_value_from_haildb(KeyInfo *key_info, unsigned char* ref, int ref_len, const unsigned char *record)
2410
KeyPartInfo* key_part= key_info->key_part;
2411
KeyPartInfo* end= key_info->key_part + key_info->key_parts;
2412
unsigned char* ref_start= ref;
2414
memset(ref, 0, ref_len);
2416
for (; key_part != end; key_part++)
2420
if(key_part->null_bit)
2422
*ref= is_null= record[key_part->null_offset] & key_part->null_bit;
2426
Field *field= key_part->field;
2428
if (field->type() == DRIZZLE_TYPE_VARCHAR)
2432
ref+= key_part->length + 2; /* 2 bytes for length */
2437
field->val_str_internal(&str);
2439
*ref++= (char)(str.length() & 0x000000ff);
2440
*ref++= (char)((str.length()>>8) & 0x000000ff);
2442
memcpy(ref, str.ptr(), str.length());
2443
ref+= key_part->length;
2450
ref+= key_part->length;
2454
memcpy(ref, record+key_part->offset, key_part->length);
2455
ref+= key_part->length;
2460
assert(ref == ref_start + ref_len);
2463
void HailDBCursor::position(const unsigned char *record)
2465
if (share->has_hidden_primary_key)
2466
*((uint64_t*) ref)= hidden_autoinc_pkey_position;
2470
if (getTable()->getShare()->getPrimaryKey() != MAX_KEY)
2471
keynr= getTable()->getShare()->getPrimaryKey();
2473
keynr= get_first_unique_index(*getTable());
2475
store_key_value_from_haildb(getTable()->key_info + keynr,
2476
ref, ref_length, record);
2482
double HailDBCursor::scan_time()
2484
ib_table_stats_t table_stats;
2487
err= ib_get_table_statistics(cursor, &table_stats, sizeof(table_stats));
2489
/* Approximate I/O seeks for full table scan */
2490
return (double) (table_stats.stat_clustered_index_size / 16384);
2493
int HailDBCursor::info(uint32_t flag)
2495
ib_table_stats_t table_stats;
2498
if (flag & HA_STATUS_VARIABLE)
2500
err= ib_get_table_statistics(cursor, &table_stats, sizeof(table_stats));
2502
stats.records= table_stats.stat_n_rows;
2504
if (table_stats.stat_n_rows < 2)
2508
stats.data_file_length= table_stats.stat_clustered_index_size;
2509
stats.index_file_length= table_stats.stat_sum_of_other_index_sizes;
2511
stats.mean_rec_length= stats.data_file_length / stats.records;
2514
if (flag & HA_STATUS_AUTO)
2515
stats.auto_increment_value= 1;
2517
if (flag & HA_STATUS_ERRKEY) {
2518
const char *err_table_name;
2519
const char *err_index_name;
2521
ib_trx_t transaction= *get_trx(getTable()->in_use);
2523
err= ib_get_duplicate_key(transaction, &err_table_name, &err_index_name);
2527
for (unsigned int i = 0; i < getTable()->getShare()->keys; i++)
2529
if (strcmp(err_index_name, getTable()->key_info[i].name) == 0)
2538
if (flag & HA_STATUS_CONST)
2540
for (unsigned int i = 0; i < getTable()->getShare()->sizeKeys(); i++)
2542
const char* index_name= getTable()->key_info[i].name;
2545
ha_rows rec_per_key;
2547
err= ib_get_index_stat_n_diff_key_vals(cursor, index_name,
2550
if (err != DB_SUCCESS)
2551
return ib_err_t_to_drizzle_error(getTable()->getSession(), err);
2553
for (unsigned int j=0; j < getTable()->key_info[i].key_parts; j++)
2555
if (n_diff[j+1] == 0)
2556
rec_per_key= stats.records;
2558
rec_per_key= stats.records / n_diff[j+1];
2560
/* We import this heuristic from ha_innodb, which says
2561
that MySQL favours table scans too much over index searches,
2562
so we pretend our index selectivity is 2 times better. */
2564
rec_per_key= rec_per_key / 2;
2566
if (rec_per_key == 0)
2569
getTable()->key_info[i].rec_per_key[j]=
2570
rec_per_key >= ~(ulong) 0 ? ~(ulong) 0 :
2571
(ulong) rec_per_key;
2581
int HailDBCursor::doStartIndexScan(uint32_t keynr, bool)
2584
ib_trx_t transaction= *get_trx(getTable()->in_use);
2586
active_index= keynr;
2588
if (active_index == 0 && ! share->has_hidden_primary_key)
2590
if (cursor_is_sec_index)
2592
err= ib_cursor_close(cursor);
2593
assert(err == DB_SUCCESS);
2595
err= ib_cursor_open_table_using_id(table_id, transaction, &cursor);
2597
if (err != DB_SUCCESS)
2598
return ib_err_t_to_drizzle_error(getTable()->getSession(), err);
2603
ib_cursor_attach_trx(cursor, transaction);
2606
cursor_is_sec_index= false;
2607
tuple= ib_clust_read_tuple_create(cursor);
2612
err= ib_index_get_id(table_path_to_haildb_name(getShare()->getPath()),
2613
getShare()->getKeyInfo(keynr).name,
2615
if (err != DB_SUCCESS)
2616
return ib_err_t_to_drizzle_error(getTable()->getSession(), err);
2618
err= ib_cursor_close(cursor);
2619
assert(err == DB_SUCCESS);
2621
err= ib_cursor_open_index_using_id(index_id, transaction, &cursor);
2623
if (err != DB_SUCCESS)
2624
return ib_err_t_to_drizzle_error(getTable()->getSession(), err);
2626
cursor_is_sec_index= true;
2628
tuple= ib_clust_read_tuple_create(cursor);
2629
ib_cursor_set_cluster_access(cursor);
2632
err= ib_cursor_set_lock_mode(cursor, ib_lock_mode);
2633
assert(err == DB_SUCCESS);
2635
advance_cursor= false;
2639
static ib_srch_mode_t ha_rkey_function_to_ib_srch_mode(drizzled::ha_rkey_function find_flag)
2643
case HA_READ_KEY_EXACT:
2645
case HA_READ_KEY_OR_NEXT:
2647
case HA_READ_KEY_OR_PREV:
2649
case HA_READ_AFTER_KEY:
2651
case HA_READ_BEFORE_KEY:
2653
case HA_READ_PREFIX:
2655
case HA_READ_PREFIX_LAST:
2657
case HA_READ_PREFIX_LAST_OR_PREV:
2659
case HA_READ_MBR_CONTAIN:
2660
case HA_READ_MBR_INTERSECT:
2661
case HA_READ_MBR_WITHIN:
2662
case HA_READ_MBR_DISJOINT:
2663
case HA_READ_MBR_EQUAL:
2664
assert(false); /* these just exist in the enum, not used. */
2668
/* Must return or compiler complains about reaching end of function */
2669
return (ib_srch_mode_t)0;
2672
static void fill_ib_search_tpl_from_drizzle_key(ib_tpl_t search_tuple,
2673
const drizzled::KeyInfo *key_info,
2674
const unsigned char *key_ptr,
2677
KeyPartInfo *key_part= key_info->key_part;
2678
KeyPartInfo *end= key_part + key_info->key_parts;
2679
const unsigned char *buff= key_ptr;
2684
for(; key_part != end && buff < key_ptr + key_len; key_part++)
2686
Field *field= key_part->field;
2687
bool is_null= false;
2689
if (key_part->null_bit)
2694
err= ib_col_set_value(search_tuple, fieldnr, NULL, IB_SQL_NULL);
2695
assert(err == DB_SUCCESS);
2700
if (field->type() == DRIZZLE_TYPE_VARCHAR)
2704
buff+= key_part->length + 2; /* 2 bytes length */
2708
int length= *buff + (*(buff + 1) << 8);
2710
err= ib_col_set_value(search_tuple, fieldnr, buff, length);
2711
assert(err == DB_SUCCESS);
2713
buff+= key_part->length;
2715
else if (field->type() == DRIZZLE_TYPE_DATE)
2717
uint32_t date_int= static_cast<uint32_t>(field->val_int());
2718
err= ib_col_set_value(search_tuple, fieldnr, &date_int, 4);
2719
buff+= key_part->length;
2726
buff+= key_part->length;
2730
err= ib_col_set_value(search_tuple, fieldnr,
2731
buff, key_part->length);
2732
assert(err == DB_SUCCESS);
2734
buff+= key_part->length;
2740
assert(buff == key_ptr + key_len);
2743
int HailDBCursor::haildb_index_read(unsigned char *buf,
2744
const unsigned char *key_ptr,
2746
drizzled::ha_rkey_function find_flag,
2747
bool allocate_blobs)
2749
ib_tpl_t search_tuple;
2753
ib_srch_mode_t search_mode;
2755
search_mode= ha_rkey_function_to_ib_srch_mode(find_flag);
2757
if (active_index == 0 && ! share->has_hidden_primary_key)
2758
search_tuple= ib_clust_search_tuple_create(cursor);
2760
search_tuple= ib_sec_search_tuple_create(cursor);
2762
fill_ib_search_tpl_from_drizzle_key(search_tuple,
2763
getTable()->key_info + active_index,
2766
err= ib_cursor_moveto(cursor, search_tuple, search_mode, &res);
2767
ib_tuple_delete(search_tuple);
2769
if ((err == DB_RECORD_NOT_FOUND || err == DB_END_OF_INDEX))
2771
getTable()->status= STATUS_NOT_FOUND;
2772
return HA_ERR_KEY_NOT_FOUND;
2775
if (err != DB_SUCCESS)
2777
return ib_err_t_to_drizzle_error(getTable()->getSession(), err);
2780
tuple= ib_tuple_clear(tuple);
2781
ret= read_row_from_haildb(getTable()->getSession(), buf, cursor, tuple,
2783
share->has_hidden_primary_key,
2784
&hidden_autoinc_pkey_position,
2785
(allocate_blobs)? &blobroot : NULL);
2787
getTable()->status= 0;
2789
getTable()->status= STATUS_NOT_FOUND;
2791
advance_cursor= true;
2796
int HailDBCursor::index_read(unsigned char *buf,
2797
const unsigned char *key_ptr,
2799
drizzled::ha_rkey_function find_flag)
2801
return haildb_index_read(buf, key_ptr, key_len, find_flag, false);
2804
/* This is straight from cursor.cc, but it's private there :( */
2805
uint32_t HailDBCursor::calculate_key_len(uint32_t key_position,
2806
key_part_map keypart_map_arg)
2808
/* works only with key prefixes */
2809
assert(((keypart_map_arg + 1) & keypart_map_arg) == 0);
2811
KeyPartInfo *key_part_found= getTable()->getShare()->getKeyInfo(key_position).key_part;
2812
KeyPartInfo *end_key_part_found= key_part_found + getTable()->getShare()->getKeyInfo(key_position).key_parts;
2815
while (key_part_found < end_key_part_found && keypart_map_arg)
2817
length+= key_part_found->store_length;
2818
keypart_map_arg >>= 1;
2825
int HailDBCursor::haildb_index_read_map(unsigned char * buf,
2826
const unsigned char *key,
2827
key_part_map keypart_map,
2828
enum ha_rkey_function find_flag,
2829
bool allocate_blobs)
2831
uint32_t key_len= calculate_key_len(active_index, keypart_map);
2832
return haildb_index_read(buf, key, key_len, find_flag, allocate_blobs);
2835
int HailDBCursor::index_read_idx_map(unsigned char * buf,
2837
const unsigned char * key,
2838
key_part_map keypart_map,
2839
enum ha_rkey_function find_flag)
2842
error= doStartIndexScan(index, 0);
2845
error= haildb_index_read_map(buf, key, keypart_map, find_flag, true);
2846
error1= doEndIndexScan();
2848
return error ? error : error1;
2851
int HailDBCursor::reset()
2854
blobroot->free_root(MYF(0));
2859
int HailDBCursor::analyze(Session*)
2863
err= ib_update_table_statistics(cursor);
2865
return ib_err_t_to_drizzle_error(getTable()->getSession(), err);
2868
int HailDBCursor::index_next(unsigned char *buf)
2870
int ret= HA_ERR_END_OF_FILE;
2874
ib_err_t err= ib_cursor_next(cursor);
2875
if (err == DB_END_OF_INDEX)
2876
return HA_ERR_END_OF_FILE;
2879
tuple= ib_tuple_clear(tuple);
2880
ret= read_row_from_haildb(getTable()->getSession(), buf, cursor, tuple,
2882
share->has_hidden_primary_key,
2883
&hidden_autoinc_pkey_position);
2885
advance_cursor= true;
2889
int HailDBCursor::doEndIndexScan()
2891
active_index= MAX_KEY;
2893
return doEndTableScan();
2896
int HailDBCursor::index_prev(unsigned char *buf)
2898
int ret= HA_ERR_END_OF_FILE;
2903
err= ib_cursor_prev(cursor);
2904
if (err != DB_SUCCESS)
2906
if (err == DB_END_OF_INDEX)
2907
return HA_ERR_END_OF_FILE;
2909
return ib_err_t_to_drizzle_error(getTable()->getSession(), err);
2913
tuple= ib_tuple_clear(tuple);
2914
ret= read_row_from_haildb(getTable()->getSession(), buf, cursor, tuple,
2916
share->has_hidden_primary_key,
2917
&hidden_autoinc_pkey_position);
2919
advance_cursor= true;
2925
int HailDBCursor::index_first(unsigned char *buf)
2927
int ret= HA_ERR_END_OF_FILE;
2930
err= ib_cursor_first(cursor);
2931
if (err != DB_SUCCESS)
2932
return ib_err_t_to_drizzle_error(getTable()->getSession(), err);
2934
tuple= ib_tuple_clear(tuple);
2935
ret= read_row_from_haildb(getTable()->getSession(), buf, cursor, tuple,
2937
share->has_hidden_primary_key,
2938
&hidden_autoinc_pkey_position);
2940
advance_cursor= true;
2946
int HailDBCursor::index_last(unsigned char *buf)
2948
int ret= HA_ERR_END_OF_FILE;
2951
err= ib_cursor_last(cursor);
2952
if (err != DB_SUCCESS)
2953
return ib_err_t_to_drizzle_error(getTable()->getSession(), err);
2955
tuple= ib_tuple_clear(tuple);
2956
ret= read_row_from_haildb(getTable()->getSession(), buf, cursor, tuple,
2958
share->has_hidden_primary_key,
2959
&hidden_autoinc_pkey_position);
2960
advance_cursor= true;
2965
int HailDBCursor::extra(enum ha_extra_function operation)
2969
case HA_EXTRA_FLUSH:
2971
blobroot->free_root(MYF(0));
2973
case HA_EXTRA_WRITE_CAN_REPLACE:
2974
write_can_replace= true;
2976
case HA_EXTRA_WRITE_CANNOT_REPLACE:
2977
write_can_replace= false;
2986
static int create_table_message_table()
2988
ib_tbl_sch_t schema;
2989
ib_idx_sch_t index_schema;
2990
ib_trx_t transaction;
2992
ib_err_t err, rollback_err;
2993
ib_bool_t create_db_err;
2995
create_db_err= ib_database_create("data_dictionary");
2996
if (create_db_err != IB_TRUE)
2999
err= ib_table_schema_create(HAILDB_TABLE_DEFINITIONS_TABLE, &schema,
3001
if (err != DB_SUCCESS)
3004
err= ib_table_schema_add_col(schema, "table_name", IB_VARCHAR, IB_COL_NONE, 0,
3005
IB_MAX_TABLE_NAME_LEN);
3006
if (err != DB_SUCCESS)
3009
err= ib_table_schema_add_col(schema, "message", IB_BLOB, IB_COL_NONE, 0, 0);
3010
if (err != DB_SUCCESS)
3013
err= ib_table_schema_add_index(schema, "PRIMARY_KEY", &index_schema);
3014
if (err != DB_SUCCESS)
3017
err= ib_index_schema_add_col(index_schema, "table_name", 0);
3018
if (err != DB_SUCCESS)
3020
err= ib_index_schema_set_clustered(index_schema);
3021
if (err != DB_SUCCESS)
3024
transaction= ib_trx_begin(IB_TRX_REPEATABLE_READ);
3025
err= ib_schema_lock_exclusive(transaction);
3026
if (err != DB_SUCCESS)
3029
err= ib_table_create(transaction, schema, &table_id);
3030
if (err != DB_SUCCESS)
3033
err= ib_trx_commit(transaction);
3034
if (err != DB_SUCCESS)
3037
ib_table_schema_delete(schema);
3041
ib_schema_unlock(transaction);
3042
rollback_err= ib_trx_rollback(transaction);
3043
assert(rollback_err == DB_SUCCESS);
3045
ib_table_schema_delete(schema);
3049
static bool innobase_use_doublewrite= true;
3050
static bool srv_file_per_table= false;
3051
static bool innobase_adaptive_hash_index;
3052
static bool srv_adaptive_flushing;
3053
static bool innobase_print_verbose_log;
3054
static bool innobase_rollback_on_timeout;
3055
static bool innobase_create_status_file;
3056
static bool srv_use_sys_malloc;
3057
static string innobase_file_format_name;
3058
typedef constrained_check<unsigned int, 1000, 1> autoextend_constraint;
3059
static autoextend_constraint srv_auto_extend_increment;
3060
typedef constrained_check<size_t, SIZE_MAX, 5242880, 1048576> buffer_pool_constraint;
3061
static buffer_pool_constraint innobase_buffer_pool_size;
3062
typedef constrained_check<size_t, SIZE_MAX, 512, 1024> additional_mem_pool_constraint;
3063
static additional_mem_pool_constraint innobase_additional_mem_pool_size;
3064
static bool innobase_use_checksums= true;
3065
typedef constrained_check<unsigned int, UINT_MAX, 100> io_capacity_constraint;
3066
typedef constrained_check<uint32_t, 2, 0> trinary_constraint;
3067
static trinary_constraint innobase_fast_shutdown;
3068
static trinary_constraint srv_flush_log_at_trx_commit;
3069
typedef constrained_check<uint32_t, 6, 0> force_recovery_constraint;
3070
static force_recovery_constraint innobase_force_recovery;
3071
typedef constrained_check<int64_t, INT64_MAX, 1024*1024, 1024*1024> log_file_constraint;
3072
static log_file_constraint haildb_log_file_size;
3074
static io_capacity_constraint srv_io_capacity;
3075
typedef constrained_check<unsigned int, 100, 2> log_files_in_group_constraint;
3076
static log_files_in_group_constraint haildb_log_files_in_group;
3077
typedef constrained_check<unsigned int, 1024*1024*1024, 1> lock_wait_constraint;
3078
static lock_wait_constraint innobase_lock_wait_timeout;
3079
typedef constrained_check<long, LONG_MAX, 256*1024, 1024> log_buffer_size_constraint;
3080
static log_buffer_size_constraint innobase_log_buffer_size;
3081
typedef constrained_check<unsigned int, 97, 5> lru_old_blocks_constraint;
3082
static lru_old_blocks_constraint innobase_lru_old_blocks_pct;
3083
typedef constrained_check<unsigned int, 99, 0> max_dirty_pages_constraint;
3084
static max_dirty_pages_constraint haildb_max_dirty_pages_pct;
3085
static uint64_constraint haildb_max_purge_lag;
3086
static uint64_constraint haildb_sync_spin_loops;
3087
typedef constrained_check<uint32_t, UINT32_MAX, 10> open_files_constraint;
3088
static open_files_constraint haildb_open_files;
3089
typedef constrained_check<unsigned int, 64, 1> io_threads_constraint;
3090
static io_threads_constraint haildb_read_io_threads;
3091
static io_threads_constraint haildb_write_io_threads;
3094
static uint32_t innobase_lru_block_access_recency;
3098
static int haildb_file_format_name_validate(Session*, set_var *var)
3101
const char *format= var->value->str_value.ptr();
3105
ib_err_t err= ib_cfg_set_text("file_format", format);
3107
if (err == DB_SUCCESS)
3109
innobase_file_format_name= format;
3116
static void haildb_lru_old_blocks_pct_update(Session*, sql_var_t)
3118
int ret= ib_cfg_set_int("lru_old_blocks_pct", static_cast<uint32_t>(innobase_lru_old_blocks_pct));
3122
static void haildb_lru_block_access_recency_update(Session*, sql_var_t)
3124
int ret= ib_cfg_set_int("lru_block_access_recency", static_cast<uint32_t>(innobase_lru_block_access_recency));
3128
static void haildb_status_file_update(Session*, sql_var_t)
3132
if (innobase_create_status_file)
3133
err= ib_cfg_set_bool_on("status_file");
3135
err= ib_cfg_set_bool_off("status_file");
3139
extern "C" int haildb_errmsg_callback(ib_msg_stream_t, const char *fmt, ...);
3142
extern bool volatile shutdown_in_progress;
3145
extern "C" int haildb_errmsg_callback(ib_msg_stream_t, const char *fmt, ...)
3149
va_start(args, fmt);
3150
if (not shutdown_in_progress)
3152
r= plugin::ErrorMessage::vprintf(error::WARN, fmt, args);
3156
vfprintf(stderr, fmt, args);
3163
static int haildb_init(drizzled::module::Context &context)
3165
haildb_system_table_names.insert(std::string("HAILDB_SYS_TABLES"));
3166
haildb_system_table_names.insert(std::string("HAILDB_SYS_COLUMNS"));
3167
haildb_system_table_names.insert(std::string("HAILDB_SYS_INDEXES"));
3168
haildb_system_table_names.insert(std::string("HAILDB_SYS_FIELDS"));
3169
haildb_system_table_names.insert(std::string("HAILDB_SYS_FOREIGN"));
3170
haildb_system_table_names.insert(std::string("HAILDB_SYS_FOREIGN_COLS"));
3172
const module::option_map &vm= context.getOptions();
3174
/* Inverted Booleans */
3176
innobase_adaptive_hash_index= (vm.count("disable-adaptive-hash-index")) ? false : true;
3177
srv_adaptive_flushing= (vm.count("disable-adaptive-flushing")) ? false : true;
3178
innobase_use_checksums= (vm.count("disable-checksums")) ? false : true;
3179
innobase_use_doublewrite= (vm.count("disable-doublewrite")) ? false : true;
3180
innobase_print_verbose_log= (vm.count("disable-print-verbose-log")) ? false : true;
3181
srv_use_sys_malloc= (vm.count("use-internal-malloc")) ? false : true;
3187
if (err != DB_SUCCESS)
3190
ib_logger_set(haildb_errmsg_callback, NULL);
3192
if (not vm["data-home-dir"].as<string>().empty())
3194
err= ib_cfg_set_text("data_home_dir", vm["data-home-dir"].as<string>().c_str());
3195
if (err != DB_SUCCESS)
3199
if (vm.count("log-group-home-dir"))
3201
err= ib_cfg_set_text("log_group_home_dir", vm["log-group-home-dir"].as<string>().c_str());
3202
if (err != DB_SUCCESS)
3206
if (innobase_print_verbose_log)
3207
err= ib_cfg_set_bool_on("print_verbose_log");
3209
err= ib_cfg_set_bool_off("print_verbose_log");
3211
if (err != DB_SUCCESS)
3214
if (innobase_rollback_on_timeout)
3215
err= ib_cfg_set_bool_on("rollback_on_timeout");
3217
err= ib_cfg_set_bool_off("rollback_on_timeout");
3219
if (err != DB_SUCCESS)
3222
if (innobase_use_doublewrite)
3223
err= ib_cfg_set_bool_on("doublewrite");
3225
err= ib_cfg_set_bool_off("doublewrite");
3227
if (err != DB_SUCCESS)
3230
if (innobase_adaptive_hash_index)
3231
err= ib_cfg_set_bool_on("adaptive_hash_index");
3233
err= ib_cfg_set_bool_off("adaptive_hash_index");
3235
if (err != DB_SUCCESS)
3238
if (srv_adaptive_flushing)
3239
err= ib_cfg_set_bool_on("adaptive_flushing");
3241
err= ib_cfg_set_bool_off("adaptive_flushing");
3243
if (err != DB_SUCCESS)
3246
err= ib_cfg_set_int("additional_mem_pool_size", innobase_additional_mem_pool_size.get());
3247
if (err != DB_SUCCESS)
3250
err= ib_cfg_set_int("autoextend_increment", srv_auto_extend_increment.get());
3251
if (err != DB_SUCCESS)
3254
err= ib_cfg_set_int("buffer_pool_size", innobase_buffer_pool_size.get());
3255
if (err != DB_SUCCESS)
3258
err= ib_cfg_set_int("io_capacity", srv_io_capacity.get());
3259
if (err != DB_SUCCESS)
3262
if (srv_file_per_table)
3263
err= ib_cfg_set_bool_on("file_per_table");
3265
err= ib_cfg_set_bool_off("file_per_table");
3267
if (err != DB_SUCCESS)
3270
err= ib_cfg_set_int("flush_log_at_trx_commit",
3271
srv_flush_log_at_trx_commit.get());
3272
if (err != DB_SUCCESS)
3275
if (vm.count("flush-method") != 0)
3277
err= ib_cfg_set_text("flush_method",
3278
vm["flush-method"].as<string>().c_str());
3279
if (err != DB_SUCCESS)
3283
err= ib_cfg_set_int("force_recovery",
3284
innobase_force_recovery.get());
3285
if (err != DB_SUCCESS)
3288
err= ib_cfg_set_text("data_file_path", vm["data-file-path"].as<string>().c_str());
3289
if (err != DB_SUCCESS)
3292
err= ib_cfg_set_int("log_file_size", haildb_log_file_size.get());
3293
if (err != DB_SUCCESS)
3296
err= ib_cfg_set_int("log_buffer_size", innobase_log_buffer_size.get());
3297
if (err != DB_SUCCESS)
3300
err= ib_cfg_set_int("log_files_in_group", haildb_log_files_in_group.get());
3301
if (err != DB_SUCCESS)
3304
err= ib_cfg_set_int("checksums", innobase_use_checksums);
3305
if (err != DB_SUCCESS)
3308
err= ib_cfg_set_int("lock_wait_timeout", innobase_lock_wait_timeout.get());
3309
if (err != DB_SUCCESS)
3312
err= ib_cfg_set_int("max_dirty_pages_pct", haildb_max_dirty_pages_pct.get());
3313
if (err != DB_SUCCESS)
3316
err= ib_cfg_set_int("max_purge_lag", haildb_max_purge_lag.get());
3317
if (err != DB_SUCCESS)
3320
err= ib_cfg_set_int("open_files", haildb_open_files.get());
3321
if (err != DB_SUCCESS)
3324
err= ib_cfg_set_int("read_io_threads", haildb_read_io_threads.get());
3325
if (err != DB_SUCCESS)
3328
err= ib_cfg_set_int("write_io_threads", haildb_write_io_threads.get());
3329
if (err != DB_SUCCESS)
3332
err= ib_cfg_set_int("sync_spin_loops", haildb_sync_spin_loops.get());
3333
if (err != DB_SUCCESS)
3336
if (srv_use_sys_malloc)
3337
err= ib_cfg_set_bool_on("use_sys_malloc");
3339
err= ib_cfg_set_bool_off("use_sys_malloc");
3341
if (err != DB_SUCCESS)
3344
err= ib_startup(innobase_file_format_name.c_str());
3345
if (err != DB_SUCCESS)
3348
create_table_message_table();
3350
haildb_engine= new HailDBEngine("InnoDB");
3351
context.add(haildb_engine);
3352
context.registerVariable(new sys_var_bool_ptr_readonly("adaptive_hash_index",
3353
&innobase_adaptive_hash_index));
3354
context.registerVariable(new sys_var_bool_ptr_readonly("adaptive_flushing",
3355
&srv_adaptive_flushing));
3356
context.registerVariable(new sys_var_constrained_value_readonly<size_t>("additional_mem_pool_size",innobase_additional_mem_pool_size));
3357
context.registerVariable(new sys_var_constrained_value_readonly<unsigned int>("autoextend_increment", srv_auto_extend_increment));
3358
context.registerVariable(new sys_var_constrained_value_readonly<size_t>("buffer_pool_size", innobase_buffer_pool_size));
3359
context.registerVariable(new sys_var_bool_ptr_readonly("checksums",
3360
&innobase_use_checksums));
3361
context.registerVariable(new sys_var_bool_ptr_readonly("doublewrite",
3362
&innobase_use_doublewrite));
3363
context.registerVariable(new sys_var_const_string_val("data_file_path",
3364
vm["data-file-path"].as<string>()));
3365
context.registerVariable(new sys_var_const_string_val("data_home_dir",
3366
vm["data-home-dir"].as<string>()));
3367
context.registerVariable(new sys_var_constrained_value_readonly<unsigned int>("io_capacity", srv_io_capacity));
3368
context.registerVariable(new sys_var_constrained_value_readonly<uint32_t>("fast_shutdown", innobase_fast_shutdown));
3369
context.registerVariable(new sys_var_bool_ptr_readonly("file_per_table",
3370
&srv_file_per_table));
3371
context.registerVariable(new sys_var_bool_ptr_readonly("rollback_on_timeout",
3372
&innobase_rollback_on_timeout));
3373
context.registerVariable(new sys_var_bool_ptr_readonly("print_verbose_log",
3374
&innobase_print_verbose_log));
3375
context.registerVariable(new sys_var_bool_ptr("status_file",
3376
&innobase_create_status_file,
3377
haildb_status_file_update));
3378
context.registerVariable(new sys_var_bool_ptr_readonly("use_sys_malloc",
3379
&srv_use_sys_malloc));
3380
context.registerVariable(new sys_var_std_string("file_format",
3381
innobase_file_format_name,
3382
haildb_file_format_name_validate));
3383
context.registerVariable(new sys_var_constrained_value_readonly<uint32_t>("flush_log_at_trx_commit", srv_flush_log_at_trx_commit));
3384
context.registerVariable(new sys_var_const_string_val("flush_method",
3385
vm.count("flush-method") ? vm["flush-method"].as<string>() : ""));
3386
context.registerVariable(new sys_var_constrained_value_readonly<uint32_t>("force_recovery", innobase_force_recovery));
3387
context.registerVariable(new sys_var_const_string_val("log_group_home_dir",
3388
vm.count("log-group-home-dir") ? vm["log-group-home-dir"].as<string>() : ""));
3389
context.registerVariable(new sys_var_constrained_value<int64_t>("log_file_size", haildb_log_file_size));
3390
context.registerVariable(new sys_var_constrained_value_readonly<unsigned int>("log_files_in_group", haildb_log_files_in_group));
3391
context.registerVariable(new sys_var_constrained_value_readonly<unsigned int>("lock_wait_timeout", innobase_lock_wait_timeout));
3392
context.registerVariable(new sys_var_constrained_value_readonly<long>("log_buffer_size", innobase_log_buffer_size));
3393
context.registerVariable(new sys_var_constrained_value<unsigned int>("lru_old_blocks_pct", innobase_lru_old_blocks_pct, haildb_lru_old_blocks_pct_update));
3394
context.registerVariable(new sys_var_uint32_t_ptr("lru_block_access_recency",
3395
&innobase_lru_block_access_recency,
3396
haildb_lru_block_access_recency_update));
3397
context.registerVariable(new sys_var_constrained_value_readonly<unsigned int>("max_dirty_pages_pct", haildb_max_dirty_pages_pct));
3398
context.registerVariable(new sys_var_constrained_value_readonly<uint64_t>("max_purge_lag", haildb_max_purge_lag));
3399
context.registerVariable(new sys_var_constrained_value_readonly<uint64_t>("sync_spin_loops", haildb_sync_spin_loops));
3400
context.registerVariable(new sys_var_constrained_value_readonly<uint32_t>("open_files", haildb_open_files));
3401
context.registerVariable(new sys_var_constrained_value_readonly<unsigned int>("read_io_threads", haildb_read_io_threads));
3402
context.registerVariable(new sys_var_constrained_value_readonly<unsigned int>("write_io_threads", haildb_write_io_threads));
3404
haildb_datadict_dump_func_initialize(context);
3405
config_table_function_initialize(context);
3406
status_table_function_initialize(context);
3410
fprintf(stderr, _("Error starting HailDB %d (%s)\n"),
3411
err, ib_strerror(err));
3416
HailDBEngine::~HailDBEngine()
3419
ib_shutdown_t shutdown_flag= IB_SHUTDOWN_NORMAL;
3421
if (innobase_fast_shutdown.get() == 1)
3422
shutdown_flag= IB_SHUTDOWN_NO_IBUFMERGE_PURGE;
3423
else if (innobase_fast_shutdown.get() == 2)
3424
shutdown_flag= IB_SHUTDOWN_NO_BUFPOOL_FLUSH;
3426
err= ib_shutdown(shutdown_flag);
3428
if (err != DB_SUCCESS)
3430
fprintf(stderr,"Error %d shutting down HailDB!\n", err);
3436
static void init_options(drizzled::module::option_context &context)
3438
context("disable-adaptive-hash-index",
3439
N_("Disable HailDB adaptive hash index (enabled by default)."));
3440
context("disable-adaptive-flushing",
3441
N_("Do not attempt to flush dirty pages to avoid IO bursts at checkpoints."));
3442
context("additional-mem-pool-size",
3443
po::value<additional_mem_pool_constraint>(&innobase_additional_mem_pool_size)->default_value(8*1024*1024L),
3444
N_("Size of a memory pool HailDB uses to store data dictionary information and other internal data structures."));
3445
context("autoextend-increment",
3446
po::value<autoextend_constraint>(&srv_auto_extend_increment)->default_value(8),
3447
N_("Data file autoextend increment in megabytes"));
3448
context("buffer-pool-size",
3449
po::value<buffer_pool_constraint>(&innobase_buffer_pool_size)->default_value(128*1024*1024L),
3450
N_("The size of the memory buffer HailDB uses to cache data and indexes of its tables."));
3451
context("data-home-dir",
3452
po::value<string>()->default_value(""),
3453
N_("The common part for HailDB table spaces."));
3454
context("disable-checksums",
3455
N_("Disable HailDB checksums validation (enabled by default)."));
3456
context("disable-doublewrite",
3457
N_("Disable HailDB doublewrite buffer (enabled by default)."));
3458
context("io-capacity",
3459
po::value<io_capacity_constraint>(&srv_io_capacity)->default_value(200),
3460
N_("Number of IOPs the server can do. Tunes the background IO rate"));
3461
context("fast-shutdown",
3462
po::value<trinary_constraint>(&innobase_fast_shutdown)->default_value(1),
3463
N_("Speeds up the shutdown process of the HailDB storage engine. Possible values are 0, 1 (faster) or 2 (fastest - crash-like)."));
3464
context("file-per-table",
3465
po::value<bool>(&srv_file_per_table)->default_value(false)->zero_tokens(),
3466
N_("Stores each HailDB table to an .ibd file in the database dir."));
3467
context("file-format",
3468
po::value<string>(&innobase_file_format_name)->default_value("Barracuda"),
3469
N_("File format to use for new tables in .ibd files."));
3470
context("flush-log-at-trx-commit",
3471
po::value<trinary_constraint>(&srv_flush_log_at_trx_commit)->default_value(1),
3472
N_("Set to 0 (write and flush once per second),1 (write and flush at each commit) or 2 (write at commit, flush once per second)."));
3473
context("flush-method",
3474
po::value<string>(),
3475
N_("With which method to flush data."));
3476
context("force-recovery",
3477
po::value<force_recovery_constraint>(&innobase_force_recovery)->default_value(0),
3478
N_("Helps to save your data in case the disk image of the database becomes corrupt."));
3479
context("data-file-path",
3480
po::value<string>()->default_value("ibdata1:10M:autoextend"),
3481
N_("Path to individual files and their sizes."));
3482
context("log-group-home-dir",
3483
po::value<string>(),
3484
N_("Path to HailDB log files."));
3485
context("log-file-size",
3486
po::value<log_file_constraint>(&haildb_log_file_size)->default_value(20*1024*1024L),
3487
N_("Size of each log file in a log group."));
3488
context("haildb-log-files-in-group",
3489
po::value<log_files_in_group_constraint>(&haildb_log_files_in_group)->default_value(2),
3490
N_("Number of log files in the log group. HailDB writes to the files in a circular fashion. Value 3 is recommended here."));
3491
context("lock-wait-timeout",
3492
po::value<lock_wait_constraint>(&innobase_lock_wait_timeout)->default_value(5),
3493
N_("Timeout in seconds an HailDB transaction may wait for a lock before being rolled back. Values above 100000000 disable the timeout."));
3494
context("log-buffer-size",
3495
po::value<log_buffer_size_constraint>(&innobase_log_buffer_size)->default_value(8*1024*1024L),
3496
N_("The size of the buffer which HailDB uses to write log to the log files on disk."));
3497
context("lru-old-blocks-pct",
3498
po::value<lru_old_blocks_constraint>(&innobase_lru_old_blocks_pct)->default_value(37),
3499
N_("Sets the point in the LRU list from where all pages are classified as old (Advanced users)"));
3500
context("lru-block-access-recency",
3501
po::value<uint32_t>(&innobase_lru_block_access_recency)->default_value(0),
3502
N_("Milliseconds between accesses to a block at which it is made young. 0=disabled (Advanced users)"));
3503
context("max-dirty-pages-pct",
3504
po::value<max_dirty_pages_constraint>(&haildb_max_dirty_pages_pct)->default_value(75),
3505
N_("Percentage of dirty pages allowed in bufferpool."));
3506
context("max-purge-lag",
3507
po::value<uint64_constraint>(&haildb_max_purge_lag)->default_value(0),
3508
N_("Desired maximum length of the purge queue (0 = no limit)"));
3509
context("rollback-on-timeout",
3510
po::value<bool>(&innobase_rollback_on_timeout)->default_value(false)->zero_tokens(),
3511
N_("Roll back the complete transaction on lock wait timeout, for 4.x compatibility (disabled by default)"));
3512
context("open-files",
3513
po::value<open_files_constraint>(&haildb_open_files)->default_value(300),
3514
N_("How many files at the maximum HailDB keeps open at the same time."));
3515
context("read-io-threads",
3516
po::value<io_threads_constraint>(&haildb_read_io_threads)->default_value(4),
3517
N_("Number of background read I/O threads in HailDB."));
3518
context("write-io-threads",
3519
po::value<io_threads_constraint>(&haildb_write_io_threads)->default_value(4),
3520
N_("Number of background write I/O threads in HailDB."));
3521
context("disable-print-verbose-log",
3522
N_("Disable if you want to reduce the number of messages written to the log (default: enabled)."));
3523
context("status-file",
3524
po::value<bool>(&innobase_create_status_file)->default_value(false)->zero_tokens(),
3525
N_("Enable SHOW HAILDB STATUS output in the log"));
3526
context("sync-spin-loops",
3527
po::value<uint64_constraint>(&haildb_sync_spin_loops)->default_value(30L),
3528
N_("Count of spin-loop rounds in HailDB mutexes (30 by default)"));
3529
context("use-internal-malloc",
3530
N_("Use HailDB's internal memory allocator instead of the OS memory allocator"));
3533
DRIZZLE_DECLARE_PLUGIN
3539
"Transactional Storage Engine using the HailDB Library",
3541
haildb_init, /* Plugin Init */
3543
init_options /* config options */
3545
DRIZZLE_DECLARE_PLUGIN_END;