12
12
You should have received a copy of the GNU General Public License
13
13
along with this program; if not, write to the Free Software
14
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
19
#include <drizzled/internal/my_bit.h>
14
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
18
#include <drizzled/server_includes.h>
19
#include <mysys/my_bit.h>
20
20
#include "myisampack.h"
21
21
#include "ha_myisam.h"
22
#include "myisam_priv.h"
23
#include <drizzled/option.h>
24
#include <drizzled/internal/my_bit.h>
25
#include <drizzled/internal/m_string.h>
22
#include "myisamdef.h"
26
23
#include <drizzled/util/test.h>
27
24
#include <drizzled/error.h>
28
25
#include <drizzled/errmsg_print.h>
29
26
#include <drizzled/gettext.h>
30
27
#include <drizzled/session.h>
31
#include <drizzled/plugin.h>
32
#include <drizzled/plugin/client.h>
28
#include <drizzled/protocol.h>
33
29
#include <drizzled/table.h>
34
#include <drizzled/memory/multi_malloc.h>
35
#include <drizzled/plugin/daemon.h>
37
#include <drizzled/plugin/storage_engine.h>
39
#include <boost/algorithm/string.hpp>
40
#include <boost/scoped_ptr.hpp>
47
#include <boost/program_options.hpp>
48
#include <drizzled/module/option_map.h>
50
namespace po= boost::program_options;
53
using namespace drizzled;
55
static const string engine_name("MyISAM");
57
boost::mutex THR_LOCK_myisam;
59
static uint32_t myisam_key_cache_block_size= KEY_CACHE_BLOCK_SIZE;
60
static uint32_t myisam_key_cache_size;
61
static uint32_t myisam_key_cache_division_limit;
62
static uint32_t myisam_key_cache_age_threshold;
30
#include <drizzled/field/timestamp.h>
32
ulong myisam_recover_options= HA_RECOVER_NONE;
33
pthread_mutex_t THR_LOCK_myisam= PTHREAD_MUTEX_INITIALIZER;
35
static uint32_t repair_threads;
36
static uint32_t block_size;
63
37
static uint64_t max_sort_file_size;
64
typedef constrained_check<size_t, SIZE_MAX, 1024, 1024> sort_buffer_constraint;
65
static sort_buffer_constraint sort_buffer_size;
67
void st_mi_isam_share::setKeyCache()
69
(void)init_key_cache(&key_cache,
70
myisam_key_cache_block_size,
71
myisam_key_cache_size,
72
myisam_key_cache_division_limit,
73
myisam_key_cache_age_threshold);
38
static uint64_t sort_buffer_size;
40
/* bits in myisam_recover_options */
41
const char *myisam_recover_names[] =
42
{ "DEFAULT", "BACKUP", "FORCE", "QUICK", NULL};
43
TYPELIB myisam_recover_typelib= {array_elements(myisam_recover_names)-1,"",
44
myisam_recover_names, NULL};
46
const char *myisam_stats_method_names[] = {"nulls_unequal", "nulls_equal",
47
"nulls_ignored", NULL};
48
TYPELIB myisam_stats_method_typelib= {
49
array_elements(myisam_stats_method_names) - 1, "",
50
myisam_stats_method_names, NULL};
76
53
/*****************************************************************************
78
55
*****************************************************************************/
80
static const char *ha_myisam_exts[] = {
86
class MyisamEngine : public plugin::StorageEngine
89
MyisamEngine(const MyisamEngine&);
90
MyisamEngine& operator=(const MyisamEngine&);
92
explicit MyisamEngine(string name_arg) :
93
plugin::StorageEngine(name_arg,
94
HTON_CAN_INDEX_BLOBS |
95
HTON_STATS_RECORDS_IS_EXACT |
101
HTON_SKIP_STORE_LOCK)
105
virtual ~MyisamEngine()
107
mi_panic(HA_PANIC_CLOSE);
110
virtual Cursor *create(Table &table)
112
return new ha_myisam(*this, table);
115
const char **bas_ext() const {
116
return ha_myisam_exts;
119
int doCreateTable(Session&,
121
const identifier::Table &identifier,
124
int doRenameTable(Session&, const identifier::Table &from, const identifier::Table &to);
126
int doDropTable(Session&, const identifier::Table &identifier);
128
int doGetTableDefinition(Session& session,
129
const identifier::Table &identifier,
130
message::Table &table_message);
132
uint32_t max_supported_keys() const { return MI_MAX_KEY; }
133
uint32_t max_supported_key_length() const { return MI_MAX_KEY_LENGTH; }
134
uint32_t max_supported_key_part_length() const { return MI_MAX_KEY_LENGTH; }
136
uint32_t index_flags(enum ha_key_alg) const
138
return (HA_READ_NEXT |
144
bool doDoesTableExist(Session& session, const identifier::Table &identifier);
146
void doGetTableIdentifiers(drizzled::CachedDirectory &directory,
147
const drizzled::identifier::Schema &schema_identifier,
148
drizzled::identifier::Table::vector &set_of_identifiers);
149
bool validateCreateTableOption(const std::string &key, const std::string &state)
152
if (boost::iequals(key, "ROW_FORMAT"))
161
void MyisamEngine::doGetTableIdentifiers(drizzled::CachedDirectory&,
162
const drizzled::identifier::Schema&,
163
drizzled::identifier::Table::vector&)
167
bool MyisamEngine::doDoesTableExist(Session &session, const identifier::Table &identifier)
169
return session.getMessageCache().doesTableMessageExist(identifier);
172
int MyisamEngine::doGetTableDefinition(Session &session,
173
const identifier::Table &identifier,
174
message::Table &table_message)
176
if (session.getMessageCache().getTableMessage(identifier, table_message))
182
Convert to push_Warnings if you ever care about this, otherwise, it is a no-op.
185
static void mi_check_print_msg(MI_CHECK *, const char* ,
186
const char *, va_list )
57
static handler *myisam_create_handler(handlerton *hton,
61
return new (mem_root) ha_myisam(hton, table);
64
// collect errors printed by mi_check routines
66
static void mi_check_print_msg(MI_CHECK *param, const char* msg_type,
67
const char *fmt, va_list args)
69
Session* session = (Session*)param->session;
70
Protocol *protocol= session->protocol;
71
uint32_t length, msg_length;
72
char msgbuf[MI_MAX_MSG_BUF];
73
char name[NAME_LEN*2+2];
75
msg_length= vsnprintf(msgbuf, sizeof(msgbuf), fmt, args);
76
msgbuf[sizeof(msgbuf) - 1] = 0; // healthy paranoia
78
if (!session->drizzleclient_vio_ok())
80
errmsg_printf(ERRMSG_LVL_ERROR, "%s",msgbuf);
84
if (param->testflag & (T_CREATE_MISSING_KEYS | T_SAFE_REPAIR |
87
my_message(ER_NOT_KEYFILE,msgbuf,MYF(MY_WME));
90
length= sprintf(name,"%s.%s",param->db_name,param->table_name);
93
TODO: switch from protocol to push_warning here. The main reason we didn't
94
it yet is parallel repair. Due to following trace:
95
mi_check_print_msg/push_warning/sql_alloc/my_pthread_getspecific_ptr.
97
Also we likely need to lock mutex here (in both cases with protocol and
100
protocol->prepare_for_resend();
101
protocol->store(name, length, system_charset_info);
102
protocol->store(param->op_name, system_charset_info);
103
protocol->store(msg_type, system_charset_info);
104
protocol->store(msgbuf, msg_length, system_charset_info);
105
if (protocol->write())
106
errmsg_printf(ERRMSG_LVL_ERROR, "Failed on drizzleclient_net_write, writing to stderr instead: %s\n",
215
static int table2myisam(Table *table_arg, MI_KEYDEF **keydef_out,
216
MI_COLUMNDEF **recinfo_out, uint32_t *records_out)
136
int table2myisam(Table *table_arg, MI_KEYDEF **keydef_out,
137
MI_COLUMNDEF **recinfo_out, uint32_t *records_out)
218
139
uint32_t i, j, recpos, minpos, fieldpos, temp_length, length;
219
140
enum ha_base_keytype type= HA_KEYTYPE_BINARY;
220
141
unsigned char *record;
221
143
MI_KEYDEF *keydef;
222
144
MI_COLUMNDEF *recinfo, *recinfo_pos;
223
145
HA_KEYSEG *keyseg;
224
TableShare *share= table_arg->getMutableShare();
146
TABLE_SHARE *share= table_arg->s;
225
147
uint32_t options= share->db_options_in_use;
226
if (!(memory::multi_malloc(false,
227
recinfo_out, (share->sizeFields() * 2 + 2) * sizeof(MI_COLUMNDEF),
228
keydef_out, share->sizeKeys() * sizeof(MI_KEYDEF),
229
&keyseg, (share->key_parts + share->sizeKeys()) * sizeof(HA_KEYSEG),
148
if (!(my_multi_malloc(MYF(MY_WME),
149
recinfo_out, (share->fields * 2 + 2) * sizeof(MI_COLUMNDEF),
150
keydef_out, share->keys * sizeof(MI_KEYDEF),
152
(share->key_parts + share->keys) * sizeof(HA_KEYSEG),
231
return(HA_ERR_OUT_OF_MEM);
154
return(HA_ERR_OUT_OF_MEM); /* purecov: inspected */
232
155
keydef= *keydef_out;
233
156
recinfo= *recinfo_out;
234
for (i= 0; i < share->sizeKeys(); i++)
157
pos= table_arg->key_info;
158
for (i= 0; i < share->keys; i++, pos++)
236
KeyInfo *pos= &table_arg->key_info[i];
237
160
keydef[i].flag= ((uint16_t) pos->flags & (HA_NOSAME));
238
161
keydef[i].key_alg= HA_KEY_ALG_BTREE;
239
162
keydef[i].block_length= pos->block_size;
532
451
const char *sfile, uint32_t sline)
534
453
Session *cur_session;
535
if ((cur_session= file->in_use))
537
errmsg_printf(error::ERROR, _("Got an error from thread_id=%"PRIu64", %s:%d"),
455
pthread_mutex_lock(&file->s->intern_lock);
456
if ((cur_session= (Session*) file->in_use.data))
457
errmsg_printf(ERRMSG_LVL_ERROR, _("Got an error from thread_id=%"PRIu64", %s:%d"),
538
458
cur_session->thread_id,
543
errmsg_printf(error::ERROR, _("Got an error from unknown thread, %s:%d"), sfile, sline);
461
errmsg_printf(ERRMSG_LVL_ERROR, _("Got an error from unknown thread, %s:%d"), sfile, sline);
547
errmsg_printf(error::ERROR, "%s", message);
549
list<Session *>::iterator it= file->s->in_use->begin();
550
while (it != file->s->in_use->end())
463
errmsg_printf(ERRMSG_LVL_ERROR, "%s", message);
464
for (element= file->s->in_use; element; element= list_rest(element))
552
errmsg_printf(error::ERROR, "%s", _("Unknown thread accessing table"));
466
errmsg_printf(ERRMSG_LVL_ERROR, "%s", _("Unknown thread accessing table"));
557
ha_myisam::ha_myisam(plugin::StorageEngine &engine_arg,
559
: Cursor(engine_arg, table_arg),
561
can_enable_indexes(true),
565
Cursor *ha_myisam::clone(memory::Root *mem_root)
468
pthread_mutex_unlock(&file->s->intern_lock);
473
ha_myisam::ha_myisam(handlerton *hton, TABLE_SHARE *table_arg)
474
:handler(hton, table_arg), file(0),
475
int_table_flags(HA_NULL_IN_KEY |
476
HA_BINLOG_ROW_CAPABLE |
477
HA_BINLOG_STMT_CAPABLE |
484
HA_STATS_RECORDS_IS_EXACT |
485
HA_NEED_READ_RANGE_BUFFER |
487
can_enable_indexes(1)
490
handler *ha_myisam::clone(MEM_ROOT *mem_root)
567
ha_myisam *new_handler= static_cast <ha_myisam *>(Cursor::clone(mem_root));
492
ha_myisam *new_handler= static_cast <ha_myisam *>(handler::clone(mem_root));
569
494
new_handler->file->state= file->state;
570
495
return new_handler;
499
static const char *ha_myisam_exts[] = {
505
const char **ha_myisam::bas_ext() const
507
return ha_myisam_exts;
573
511
const char *ha_myisam::index_type(uint32_t )
578
516
/* Name is here without an extension */
579
int ha_myisam::doOpen(const drizzled::identifier::Table &identifier, int mode, uint32_t test_if_locked)
517
int ha_myisam::open(const char *name, int mode, uint32_t test_if_locked)
581
519
MI_KEYDEF *keyinfo;
582
520
MI_COLUMNDEF *recinfo= 0;
598
536
open of a table that is in use by other threads already (if the
599
537
MyISAM share exists already).
601
if (!(file= mi_open(identifier, mode, test_if_locked)))
602
return (errno ? errno : -1);
604
if (!getTable()->getShare()->getType()) /* No need to perform a check for tmp table */
539
if (!(file=mi_open(name, mode, test_if_locked | HA_OPEN_FROM_SQL_LAYER)))
540
return (my_errno ? my_errno : -1);
541
if (!table->s->tmp_table) /* No need to perform a check for tmp table */
606
if ((errno= table2myisam(getTable(), &keyinfo, &recinfo, &recs)))
543
if ((my_errno= table2myisam(table, &keyinfo, &recinfo, &recs)))
545
/* purecov: begin inspected */
610
if (check_definition(keyinfo, recinfo, getTable()->getShare()->sizeKeys(), recs,
549
if (check_definition(keyinfo, recinfo, table->s->keys, recs,
611
550
file->s->keyinfo, file->s->rec,
612
551
file->s->base.keys, file->s->base.fields, true))
614
errno= HA_ERR_CRASHED;
553
/* purecov: begin inspected */
554
my_errno= HA_ERR_CRASHED;
619
assert(test_if_locked);
620
560
if (test_if_locked & (HA_OPEN_IGNORE_IF_LOCKED | HA_OPEN_TMP_TABLE))
621
561
mi_extra(file, HA_EXTRA_NO_WAIT_LOCK, 0);
623
563
info(HA_STATUS_NO_LOCK | HA_STATUS_VARIABLE | HA_STATUS_CONST);
624
564
if (!(test_if_locked & HA_OPEN_WAIT_IF_LOCKED))
625
565
mi_extra(file, HA_EXTRA_WAIT_LOCK, 0);
626
if (!getTable()->getShare()->db_record_offset)
630
keys_with_parts.reset();
631
for (i= 0; i < getTable()->getShare()->sizeKeys(); i++)
566
if (!table->s->db_record_offset)
567
int_table_flags|=HA_REC_NOT_IN_SEQ;
568
if (file->s->options & (HA_OPTION_CHECKSUM | HA_OPTION_COMPRESS_RECORD))
569
int_table_flags|=HA_HAS_CHECKSUM;
571
keys_with_parts.clear_all();
572
for (i= 0; i < table->s->keys; i++)
633
getTable()->key_info[i].block_size= file->s->keyinfo[i].block_length;
574
table->key_info[i].block_size= file->s->keyinfo[i].block_length;
635
KeyPartInfo *kp= getTable()->key_info[i].key_part;
636
KeyPartInfo *kp_end= kp + getTable()->key_info[i].key_parts;
576
KEY_PART_INFO *kp= table->key_info[i].key_part;
577
KEY_PART_INFO *kp_end= kp + table->key_info[i].key_parts;
637
578
for (; kp != kp_end; kp++)
639
if (!kp->field->part_of_key.test(i))
580
if (!kp->field->part_of_key.is_set(i))
641
keys_with_parts.set(i);
582
keys_with_parts.set_bit(i);
652
Both recinfo and keydef are allocated by multi_malloc(), thus only
593
Both recinfo and keydef are allocated by my_multi_malloc(), thus only
653
594
recinfo must be freed.
656
597
free((unsigned char*) recinfo);
660
601
int ha_myisam::close(void)
679
622
return mi_write(file,buf);
625
int ha_myisam::check(Session* session, HA_CHECK_OPT* check_opt)
627
if (!file) return HA_ADMIN_INTERNAL_ERROR;
630
MYISAM_SHARE* share = file->s;
631
const char *old_proc_info= session->get_proc_info();
633
session->set_proc_info("Checking table");
634
myisamchk_init(¶m);
635
param.session = session;
636
param.op_name = "check";
637
param.db_name= table->s->db.str;
638
param.table_name= table->alias;
639
param.testflag = check_opt->flags | T_CHECK | T_SILENT;
640
param.stats_method= (enum_mi_stats_method)session->variables.myisam_stats_method;
642
if (!(table->db_stat & HA_READ_ONLY))
643
param.testflag|= T_STATISTICS;
644
param.using_global_keycache = 1;
646
if (!mi_is_crashed(file) &&
647
(((param.testflag & T_CHECK_ONLY_CHANGED) &&
648
!(share->state.changed & (STATE_CHANGED | STATE_CRASHED |
649
STATE_CRASHED_ON_REPAIR)) &&
650
share->state.open_count == 0) ||
651
((param.testflag & T_FAST) && (share->state.open_count ==
652
(uint) (share->global_changed ? 1 : 0)))))
653
return HA_ADMIN_ALREADY_DONE;
655
error = chk_status(¶m, file); // Not fatal
656
error = chk_size(¶m, file);
658
error |= chk_del(¶m, file, param.testflag);
660
error = chk_key(¶m, file);
663
if ((!(param.testflag & T_QUICK) &&
665
(HA_OPTION_PACK_RECORD | HA_OPTION_COMPRESS_RECORD)) ||
666
(param.testflag & (T_EXTEND | T_MEDIUM)))) ||
669
uint32_t old_testflag=param.testflag;
670
param.testflag|=T_MEDIUM;
671
if (!(error= init_io_cache(¶m.read_cache, file->dfile,
672
my_default_record_cache_size, READ_CACHE,
673
share->pack.header_length, 1, MYF(MY_WME))))
675
error= chk_data_link(¶m, file, param.testflag & T_EXTEND);
676
end_io_cache(&(param.read_cache));
678
param.testflag= old_testflag;
683
if ((share->state.changed & (STATE_CHANGED |
684
STATE_CRASHED_ON_REPAIR |
685
STATE_CRASHED | STATE_NOT_ANALYZED)) ||
686
(param.testflag & T_STATISTICS) ||
689
file->update|=HA_STATE_CHANGED | HA_STATE_ROW_CHANGED;
690
pthread_mutex_lock(&share->intern_lock);
691
share->state.changed&= ~(STATE_CHANGED | STATE_CRASHED |
692
STATE_CRASHED_ON_REPAIR);
693
if (!(table->db_stat & HA_READ_ONLY))
694
error=update_state_info(¶m,file,UPDATE_TIME | UPDATE_OPEN_COUNT |
696
pthread_mutex_unlock(&share->intern_lock);
697
info(HA_STATUS_NO_LOCK | HA_STATUS_TIME | HA_STATUS_VARIABLE |
701
else if (!mi_is_crashed(file) && !session->killed)
703
mi_mark_crashed(file);
704
file->update |= HA_STATE_CHANGED | HA_STATE_ROW_CHANGED;
707
session->set_proc_info(old_proc_info);
708
return error ? HA_ADMIN_CORRUPT : HA_ADMIN_OK;
713
analyze the key distribution in the table
714
As the table may be only locked for read, we have to take into account that
715
two threads may do an analyze at the same time!
718
int ha_myisam::analyze(Session *session,
723
MYISAM_SHARE* share = file->s;
725
myisamchk_init(¶m);
726
param.session = session;
727
param.op_name= "analyze";
728
param.db_name= table->s->db.str;
729
param.table_name= table->alias;
730
param.testflag= (T_FAST | T_CHECK | T_SILENT | T_STATISTICS |
731
T_DONT_CHECK_CHECKSUM);
732
param.using_global_keycache = 1;
733
param.stats_method= (enum_mi_stats_method)session->variables.myisam_stats_method;
735
if (!(share->state.changed & STATE_NOT_ANALYZED))
736
return HA_ADMIN_ALREADY_DONE;
738
error = chk_key(¶m, file);
741
pthread_mutex_lock(&share->intern_lock);
742
error=update_state_info(¶m,file,UPDATE_STAT);
743
pthread_mutex_unlock(&share->intern_lock);
745
else if (!mi_is_crashed(file) && !session->killed)
746
mi_mark_crashed(file);
747
return error ? HA_ADMIN_CORRUPT : HA_ADMIN_OK;
751
int ha_myisam::repair(Session* session, HA_CHECK_OPT *check_opt)
755
ha_rows start_records;
757
if (!file) return HA_ADMIN_INTERNAL_ERROR;
759
myisamchk_init(¶m);
760
param.session = session;
761
param.op_name= "repair";
762
param.testflag= ((check_opt->flags & ~(T_EXTEND)) |
763
T_SILENT | T_FORCE_CREATE | T_CALC_CHECKSUM |
764
(check_opt->flags & T_EXTEND ? T_REP : T_REP_BY_SORT));
765
param.sort_buffer_length= (size_t)sort_buffer_size;
767
// Release latches since this can take a long time
768
ha_release_temporary_latches(session);
770
start_records=file->state->records;
771
while ((error=repair(session,param,0)) && param.retry_repair)
773
param.retry_repair=0;
774
if (test_all_bits(param.testflag,
775
(uint) (T_RETRY_WITHOUT_QUICK | T_QUICK)))
777
param.testflag&= ~T_RETRY_WITHOUT_QUICK;
778
errmsg_printf(ERRMSG_LVL_INFO, "Retrying repair of: '%s' without quick",
782
param.testflag&= ~T_QUICK;
783
if ((param.testflag & T_REP_BY_SORT))
785
param.testflag= (param.testflag & ~T_REP_BY_SORT) | T_REP;
786
errmsg_printf(ERRMSG_LVL_INFO, "Retrying repair of: '%s' with keycache",
792
if (!error && start_records != file->state->records &&
793
!(check_opt->flags & T_VERY_SILENT))
795
char llbuff[22],llbuff2[22];
796
errmsg_printf(ERRMSG_LVL_INFO, "Found %s of %s rows when repairing '%s'",
797
llstr(file->state->records, llbuff),
798
llstr(start_records, llbuff2),
804
int ha_myisam::optimize(Session* session, HA_CHECK_OPT *check_opt)
807
if (!file) return HA_ADMIN_INTERNAL_ERROR;
810
myisamchk_init(¶m);
811
param.session = session;
812
param.op_name= "optimize";
813
param.testflag= (check_opt->flags | T_SILENT | T_FORCE_CREATE |
814
T_REP_BY_SORT | T_STATISTICS | T_SORT_INDEX);
815
param.sort_buffer_length= (size_t)sort_buffer_size;
816
if ((error= repair(session,param,1)) && param.retry_repair)
818
errmsg_printf(ERRMSG_LVL_WARN, "Warning: Optimize table got errno %d on %s.%s, retrying",
819
my_errno, param.db_name, param.table_name);
820
param.testflag&= ~T_REP_BY_SORT;
821
error= repair(session,param,1);
683
827
int ha_myisam::repair(Session *session, MI_CHECK ¶m, bool do_optimize)
813
970
update_state_info(¶m, file, 0);
815
972
session->set_proc_info(old_proc_info);
816
mi_lock_database(file,F_UNLCK);
973
if (!session->locked_tables)
974
mi_lock_database(file,F_UNLCK);
818
975
return(error ? HA_ADMIN_FAILED :
819
976
!optimize_done ? HA_ADMIN_ALREADY_DONE : HA_ADMIN_OK);
981
Assign table indexes to a specific key cache.
984
int ha_myisam::assign_to_keycache(Session* session, HA_CHECK_OPT *check_opt)
986
KEY_CACHE *new_key_cache= check_opt->key_cache;
987
const char *errmsg= 0;
988
int error= HA_ADMIN_OK;
990
TableList *table_list= table->pos_in_table_list;
992
table->keys_in_use_for_query.clear_all();
994
if (table_list->process_index_hints(table))
995
return(HA_ADMIN_FAILED);
997
if (!table->keys_in_use_for_query.is_clear_all())
998
/* use all keys if there's no list specified by the user through hints */
999
map= table->keys_in_use_for_query.to_uint64_t();
1001
if ((error= mi_assign_to_key_cache(file, map, new_key_cache)))
1003
char buf[STRING_BUFFER_USUAL_SIZE];
1004
snprintf(buf, sizeof(buf),
1005
"Failed to flush to index file (errno: %d)", error);
1007
error= HA_ADMIN_CORRUPT;
1010
if (error != HA_ADMIN_OK)
1012
/* Send error to user */
1014
myisamchk_init(¶m);
1015
param.session= session;
1016
param.op_name= "assign_to_keycache";
1017
param.db_name= table->s->db.str;
1018
param.table_name= table->s->table_name.str;
1020
mi_check_print_error(¶m, errmsg);
824
1027
Disable indexes, making it persistent if requested.
1045
int ha_myisam::doUpdateRecord(const unsigned char *old_data, unsigned char *new_data)
1249
bool ha_myisam::check_and_repair(Session *session)
1254
uint32_t old_query_length;
1255
HA_CHECK_OPT check_opt;
1258
check_opt.flags= T_MEDIUM | T_AUTO_REPAIR;
1259
// Don't use quick if deleted rows
1260
if (!file->state->del && (myisam_recover_options & HA_RECOVER_QUICK))
1261
check_opt.flags|=T_QUICK;
1262
errmsg_printf(ERRMSG_LVL_WARN, "Checking table: '%s'",table->s->path.str);
1264
old_query= session->query;
1265
old_query_length= session->query_length;
1266
pthread_mutex_lock(&LOCK_thread_count);
1267
session->query= table->s->table_name.str;
1268
session->query_length= table->s->table_name.length;
1269
pthread_mutex_unlock(&LOCK_thread_count);
1271
if ((marked_crashed= mi_is_crashed(file)) || check(session, &check_opt))
1273
errmsg_printf(ERRMSG_LVL_WARN, "Recovering table: '%s'",table->s->path.str);
1275
((myisam_recover_options & HA_RECOVER_BACKUP ? T_BACKUP_DATA : 0) |
1276
(marked_crashed ? 0 : T_QUICK) |
1277
(myisam_recover_options & HA_RECOVER_FORCE ? 0 : T_SAFE_REPAIR) |
1279
if (repair(session, &check_opt))
1282
pthread_mutex_lock(&LOCK_thread_count);
1283
session->query= old_query;
1284
session->query_length= old_query_length;
1285
pthread_mutex_unlock(&LOCK_thread_count);
1289
bool ha_myisam::is_crashed() const
1291
return (file->s->state.changed & STATE_CRASHED ||
1292
(file->s->state.open_count));
1295
int ha_myisam::update_row(const unsigned char *old_data, unsigned char *new_data)
1297
ha_statistic_increment(&SSV::ha_update_count);
1298
if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_UPDATE)
1299
table->timestamp_field->set_time();
1047
1300
return mi_update(file,old_data,new_data);
1050
int ha_myisam::doDeleteRecord(const unsigned char *buf)
1303
int ha_myisam::delete_row(const unsigned char *buf)
1305
ha_statistic_increment(&SSV::ha_delete_count);
1052
1306
return mi_delete(file,buf);
1056
int ha_myisam::doStartIndexScan(uint32_t idx, bool )
1313
bool index_cond_func_myisam(void *arg)
1315
ha_myisam *h= (ha_myisam*)arg;
1316
/*if (h->in_range_read)*/
1319
if (h->compare_key2(h->end_range) > 0)
1320
return 2; /* caller should return HA_ERR_END_OF_FILE already */
1322
return (bool)h->pushed_idx_cond->val_int();
1330
int ha_myisam::index_init(uint32_t idx, bool )
1058
1332
active_index=idx;
1059
1333
//in_range_read= false;
1334
if (pushed_idx_cond_keyno == idx)
1335
mi_set_index_cond_func(file, index_cond_func_myisam, this);
1064
int ha_myisam::doEndIndexScan()
1340
int ha_myisam::index_end()
1066
1342
active_index=MAX_KEY;
1343
//pushed_idx_cond_keyno= MAX_KEY;
1344
mi_set_index_cond_func(file, NULL, 0);
1345
in_range_check_pushed_down= false;
1346
ds_mrr.dsmrr_close();
1351
uint32_t ha_myisam::index_flags(uint32_t inx, uint32_t, bool) const
1353
return ((table_share->key_info[inx].algorithm == HA_KEY_ALG_FULLTEXT) ?
1354
0 : HA_READ_NEXT | HA_READ_PREV | HA_READ_RANGE |
1355
HA_READ_ORDER | HA_KEYREAD_ONLY |
1356
(keys_with_parts.is_set(inx)?0:HA_DO_INDEX_COND_PUSHDOWN));
1071
1360
int ha_myisam::index_read_map(unsigned char *buf, const unsigned char *key,
1072
1361
key_part_map keypart_map,
1073
1362
enum ha_rkey_function find_flag)
1075
1364
assert(inited==INDEX);
1076
ha_statistic_increment(&system_status_var::ha_read_key_count);
1365
ha_statistic_increment(&SSV::ha_read_key_count);
1077
1366
int error=mi_rkey(file, buf, active_index, key, keypart_map, find_flag);
1078
getTable()->status=error ? STATUS_NOT_FOUND: 0;
1367
table->status=error ? STATUS_NOT_FOUND: 0;
1093
1382
key_part_map keypart_map)
1095
1384
assert(inited==INDEX);
1096
ha_statistic_increment(&system_status_var::ha_read_key_count);
1385
ha_statistic_increment(&SSV::ha_read_key_count);
1097
1386
int error=mi_rkey(file, buf, active_index, key, keypart_map,
1098
1387
HA_READ_PREFIX_LAST);
1099
getTable()->status=error ? STATUS_NOT_FOUND: 0;
1388
table->status=error ? STATUS_NOT_FOUND: 0;
1103
1392
int ha_myisam::index_next(unsigned char *buf)
1105
1394
assert(inited==INDEX);
1106
ha_statistic_increment(&system_status_var::ha_read_next_count);
1395
ha_statistic_increment(&SSV::ha_read_next_count);
1107
1396
int error=mi_rnext(file,buf,active_index);
1108
getTable()->status=error ? STATUS_NOT_FOUND: 0;
1397
table->status=error ? STATUS_NOT_FOUND: 0;
1112
1401
int ha_myisam::index_prev(unsigned char *buf)
1114
1403
assert(inited==INDEX);
1115
ha_statistic_increment(&system_status_var::ha_read_prev_count);
1404
ha_statistic_increment(&SSV::ha_read_prev_count);
1116
1405
int error=mi_rprev(file,buf, active_index);
1117
getTable()->status=error ? STATUS_NOT_FOUND: 0;
1406
table->status=error ? STATUS_NOT_FOUND: 0;
1121
1410
int ha_myisam::index_first(unsigned char *buf)
1123
1412
assert(inited==INDEX);
1124
ha_statistic_increment(&system_status_var::ha_read_first_count);
1413
ha_statistic_increment(&SSV::ha_read_first_count);
1125
1414
int error=mi_rfirst(file, buf, active_index);
1126
getTable()->status=error ? STATUS_NOT_FOUND: 0;
1415
table->status=error ? STATUS_NOT_FOUND: 0;
1130
1419
int ha_myisam::index_last(unsigned char *buf)
1132
1421
assert(inited==INDEX);
1133
ha_statistic_increment(&system_status_var::ha_read_last_count);
1422
ha_statistic_increment(&SSV::ha_read_last_count);
1134
1423
int error=mi_rlast(file, buf, active_index);
1135
getTable()->status=error ? STATUS_NOT_FOUND: 0;
1424
table->status=error ? STATUS_NOT_FOUND: 0;
1226
1520
if (flag & HA_STATUS_CONST)
1228
TableShare *share= getTable()->getMutableShare();
1522
TABLE_SHARE *share= table->s;
1229
1523
stats.max_data_file_length= misam_info.max_data_file_length;
1230
1524
stats.max_index_file_length= misam_info.max_index_file_length;
1231
1525
stats.create_time= misam_info.create_time;
1232
1526
ref_length= misam_info.reflength;
1233
1527
share->db_options_in_use= misam_info.options;
1234
stats.block_size= myisam_key_cache_block_size; /* record block size */
1528
stats.block_size= block_size; /* record block size */
1236
set_prefix(share->keys_in_use, share->sizeKeys());
1238
* Due to bug 394932 (32-bit solaris build failure), we need
1239
* to convert the uint64_t key_map member of the misam_info
1240
* structure in to a std::bitset so that we can logically and
1241
* it with the share->key_in_use key_map.
1244
string binary_key_map;
1245
uint64_t num= misam_info.key_map;
1247
* Convert the uint64_t to a binary
1248
* string representation of it.
1252
uint64_t bin_digit= num % 2;
1256
binary_key_map.append(ostr.str());
1258
* Now we have the binary string representation of the
1259
* flags, we need to fill that string representation out
1260
* with the appropriate number of bits. This is needed
1261
* since key_map is declared as a std::bitset of a certain bit
1262
* width that depends on the MAX_INDEXES variable.
1264
if (MAX_INDEXES <= 64)
1266
size_t len= 72 - binary_key_map.length();
1267
string all_zeros(len, '0');
1268
binary_key_map.insert(binary_key_map.begin(),
1274
size_t len= (MAX_INDEXES + 7) / 8 * 8;
1275
string all_zeros(len, '0');
1276
binary_key_map.insert(binary_key_map.begin(),
1280
key_map tmp_map(binary_key_map);
1281
share->keys_in_use&= tmp_map;
1282
share->keys_for_keyread&= share->keys_in_use;
1531
if (share->tmp_table == NO_TMP_TABLE)
1532
pthread_mutex_lock(&share->mutex);
1533
share->keys_in_use.set_prefix(share->keys);
1534
share->keys_in_use.intersect_extended(misam_info.key_map);
1535
share->keys_for_keyread.intersect(share->keys_in_use);
1283
1536
share->db_record_offset= misam_info.record_offset;
1284
1537
if (share->key_parts)
1285
memcpy(getTable()->key_info[0].rec_per_key,
1538
memcpy(table->key_info[0].rec_per_key,
1286
1539
misam_info.rec_per_key,
1287
sizeof(getTable()->key_info[0].rec_per_key)*share->key_parts);
1288
assert(share->getType() != message::Table::STANDARD);
1540
sizeof(table->key_info[0].rec_per_key)*share->key_parts);
1541
if (share->tmp_table == NO_TMP_TABLE)
1542
pthread_mutex_unlock(&share->mutex);
1291
1545
Set data_file_name and index_file_name to point at the symlink value
1292
1546
if table is symlinked (Ie; Real name is not same as generated name)
1294
1548
data_file_name= index_file_name= 0;
1295
internal::fn_format(name_buff, file->filename, "", MI_NAME_DEXT,
1549
fn_format(name_buff, file->filename, "", MI_NAME_DEXT,
1296
1550
MY_APPEND_EXT | MY_UNPACK_FILENAME);
1297
1551
if (strcmp(name_buff, misam_info.data_file_name))
1298
1552
data_file_name=misam_info.data_file_name;
1299
internal::fn_format(name_buff, file->filename, "", MI_NAME_IEXT,
1553
fn_format(name_buff, file->filename, "", MI_NAME_IEXT,
1300
1554
MY_APPEND_EXT | MY_UNPACK_FILENAME);
1301
1555
if (strcmp(name_buff, misam_info.index_file_name))
1302
1556
index_file_name=misam_info.index_file_name;
1337
1595
return mi_delete_all_rows(file);
1340
int MyisamEngine::doDropTable(Session &session,
1341
const identifier::Table &identifier)
1598
int ha_myisam::delete_table(const char *name)
1343
session.getMessageCache().removeTableMessage(identifier);
1345
return mi_delete_table(identifier.getPath().c_str());
1600
return mi_delete_table(name);
1349
1604
int ha_myisam::external_lock(Session *session, int lock_type)
1351
file->in_use= session;
1352
return mi_lock_database(file, !getTable()->getShare()->getType() ?
1606
file->in_use.data= session;
1607
return mi_lock_database(file, !table->s->tmp_table ?
1353
1608
lock_type : ((lock_type == F_UNLCK) ?
1354
1609
F_UNLCK : F_EXTRA_LCK));
1357
int MyisamEngine::doCreateTable(Session &session,
1359
const identifier::Table &identifier,
1360
message::Table& create_proto)
1612
THR_LOCK_DATA **ha_myisam::store_lock(Session *,
1614
enum thr_lock_type lock_type)
1616
if (lock_type != TL_IGNORE && file->lock.type == TL_UNLOCK)
1617
file->lock.type=lock_type;
1622
void ha_myisam::update_create_info(HA_CREATE_INFO *create_info)
1624
ha_myisam::info(HA_STATUS_AUTO | HA_STATUS_CONST);
1625
if (!(create_info->used_fields & HA_CREATE_USED_AUTO))
1627
create_info->auto_increment_value= stats.auto_increment_value;
1629
create_info->data_file_name=data_file_name;
1630
create_info->index_file_name=index_file_name;
1634
int ha_myisam::create(const char *name, register Table *table_arg,
1635
HA_CREATE_INFO *ha_create_info)
1363
1638
uint32_t create_flags= 0, create_records;
1365
1640
MI_KEYDEF *keydef;
1366
1641
MI_COLUMNDEF *recinfo;
1367
1642
MI_CREATE_INFO create_info;
1368
TableShare *share= table_arg.getMutableShare();
1643
TABLE_SHARE *share= table_arg->s;
1369
1644
uint32_t options= share->db_options_in_use;
1370
if ((error= table2myisam(&table_arg, &keydef, &recinfo, &create_records)))
1645
if ((error= table2myisam(table_arg, &keydef, &recinfo, &create_records)))
1646
return(error); /* purecov: inspected */
1372
1647
memset(&create_info, 0, sizeof(create_info));
1373
create_info.max_rows= create_proto.options().max_rows();
1374
create_info.reloc_rows= create_proto.options().min_rows();
1648
create_info.max_rows= share->max_rows;
1649
create_info.reloc_rows= share->min_rows;
1375
1650
create_info.with_auto_increment= share->next_number_key_offset == 0;
1376
create_info.auto_increment= (create_proto.options().has_auto_increment_value() ?
1377
create_proto.options().auto_increment_value() -1 :
1651
create_info.auto_increment= (ha_create_info->auto_increment_value ?
1652
ha_create_info->auto_increment_value -1 :
1379
create_info.data_file_length= (create_proto.options().max_rows() *
1380
create_proto.options().avg_row_length());
1381
create_info.data_file_name= NULL;
1382
create_info.index_file_name= NULL;
1654
create_info.data_file_length= ((uint64_t) share->max_rows *
1655
share->avg_row_length);
1656
create_info.data_file_name= ha_create_info->data_file_name;
1657
create_info.index_file_name= ha_create_info->index_file_name;
1383
1658
create_info.language= share->table_charset->number;
1385
if (create_proto.type() == message::Table::TEMPORARY)
1660
if (ha_create_info->options & HA_LEX_CREATE_TMP_TABLE)
1386
1661
create_flags|= HA_CREATE_TMP_TABLE;
1662
if (ha_create_info->options & HA_CREATE_KEEP_FILES)
1663
create_flags|= HA_CREATE_KEEP_FILES;
1387
1664
if (options & HA_OPTION_PACK_RECORD)
1388
1665
create_flags|= HA_PACK_RECORD;
1666
if (options & HA_OPTION_CHECKSUM)
1667
create_flags|= HA_CREATE_CHECKSUM;
1668
if (options & HA_OPTION_DELAY_KEY_WRITE)
1669
create_flags|= HA_CREATE_DELAY_KEY_WRITE;
1390
/* TODO: Check that the following internal::fn_format is really needed */
1391
error= mi_create(internal::fn_format(buff, identifier.getPath().c_str(), "", "",
1392
MY_UNPACK_FILENAME|MY_APPEND_EXT),
1393
share->sizeKeys(), keydef,
1671
/* TODO: Check that the following fn_format is really needed */
1672
error= mi_create(fn_format(buff, name, "", "",
1673
MY_UNPACK_FILENAME|MY_APPEND_EXT),
1674
share->keys, keydef,
1394
1675
create_records, recinfo,
1395
1676
0, (MI_UNIQUEDEF*) 0,
1396
1677
&create_info, create_flags);
1397
1678
free((unsigned char*) recinfo);
1399
session.getMessageCache().storeTableMessage(identifier, create_proto);
1405
int MyisamEngine::doRenameTable(Session &session, const identifier::Table &from, const identifier::Table &to)
1683
int ha_myisam::rename_table(const char * from, const char * to)
1407
session.getMessageCache().renameTableMessage(from, to);
1409
return mi_rename(from.getPath().c_str(), to.getPath().c_str());
1685
return mi_rename(from,to);
1432
1708
/* it's safe to call the following if bulk_insert isn't on */
1433
mi_flush_bulk_insert(file, getTable()->getShare()->next_number_index);
1709
mi_flush_bulk_insert(file, table->s->next_number_index);
1435
1711
(void) extra(HA_EXTRA_KEYREAD);
1436
key_copy(key, getTable()->getInsertRecord(),
1437
&getTable()->key_info[getTable()->getShare()->next_number_index],
1438
getTable()->getShare()->next_number_key_offset);
1439
error= mi_rkey(file, getTable()->getUpdateRecord(), (int) getTable()->getShare()->next_number_index,
1440
key, make_prev_keypart_map(getTable()->getShare()->next_number_keypart),
1712
key_copy(key, table->record[0],
1713
table->key_info + table->s->next_number_index,
1714
table->s->next_number_key_offset);
1715
error= mi_rkey(file, table->record[1], (int) table->s->next_number_index,
1716
key, make_prev_keypart_map(table->s->next_number_keypart),
1441
1717
HA_READ_PREFIX_LAST);
1446
/* Get data from getUpdateRecord() */
1447
nr= ((uint64_t) getTable()->next_number_field->
1448
val_int_offset(getTable()->getShare()->rec_buff_length)+1);
1722
/* Get data from record[1] */
1723
nr= ((uint64_t) table->next_number_field->
1724
val_int_offset(table->s->rec_buff_length)+1);
1450
1726
extra(HA_EXTRA_NO_KEYREAD);
1451
1727
*first_value= nr;
1496
1772
return (uint)file->state->checksum;
1499
static int myisam_init(module::Context &context)
1501
context.add(new MyisamEngine(engine_name));
1502
context.registerVariable(new sys_var_constrained_value<size_t>("sort-buffer-size",
1504
context.registerVariable(new sys_var_uint64_t_ptr("max_sort_file_size",
1505
&max_sort_file_size,
1506
context.getOptions()["max-sort-file-size"].as<uint64_t>()));
1776
bool ha_myisam::check_if_incompatible_data(HA_CREATE_INFO *create_info,
1777
uint32_t table_changes)
1779
uint32_t options= table->s->db_options_in_use;
1781
if (create_info->auto_increment_value != stats.auto_increment_value ||
1782
create_info->data_file_name != data_file_name ||
1783
create_info->index_file_name != index_file_name ||
1784
table_changes == IS_EQUAL_NO ||
1785
table_changes & IS_EQUAL_PACK_LENGTH) // Not implemented yet
1786
return COMPATIBLE_DATA_NO;
1788
if ((options & (HA_OPTION_PACK_RECORD | HA_OPTION_CHECKSUM |
1789
HA_OPTION_DELAY_KEY_WRITE)) !=
1790
(create_info->table_options & (HA_OPTION_PACK_RECORD |
1791
HA_OPTION_CHECKSUM |
1792
HA_OPTION_DELAY_KEY_WRITE)))
1793
return COMPATIBLE_DATA_NO;
1794
return COMPATIBLE_DATA_YES;
1797
int myisam_deinit(void *)
1799
pthread_mutex_destroy(&THR_LOCK_myisam);
1801
return mi_panic(HA_PANIC_CLOSE);
1804
static int myisam_init(void *p)
1806
myisam_hton= (handlerton *)p;
1807
myisam_hton->state= SHOW_OPTION_YES;
1808
myisam_hton->create= myisam_create_handler;
1809
myisam_hton->flags= HTON_CAN_RECREATE | HTON_SUPPORT_LOG_TABLES;
1512
static void init_options(drizzled::module::option_context &context)
1514
context("max-sort-file-size",
1515
po::value<uint64_t>(&max_sort_file_size)->default_value(INT32_MAX),
1516
_("Don't use the fast sort index method to created index if the temporary file would get bigger than this."));
1517
context("sort-buffer-size",
1518
po::value<sort_buffer_constraint>(&sort_buffer_size)->default_value(8192*1024),
1519
_("The buffer that is allocated when sorting the index when doing a REPAIR or when creating indexes with CREATE INDEX or ALTER TABLE."));
1523
DRIZZLE_DECLARE_PLUGIN
1815
/****************************************************************************
1816
* MyISAM MRR implementation: use DS-MRR
1817
***************************************************************************/
1819
int ha_myisam::multi_range_read_init(RANGE_SEQ_IF *seq, void *seq_init_param,
1820
uint32_t n_ranges, uint32_t mode,
1821
HANDLER_BUFFER *buf)
1823
return ds_mrr.dsmrr_init(this, &table->key_info[active_index],
1824
seq, seq_init_param, n_ranges, mode, buf);
1827
int ha_myisam::multi_range_read_next(char **range_info)
1829
return ds_mrr.dsmrr_next(this, range_info);
1832
ha_rows ha_myisam::multi_range_read_info_const(uint32_t keyno, RANGE_SEQ_IF *seq,
1833
void *seq_init_param,
1834
uint32_t n_ranges, uint32_t *bufsz,
1835
uint32_t *flags, COST_VECT *cost)
1838
This call is here because there is no location where this->table would
1840
TODO: consider moving it into some per-query initialization call.
1842
ds_mrr.init(this, table);
1843
return ds_mrr.dsmrr_info_const(keyno, seq, seq_init_param, n_ranges, bufsz,
1847
int ha_myisam::multi_range_read_info(uint32_t keyno, uint32_t n_ranges, uint32_t keys,
1848
uint32_t *bufsz, uint32_t *flags, COST_VECT *cost)
1850
ds_mrr.init(this, table);
1851
return ds_mrr.dsmrr_info(keyno, n_ranges, keys, bufsz, flags, cost);
1854
/* MyISAM MRR implementation ends */
1857
/* Index condition pushdown implementation*/
1860
Item *ha_myisam::idx_cond_push(uint32_t keyno_arg, Item* idx_cond_arg)
1862
pushed_idx_cond_keyno= keyno_arg;
1863
pushed_idx_cond= idx_cond_arg;
1864
in_range_check_pushed_down= true;
1865
if (active_index == pushed_idx_cond_keyno)
1866
mi_set_index_cond_func(file, index_cond_func_myisam, this);
1870
static DRIZZLE_SYSVAR_UINT(block_size, block_size,
1871
PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
1872
N_("Block size to be used for MyISAM index pages."),
1873
NULL, NULL, MI_KEY_BLOCK_LENGTH, MI_MIN_KEY_BLOCK_LENGTH,
1874
MI_MAX_KEY_BLOCK_LENGTH, 0);
1876
static DRIZZLE_SYSVAR_UINT(repair_threads, repair_threads,
1877
PLUGIN_VAR_RQCMDARG,
1878
N_("Number of threads to use when repairing MyISAM tables. The value of "
1879
"1 disables parallel repair."),
1880
NULL, NULL, 1, 1, UINT32_MAX, 0);
1882
static DRIZZLE_SYSVAR_ULONGLONG(max_sort_file_size, max_sort_file_size,
1883
PLUGIN_VAR_RQCMDARG,
1884
N_("Don't use the fast sort index method to created index if the temporary file would get bigger than this."),
1885
NULL, NULL, INT32_MAX, 0, UINT64_MAX, 0);
1887
static DRIZZLE_SYSVAR_ULONGLONG(sort_buffer_size, sort_buffer_size,
1888
PLUGIN_VAR_RQCMDARG,
1889
N_("The buffer that is allocated when sorting the index when doing a REPAIR or when creating indexes with CREATE INDEX or ALTER TABLE."),
1890
NULL, NULL, 8192*1024, 1024, SIZE_MAX, 0);
1892
extern uint32_t data_pointer_size;
1893
static DRIZZLE_SYSVAR_UINT(data_pointer_size, data_pointer_size,
1894
PLUGIN_VAR_RQCMDARG,
1895
N_("Default pointer size to be used for MyISAM tables."),
1896
NULL, NULL, 6, 2, 7, 0);
1898
static struct st_mysql_sys_var* system_variables[]= {
1899
DRIZZLE_SYSVAR(block_size),
1900
DRIZZLE_SYSVAR(repair_threads),
1901
DRIZZLE_SYSVAR(max_sort_file_size),
1902
DRIZZLE_SYSVAR(sort_buffer_size),
1903
DRIZZLE_SYSVAR(data_pointer_size),
1908
drizzle_declare_plugin(myisam)
1910
DRIZZLE_STORAGE_ENGINE_PLUGIN,
1529
1914
"Default engine as of MySQL 3.23 with great performance",
1530
1915
PLUGIN_LICENSE_GPL,
1531
1916
myisam_init, /* Plugin Init */
1533
init_options /* config options */
1917
myisam_deinit, /* Plugin Deinit */
1918
NULL, /* status variables */
1919
system_variables, /* system variables */
1920
NULL /* config options */
1535
DRIZZLE_DECLARE_PLUGIN_END;
1922
drizzle_declare_plugin_end;