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 <boost/program_options.hpp>
108
#include <drizzled/module/option_map.h>
110
#include <drizzled/charset.h>
112
namespace po= boost::program_options;
113
#include <boost/algorithm/string.hpp>
116
using namespace google;
117
using namespace drizzled;
119
int read_row_from_haildb(Session *session, unsigned char* buf, ib_crsr_t cursor, ib_tpl_t tuple, Table* table, bool has_hidden_primary_key, uint64_t *hidden_pkey, drizzled::memory::Root **blobroot= NULL);
120
static void fill_ib_search_tpl_from_drizzle_key(ib_tpl_t search_tuple,
121
const drizzled::KeyInfo *key_info,
122
const unsigned char *key_ptr,
124
static void store_key_value_from_haildb(KeyInfo *key_info, unsigned char* ref, int ref_len, const unsigned char *record);
126
#define HAILDB_EXT ".EID"
128
const char HAILDB_TABLE_DEFINITIONS_TABLE[]= "data_dictionary/haildb_table_definitions";
129
const string statement_savepoint_name("STATEMENT");
131
static boost::unordered_set<std::string> haildb_system_table_names;
134
static const char *HailDBCursor_exts[] = {
138
class HailDBEngine : public drizzled::plugin::TransactionalStorageEngine
141
HailDBEngine(const string &name_arg)
142
: drizzled::plugin::TransactionalStorageEngine(name_arg,
144
HTON_CAN_INDEX_BLOBS |
146
HTON_PARTIAL_COLUMN_READ |
147
HTON_HAS_DOES_TRANSACTIONS)
149
table_definition_ext= HAILDB_EXT;
154
virtual Cursor *create(Table &table)
156
return new HailDBCursor(*this, table);
159
const char **bas_ext() const {
160
return HailDBCursor_exts;
163
bool validateCreateTableOption(const std::string &key,
164
const std::string &state);
166
int doCreateTable(Session&,
168
const drizzled::identifier::Table &identifier,
169
drizzled::message::Table& proto);
171
int doDropTable(Session&, const identifier::Table &identifier);
173
int doRenameTable(drizzled::Session&,
174
const drizzled::identifier::Table&,
175
const drizzled::identifier::Table&);
177
int doGetTableDefinition(Session& session,
178
const identifier::Table &identifier,
179
drizzled::message::Table &table_proto);
181
bool doDoesTableExist(Session&, const identifier::Table &identifier);
184
void getTableNamesInSchemaFromHailDB(const drizzled::identifier::Schema &schema,
185
drizzled::plugin::TableNameList *set_of_names,
186
drizzled::identifier::Table::vector *identifiers);
189
void doGetTableIdentifiers(drizzled::CachedDirectory &,
190
const drizzled::identifier::Schema &schema,
191
drizzled::identifier::Table::vector &identifiers);
193
/* The following defines can be increased if necessary */
194
uint32_t max_supported_keys() const { return 1000; }
195
uint32_t max_supported_key_length() const { return 3500; }
196
uint32_t max_supported_key_part_length() const { return 767; }
198
uint32_t index_flags(enum ha_key_alg) const
200
return (HA_READ_NEXT |
206
virtual int doStartTransaction(Session *session,
207
start_transaction_option_t options);
208
virtual void doStartStatement(Session *session);
209
virtual void doEndStatement(Session *session);
211
virtual int doSetSavepoint(Session* session,
212
drizzled::NamedSavepoint &savepoint);
213
virtual int doRollbackToSavepoint(Session* session,
214
drizzled::NamedSavepoint &savepoint);
215
virtual int doReleaseSavepoint(Session* session,
216
drizzled::NamedSavepoint &savepoint);
217
virtual int doCommit(Session* session, bool all);
218
virtual int doRollback(Session* session, bool all);
220
typedef std::map<std::string, HailDBTableShare*> HailDBMap;
221
HailDBMap haildb_open_tables;
222
HailDBTableShare *findOpenTable(const std::string table_name);
223
void addOpenTable(const std::string &table_name, HailDBTableShare *);
224
void deleteOpenTable(const std::string &table_name);
226
uint64_t getInitialAutoIncrementValue(HailDBCursor *cursor);
227
uint64_t getHiddenPrimaryKeyInitialAutoIncrementValue(HailDBCursor *cursor);
231
static drizzled::plugin::StorageEngine *haildb_engine= NULL;
234
static ib_trx_t* get_trx(Session* session)
236
return (ib_trx_t*) session->getEngineData(haildb_engine);
239
/* This is a superset of the map from innobase plugin.
240
Unlike innobase plugin we don't act on errors here, we just
242
static int ib_err_t_to_drizzle_error(Session* session, ib_err_t err)
254
return ER_QUERY_INTERRUPTED; // FIXME: is this correct?
256
case DB_OUT_OF_MEMORY:
257
return HA_ERR_OUT_OF_MEM;
259
case DB_DUPLICATE_KEY:
260
return HA_ERR_FOUND_DUPP_KEY;
262
case DB_FOREIGN_DUPLICATE_KEY:
263
return HA_ERR_FOREIGN_DUPLICATE_KEY;
265
case DB_MISSING_HISTORY:
266
return HA_ERR_TABLE_DEF_CHANGED;
268
case DB_RECORD_NOT_FOUND:
269
return HA_ERR_NO_ACTIVE_RECORD;
272
/* HailDB will roll back a transaction itself due to DB_DEADLOCK.
273
This means we have to tell Drizzle about it */
274
session->markTransactionForRollback(true);
275
return HA_ERR_LOCK_DEADLOCK;
277
case DB_LOCK_WAIT_TIMEOUT:
278
return HA_ERR_LOCK_WAIT_TIMEOUT;
280
case DB_NO_REFERENCED_ROW:
281
return HA_ERR_NO_REFERENCED_ROW;
283
case DB_ROW_IS_REFERENCED:
284
return HA_ERR_ROW_IS_REFERENCED;
286
case DB_CANNOT_ADD_CONSTRAINT:
287
return HA_ERR_CANNOT_ADD_FOREIGN;
289
case DB_CANNOT_DROP_CONSTRAINT:
290
return HA_ERR_ROW_IS_REFERENCED; /* misleading. should have new err code */
292
case DB_COL_APPEARS_TWICE_IN_INDEX:
294
return HA_ERR_CRASHED;
296
case DB_MUST_GET_MORE_FILE_SPACE:
297
case DB_OUT_OF_FILE_SPACE:
298
return HA_ERR_RECORD_FILE_FULL;
300
case DB_TABLE_IS_BEING_USED:
301
return HA_ERR_WRONG_COMMAND;
303
case DB_TABLE_NOT_FOUND:
304
return HA_ERR_NO_SUCH_TABLE;
306
case DB_TOO_BIG_RECORD:
307
return HA_ERR_TO_BIG_ROW;
309
case DB_NO_SAVEPOINT:
310
return HA_ERR_NO_SAVEPOINT;
312
case DB_LOCK_TABLE_FULL:
313
return HA_ERR_LOCK_TABLE_FULL;
315
case DB_PRIMARY_KEY_IS_NULL:
316
return ER_PRIMARY_CANT_HAVE_NULL;
318
case DB_TOO_MANY_CONCURRENT_TRXS:
319
return HA_ERR_RECORD_FILE_FULL; /* need better error code */
321
case DB_END_OF_INDEX:
322
return HA_ERR_END_OF_FILE;
325
return HA_ERR_UNSUPPORTED;
329
static ib_trx_level_t tx_isolation_to_ib_trx_level(enum_tx_isolation level)
333
case ISO_REPEATABLE_READ:
334
return IB_TRX_REPEATABLE_READ;
335
case ISO_READ_COMMITTED:
336
return IB_TRX_READ_COMMITTED;
337
case ISO_SERIALIZABLE:
338
return IB_TRX_SERIALIZABLE;
339
case ISO_READ_UNCOMMITTED:
340
return IB_TRX_READ_UNCOMMITTED;
344
return IB_TRX_REPEATABLE_READ;
347
int HailDBEngine::doStartTransaction(Session *session,
348
start_transaction_option_t options)
350
ib_trx_t *transaction;
351
ib_trx_level_t isolation_level;
355
transaction= get_trx(session);
356
isolation_level= tx_isolation_to_ib_trx_level(session->getTxIsolation());
357
*transaction= ib_trx_begin(isolation_level);
359
return *transaction == NULL;
362
void HailDBEngine::doStartStatement(Session *session)
364
if(*get_trx(session) == NULL)
365
doStartTransaction(session, START_TRANS_NO_OPTIONS);
367
ib_savepoint_take(*get_trx(session), statement_savepoint_name.c_str(),
368
statement_savepoint_name.length());
371
void HailDBEngine::doEndStatement(Session *)
375
int HailDBEngine::doSetSavepoint(Session* session,
376
drizzled::NamedSavepoint &savepoint)
378
ib_trx_t *transaction= get_trx(session);
379
ib_savepoint_take(*transaction, savepoint.getName().c_str(),
380
savepoint.getName().length());
384
int HailDBEngine::doRollbackToSavepoint(Session* session,
385
drizzled::NamedSavepoint &savepoint)
387
ib_trx_t *transaction= get_trx(session);
390
err= ib_savepoint_rollback(*transaction, savepoint.getName().c_str(),
391
savepoint.getName().length());
393
return ib_err_t_to_drizzle_error(session, err);
396
int HailDBEngine::doReleaseSavepoint(Session* session,
397
drizzled::NamedSavepoint &savepoint)
399
ib_trx_t *transaction= get_trx(session);
402
err= ib_savepoint_release(*transaction, savepoint.getName().c_str(),
403
savepoint.getName().length());
404
if (err != DB_SUCCESS)
405
return ib_err_t_to_drizzle_error(session, err);
410
int HailDBEngine::doCommit(Session* session, bool all)
413
ib_trx_t *transaction= get_trx(session);
417
err= ib_trx_commit(*transaction);
419
if (err != DB_SUCCESS)
420
return ib_err_t_to_drizzle_error(session, err);
428
int HailDBEngine::doRollback(Session* session, bool all)
431
ib_trx_t *transaction= get_trx(session);
435
if (ib_trx_state(*transaction) == IB_TRX_NOT_STARTED)
436
err= ib_trx_release(*transaction);
438
err= ib_trx_rollback(*transaction);
440
if (err != DB_SUCCESS)
441
return ib_err_t_to_drizzle_error(session, err);
447
if (ib_trx_state(*transaction) == IB_TRX_NOT_STARTED)
450
err= ib_savepoint_rollback(*transaction, statement_savepoint_name.c_str(),
451
statement_savepoint_name.length());
452
if (err != DB_SUCCESS)
453
return ib_err_t_to_drizzle_error(session, err);
459
HailDBTableShare *HailDBEngine::findOpenTable(const string table_name)
461
HailDBMap::iterator find_iter=
462
haildb_open_tables.find(table_name);
464
if (find_iter != haildb_open_tables.end())
465
return (*find_iter).second;
470
void HailDBEngine::addOpenTable(const string &table_name, HailDBTableShare *share)
472
haildb_open_tables[table_name]= share;
475
void HailDBEngine::deleteOpenTable(const string &table_name)
477
haildb_open_tables.erase(table_name);
480
static pthread_mutex_t haildb_mutex= PTHREAD_MUTEX_INITIALIZER;
482
uint64_t HailDBCursor::getHiddenPrimaryKeyInitialAutoIncrementValue()
486
ib_trx_t transaction= *get_trx(getTable()->in_use);
487
ib_cursor_attach_trx(cursor, transaction);
488
tuple= ib_clust_read_tuple_create(cursor);
489
err= ib_cursor_last(cursor);
490
assert(err == DB_SUCCESS || err == DB_END_OF_INDEX); // Probably a FIXME
491
err= ib_cursor_read_row(cursor, tuple);
492
if (err == DB_RECORD_NOT_FOUND)
496
assert (err == DB_SUCCESS);
497
err= ib_tuple_read_u64(tuple, getTable()->getShare()->sizeFields(), &nr);
500
ib_tuple_delete(tuple);
502
err= ib_cursor_reset(cursor);
503
assert(err == DB_SUCCESS);
507
uint64_t HailDBCursor::getInitialAutoIncrementValue()
512
(void) extra(HA_EXTRA_KEYREAD);
513
getTable()->mark_columns_used_by_index_no_reset(getTable()->getShare()->next_number_index);
514
doStartIndexScan(getTable()->getShare()->next_number_index, 1);
515
if (getTable()->getShare()->next_number_keypart == 0)
516
{ // Autoincrement at key-start
517
error=index_last(getTable()->getUpdateRecord());
521
unsigned char key[MAX_KEY_LENGTH];
522
key_copy(key, getTable()->getInsertRecord(),
523
getTable()->key_info + getTable()->getShare()->next_number_index,
524
getTable()->getShare()->next_number_key_offset);
525
error= index_read_map(getTable()->getUpdateRecord(), key,
526
make_prev_keypart_map(getTable()->getShare()->next_number_keypart),
527
HA_READ_PREFIX_LAST);
533
nr= ((uint64_t) getTable()->found_next_number_field->
534
val_int_offset(getTable()->getShare()->rec_buff_length)+1);
536
(void) extra(HA_EXTRA_NO_KEYREAD);
538
if (getTable()->getShare()->getTableMessage()->options().auto_increment_value() > nr)
539
nr= getTable()->getShare()->getTableMessage()->options().auto_increment_value();
544
HailDBTableShare::HailDBTableShare(const char* name, bool hidden_primary_key)
545
: use_count(0), has_hidden_primary_key(hidden_primary_key)
547
table_name.assign(name);
550
uint64_t HailDBEngine::getInitialAutoIncrementValue(HailDBCursor *cursor)
552
doStartTransaction(current_session, START_TRANS_NO_OPTIONS);
553
uint64_t initial_auto_increment_value= cursor->getInitialAutoIncrementValue();
554
doCommit(current_session, true);
556
return initial_auto_increment_value;
559
uint64_t HailDBEngine::getHiddenPrimaryKeyInitialAutoIncrementValue(HailDBCursor *cursor)
561
doStartTransaction(current_session, START_TRANS_NO_OPTIONS);
562
uint64_t initial_auto_increment_value= cursor->getHiddenPrimaryKeyInitialAutoIncrementValue();
563
doCommit(current_session, true);
565
return initial_auto_increment_value;
568
HailDBTableShare *HailDBCursor::get_share(const char *table_name, bool has_hidden_primary_key, int *rc)
570
pthread_mutex_lock(&haildb_mutex);
572
HailDBEngine *a_engine= static_cast<HailDBEngine *>(getEngine());
573
share= a_engine->findOpenTable(table_name);
577
share= new HailDBTableShare(table_name, has_hidden_primary_key);
581
pthread_mutex_unlock(&haildb_mutex);
582
*rc= HA_ERR_OUT_OF_MEM;
586
if (getTable()->found_next_number_field)
588
share->auto_increment_value.fetch_and_store(
589
a_engine->getInitialAutoIncrementValue(this));
593
if (has_hidden_primary_key)
595
uint64_t hidden_pkey= 0;
596
hidden_pkey= a_engine->getHiddenPrimaryKeyInitialAutoIncrementValue(this);
597
share->hidden_pkey_auto_increment_value.fetch_and_store(hidden_pkey);
600
a_engine->addOpenTable(share->table_name, share);
601
thr_lock_init(&share->lock);
605
pthread_mutex_unlock(&haildb_mutex);
610
int HailDBCursor::free_share()
612
pthread_mutex_lock(&haildb_mutex);
613
if (!--share->use_count)
615
HailDBEngine *a_engine= static_cast<HailDBEngine *>(getEngine());
616
a_engine->deleteOpenTable(share->table_name);
619
pthread_mutex_unlock(&haildb_mutex);
625
THR_LOCK_DATA **HailDBCursor::store_lock(Session *session,
627
thr_lock_type lock_type)
629
/* Currently, we can get a transaction start by ::store_lock
630
instead of beginTransaction, startStatement.
632
See https://bugs.launchpad.net/drizzle/+bug/535528
634
all stemming from the transactional engine interface needing
635
a severe amount of immodium.
638
if(*get_trx(session) == NULL)
640
static_cast<HailDBEngine*>(getEngine())->
641
doStartTransaction(session, START_TRANS_NO_OPTIONS);
644
if (lock_type != TL_UNLOCK)
646
ib_savepoint_take(*get_trx(session), statement_savepoint_name.c_str(),
647
statement_savepoint_name.length());
650
/* the below is adapted from ha_innodb.cc */
652
const uint32_t sql_command = session->getSqlCommand();
654
if (sql_command == SQLCOM_DROP_TABLE) {
656
/* MySQL calls this function in DROP Table though this table
657
handle may belong to another session that is running a query.
658
Let us in that case skip any changes to the prebuilt struct. */
660
} else if (lock_type == TL_READ_WITH_SHARED_LOCKS
661
|| lock_type == TL_READ_NO_INSERT
662
|| (lock_type != TL_IGNORE
663
&& sql_command != SQLCOM_SELECT)) {
665
/* The OR cases above are in this order:
666
1) MySQL is doing LOCK TABLES ... READ LOCAL, or we
667
are processing a stored procedure or function, or
668
2) (we do not know when TL_READ_HIGH_PRIORITY is used), or
669
3) this is a SELECT ... IN SHARE MODE, or
670
4) we are doing a complex SQL statement like
671
INSERT INTO ... SELECT ... and the logical logging (MySQL
672
binlog) requires the use of a locking read, or
673
MySQL is doing LOCK TABLES ... READ.
674
5) we let InnoDB do locking reads for all SQL statements that
675
are not simple SELECTs; note that select_lock_type in this
676
case may get strengthened in ::external_lock() to LOCK_X.
677
Note that we MUST use a locking read in all data modifying
678
SQL statements, because otherwise the execution would not be
679
serializable, and also the results from the update could be
680
unexpected if an obsolete consistent read view would be
683
enum_tx_isolation isolation_level= session->getTxIsolation();
685
if (isolation_level != ISO_SERIALIZABLE
686
&& (lock_type == TL_READ || lock_type == TL_READ_NO_INSERT)
687
&& (sql_command == SQLCOM_INSERT_SELECT
688
|| sql_command == SQLCOM_UPDATE
689
|| sql_command == SQLCOM_CREATE_TABLE)) {
691
/* If we either have innobase_locks_unsafe_for_binlog
692
option set or this session is using READ COMMITTED
693
isolation level and isolation level of the transaction
694
is not set to serializable and MySQL is doing
695
INSERT INTO...SELECT or UPDATE ... = (SELECT ...) or
696
CREATE ... SELECT... without FOR UPDATE or
697
IN SHARE MODE in select, then we use consistent
700
ib_lock_mode= IB_LOCK_NONE;
701
} else if (sql_command == SQLCOM_CHECKSUM) {
702
/* Use consistent read for checksum table */
704
ib_lock_mode= IB_LOCK_NONE;
706
ib_lock_mode= IB_LOCK_S;
709
} else if (lock_type != TL_IGNORE) {
711
/* We set possible LOCK_X value in external_lock, not yet
712
here even if this would be SELECT ... FOR UPDATE */
713
ib_lock_mode= IB_LOCK_NONE;
716
if (lock_type != TL_IGNORE && lock.type == TL_UNLOCK) {
718
/* If we are not doing a LOCK TABLE, DISCARD/IMPORT
719
TABLESPACE or TRUNCATE TABLE then allow multiple
720
writers. Note that ALTER TABLE uses a TL_WRITE_ALLOW_READ
721
< TL_WRITE_CONCURRENT_INSERT.
724
if ((lock_type >= TL_WRITE_CONCURRENT_INSERT
725
&& lock_type <= TL_WRITE)
726
&& ! session->doing_tablespace_operation()
727
&& sql_command != SQLCOM_TRUNCATE
728
&& sql_command != SQLCOM_CREATE_TABLE) {
730
lock_type = TL_WRITE_ALLOW_WRITE;
733
/* In queries of type INSERT INTO t1 SELECT ... FROM t2 ...
734
MySQL would use the lock TL_READ_NO_INSERT on t2, and that
735
would conflict with TL_WRITE_ALLOW_WRITE, blocking all inserts
736
to t2. Convert the lock to a normal read lock to allow
737
concurrent inserts to t2.
740
if (lock_type == TL_READ_NO_INSERT) {
745
lock.type = lock_type;
753
void HailDBCursor::get_auto_increment(uint64_t, //offset,
754
uint64_t, //increment,
756
uint64_t *first_value,
757
uint64_t *nb_reserved_values)
760
*first_value= share->auto_increment_value.fetch_and_increment();
761
if (*first_value == 0)
763
/* if it's zero, then we skip it... why? because of ass.
764
set auto-inc to -1 and the sequence is:
766
Zero is still "magic".
768
share->auto_increment_value.compare_and_swap(1, 0);
771
*nb_reserved_values= 1;
774
static const char* table_path_to_haildb_name(const char* name)
776
size_t l= strlen(name);
777
static string datadict_path("data_dictionary/");
778
static string sys_prefix("data_dictionary/haildb_");
779
static string sys_table_prefix("HAILDB_");
781
if (strncmp(name, sys_prefix.c_str(), sys_prefix.length()) == 0)
783
string find_name(name+datadict_path.length());
784
std::transform(find_name.begin(), find_name.end(), find_name.begin(), ::toupper);
785
boost::unordered_set<string>::iterator iter= haildb_system_table_names.find(find_name);
786
if (iter != haildb_system_table_names.end())
787
return (*iter).c_str()+sys_table_prefix.length();
791
while(slashes>0 && l > 0)
803
static void TableIdentifier_to_haildb_name(const identifier::Table &identifier, std::string *str)
805
str->assign(table_path_to_haildb_name(identifier.getPath().c_str()));
808
HailDBCursor::HailDBCursor(drizzled::plugin::StorageEngine &engine_arg,
810
:Cursor(engine_arg, table_arg),
811
ib_lock_mode(IB_LOCK_NONE),
812
write_can_replace(false),
816
static unsigned int get_first_unique_index(drizzled::Table &table)
818
for (uint32_t k= 0; k < table.getShare()->keys; k++)
820
if (table.key_info[k].flags & HA_NOSAME)
829
int HailDBCursor::open(const char *name, int, uint32_t)
831
const char* haildb_table_name= table_path_to_haildb_name(name);
832
ib_err_t err= ib_table_get_id(haildb_table_name, &table_id);
833
bool has_hidden_primary_key= false;
836
if (err != DB_SUCCESS)
837
return ib_err_t_to_drizzle_error(getTable()->getSession(), err);
839
err= ib_cursor_open_table_using_id(table_id, NULL, &cursor);
840
cursor_is_sec_index= false;
842
if (err != DB_SUCCESS)
843
return ib_err_t_to_drizzle_error(getTable()->getSession(), err);
845
err= ib_index_get_id(haildb_table_name, "HIDDEN_PRIMARY", &idx_id);
847
if (err == DB_SUCCESS)
848
has_hidden_primary_key= true;
851
share= get_share(name, has_hidden_primary_key, &rc);
852
lock.init(&share->lock);
855
if (getTable()->getShare()->getPrimaryKey() != MAX_KEY)
856
ref_length= getTable()->key_info[getTable()->getShare()->getPrimaryKey()].key_length;
857
else if (share->has_hidden_primary_key)
858
ref_length= sizeof(uint64_t);
861
unsigned int keynr= get_first_unique_index(*getTable());
862
ref_length= getTable()->key_info[keynr].key_length;
865
in_table_scan= false;
870
int HailDBCursor::close(void)
872
ib_err_t err= ib_cursor_close(cursor);
873
if (err != DB_SUCCESS)
874
return ib_err_t_to_drizzle_error(getTable()->getSession(), err);
884
int HailDBCursor::external_lock(Session* session, int lock_type)
886
ib_cursor_stmt_begin(cursor);
890
if (lock_type == F_WRLCK)
892
/* SELECT ... FOR UPDATE or UPDATE TABLE */
893
ib_lock_mode= IB_LOCK_X;
896
ib_lock_mode= IB_LOCK_NONE;
901
static int create_table_add_field(ib_tbl_sch_t schema,
902
const message::Table::Field &field,
905
ib_col_attr_t column_attr= IB_COL_NONE;
907
if (field.has_constraints() && field.constraints().is_notnull())
908
column_attr= IB_COL_NOT_NULL;
910
switch (field.type())
912
case message::Table::Field::VARCHAR:
913
*err= ib_table_schema_add_col(schema, field.name().c_str(), IB_VARCHAR,
915
field.string_options().length());
917
case message::Table::Field::INTEGER:
918
*err= ib_table_schema_add_col(schema, field.name().c_str(), IB_INT,
921
case message::Table::Field::BIGINT:
922
*err= ib_table_schema_add_col(schema, field.name().c_str(), IB_INT,
925
case message::Table::Field::DOUBLE:
926
case message::Table::Field::DATETIME:
927
*err= ib_table_schema_add_col(schema, field.name().c_str(), IB_DOUBLE,
928
column_attr, 0, sizeof(double));
930
case message::Table::Field::ENUM:
931
*err= ib_table_schema_add_col(schema, field.name().c_str(), IB_INT,
934
case message::Table::Field::DATE:
935
*err= ib_table_schema_add_col(schema, field.name().c_str(), IB_INT,
938
case message::Table::Field::EPOCH:
939
*err= ib_table_schema_add_col(schema, field.name().c_str(), IB_INT,
942
case message::Table::Field::BLOB:
943
*err= ib_table_schema_add_col(schema, field.name().c_str(), IB_BLOB,
946
case message::Table::Field::DECIMAL:
947
*err= ib_table_schema_add_col(schema, field.name().c_str(), IB_DECIMAL,
951
my_error(ER_CHECK_NOT_IMPLEMENTED, MYF(0), "Column Type");
952
return(HA_ERR_UNSUPPORTED);
958
static ib_err_t store_table_message(ib_trx_t transaction, const char* table_name, drizzled::message::Table& table_message)
961
ib_tpl_t message_tuple;
963
string serialized_message;
965
err= ib_cursor_open_table(HAILDB_TABLE_DEFINITIONS_TABLE, transaction, &cursor);
966
if (err != DB_SUCCESS)
969
message_tuple= ib_clust_read_tuple_create(cursor);
971
err= ib_col_set_value(message_tuple, 0, table_name, strlen(table_name));
972
if (err != DB_SUCCESS)
976
table_message.SerializeToString(&serialized_message);
983
err= ib_col_set_value(message_tuple, 1, serialized_message.c_str(),
984
serialized_message.length());
985
if (err != DB_SUCCESS)
988
err= ib_cursor_insert_row(cursor, message_tuple);
991
ib_tuple_delete(message_tuple);
993
ib_err_t cleanup_err= ib_cursor_close(cursor);
994
if (err == DB_SUCCESS)
1000
bool HailDBEngine::validateCreateTableOption(const std::string &key,
1001
const std::string &state)
1003
if (boost::iequals(key, "ROW_FORMAT"))
1005
if (boost::iequals(state, "COMPRESSED"))
1008
if (boost::iequals(state, "COMPACT"))
1011
if (boost::iequals(state, "DYNAMIC"))
1014
if (boost::iequals(state, "REDUNDANT"))
1021
static ib_tbl_fmt_t parse_ib_table_format(const std::string &value)
1023
if (boost::iequals(value, "REDUNDANT"))
1024
return IB_TBL_REDUNDANT;
1025
else if (boost::iequals(value, "COMPACT"))
1026
return IB_TBL_COMPACT;
1027
else if (boost::iequals(value, "DYNAMIC"))
1028
return IB_TBL_DYNAMIC;
1029
else if (boost::iequals(value, "COMPRESSED"))
1030
return IB_TBL_COMPRESSED;
1032
assert(false); /* You need to add possible table formats here */
1033
return IB_TBL_COMPACT;
1036
int HailDBEngine::doCreateTable(Session &session,
1038
const drizzled::identifier::Table &identifier,
1039
drizzled::message::Table& table_message)
1041
ib_tbl_sch_t haildb_table_schema= NULL;
1042
// ib_idx_sch_t haildb_pkey= NULL;
1043
ib_trx_t haildb_schema_transaction;
1044
ib_id_t haildb_table_id;
1045
ib_err_t haildb_err= DB_SUCCESS;
1046
string haildb_table_name;
1047
bool has_explicit_pkey= false;
1051
if (table_message.type() == message::Table::TEMPORARY)
1053
ib_bool_t create_db_err= ib_database_create(GLOBAL_TEMPORARY_EXT);
1054
if (create_db_err != IB_TRUE)
1058
TableIdentifier_to_haildb_name(identifier, &haildb_table_name);
1060
ib_tbl_fmt_t haildb_table_format= IB_TBL_COMPACT;
1062
const size_t num_engine_options= table_message.engine().options_size();
1063
for (size_t x= 0; x < num_engine_options; x++)
1065
const message::Engine::Option &engine_option= table_message.engine().options(x);
1066
if (boost::iequals(engine_option.name(), "ROW_FORMAT"))
1068
haildb_table_format= parse_ib_table_format(engine_option.state());
1072
haildb_err= ib_table_schema_create(haildb_table_name.c_str(),
1073
&haildb_table_schema,
1074
haildb_table_format, 0);
1076
if (haildb_err != DB_SUCCESS)
1078
push_warning_printf(&session, DRIZZLE_ERROR::WARN_LEVEL_ERROR,
1079
ER_CANT_CREATE_TABLE,
1080
_("Cannot create table %s. HailDB Error %d (%s)\n"),
1081
haildb_table_name.c_str(), haildb_err, ib_strerror(haildb_err));
1082
return ib_err_t_to_drizzle_error(&session, haildb_err);
1085
for (int colnr= 0; colnr < table_message.field_size() ; colnr++)
1087
const message::Table::Field field = table_message.field(colnr);
1089
int field_err= create_table_add_field(haildb_table_schema, field,
1092
if (haildb_err != DB_SUCCESS || field_err != 0)
1093
ib_table_schema_delete(haildb_table_schema); /* cleanup */
1095
if (haildb_err != DB_SUCCESS)
1097
push_warning_printf(&session, DRIZZLE_ERROR::WARN_LEVEL_ERROR,
1098
ER_CANT_CREATE_TABLE,
1099
_("Cannot create field %s on table %s."
1100
" HailDB Error %d (%s)\n"),
1101
field.name().c_str(), haildb_table_name.c_str(),
1102
haildb_err, ib_strerror(haildb_err));
1103
return ib_err_t_to_drizzle_error(&session, haildb_err);
1109
bool has_primary= false;
1110
for (int indexnr= 0; indexnr < table_message.indexes_size() ; indexnr++)
1112
message::Table::Index *index = table_message.mutable_indexes(indexnr);
1114
ib_idx_sch_t haildb_index;
1116
haildb_err= ib_table_schema_add_index(haildb_table_schema, index->name().c_str(),
1118
if (haildb_err != DB_SUCCESS)
1121
if (index->is_primary())
1124
haildb_err= ib_index_schema_set_clustered(haildb_index);
1125
has_explicit_pkey= true;
1126
if (haildb_err != DB_SUCCESS)
1130
if (index->is_unique())
1132
haildb_err= ib_index_schema_set_unique(haildb_index);
1133
if (haildb_err != DB_SUCCESS)
1137
if (index->type() == message::Table::Index::UNKNOWN_INDEX)
1138
index->set_type(message::Table::Index::BTREE);
1140
for (int partnr= 0; partnr < index->index_part_size(); partnr++)
1142
const message::Table::Index::IndexPart part= index->index_part(partnr);
1143
const message::Table::Field::FieldType part_type= table_message.field(part.fieldnr()).type();
1144
uint64_t compare_length= 0;
1146
if (part_type == message::Table::Field::BLOB
1147
|| part_type == message::Table::Field::VARCHAR)
1148
compare_length= part.compare_length();
1150
haildb_err= ib_index_schema_add_col(haildb_index,
1151
table_message.field(part.fieldnr()).name().c_str(),
1153
if (haildb_err != DB_SUCCESS)
1157
if (! has_primary && index->is_unique())
1159
haildb_err= ib_index_schema_set_clustered(haildb_index);
1160
has_explicit_pkey= true;
1161
if (haildb_err != DB_SUCCESS)
1167
if (! has_explicit_pkey)
1169
ib_idx_sch_t haildb_index;
1171
haildb_err= ib_table_schema_add_col(haildb_table_schema, "hidden_primary_key_col",
1172
IB_INT, IB_COL_NOT_NULL, 0, 8);
1174
haildb_err= ib_table_schema_add_index(haildb_table_schema, "HIDDEN_PRIMARY",
1176
if (haildb_err != DB_SUCCESS)
1179
haildb_err= ib_index_schema_set_clustered(haildb_index);
1180
if (haildb_err != DB_SUCCESS)
1183
haildb_err= ib_index_schema_add_col(haildb_index, "hidden_primary_key_col", 0);
1184
if (haildb_err != DB_SUCCESS)
1188
haildb_schema_transaction= ib_trx_begin(IB_TRX_REPEATABLE_READ);
1189
haildb_err= ib_schema_lock_exclusive(haildb_schema_transaction);
1190
if (haildb_err != DB_SUCCESS)
1192
ib_err_t rollback_err= ib_trx_rollback(haildb_schema_transaction);
1193
ib_table_schema_delete(haildb_table_schema);
1195
push_warning_printf(&session, DRIZZLE_ERROR::WARN_LEVEL_ERROR,
1196
ER_CANT_CREATE_TABLE,
1197
_("Cannot Lock HailDB Data Dictionary. HailDB Error %d (%s)\n"),
1198
haildb_err, ib_strerror(haildb_err));
1200
assert (rollback_err == DB_SUCCESS);
1202
return HA_ERR_GENERIC;
1205
haildb_err= ib_table_create(haildb_schema_transaction, haildb_table_schema,
1208
if (haildb_err != DB_SUCCESS)
1210
ib_err_t rollback_err= ib_trx_rollback(haildb_schema_transaction);
1211
ib_table_schema_delete(haildb_table_schema);
1213
if (haildb_err == DB_TABLE_IS_BEING_USED)
1216
push_warning_printf(&session, DRIZZLE_ERROR::WARN_LEVEL_ERROR,
1217
ER_CANT_CREATE_TABLE,
1218
_("Cannot create table %s. HailDB Error %d (%s)\n"),
1219
haildb_table_name.c_str(),
1220
haildb_err, ib_strerror(haildb_err));
1222
assert (rollback_err == DB_SUCCESS);
1223
return HA_ERR_GENERIC;
1226
if (table_message.type() == message::Table::TEMPORARY)
1228
session.getMessageCache().storeTableMessage(identifier, table_message);
1229
haildb_err= DB_SUCCESS;
1232
haildb_err= store_table_message(haildb_schema_transaction,
1233
haildb_table_name.c_str(),
1236
if (haildb_err == DB_SUCCESS)
1237
haildb_err= ib_trx_commit(haildb_schema_transaction);
1239
haildb_err= ib_trx_rollback(haildb_schema_transaction);
1242
ib_table_schema_delete(haildb_table_schema);
1244
if (haildb_err != DB_SUCCESS)
1246
push_warning_printf(&session, DRIZZLE_ERROR::WARN_LEVEL_ERROR,
1247
ER_CANT_CREATE_TABLE,
1248
_("Cannot create table %s. HailDB Error %d (%s)\n"),
1249
haildb_table_name.c_str(),
1250
haildb_err, ib_strerror(haildb_err));
1251
return ib_err_t_to_drizzle_error(&session, haildb_err);
1257
static int delete_table_message_from_haildb(ib_trx_t transaction, const char* table_name)
1260
ib_tpl_t search_tuple;
1264
err= ib_cursor_open_table(HAILDB_TABLE_DEFINITIONS_TABLE, transaction, &cursor);
1265
if (err != DB_SUCCESS)
1268
search_tuple= ib_clust_search_tuple_create(cursor);
1270
err= ib_col_set_value(search_tuple, 0, table_name, strlen(table_name));
1271
if (err != DB_SUCCESS)
1274
// ib_cursor_set_match_mode(cursor, IB_EXACT_MATCH);
1276
err= ib_cursor_moveto(cursor, search_tuple, IB_CUR_GE, &res);
1277
if (err == DB_RECORD_NOT_FOUND || res != 0)
1280
err= ib_cursor_delete_row(cursor);
1281
assert (err == DB_SUCCESS);
1284
ib_err_t rollback_err= ib_cursor_close(cursor);
1285
if (err == DB_SUCCESS)
1288
ib_tuple_delete(search_tuple);
1293
int HailDBEngine::doDropTable(Session &session,
1294
const identifier::Table &identifier)
1296
ib_trx_t haildb_schema_transaction;
1297
ib_err_t haildb_err;
1298
string haildb_table_name;
1300
TableIdentifier_to_haildb_name(identifier, &haildb_table_name);
1302
haildb_schema_transaction= ib_trx_begin(IB_TRX_REPEATABLE_READ);
1303
haildb_err= ib_schema_lock_exclusive(haildb_schema_transaction);
1304
if (haildb_err != DB_SUCCESS)
1306
ib_err_t rollback_err= ib_trx_rollback(haildb_schema_transaction);
1308
push_warning_printf(&session, DRIZZLE_ERROR::WARN_LEVEL_ERROR,
1309
ER_CANT_DELETE_FILE,
1310
_("Cannot Lock HailDB Data Dictionary. HailDB Error %d (%s)\n"),
1311
haildb_err, ib_strerror(haildb_err));
1313
assert (rollback_err == DB_SUCCESS);
1315
return HA_ERR_GENERIC;
1318
if (identifier.getType() == message::Table::TEMPORARY)
1320
session.getMessageCache().removeTableMessage(identifier);
1321
delete_table_message_from_haildb(haildb_schema_transaction,
1322
haildb_table_name.c_str());
1326
if (delete_table_message_from_haildb(haildb_schema_transaction, haildb_table_name.c_str()) != DB_SUCCESS)
1328
ib_schema_unlock(haildb_schema_transaction);
1329
ib_err_t rollback_err= ib_trx_rollback(haildb_schema_transaction);
1330
assert(rollback_err == DB_SUCCESS);
1331
return HA_ERR_GENERIC;
1335
haildb_err= ib_table_drop(haildb_schema_transaction, haildb_table_name.c_str());
1337
if (haildb_err == DB_TABLE_NOT_FOUND)
1339
haildb_err= ib_trx_rollback(haildb_schema_transaction);
1340
assert(haildb_err == DB_SUCCESS);
1343
else if (haildb_err != DB_SUCCESS)
1345
ib_err_t rollback_err= ib_trx_rollback(haildb_schema_transaction);
1347
push_warning_printf(&session, DRIZZLE_ERROR::WARN_LEVEL_ERROR,
1348
ER_CANT_DELETE_FILE,
1349
_("Cannot DROP table %s. HailDB Error %d (%s)\n"),
1350
haildb_table_name.c_str(),
1351
haildb_err, ib_strerror(haildb_err));
1353
assert(rollback_err == DB_SUCCESS);
1355
return HA_ERR_GENERIC;
1358
haildb_err= ib_trx_commit(haildb_schema_transaction);
1359
if (haildb_err != DB_SUCCESS)
1361
ib_err_t rollback_err= ib_trx_rollback(haildb_schema_transaction);
1363
push_warning_printf(&session, DRIZZLE_ERROR::WARN_LEVEL_ERROR,
1364
ER_CANT_DELETE_FILE,
1365
_("Cannot DROP table %s. HailDB Error %d (%s)\n"),
1366
haildb_table_name.c_str(),
1367
haildb_err, ib_strerror(haildb_err));
1369
assert(rollback_err == DB_SUCCESS);
1370
return HA_ERR_GENERIC;
1376
static ib_err_t rename_table_message(ib_trx_t transaction, const identifier::Table &from_identifier, const identifier::Table &to_identifier)
1379
ib_tpl_t search_tuple;
1380
ib_tpl_t read_tuple;
1381
ib_tpl_t update_tuple;
1384
ib_err_t rollback_err;
1385
const char *message;
1386
ib_ulint_t message_len;
1387
drizzled::message::Table table_message;
1388
string from_haildb_table_name;
1389
string to_haildb_table_name;
1392
string serialized_message;
1393
ib_col_meta_t col_meta;
1395
TableIdentifier_to_haildb_name(from_identifier, &from_haildb_table_name);
1396
TableIdentifier_to_haildb_name(to_identifier, &to_haildb_table_name);
1398
from= from_haildb_table_name.c_str();
1399
to= to_haildb_table_name.c_str();
1401
err= ib_cursor_open_table(HAILDB_TABLE_DEFINITIONS_TABLE, transaction, &cursor);
1402
if (err != DB_SUCCESS)
1404
rollback_err= ib_trx_rollback(transaction);
1405
assert(rollback_err == DB_SUCCESS);
1409
search_tuple= ib_clust_search_tuple_create(cursor);
1410
read_tuple= ib_clust_read_tuple_create(cursor);
1412
err= ib_col_set_value(search_tuple, 0, from, strlen(from));
1413
if (err != DB_SUCCESS)
1416
// ib_cursor_set_match_mode(cursor, IB_EXACT_MATCH);
1418
err= ib_cursor_moveto(cursor, search_tuple, IB_CUR_GE, &res);
1419
if (err == DB_RECORD_NOT_FOUND || res != 0)
1422
err= ib_cursor_read_row(cursor, read_tuple);
1423
if (err == DB_RECORD_NOT_FOUND || res != 0)
1426
message= (const char*)ib_col_get_value(read_tuple, 1);
1427
message_len= ib_col_get_meta(read_tuple, 1, &col_meta);
1429
if (table_message.ParseFromArray(message, message_len) == false)
1432
table_message.set_name(to_identifier.getTableName());
1433
table_message.set_schema(to_identifier.getSchemaName());
1435
update_tuple= ib_clust_read_tuple_create(cursor);
1437
err= ib_tuple_copy(update_tuple, read_tuple);
1438
assert(err == DB_SUCCESS);
1440
err= ib_col_set_value(update_tuple, 0, to, strlen(to));
1443
table_message.SerializeToString(&serialized_message);
1450
err= ib_col_set_value(update_tuple, 1, serialized_message.c_str(),
1451
serialized_message.length());
1453
err= ib_cursor_update_row(cursor, read_tuple, update_tuple);
1456
ib_tuple_delete(update_tuple);
1457
ib_tuple_delete(read_tuple);
1458
ib_tuple_delete(search_tuple);
1460
err= ib_cursor_close(cursor);
1466
int HailDBEngine::doRenameTable(drizzled::Session &session,
1467
const drizzled::identifier::Table &from,
1468
const drizzled::identifier::Table &to)
1470
ib_trx_t haildb_schema_transaction;
1472
string from_haildb_table_name;
1473
string to_haildb_table_name;
1475
if (to.getType() == message::Table::TEMPORARY
1476
&& from.getType() == message::Table::TEMPORARY)
1478
session.getMessageCache().renameTableMessage(from, to);
1482
TableIdentifier_to_haildb_name(from, &from_haildb_table_name);
1483
TableIdentifier_to_haildb_name(to, &to_haildb_table_name);
1485
haildb_schema_transaction= ib_trx_begin(IB_TRX_REPEATABLE_READ);
1486
err= ib_schema_lock_exclusive(haildb_schema_transaction);
1487
if (err != DB_SUCCESS)
1489
push_warning_printf(&session, DRIZZLE_ERROR::WARN_LEVEL_ERROR,
1490
ER_CANT_DELETE_FILE,
1491
_("Cannot Lock HailDB Data Dictionary. HailDB Error %d (%s)\n"),
1492
err, ib_strerror(err));
1497
err= ib_table_rename(haildb_schema_transaction,
1498
from_haildb_table_name.c_str(),
1499
to_haildb_table_name.c_str());
1500
if (err != DB_SUCCESS)
1503
err= rename_table_message(haildb_schema_transaction, from, to);
1505
if (err != DB_SUCCESS)
1508
err= ib_trx_commit(haildb_schema_transaction);
1509
if (err != DB_SUCCESS)
1514
ib_err_t rollback_err= ib_schema_unlock(haildb_schema_transaction);
1515
assert(rollback_err == DB_SUCCESS);
1516
rollback_err= ib_trx_rollback(haildb_schema_transaction);
1517
assert(rollback_err == DB_SUCCESS);
1518
return ib_err_t_to_drizzle_error(&session, err);
1521
void HailDBEngine::getTableNamesInSchemaFromHailDB(
1522
const drizzled::identifier::Schema &schema,
1523
drizzled::plugin::TableNameList *set_of_names,
1524
drizzled::identifier::Table::vector *identifiers)
1526
ib_trx_t transaction;
1529
Why not use getPath()?
1531
string search_string(schema.getSchemaName());
1533
boost::algorithm::to_lower(search_string);
1535
search_string.append("/");
1537
transaction = ib_trx_begin(IB_TRX_REPEATABLE_READ);
1538
ib_err_t haildb_err= ib_schema_lock_exclusive(transaction);
1539
assert(haildb_err == DB_SUCCESS); /* FIXME: doGetTableNames needs to be able to return error */
1541
if (search_string.compare("data_dictionary/") == 0)
1545
BOOST_FOREACH(std::string table_name, haildb_system_table_names)
1547
set_of_names->insert(table_name);
1552
BOOST_FOREACH(std::string table_name, haildb_system_table_names)
1554
identifiers->push_back(identifier::Table(schema.getSchemaName(),
1560
haildb_err= ib_cursor_open_table("SYS_TABLES", transaction, &cursor);
1561
assert(haildb_err == DB_SUCCESS); /* FIXME */
1563
ib_tpl_t read_tuple;
1564
ib_tpl_t search_tuple;
1566
read_tuple= ib_clust_read_tuple_create(cursor);
1567
search_tuple= ib_clust_search_tuple_create(cursor);
1569
haildb_err= ib_col_set_value(search_tuple, 0, search_string.c_str(),
1570
search_string.length());
1571
assert (haildb_err == DB_SUCCESS); // FIXME
1574
haildb_err = ib_cursor_moveto(cursor, search_tuple, IB_CUR_GE, &res);
1575
// fixme: check error above
1577
while (haildb_err == DB_SUCCESS)
1579
haildb_err= ib_cursor_read_row(cursor, read_tuple);
1581
const char *table_name;
1583
ib_col_meta_t column_metadata;
1585
table_name= (const char*)ib_col_get_value(read_tuple, 0);
1586
table_name_len= ib_col_get_meta(read_tuple, 0, &column_metadata);
1588
if (search_string.compare(0, search_string.length(),
1589
table_name, search_string.length()) == 0)
1591
const char *just_table_name= strchr(table_name, '/');
1592
assert(just_table_name);
1593
just_table_name++; /* skip over '/' */
1595
set_of_names->insert(just_table_name);
1597
identifiers->push_back(identifier::Table(schema.getSchemaName(), just_table_name));
1601
haildb_err= ib_cursor_next(cursor);
1602
read_tuple= ib_tuple_clear(read_tuple);
1605
ib_tuple_delete(read_tuple);
1606
ib_tuple_delete(search_tuple);
1608
haildb_err= ib_cursor_close(cursor);
1609
assert(haildb_err == DB_SUCCESS); // FIXME
1611
haildb_err= ib_trx_commit(transaction);
1612
assert(haildb_err == DB_SUCCESS); // FIXME
1615
void HailDBEngine::doGetTableIdentifiers(drizzled::CachedDirectory &,
1616
const drizzled::identifier::Schema &schema,
1617
drizzled::identifier::Table::vector &identifiers)
1619
getTableNamesInSchemaFromHailDB(schema, NULL, &identifiers);
1622
static int read_table_message_from_haildb(const char* table_name, drizzled::message::Table *table_message)
1624
ib_trx_t transaction;
1625
ib_tpl_t search_tuple;
1626
ib_tpl_t read_tuple;
1628
const char *message;
1629
ib_ulint_t message_len;
1630
ib_col_meta_t col_meta;
1633
ib_err_t rollback_err;
1635
transaction= ib_trx_begin(IB_TRX_REPEATABLE_READ);
1636
err= ib_schema_lock_exclusive(transaction);
1637
if (err != DB_SUCCESS)
1639
rollback_err= ib_trx_rollback(transaction);
1640
assert(rollback_err == DB_SUCCESS);
1644
err= ib_cursor_open_table(HAILDB_TABLE_DEFINITIONS_TABLE, transaction, &cursor);
1645
if (err != DB_SUCCESS)
1647
rollback_err= ib_trx_rollback(transaction);
1648
assert(rollback_err == DB_SUCCESS);
1652
search_tuple= ib_clust_search_tuple_create(cursor);
1653
read_tuple= ib_clust_read_tuple_create(cursor);
1655
err= ib_col_set_value(search_tuple, 0, table_name, strlen(table_name));
1656
if (err != DB_SUCCESS)
1659
// ib_cursor_set_match_mode(cursor, IB_EXACT_MATCH);
1661
err= ib_cursor_moveto(cursor, search_tuple, IB_CUR_GE, &res);
1662
if (err == DB_RECORD_NOT_FOUND || res != 0)
1665
err= ib_cursor_read_row(cursor, read_tuple);
1666
if (err == DB_RECORD_NOT_FOUND || res != 0)
1669
message= (const char*)ib_col_get_value(read_tuple, 1);
1670
message_len= ib_col_get_meta(read_tuple, 1, &col_meta);
1672
if (table_message->ParseFromArray(message, message_len) == false)
1675
ib_tuple_delete(search_tuple);
1676
ib_tuple_delete(read_tuple);
1677
err= ib_cursor_close(cursor);
1678
if (err != DB_SUCCESS)
1679
goto rollback_close_err;
1680
err= ib_trx_commit(transaction);
1681
if (err != DB_SUCCESS)
1682
goto rollback_close_err;
1687
ib_tuple_delete(search_tuple);
1688
ib_tuple_delete(read_tuple);
1689
rollback_err= ib_cursor_close(cursor);
1690
assert(rollback_err == DB_SUCCESS);
1692
ib_schema_unlock(transaction);
1693
rollback_err= ib_trx_rollback(transaction);
1694
assert(rollback_err == DB_SUCCESS);
1696
if (strcmp(table_name, HAILDB_TABLE_DEFINITIONS_TABLE) == 0)
1698
message::Engine *engine= table_message->mutable_engine();
1699
engine->set_name("InnoDB");
1700
table_message->set_name("haildb_table_definitions");
1701
table_message->set_schema("data_dictionary");
1702
table_message->set_type(message::Table::STANDARD);
1703
table_message->set_creation_timestamp(0);
1704
table_message->set_update_timestamp(0);
1706
message::Table::TableOptions *options= table_message->mutable_options();
1707
options->set_collation_id(my_charset_bin.number);
1708
options->set_collation(my_charset_bin.name);
1710
message::Table::Field *field= table_message->add_field();
1711
field->set_name("table_name");
1712
field->set_type(message::Table::Field::VARCHAR);
1713
message::Table::Field::StringFieldOptions *stropt= field->mutable_string_options();
1714
stropt->set_length(IB_MAX_TABLE_NAME_LEN);
1715
stropt->set_collation_id(my_charset_bin.number);
1716
stropt->set_collation(my_charset_bin.name);
1718
field= table_message->add_field();
1719
field->set_name("message");
1720
field->set_type(message::Table::Field::BLOB);
1721
stropt= field->mutable_string_options();
1722
stropt->set_collation_id(my_charset_bin.number);
1723
stropt->set_collation(my_charset_bin.name);
1725
message::Table::Index *index= table_message->add_indexes();
1726
index->set_name("PRIMARY");
1727
index->set_is_primary(true);
1728
index->set_is_unique(true);
1729
index->set_type(message::Table::Index::BTREE);
1730
index->set_key_length(IB_MAX_TABLE_NAME_LEN);
1731
message::Table::Index::IndexPart *part= index->add_index_part();
1732
part->set_fieldnr(0);
1733
part->set_compare_length(IB_MAX_TABLE_NAME_LEN);
1741
int HailDBEngine::doGetTableDefinition(Session &session,
1742
const identifier::Table &identifier,
1743
drizzled::message::Table &table)
1745
ib_crsr_t haildb_cursor= NULL;
1746
string haildb_table_name;
1748
/* Check temporary tables!? */
1749
if (session.getMessageCache().getTableMessage(identifier, table))
1752
TableIdentifier_to_haildb_name(identifier, &haildb_table_name);
1754
if (ib_cursor_open_table(haildb_table_name.c_str(), NULL, &haildb_cursor) != DB_SUCCESS)
1757
ib_err_t err= ib_cursor_close(haildb_cursor);
1759
assert (err == DB_SUCCESS);
1761
if (read_table_message_from_haildb(haildb_table_name.c_str(), &table) != 0)
1763
if (get_haildb_system_table_message(haildb_table_name.c_str(), &table) == 0)
1770
bool HailDBEngine::doDoesTableExist(Session &,
1771
const identifier::Table& identifier)
1773
ib_crsr_t haildb_cursor;
1774
string haildb_table_name;
1776
TableIdentifier_to_haildb_name(identifier, &haildb_table_name);
1778
boost::unordered_set<string>::iterator iter= haildb_system_table_names.find(identifier.getTableName());
1779
if (iter != haildb_system_table_names.end())
1782
if (ib_cursor_open_table(haildb_table_name.c_str(), NULL, &haildb_cursor) != DB_SUCCESS)
1785
ib_err_t err= ib_cursor_close(haildb_cursor);
1786
assert(err == DB_SUCCESS);
1791
const char *HailDBCursor::index_type(uint32_t)
1796
static ib_err_t write_row_to_haildb_tuple(const unsigned char* buf,
1797
Field **fields, ib_tpl_t tuple)
1800
ib_err_t err= DB_ERROR;
1801
ptrdiff_t row_offset= buf - (*fields)->getTable()->getInsertRecord();
1803
for (Field **field= fields; *field; field++, colnr++)
1805
(**field).move_field_offset(row_offset);
1807
if (! (**field).isWriteSet() && (**field).is_null())
1809
(**field).move_field_offset(-row_offset);
1813
if ((**field).is_null())
1815
err= ib_col_set_value(tuple, colnr, NULL, IB_SQL_NULL);
1816
assert(err == DB_SUCCESS);
1817
(**field).move_field_offset(-row_offset);
1821
if ((**field).type() == DRIZZLE_TYPE_VARCHAR)
1823
/* To get around the length bytes (1 or 2) at (**field).ptr
1824
we can use Field_varstring::val_str to a String
1825
to get a pointer to the real string without copying it.
1828
(**field).setReadSet();
1829
(**field).val_str_internal(&str);
1830
err= ib_col_set_value(tuple, colnr, str.ptr(), str.length());
1832
else if ((**field).type() == DRIZZLE_TYPE_ENUM)
1834
err= ib_tuple_write_u32(tuple, colnr, *((ib_u32_t*)(*field)->ptr));
1836
else if ((**field).type() == DRIZZLE_TYPE_DATE)
1838
(**field).setReadSet();
1839
err= ib_tuple_write_u32(tuple, colnr, (*field)->val_int());
1841
else if ((**field).type() == DRIZZLE_TYPE_BLOB)
1843
Field_blob *blob= reinterpret_cast<Field_blob*>(*field);
1844
unsigned char* blob_ptr;
1845
uint32_t blob_length= blob->get_length();
1846
blob->get_ptr(&blob_ptr);
1847
err= ib_col_set_value(tuple, colnr, blob_ptr, blob_length);
1851
err= ib_col_set_value(tuple, colnr, (*field)->ptr, (*field)->data_length());
1854
assert (err == DB_SUCCESS);
1856
(**field).move_field_offset(-row_offset);
1862
static uint64_t innobase_get_int_col_max_value(const Field* field)
1864
uint64_t max_value = 0;
1866
switch(field->key_type()) {
1868
case HA_KEYTYPE_BINARY:
1869
max_value = 0xFFULL;
1872
case HA_KEYTYPE_ULONG_INT:
1873
max_value = 0xFFFFFFFFULL;
1875
case HA_KEYTYPE_LONG_INT:
1876
max_value = 0x7FFFFFFFULL;
1879
case HA_KEYTYPE_ULONGLONG:
1880
max_value = 0xFFFFFFFFFFFFFFFFULL;
1882
case HA_KEYTYPE_LONGLONG:
1883
max_value = 0x7FFFFFFFFFFFFFFFULL;
1885
case HA_KEYTYPE_DOUBLE:
1886
/* We use the maximum as per IEEE754-2008 standard, 2^53 */
1887
max_value = 0x20000000000000ULL;
1896
int HailDBCursor::doInsertRecord(unsigned char *record)
1901
ib_trx_t transaction= *get_trx(getTable()->in_use);
1903
tuple= ib_clust_read_tuple_create(cursor);
1905
if (cursor_is_sec_index)
1907
err= ib_cursor_close(cursor);
1908
assert(err == DB_SUCCESS);
1910
err= ib_cursor_open_table_using_id(table_id, transaction, &cursor);
1912
if (err != DB_SUCCESS)
1913
return ib_err_t_to_drizzle_error(getTable()->getSession(), err);
1915
cursor_is_sec_index= false;
1919
ib_cursor_attach_trx(cursor, transaction);
1922
err= ib_cursor_first(cursor);
1923
if (current_session->lex->sql_command == SQLCOM_CREATE_TABLE
1924
&& err == DB_MISSING_HISTORY)
1926
/* See https://bugs.launchpad.net/drizzle/+bug/556978
1928
* In CREATE SELECT, transaction is started in ::store_lock
1929
* at the start of the statement, before the table is created.
1930
* This means the table doesn't exist in our snapshot,
1931
* and we get a DB_MISSING_HISTORY error on ib_cursor_first().
1932
* The way to get around this is to here, restart the transaction
1938
HailDBEngine *storage_engine= static_cast<HailDBEngine*>(getEngine());
1939
err= ib_cursor_reset(cursor);
1940
storage_engine->doCommit(current_session, true);
1941
storage_engine->doStartTransaction(current_session, START_TRANS_NO_OPTIONS);
1942
transaction= *get_trx(getTable()->in_use);
1943
assert(err == DB_SUCCESS);
1944
ib_cursor_attach_trx(cursor, transaction);
1945
err= ib_cursor_first(cursor);
1948
assert(err == DB_SUCCESS || err == DB_END_OF_INDEX);
1951
if (getTable()->next_number_field)
1953
update_auto_increment();
1955
uint64_t temp_auto= getTable()->next_number_field->val_int();
1957
if (temp_auto <= innobase_get_int_col_max_value(getTable()->next_number_field))
1961
uint64_t fetched_auto= share->auto_increment_value;
1963
if (temp_auto >= fetched_auto)
1965
uint64_t store_value= temp_auto+1;
1966
if (store_value == 0)
1969
if (share->auto_increment_value.compare_and_swap(store_value, fetched_auto) == fetched_auto)
1979
write_row_to_haildb_tuple(record, getTable()->getFields(), tuple);
1981
if (share->has_hidden_primary_key)
1983
err= ib_tuple_write_u64(tuple, getTable()->getShare()->sizeFields(),
1984
share->hidden_pkey_auto_increment_value.fetch_and_increment());
1987
err= ib_cursor_insert_row(cursor, tuple);
1989
if (err == DB_DUPLICATE_KEY)
1991
if (write_can_replace)
1993
store_key_value_from_haildb(getTable()->key_info + getTable()->getShare()->getPrimaryKey(),
1994
ref, ref_length, record);
1996
ib_tpl_t search_tuple= ib_clust_search_tuple_create(cursor);
1998
fill_ib_search_tpl_from_drizzle_key(search_tuple,
1999
getTable()->key_info + 0,
2003
err= ib_cursor_moveto(cursor, search_tuple, IB_CUR_GE, &res);
2004
assert(err == DB_SUCCESS);
2005
ib_tuple_delete(search_tuple);
2007
tuple= ib_tuple_clear(tuple);
2008
err= ib_cursor_delete_row(cursor);
2010
err= ib_cursor_first(cursor);
2011
assert(err == DB_SUCCESS || err == DB_END_OF_INDEX);
2013
write_row_to_haildb_tuple(record, getTable()->getFields(), tuple);
2015
err= ib_cursor_insert_row(cursor, tuple);
2016
assert(err==DB_SUCCESS); // probably be nice and process errors
2019
ret= HA_ERR_FOUND_DUPP_KEY;
2021
else if (err != DB_SUCCESS)
2022
ret= ib_err_t_to_drizzle_error(getTable()->getSession(), err);
2024
tuple= ib_tuple_clear(tuple);
2025
ib_tuple_delete(tuple);
2027
err= ib_cursor_reset(cursor);
2032
int HailDBCursor::doUpdateRecord(const unsigned char *old_data,
2033
unsigned char *new_data)
2035
ib_tpl_t update_tuple;
2037
bool created_tuple= false;
2039
update_tuple= ib_clust_read_tuple_create(cursor);
2043
ib_trx_t transaction= *get_trx(getTable()->in_use);
2045
if (cursor_is_sec_index)
2047
err= ib_cursor_close(cursor);
2048
assert(err == DB_SUCCESS);
2050
err= ib_cursor_open_table_using_id(table_id, transaction, &cursor);
2052
if (err != DB_SUCCESS)
2053
return ib_err_t_to_drizzle_error(getTable()->getSession(), err);
2054
cursor_is_sec_index= false;
2058
ib_cursor_attach_trx(cursor, transaction);
2061
store_key_value_from_haildb(getTable()->key_info + getTable()->getShare()->getPrimaryKey(),
2062
ref, ref_length, old_data);
2064
ib_tpl_t search_tuple= ib_clust_search_tuple_create(cursor);
2066
fill_ib_search_tpl_from_drizzle_key(search_tuple,
2067
getTable()->key_info + 0,
2070
err= ib_cursor_set_lock_mode(cursor, IB_LOCK_X);
2071
assert(err == DB_SUCCESS);
2074
err= ib_cursor_moveto(cursor, search_tuple, IB_CUR_GE, &res);
2075
assert(err == DB_SUCCESS);
2077
tuple= ib_clust_read_tuple_create(cursor);
2079
err= ib_cursor_read_row(cursor, tuple);
2080
assert(err == DB_SUCCESS);// FIXME
2082
created_tuple= true;
2085
err= ib_tuple_copy(update_tuple, tuple);
2086
assert(err == DB_SUCCESS);
2088
write_row_to_haildb_tuple(new_data, getTable()->getFields(), update_tuple);
2090
err= ib_cursor_update_row(cursor, tuple, update_tuple);
2092
ib_tuple_delete(update_tuple);
2096
ib_err_t ib_err= ib_cursor_reset(cursor); //fixme check error
2097
assert(ib_err == DB_SUCCESS);
2098
tuple= ib_tuple_clear(tuple);
2099
ib_tuple_delete(tuple);
2103
advance_cursor= true;
2105
return ib_err_t_to_drizzle_error(getTable()->getSession(), err);
2108
int HailDBCursor::doDeleteRecord(const unsigned char *)
2112
assert(ib_cursor_is_positioned(cursor) == IB_TRUE);
2113
err= ib_cursor_delete_row(cursor);
2115
advance_cursor= true;
2117
return ib_err_t_to_drizzle_error(getTable()->getSession(), err);
2120
int HailDBCursor::delete_all_rows(void)
2122
/* I *think* ib_truncate is non-transactional....
2123
so only support TRUNCATE and not DELETE FROM t;
2124
(this is what ha_innodb does)
2126
if (getTable()->in_use->getSqlCommand() != SQLCOM_TRUNCATE)
2127
return HA_ERR_WRONG_COMMAND;
2132
ib_trx_t transaction= ib_trx_begin(IB_TRX_REPEATABLE_READ);
2134
if (cursor_is_sec_index)
2136
err= ib_cursor_close(cursor);
2137
assert(err == DB_SUCCESS);
2139
err= ib_cursor_open_table_using_id(table_id, transaction, &cursor);
2141
if (err != DB_SUCCESS)
2142
return ib_err_t_to_drizzle_error(getTable()->getSession(), err);
2143
cursor_is_sec_index= false;
2147
ib_cursor_attach_trx(cursor, transaction);
2150
err= ib_schema_lock_exclusive(transaction);
2151
if (err != DB_SUCCESS)
2153
ib_err_t rollback_err= ib_trx_rollback(transaction);
2155
push_warning_printf(getTable()->in_use, DRIZZLE_ERROR::WARN_LEVEL_ERROR,
2156
ER_CANT_DELETE_FILE,
2157
_("Cannot Lock HailDB Data Dictionary. HailDB Error %d (%s)\n"),
2158
err, ib_strerror(err));
2160
assert (rollback_err == DB_SUCCESS);
2162
return HA_ERR_GENERIC;
2165
share->auto_increment_value.fetch_and_store(1);
2167
err= ib_cursor_truncate(&cursor, &id);
2168
if (err != DB_SUCCESS)
2171
ib_schema_unlock(transaction);
2172
/* ib_cursor_truncate commits on success */
2174
err= ib_cursor_open_table_using_id(id, NULL, &cursor);
2175
if (err != DB_SUCCESS)
2181
ib_schema_unlock(transaction);
2182
ib_err_t rollback_err= ib_trx_rollback(transaction);
2183
assert(rollback_err == DB_SUCCESS);
2184
return ib_err_t_to_drizzle_error(getTable()->getSession(), err);
2187
int HailDBCursor::doStartTableScan(bool)
2189
ib_err_t err= DB_SUCCESS;
2190
ib_trx_t transaction;
2194
in_table_scan= true;
2196
transaction= *get_trx(getTable()->in_use);
2198
assert(transaction != NULL);
2200
if (cursor_is_sec_index)
2202
err= ib_cursor_close(cursor);
2203
assert(err == DB_SUCCESS);
2205
err= ib_cursor_open_table_using_id(table_id, transaction, &cursor);
2206
cursor_is_sec_index= false;
2210
ib_cursor_attach_trx(cursor, transaction);
2213
if (err != DB_SUCCESS)
2214
return ib_err_t_to_drizzle_error(getTable()->getSession(), err);
2216
err= ib_cursor_set_lock_mode(cursor, ib_lock_mode);
2217
assert(err == DB_SUCCESS); // FIXME
2219
tuple= ib_clust_read_tuple_create(cursor);
2221
err= ib_cursor_first(cursor);
2222
if (err != DB_SUCCESS && err != DB_END_OF_INDEX)
2224
int reset_err= ib_cursor_reset(cursor);
2225
assert(reset_err == DB_SUCCESS);
2226
return ib_err_t_to_drizzle_error(getTable()->getSession(), err);
2229
advance_cursor= false;
2234
int read_row_from_haildb(Session *session, unsigned char* buf, ib_crsr_t cursor, ib_tpl_t tuple, Table* table, bool has_hidden_primary_key, uint64_t *hidden_pkey, drizzled::memory::Root **blobroot)
2237
ptrdiff_t row_offset= buf - table->getInsertRecord();
2239
err= ib_cursor_read_row(cursor, tuple);
2241
if (err == DB_RECORD_NOT_FOUND)
2242
return HA_ERR_END_OF_FILE;
2243
if (err != DB_SUCCESS)
2244
return ib_err_t_to_drizzle_error(session, err);
2248
/* We need the primary key for ::position() to work */
2249
if (table->getShare()->getPrimaryKey() != MAX_KEY)
2250
table->mark_columns_used_by_index_no_reset(table->getShare()->getPrimaryKey());
2252
for (Field **field= table->getFields() ; *field ; field++, colnr++)
2254
if (! (**field).isReadSet())
2255
(**field).setReadSet(); /* Fucking broken API screws us royally. */
2257
(**field).move_field_offset(row_offset);
2259
(**field).setWriteSet();
2261
uint32_t length= ib_col_get_len(tuple, colnr);
2262
if (length == IB_SQL_NULL)
2264
(**field).set_null();
2265
(**field).move_field_offset(-row_offset);
2269
(**field).set_notnull();
2271
if ((**field).type() == DRIZZLE_TYPE_VARCHAR)
2273
(*field)->store((const char*)ib_col_get_value(tuple, colnr),
2277
else if ((**field).type() == DRIZZLE_TYPE_DATE)
2280
err= ib_tuple_read_u32(tuple, colnr, &date_read);
2281
(*field)->store(date_read);
2283
else if ((**field).type() == DRIZZLE_TYPE_BLOB)
2285
if (blobroot == NULL)
2286
(reinterpret_cast<Field_blob*>(*field))->set_ptr(length,
2287
(unsigned char*)ib_col_get_value(tuple,
2291
if (*blobroot == NULL)
2293
*blobroot= new drizzled::memory::Root();
2294
(**blobroot).init_alloc_root();
2297
unsigned char *blob_ptr= (unsigned char*)(**blobroot).alloc_root(length);
2298
memcpy(blob_ptr, ib_col_get_value(tuple, colnr), length);
2299
(reinterpret_cast<Field_blob*>(*field))->set_ptr(length, blob_ptr);
2304
ib_col_copy_value(tuple, colnr, (*field)->ptr, (*field)->data_length());
2307
(**field).move_field_offset(-row_offset);
2309
if (err != DB_SUCCESS)
2310
return ib_err_t_to_drizzle_error(session, err);
2313
if (has_hidden_primary_key)
2315
err= ib_tuple_read_u64(tuple, colnr, hidden_pkey);
2318
return ib_err_t_to_drizzle_error(session, err);
2321
int HailDBCursor::rnd_next(unsigned char *buf)
2328
err= ib_cursor_next(cursor);
2329
if (err != DB_SUCCESS)
2330
return ib_err_t_to_drizzle_error(getTable()->getSession(), err);
2333
tuple= ib_tuple_clear(tuple);
2334
ret= read_row_from_haildb(getTable()->getSession(), buf, cursor, tuple,
2336
share->has_hidden_primary_key,
2337
&hidden_autoinc_pkey_position);
2339
advance_cursor= true;
2343
int HailDBCursor::doEndTableScan()
2347
ib_tuple_delete(tuple);
2349
err= ib_cursor_reset(cursor);
2350
assert(err == DB_SUCCESS);
2351
in_table_scan= false;
2352
return ib_err_t_to_drizzle_error(getTable()->getSession(), err);
2355
int HailDBCursor::rnd_pos(unsigned char *buf, unsigned char *pos)
2360
ib_tpl_t search_tuple= ib_clust_search_tuple_create(cursor);
2362
if (share->has_hidden_primary_key)
2364
err= ib_col_set_value(search_tuple, 0,
2365
((uint64_t*)(pos)), sizeof(uint64_t));
2366
if (err != DB_SUCCESS)
2367
return ib_err_t_to_drizzle_error(getTable()->getSession(), err);
2372
if (getTable()->getShare()->getPrimaryKey() != MAX_KEY)
2373
keynr= getTable()->getShare()->getPrimaryKey();
2375
keynr= get_first_unique_index(*getTable());
2377
fill_ib_search_tpl_from_drizzle_key(search_tuple,
2378
getTable()->key_info + keynr,
2382
err= ib_cursor_moveto(cursor, search_tuple, IB_CUR_GE, &res);
2383
if (err != DB_SUCCESS)
2384
return ib_err_t_to_drizzle_error(getTable()->getSession(), err);
2390
ib_tuple_delete(search_tuple);
2392
tuple= ib_tuple_clear(tuple);
2395
ret= read_row_from_haildb(getTable()->getSession(), buf, cursor, tuple,
2397
share->has_hidden_primary_key,
2398
&hidden_autoinc_pkey_position);
2400
advance_cursor= true;
2405
static void store_key_value_from_haildb(KeyInfo *key_info, unsigned char* ref, int ref_len, const unsigned char *record)
2407
KeyPartInfo* key_part= key_info->key_part;
2408
KeyPartInfo* end= key_info->key_part + key_info->key_parts;
2409
unsigned char* ref_start= ref;
2411
memset(ref, 0, ref_len);
2413
for (; key_part != end; key_part++)
2417
if(key_part->null_bit)
2419
*ref= is_null= record[key_part->null_offset] & key_part->null_bit;
2423
Field *field= key_part->field;
2425
if (field->type() == DRIZZLE_TYPE_VARCHAR)
2429
ref+= key_part->length + 2; /* 2 bytes for length */
2434
field->val_str_internal(&str);
2436
*ref++= (char)(str.length() & 0x000000ff);
2437
*ref++= (char)((str.length()>>8) & 0x000000ff);
2439
memcpy(ref, str.ptr(), str.length());
2440
ref+= key_part->length;
2447
ref+= key_part->length;
2451
memcpy(ref, record+key_part->offset, key_part->length);
2452
ref+= key_part->length;
2457
assert(ref == ref_start + ref_len);
2460
void HailDBCursor::position(const unsigned char *record)
2462
if (share->has_hidden_primary_key)
2463
*((uint64_t*) ref)= hidden_autoinc_pkey_position;
2467
if (getTable()->getShare()->getPrimaryKey() != MAX_KEY)
2468
keynr= getTable()->getShare()->getPrimaryKey();
2470
keynr= get_first_unique_index(*getTable());
2472
store_key_value_from_haildb(getTable()->key_info + keynr,
2473
ref, ref_length, record);
2479
double HailDBCursor::scan_time()
2481
ib_table_stats_t table_stats;
2484
err= ib_get_table_statistics(cursor, &table_stats, sizeof(table_stats));
2486
/* Approximate I/O seeks for full table scan */
2487
return (double) (table_stats.stat_clustered_index_size / 16384);
2490
int HailDBCursor::info(uint32_t flag)
2492
ib_table_stats_t table_stats;
2495
if (flag & HA_STATUS_VARIABLE)
2497
err= ib_get_table_statistics(cursor, &table_stats, sizeof(table_stats));
2499
stats.records= table_stats.stat_n_rows;
2501
if (table_stats.stat_n_rows < 2)
2505
stats.data_file_length= table_stats.stat_clustered_index_size;
2506
stats.index_file_length= table_stats.stat_sum_of_other_index_sizes;
2508
stats.mean_rec_length= stats.data_file_length / stats.records;
2511
if (flag & HA_STATUS_AUTO)
2512
stats.auto_increment_value= 1;
2514
if (flag & HA_STATUS_ERRKEY) {
2515
const char *err_table_name;
2516
const char *err_index_name;
2518
ib_trx_t transaction= *get_trx(getTable()->in_use);
2520
err= ib_get_duplicate_key(transaction, &err_table_name, &err_index_name);
2524
for (unsigned int i = 0; i < getTable()->getShare()->keys; i++)
2526
if (strcmp(err_index_name, getTable()->key_info[i].name) == 0)
2535
if (flag & HA_STATUS_CONST)
2537
for (unsigned int i = 0; i < getTable()->getShare()->sizeKeys(); i++)
2539
const char* index_name= getTable()->key_info[i].name;
2542
ha_rows rec_per_key;
2544
err= ib_get_index_stat_n_diff_key_vals(cursor, index_name,
2547
if (err != DB_SUCCESS)
2548
return ib_err_t_to_drizzle_error(getTable()->getSession(), err);
2550
for (unsigned int j=0; j < getTable()->key_info[i].key_parts; j++)
2552
if (n_diff[j+1] == 0)
2553
rec_per_key= stats.records;
2555
rec_per_key= stats.records / n_diff[j+1];
2557
/* We import this heuristic from ha_innodb, which says
2558
that MySQL favours table scans too much over index searches,
2559
so we pretend our index selectivity is 2 times better. */
2561
rec_per_key= rec_per_key / 2;
2563
if (rec_per_key == 0)
2566
getTable()->key_info[i].rec_per_key[j]=
2567
rec_per_key >= ~(ulong) 0 ? ~(ulong) 0 :
2568
(ulong) rec_per_key;
2578
int HailDBCursor::doStartIndexScan(uint32_t keynr, bool)
2581
ib_trx_t transaction= *get_trx(getTable()->in_use);
2583
active_index= keynr;
2585
if (active_index == 0 && ! share->has_hidden_primary_key)
2587
if (cursor_is_sec_index)
2589
err= ib_cursor_close(cursor);
2590
assert(err == DB_SUCCESS);
2592
err= ib_cursor_open_table_using_id(table_id, transaction, &cursor);
2594
if (err != DB_SUCCESS)
2595
return ib_err_t_to_drizzle_error(getTable()->getSession(), err);
2600
ib_cursor_attach_trx(cursor, transaction);
2603
cursor_is_sec_index= false;
2604
tuple= ib_clust_read_tuple_create(cursor);
2609
err= ib_index_get_id(table_path_to_haildb_name(getShare()->getPath()),
2610
getShare()->getKeyInfo(keynr).name,
2612
if (err != DB_SUCCESS)
2613
return ib_err_t_to_drizzle_error(getTable()->getSession(), err);
2615
err= ib_cursor_close(cursor);
2616
assert(err == DB_SUCCESS);
2618
err= ib_cursor_open_index_using_id(index_id, transaction, &cursor);
2620
if (err != DB_SUCCESS)
2621
return ib_err_t_to_drizzle_error(getTable()->getSession(), err);
2623
cursor_is_sec_index= true;
2625
tuple= ib_clust_read_tuple_create(cursor);
2626
ib_cursor_set_cluster_access(cursor);
2629
err= ib_cursor_set_lock_mode(cursor, ib_lock_mode);
2630
assert(err == DB_SUCCESS);
2632
advance_cursor= false;
2636
static ib_srch_mode_t ha_rkey_function_to_ib_srch_mode(drizzled::ha_rkey_function find_flag)
2640
case HA_READ_KEY_EXACT:
2642
case HA_READ_KEY_OR_NEXT:
2644
case HA_READ_KEY_OR_PREV:
2646
case HA_READ_AFTER_KEY:
2648
case HA_READ_BEFORE_KEY:
2650
case HA_READ_PREFIX:
2652
case HA_READ_PREFIX_LAST:
2654
case HA_READ_PREFIX_LAST_OR_PREV:
2656
case HA_READ_MBR_CONTAIN:
2657
case HA_READ_MBR_INTERSECT:
2658
case HA_READ_MBR_WITHIN:
2659
case HA_READ_MBR_DISJOINT:
2660
case HA_READ_MBR_EQUAL:
2661
assert(false); /* these just exist in the enum, not used. */
2665
/* Must return or compiler complains about reaching end of function */
2666
return (ib_srch_mode_t)0;
2669
static void fill_ib_search_tpl_from_drizzle_key(ib_tpl_t search_tuple,
2670
const drizzled::KeyInfo *key_info,
2671
const unsigned char *key_ptr,
2674
KeyPartInfo *key_part= key_info->key_part;
2675
KeyPartInfo *end= key_part + key_info->key_parts;
2676
const unsigned char *buff= key_ptr;
2681
for(; key_part != end && buff < key_ptr + key_len; key_part++)
2683
Field *field= key_part->field;
2684
bool is_null= false;
2686
if (key_part->null_bit)
2691
err= ib_col_set_value(search_tuple, fieldnr, NULL, IB_SQL_NULL);
2692
assert(err == DB_SUCCESS);
2697
if (field->type() == DRIZZLE_TYPE_VARCHAR)
2701
buff+= key_part->length + 2; /* 2 bytes length */
2705
int length= *buff + (*(buff + 1) << 8);
2707
err= ib_col_set_value(search_tuple, fieldnr, buff, length);
2708
assert(err == DB_SUCCESS);
2710
buff+= key_part->length;
2712
else if (field->type() == DRIZZLE_TYPE_DATE)
2714
uint32_t date_int= static_cast<uint32_t>(field->val_int());
2715
err= ib_col_set_value(search_tuple, fieldnr, &date_int, 4);
2716
buff+= key_part->length;
2723
buff+= key_part->length;
2727
err= ib_col_set_value(search_tuple, fieldnr,
2728
buff, key_part->length);
2729
assert(err == DB_SUCCESS);
2731
buff+= key_part->length;
2737
assert(buff == key_ptr + key_len);
2740
int HailDBCursor::haildb_index_read(unsigned char *buf,
2741
const unsigned char *key_ptr,
2743
drizzled::ha_rkey_function find_flag,
2744
bool allocate_blobs)
2746
ib_tpl_t search_tuple;
2750
ib_srch_mode_t search_mode;
2752
search_mode= ha_rkey_function_to_ib_srch_mode(find_flag);
2754
if (active_index == 0 && ! share->has_hidden_primary_key)
2755
search_tuple= ib_clust_search_tuple_create(cursor);
2757
search_tuple= ib_sec_search_tuple_create(cursor);
2759
fill_ib_search_tpl_from_drizzle_key(search_tuple,
2760
getTable()->key_info + active_index,
2763
err= ib_cursor_moveto(cursor, search_tuple, search_mode, &res);
2764
ib_tuple_delete(search_tuple);
2766
if ((err == DB_RECORD_NOT_FOUND || err == DB_END_OF_INDEX))
2768
getTable()->status= STATUS_NOT_FOUND;
2769
return HA_ERR_KEY_NOT_FOUND;
2772
if (err != DB_SUCCESS)
2774
return ib_err_t_to_drizzle_error(getTable()->getSession(), err);
2777
tuple= ib_tuple_clear(tuple);
2778
ret= read_row_from_haildb(getTable()->getSession(), buf, cursor, tuple,
2780
share->has_hidden_primary_key,
2781
&hidden_autoinc_pkey_position,
2782
(allocate_blobs)? &blobroot : NULL);
2784
getTable()->status= 0;
2786
getTable()->status= STATUS_NOT_FOUND;
2788
advance_cursor= true;
2793
int HailDBCursor::index_read(unsigned char *buf,
2794
const unsigned char *key_ptr,
2796
drizzled::ha_rkey_function find_flag)
2798
return haildb_index_read(buf, key_ptr, key_len, find_flag, false);
2801
/* This is straight from cursor.cc, but it's private there :( */
2802
uint32_t HailDBCursor::calculate_key_len(uint32_t key_position,
2803
key_part_map keypart_map_arg)
2805
/* works only with key prefixes */
2806
assert(((keypart_map_arg + 1) & keypart_map_arg) == 0);
2808
KeyPartInfo *key_part_found= getTable()->getShare()->getKeyInfo(key_position).key_part;
2809
KeyPartInfo *end_key_part_found= key_part_found + getTable()->getShare()->getKeyInfo(key_position).key_parts;
2812
while (key_part_found < end_key_part_found && keypart_map_arg)
2814
length+= key_part_found->store_length;
2815
keypart_map_arg >>= 1;
2822
int HailDBCursor::haildb_index_read_map(unsigned char * buf,
2823
const unsigned char *key,
2824
key_part_map keypart_map,
2825
enum ha_rkey_function find_flag,
2826
bool allocate_blobs)
2828
uint32_t key_len= calculate_key_len(active_index, keypart_map);
2829
return haildb_index_read(buf, key, key_len, find_flag, allocate_blobs);
2832
int HailDBCursor::index_read_idx_map(unsigned char * buf,
2834
const unsigned char * key,
2835
key_part_map keypart_map,
2836
enum ha_rkey_function find_flag)
2839
error= doStartIndexScan(index, 0);
2842
error= haildb_index_read_map(buf, key, keypart_map, find_flag, true);
2843
error1= doEndIndexScan();
2845
return error ? error : error1;
2848
int HailDBCursor::reset()
2851
blobroot->free_root(MYF(0));
2856
int HailDBCursor::analyze(Session*)
2860
err= ib_update_table_statistics(cursor);
2862
return ib_err_t_to_drizzle_error(getTable()->getSession(), err);
2865
int HailDBCursor::index_next(unsigned char *buf)
2867
int ret= HA_ERR_END_OF_FILE;
2871
ib_err_t err= ib_cursor_next(cursor);
2872
if (err == DB_END_OF_INDEX)
2873
return HA_ERR_END_OF_FILE;
2876
tuple= ib_tuple_clear(tuple);
2877
ret= read_row_from_haildb(getTable()->getSession(), buf, cursor, tuple,
2879
share->has_hidden_primary_key,
2880
&hidden_autoinc_pkey_position);
2882
advance_cursor= true;
2886
int HailDBCursor::doEndIndexScan()
2888
active_index= MAX_KEY;
2890
return doEndTableScan();
2893
int HailDBCursor::index_prev(unsigned char *buf)
2895
int ret= HA_ERR_END_OF_FILE;
2900
err= ib_cursor_prev(cursor);
2901
if (err != DB_SUCCESS)
2903
if (err == DB_END_OF_INDEX)
2904
return HA_ERR_END_OF_FILE;
2906
return ib_err_t_to_drizzle_error(getTable()->getSession(), err);
2910
tuple= ib_tuple_clear(tuple);
2911
ret= read_row_from_haildb(getTable()->getSession(), buf, cursor, tuple,
2913
share->has_hidden_primary_key,
2914
&hidden_autoinc_pkey_position);
2916
advance_cursor= true;
2922
int HailDBCursor::index_first(unsigned char *buf)
2924
int ret= HA_ERR_END_OF_FILE;
2927
err= ib_cursor_first(cursor);
2928
if (err != DB_SUCCESS)
2929
return ib_err_t_to_drizzle_error(getTable()->getSession(), err);
2931
tuple= ib_tuple_clear(tuple);
2932
ret= read_row_from_haildb(getTable()->getSession(), buf, cursor, tuple,
2934
share->has_hidden_primary_key,
2935
&hidden_autoinc_pkey_position);
2937
advance_cursor= true;
2943
int HailDBCursor::index_last(unsigned char *buf)
2945
int ret= HA_ERR_END_OF_FILE;
2948
err= ib_cursor_last(cursor);
2949
if (err != DB_SUCCESS)
2950
return ib_err_t_to_drizzle_error(getTable()->getSession(), err);
2952
tuple= ib_tuple_clear(tuple);
2953
ret= read_row_from_haildb(getTable()->getSession(), buf, cursor, tuple,
2955
share->has_hidden_primary_key,
2956
&hidden_autoinc_pkey_position);
2957
advance_cursor= true;
2962
int HailDBCursor::extra(enum ha_extra_function operation)
2966
case HA_EXTRA_FLUSH:
2968
blobroot->free_root(MYF(0));
2970
case HA_EXTRA_WRITE_CAN_REPLACE:
2971
write_can_replace= true;
2973
case HA_EXTRA_WRITE_CANNOT_REPLACE:
2974
write_can_replace= false;
2983
static int create_table_message_table()
2985
ib_tbl_sch_t schema;
2986
ib_idx_sch_t index_schema;
2987
ib_trx_t transaction;
2989
ib_err_t err, rollback_err;
2990
ib_bool_t create_db_err;
2992
create_db_err= ib_database_create("data_dictionary");
2993
if (create_db_err != IB_TRUE)
2996
err= ib_table_schema_create(HAILDB_TABLE_DEFINITIONS_TABLE, &schema,
2998
if (err != DB_SUCCESS)
3001
err= ib_table_schema_add_col(schema, "table_name", IB_VARCHAR, IB_COL_NONE, 0,
3002
IB_MAX_TABLE_NAME_LEN);
3003
if (err != DB_SUCCESS)
3006
err= ib_table_schema_add_col(schema, "message", IB_BLOB, IB_COL_NONE, 0, 0);
3007
if (err != DB_SUCCESS)
3010
err= ib_table_schema_add_index(schema, "PRIMARY_KEY", &index_schema);
3011
if (err != DB_SUCCESS)
3014
err= ib_index_schema_add_col(index_schema, "table_name", 0);
3015
if (err != DB_SUCCESS)
3017
err= ib_index_schema_set_clustered(index_schema);
3018
if (err != DB_SUCCESS)
3021
transaction= ib_trx_begin(IB_TRX_REPEATABLE_READ);
3022
err= ib_schema_lock_exclusive(transaction);
3023
if (err != DB_SUCCESS)
3026
err= ib_table_create(transaction, schema, &table_id);
3027
if (err != DB_SUCCESS)
3030
err= ib_trx_commit(transaction);
3031
if (err != DB_SUCCESS)
3034
ib_table_schema_delete(schema);
3038
ib_schema_unlock(transaction);
3039
rollback_err= ib_trx_rollback(transaction);
3040
assert(rollback_err == DB_SUCCESS);
3042
ib_table_schema_delete(schema);
3046
static bool innobase_use_doublewrite= true;
3047
static bool srv_file_per_table= false;
3048
static bool innobase_adaptive_hash_index;
3049
static bool srv_adaptive_flushing;
3050
static bool innobase_print_verbose_log;
3051
static bool innobase_rollback_on_timeout;
3052
static bool innobase_create_status_file;
3053
static bool srv_use_sys_malloc;
3054
static string innobase_file_format_name;
3055
typedef constrained_check<unsigned int, 1000, 1> autoextend_constraint;
3056
static autoextend_constraint srv_auto_extend_increment;
3057
typedef constrained_check<size_t, SIZE_MAX, 5242880, 1048576> buffer_pool_constraint;
3058
static buffer_pool_constraint innobase_buffer_pool_size;
3059
typedef constrained_check<size_t, SIZE_MAX, 512, 1024> additional_mem_pool_constraint;
3060
static additional_mem_pool_constraint innobase_additional_mem_pool_size;
3061
static bool innobase_use_checksums= true;
3062
typedef constrained_check<unsigned int, UINT_MAX, 100> io_capacity_constraint;
3063
typedef constrained_check<uint32_t, 2, 0> trinary_constraint;
3064
static trinary_constraint innobase_fast_shutdown;
3065
static trinary_constraint srv_flush_log_at_trx_commit;
3066
typedef constrained_check<uint32_t, 6, 0> force_recovery_constraint;
3067
static force_recovery_constraint innobase_force_recovery;
3068
typedef constrained_check<int64_t, INT64_MAX, 1024*1024, 1024*1024> log_file_constraint;
3069
static log_file_constraint haildb_log_file_size;
3071
static io_capacity_constraint srv_io_capacity;
3072
typedef constrained_check<unsigned int, 100, 2> log_files_in_group_constraint;
3073
static log_files_in_group_constraint haildb_log_files_in_group;
3074
typedef constrained_check<unsigned int, 1024*1024*1024, 1> lock_wait_constraint;
3075
static lock_wait_constraint innobase_lock_wait_timeout;
3076
typedef constrained_check<long, LONG_MAX, 256*1024, 1024> log_buffer_size_constraint;
3077
static log_buffer_size_constraint innobase_log_buffer_size;
3078
typedef constrained_check<unsigned int, 97, 5> lru_old_blocks_constraint;
3079
static lru_old_blocks_constraint innobase_lru_old_blocks_pct;
3080
typedef constrained_check<unsigned int, 99, 0> max_dirty_pages_constraint;
3081
static max_dirty_pages_constraint haildb_max_dirty_pages_pct;
3082
static uint64_constraint haildb_max_purge_lag;
3083
static uint64_constraint haildb_sync_spin_loops;
3084
typedef constrained_check<uint32_t, UINT32_MAX, 10> open_files_constraint;
3085
static open_files_constraint haildb_open_files;
3086
typedef constrained_check<unsigned int, 64, 1> io_threads_constraint;
3087
static io_threads_constraint haildb_read_io_threads;
3088
static io_threads_constraint haildb_write_io_threads;
3091
static uint32_t innobase_lru_block_access_recency;
3095
static int haildb_file_format_name_validate(Session*, set_var *var)
3098
const char *format= var->value->str_value.ptr();
3102
ib_err_t err= ib_cfg_set_text("file_format", format);
3104
if (err == DB_SUCCESS)
3106
innobase_file_format_name= format;
3113
static void haildb_lru_old_blocks_pct_update(Session*, sql_var_t)
3115
int ret= ib_cfg_set_int("lru_old_blocks_pct", static_cast<uint32_t>(innobase_lru_old_blocks_pct));
3119
static void haildb_lru_block_access_recency_update(Session*, sql_var_t)
3121
int ret= ib_cfg_set_int("lru_block_access_recency", static_cast<uint32_t>(innobase_lru_block_access_recency));
3125
static void haildb_status_file_update(Session*, sql_var_t)
3129
if (innobase_create_status_file)
3130
err= ib_cfg_set_bool_on("status_file");
3132
err= ib_cfg_set_bool_off("status_file");
3136
extern "C" int haildb_errmsg_callback(ib_msg_stream_t, const char *fmt, ...);
3139
extern bool volatile shutdown_in_progress;
3142
extern "C" int haildb_errmsg_callback(ib_msg_stream_t, const char *fmt, ...)
3146
va_start(args, fmt);
3147
if (not shutdown_in_progress)
3149
r= plugin::ErrorMessage::vprintf(error::WARN, fmt, args);
3153
vfprintf(stderr, fmt, args);
3160
static int haildb_init(drizzled::module::Context &context)
3162
haildb_system_table_names.insert(std::string("HAILDB_SYS_TABLES"));
3163
haildb_system_table_names.insert(std::string("HAILDB_SYS_COLUMNS"));
3164
haildb_system_table_names.insert(std::string("HAILDB_SYS_INDEXES"));
3165
haildb_system_table_names.insert(std::string("HAILDB_SYS_FIELDS"));
3166
haildb_system_table_names.insert(std::string("HAILDB_SYS_FOREIGN"));
3167
haildb_system_table_names.insert(std::string("HAILDB_SYS_FOREIGN_COLS"));
3169
const module::option_map &vm= context.getOptions();
3171
/* Inverted Booleans */
3173
innobase_adaptive_hash_index= (vm.count("disable-adaptive-hash-index")) ? false : true;
3174
srv_adaptive_flushing= (vm.count("disable-adaptive-flushing")) ? false : true;
3175
innobase_use_checksums= (vm.count("disable-checksums")) ? false : true;
3176
innobase_use_doublewrite= (vm.count("disable-doublewrite")) ? false : true;
3177
innobase_print_verbose_log= (vm.count("disable-print-verbose-log")) ? false : true;
3178
srv_use_sys_malloc= (vm.count("use-internal-malloc")) ? false : true;
3184
if (err != DB_SUCCESS)
3187
ib_logger_set(haildb_errmsg_callback, NULL);
3189
if (not vm["data-home-dir"].as<string>().empty())
3191
err= ib_cfg_set_text("data_home_dir", vm["data-home-dir"].as<string>().c_str());
3192
if (err != DB_SUCCESS)
3196
if (vm.count("log-group-home-dir"))
3198
err= ib_cfg_set_text("log_group_home_dir", vm["log-group-home-dir"].as<string>().c_str());
3199
if (err != DB_SUCCESS)
3203
if (innobase_print_verbose_log)
3204
err= ib_cfg_set_bool_on("print_verbose_log");
3206
err= ib_cfg_set_bool_off("print_verbose_log");
3208
if (err != DB_SUCCESS)
3211
if (innobase_rollback_on_timeout)
3212
err= ib_cfg_set_bool_on("rollback_on_timeout");
3214
err= ib_cfg_set_bool_off("rollback_on_timeout");
3216
if (err != DB_SUCCESS)
3219
if (innobase_use_doublewrite)
3220
err= ib_cfg_set_bool_on("doublewrite");
3222
err= ib_cfg_set_bool_off("doublewrite");
3224
if (err != DB_SUCCESS)
3227
if (innobase_adaptive_hash_index)
3228
err= ib_cfg_set_bool_on("adaptive_hash_index");
3230
err= ib_cfg_set_bool_off("adaptive_hash_index");
3232
if (err != DB_SUCCESS)
3235
if (srv_adaptive_flushing)
3236
err= ib_cfg_set_bool_on("adaptive_flushing");
3238
err= ib_cfg_set_bool_off("adaptive_flushing");
3240
if (err != DB_SUCCESS)
3243
err= ib_cfg_set_int("additional_mem_pool_size", innobase_additional_mem_pool_size.get());
3244
if (err != DB_SUCCESS)
3247
err= ib_cfg_set_int("autoextend_increment", srv_auto_extend_increment.get());
3248
if (err != DB_SUCCESS)
3251
err= ib_cfg_set_int("buffer_pool_size", innobase_buffer_pool_size.get());
3252
if (err != DB_SUCCESS)
3255
err= ib_cfg_set_int("io_capacity", srv_io_capacity.get());
3256
if (err != DB_SUCCESS)
3259
if (srv_file_per_table)
3260
err= ib_cfg_set_bool_on("file_per_table");
3262
err= ib_cfg_set_bool_off("file_per_table");
3264
if (err != DB_SUCCESS)
3267
err= ib_cfg_set_int("flush_log_at_trx_commit",
3268
srv_flush_log_at_trx_commit.get());
3269
if (err != DB_SUCCESS)
3272
if (vm.count("flush-method") != 0)
3274
err= ib_cfg_set_text("flush_method",
3275
vm["flush-method"].as<string>().c_str());
3276
if (err != DB_SUCCESS)
3280
err= ib_cfg_set_int("force_recovery",
3281
innobase_force_recovery.get());
3282
if (err != DB_SUCCESS)
3285
err= ib_cfg_set_text("data_file_path", vm["data-file-path"].as<string>().c_str());
3286
if (err != DB_SUCCESS)
3289
err= ib_cfg_set_int("log_file_size", haildb_log_file_size.get());
3290
if (err != DB_SUCCESS)
3293
err= ib_cfg_set_int("log_buffer_size", innobase_log_buffer_size.get());
3294
if (err != DB_SUCCESS)
3297
err= ib_cfg_set_int("log_files_in_group", haildb_log_files_in_group.get());
3298
if (err != DB_SUCCESS)
3301
err= ib_cfg_set_int("checksums", innobase_use_checksums);
3302
if (err != DB_SUCCESS)
3305
err= ib_cfg_set_int("lock_wait_timeout", innobase_lock_wait_timeout.get());
3306
if (err != DB_SUCCESS)
3309
err= ib_cfg_set_int("max_dirty_pages_pct", haildb_max_dirty_pages_pct.get());
3310
if (err != DB_SUCCESS)
3313
err= ib_cfg_set_int("max_purge_lag", haildb_max_purge_lag.get());
3314
if (err != DB_SUCCESS)
3317
err= ib_cfg_set_int("open_files", haildb_open_files.get());
3318
if (err != DB_SUCCESS)
3321
err= ib_cfg_set_int("read_io_threads", haildb_read_io_threads.get());
3322
if (err != DB_SUCCESS)
3325
err= ib_cfg_set_int("write_io_threads", haildb_write_io_threads.get());
3326
if (err != DB_SUCCESS)
3329
err= ib_cfg_set_int("sync_spin_loops", haildb_sync_spin_loops.get());
3330
if (err != DB_SUCCESS)
3333
if (srv_use_sys_malloc)
3334
err= ib_cfg_set_bool_on("use_sys_malloc");
3336
err= ib_cfg_set_bool_off("use_sys_malloc");
3338
if (err != DB_SUCCESS)
3341
err= ib_startup(innobase_file_format_name.c_str());
3342
if (err != DB_SUCCESS)
3345
create_table_message_table();
3347
haildb_engine= new HailDBEngine("InnoDB");
3348
context.add(haildb_engine);
3349
context.registerVariable(new sys_var_bool_ptr_readonly("adaptive_hash_index",
3350
&innobase_adaptive_hash_index));
3351
context.registerVariable(new sys_var_bool_ptr_readonly("adaptive_flushing",
3352
&srv_adaptive_flushing));
3353
context.registerVariable(new sys_var_constrained_value_readonly<size_t>("additional_mem_pool_size",innobase_additional_mem_pool_size));
3354
context.registerVariable(new sys_var_constrained_value_readonly<unsigned int>("autoextend_increment", srv_auto_extend_increment));
3355
context.registerVariable(new sys_var_constrained_value_readonly<size_t>("buffer_pool_size", innobase_buffer_pool_size));
3356
context.registerVariable(new sys_var_bool_ptr_readonly("checksums",
3357
&innobase_use_checksums));
3358
context.registerVariable(new sys_var_bool_ptr_readonly("doublewrite",
3359
&innobase_use_doublewrite));
3360
context.registerVariable(new sys_var_const_string_val("data_file_path",
3361
vm["data-file-path"].as<string>()));
3362
context.registerVariable(new sys_var_const_string_val("data_home_dir",
3363
vm["data-home-dir"].as<string>()));
3364
context.registerVariable(new sys_var_constrained_value_readonly<unsigned int>("io_capacity", srv_io_capacity));
3365
context.registerVariable(new sys_var_constrained_value_readonly<uint32_t>("fast_shutdown", innobase_fast_shutdown));
3366
context.registerVariable(new sys_var_bool_ptr_readonly("file_per_table",
3367
&srv_file_per_table));
3368
context.registerVariable(new sys_var_bool_ptr_readonly("rollback_on_timeout",
3369
&innobase_rollback_on_timeout));
3370
context.registerVariable(new sys_var_bool_ptr_readonly("print_verbose_log",
3371
&innobase_print_verbose_log));
3372
context.registerVariable(new sys_var_bool_ptr("status_file",
3373
&innobase_create_status_file,
3374
haildb_status_file_update));
3375
context.registerVariable(new sys_var_bool_ptr_readonly("use_sys_malloc",
3376
&srv_use_sys_malloc));
3377
context.registerVariable(new sys_var_std_string("file_format",
3378
innobase_file_format_name,
3379
haildb_file_format_name_validate));
3380
context.registerVariable(new sys_var_constrained_value_readonly<uint32_t>("flush_log_at_trx_commit", srv_flush_log_at_trx_commit));
3381
context.registerVariable(new sys_var_const_string_val("flush_method",
3382
vm.count("flush-method") ? vm["flush-method"].as<string>() : ""));
3383
context.registerVariable(new sys_var_constrained_value_readonly<uint32_t>("force_recovery", innobase_force_recovery));
3384
context.registerVariable(new sys_var_const_string_val("log_group_home_dir",
3385
vm.count("log-group-home-dir") ? vm["log-group-home-dir"].as<string>() : ""));
3386
context.registerVariable(new sys_var_constrained_value<int64_t>("log_file_size", haildb_log_file_size));
3387
context.registerVariable(new sys_var_constrained_value_readonly<unsigned int>("log_files_in_group", haildb_log_files_in_group));
3388
context.registerVariable(new sys_var_constrained_value_readonly<unsigned int>("lock_wait_timeout", innobase_lock_wait_timeout));
3389
context.registerVariable(new sys_var_constrained_value_readonly<long>("log_buffer_size", innobase_log_buffer_size));
3390
context.registerVariable(new sys_var_constrained_value<unsigned int>("lru_old_blocks_pct", innobase_lru_old_blocks_pct, haildb_lru_old_blocks_pct_update));
3391
context.registerVariable(new sys_var_uint32_t_ptr("lru_block_access_recency",
3392
&innobase_lru_block_access_recency,
3393
haildb_lru_block_access_recency_update));
3394
context.registerVariable(new sys_var_constrained_value_readonly<unsigned int>("max_dirty_pages_pct", haildb_max_dirty_pages_pct));
3395
context.registerVariable(new sys_var_constrained_value_readonly<uint64_t>("max_purge_lag", haildb_max_purge_lag));
3396
context.registerVariable(new sys_var_constrained_value_readonly<uint64_t>("sync_spin_loops", haildb_sync_spin_loops));
3397
context.registerVariable(new sys_var_constrained_value_readonly<uint32_t>("open_files", haildb_open_files));
3398
context.registerVariable(new sys_var_constrained_value_readonly<unsigned int>("read_io_threads", haildb_read_io_threads));
3399
context.registerVariable(new sys_var_constrained_value_readonly<unsigned int>("write_io_threads", haildb_write_io_threads));
3401
haildb_datadict_dump_func_initialize(context);
3402
config_table_function_initialize(context);
3403
status_table_function_initialize(context);
3407
fprintf(stderr, _("Error starting HailDB %d (%s)\n"),
3408
err, ib_strerror(err));
3413
HailDBEngine::~HailDBEngine()
3416
ib_shutdown_t shutdown_flag= IB_SHUTDOWN_NORMAL;
3418
if (innobase_fast_shutdown.get() == 1)
3419
shutdown_flag= IB_SHUTDOWN_NO_IBUFMERGE_PURGE;
3420
else if (innobase_fast_shutdown.get() == 2)
3421
shutdown_flag= IB_SHUTDOWN_NO_BUFPOOL_FLUSH;
3423
err= ib_shutdown(shutdown_flag);
3425
if (err != DB_SUCCESS)
3427
fprintf(stderr,"Error %d shutting down HailDB!\n", err);
3433
static void init_options(drizzled::module::option_context &context)
3435
context("disable-adaptive-hash-index",
3436
N_("Disable HailDB adaptive hash index (enabled by default)."));
3437
context("disable-adaptive-flushing",
3438
N_("Do not attempt to flush dirty pages to avoid IO bursts at checkpoints."));
3439
context("additional-mem-pool-size",
3440
po::value<additional_mem_pool_constraint>(&innobase_additional_mem_pool_size)->default_value(8*1024*1024L),
3441
N_("Size of a memory pool HailDB uses to store data dictionary information and other internal data structures."));
3442
context("autoextend-increment",
3443
po::value<autoextend_constraint>(&srv_auto_extend_increment)->default_value(8),
3444
N_("Data file autoextend increment in megabytes"));
3445
context("buffer-pool-size",
3446
po::value<buffer_pool_constraint>(&innobase_buffer_pool_size)->default_value(128*1024*1024L),
3447
N_("The size of the memory buffer HailDB uses to cache data and indexes of its tables."));
3448
context("data-home-dir",
3449
po::value<string>()->default_value(""),
3450
N_("The common part for HailDB table spaces."));
3451
context("disable-checksums",
3452
N_("Disable HailDB checksums validation (enabled by default)."));
3453
context("disable-doublewrite",
3454
N_("Disable HailDB doublewrite buffer (enabled by default)."));
3455
context("io-capacity",
3456
po::value<io_capacity_constraint>(&srv_io_capacity)->default_value(200),
3457
N_("Number of IOPs the server can do. Tunes the background IO rate"));
3458
context("fast-shutdown",
3459
po::value<trinary_constraint>(&innobase_fast_shutdown)->default_value(1),
3460
N_("Speeds up the shutdown process of the HailDB storage engine. Possible values are 0, 1 (faster) or 2 (fastest - crash-like)."));
3461
context("file-per-table",
3462
po::value<bool>(&srv_file_per_table)->default_value(false)->zero_tokens(),
3463
N_("Stores each HailDB table to an .ibd file in the database dir."));
3464
context("file-format",
3465
po::value<string>(&innobase_file_format_name)->default_value("Barracuda"),
3466
N_("File format to use for new tables in .ibd files."));
3467
context("flush-log-at-trx-commit",
3468
po::value<trinary_constraint>(&srv_flush_log_at_trx_commit)->default_value(1),
3469
N_("Set to 0 (write and flush once per second),1 (write and flush at each commit) or 2 (write at commit, flush once per second)."));
3470
context("flush-method",
3471
po::value<string>(),
3472
N_("With which method to flush data."));
3473
context("force-recovery",
3474
po::value<force_recovery_constraint>(&innobase_force_recovery)->default_value(0),
3475
N_("Helps to save your data in case the disk image of the database becomes corrupt."));
3476
context("data-file-path",
3477
po::value<string>()->default_value("ibdata1:10M:autoextend"),
3478
N_("Path to individual files and their sizes."));
3479
context("log-group-home-dir",
3480
po::value<string>(),
3481
N_("Path to HailDB log files."));
3482
context("log-file-size",
3483
po::value<log_file_constraint>(&haildb_log_file_size)->default_value(20*1024*1024L),
3484
N_("Size of each log file in a log group."));
3485
context("haildb-log-files-in-group",
3486
po::value<log_files_in_group_constraint>(&haildb_log_files_in_group)->default_value(2),
3487
N_("Number of log files in the log group. HailDB writes to the files in a circular fashion. Value 3 is recommended here."));
3488
context("lock-wait-timeout",
3489
po::value<lock_wait_constraint>(&innobase_lock_wait_timeout)->default_value(5),
3490
N_("Timeout in seconds an HailDB transaction may wait for a lock before being rolled back. Values above 100000000 disable the timeout."));
3491
context("log-buffer-size",
3492
po::value<log_buffer_size_constraint>(&innobase_log_buffer_size)->default_value(8*1024*1024L),
3493
N_("The size of the buffer which HailDB uses to write log to the log files on disk."));
3494
context("lru-old-blocks-pct",
3495
po::value<lru_old_blocks_constraint>(&innobase_lru_old_blocks_pct)->default_value(37),
3496
N_("Sets the point in the LRU list from where all pages are classified as old (Advanced users)"));
3497
context("lru-block-access-recency",
3498
po::value<uint32_t>(&innobase_lru_block_access_recency)->default_value(0),
3499
N_("Milliseconds between accesses to a block at which it is made young. 0=disabled (Advanced users)"));
3500
context("max-dirty-pages-pct",
3501
po::value<max_dirty_pages_constraint>(&haildb_max_dirty_pages_pct)->default_value(75),
3502
N_("Percentage of dirty pages allowed in bufferpool."));
3503
context("max-purge-lag",
3504
po::value<uint64_constraint>(&haildb_max_purge_lag)->default_value(0),
3505
N_("Desired maximum length of the purge queue (0 = no limit)"));
3506
context("rollback-on-timeout",
3507
po::value<bool>(&innobase_rollback_on_timeout)->default_value(false)->zero_tokens(),
3508
N_("Roll back the complete transaction on lock wait timeout, for 4.x compatibility (disabled by default)"));
3509
context("open-files",
3510
po::value<open_files_constraint>(&haildb_open_files)->default_value(300),
3511
N_("How many files at the maximum HailDB keeps open at the same time."));
3512
context("read-io-threads",
3513
po::value<io_threads_constraint>(&haildb_read_io_threads)->default_value(4),
3514
N_("Number of background read I/O threads in HailDB."));
3515
context("write-io-threads",
3516
po::value<io_threads_constraint>(&haildb_write_io_threads)->default_value(4),
3517
N_("Number of background write I/O threads in HailDB."));
3518
context("disable-print-verbose-log",
3519
N_("Disable if you want to reduce the number of messages written to the log (default: enabled)."));
3520
context("status-file",
3521
po::value<bool>(&innobase_create_status_file)->default_value(false)->zero_tokens(),
3522
N_("Enable SHOW HAILDB STATUS output in the log"));
3523
context("sync-spin-loops",
3524
po::value<uint64_constraint>(&haildb_sync_spin_loops)->default_value(30L),
3525
N_("Count of spin-loop rounds in HailDB mutexes (30 by default)"));
3526
context("use-internal-malloc",
3527
N_("Use HailDB's internal memory allocator instead of the OS memory allocator"));
3530
DRIZZLE_DECLARE_PLUGIN
3536
"Transactional Storage Engine using the HailDB Library",
3538
haildb_init, /* Plugin Init */
3540
init_options /* config options */
3542
DRIZZLE_DECLARE_PLUGIN_END;