1
/* Copyright (C) 2000-2006 MySQL AB
3
This program is free software; you can redistribute it and/or modify
4
it under the terms of the GNU General Public License as published by
5
the Free Software Foundation; version 2 of the License.
7
This program is distributed in the hope that it will be useful,
8
but WITHOUT ANY WARRANTY; without even the implied warranty of
9
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10
GNU General Public License for more details.
12
You should have received a copy of the GNU General Public License
13
along with this program; if not, write to the Free Software
14
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
1
/* -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*-
2
* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
4
* Copyright (C) 2008 Sun Microsystems
6
* This program is free software; you can redistribute it and/or modify
7
* it under the terms of the GNU General Public License as published by
8
* the Free Software Foundation; version 2 of the License.
10
* This program is distributed in the hope that it will be useful,
11
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
* GNU General Public License for more details.
15
* You should have received a copy of the GNU General Public License
16
* along with this program; if not, write to the Free Software
17
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19
23
Handler-calling-functions
22
#ifdef USE_PRAGMA_IMPLEMENTATION
23
#pragma implementation // gcc: Class implementation
26
#include <drizzled/server_includes.h>
27
#include "rpl_filter.h"
28
#include <drizzled/drizzled_error_messages.h>
31
While we have legacy_db_type, we have this array to
32
check for dups and to find handlerton from legacy_db_type.
33
Remove when legacy_db_type is finally gone
35
st_plugin_int *hton2plugin[MAX_HA];
37
static handlerton *installed_htons[128];
39
#define BITMAP_STACKBUF_SIZE (128/8)
26
#include "drizzled/server_includes.h"
27
#include "mysys/hash.h"
28
#include "drizzled/error.h"
29
#include "drizzled/gettext.h"
30
#include "drizzled/data_home.h"
31
#include "drizzled/probes.h"
32
#include "drizzled/sql_parse.h"
33
#include "drizzled/cost_vect.h"
34
#include "drizzled/session.h"
35
#include "drizzled/sql_base.h"
36
#include "drizzled/transaction_services.h"
37
#include "drizzled/lock.h"
38
#include "drizzled/item/int.h"
39
#include "drizzled/item/empty_string.h"
40
#include "drizzled/unireg.h" // for mysql_frm_type
41
#include "drizzled/field/timestamp.h"
42
#include "drizzled/message/table.pb.h"
46
extern drizzled::TransactionServices transaction_services;
41
48
KEY_CREATE_INFO default_key_create_info= { HA_KEY_ALG_UNDEF, 0, {NULL,0}, {NULL,0} };
43
/* number of entries in handlertons[] */
50
/* number of entries in storage_engines[] */
44
51
uint32_t total_ha= 0;
45
/* number of storage engines (from handlertons[]) that support 2pc */
52
/* number of storage engines (from storage_engines[]) that support 2pc */
46
53
uint32_t total_ha_2pc= 0;
47
54
/* size of savepoint storage area (see ha_init) */
48
55
uint32_t savepoint_alloc_size= 0;
50
static const LEX_STRING sys_table_aliases[]=
52
{ C_STRING_WITH_LEN("INNOBASE") }, { C_STRING_WITH_LEN("INNODB") },
53
{ C_STRING_WITH_LEN("HEAP") }, { C_STRING_WITH_LEN("MEMORY") },
57
57
const char *ha_row_type[] = {
58
58
"", "FIXED", "DYNAMIC", "COMPRESSED", "REDUNDANT", "COMPACT", "PAGE", "?","?","?"
61
61
const char *tx_isolation_names[] =
62
62
{ "READ-UNCOMMITTED", "READ-COMMITTED", "REPEATABLE-READ", "SERIALIZABLE",
64
65
TYPELIB tx_isolation_typelib= {array_elements(tx_isolation_names)-1,"",
65
tx_isolation_names, NULL};
67
static TYPELIB known_extensions= {0,"known_exts", NULL, NULL};
68
uint32_t known_extensions_id= 0;
72
static plugin_ref ha_default_plugin(THD *thd)
74
if (thd->variables.table_plugin)
75
return thd->variables.table_plugin;
76
return my_plugin_lock(thd, &global_system_variables.table_plugin);
81
Return the default storage engine handlerton for thread
83
@param ha_default_handlerton(thd)
84
@param thd current thread
89
handlerton *ha_default_handlerton(THD *thd)
91
plugin_ref plugin= ha_default_plugin(thd);
93
handlerton *hton= plugin_data(plugin, handlerton*);
100
Return the storage engine handlerton for the supplied name
102
@param thd current thread
103
@param name name of storage engine
106
pointer to storage engine plugin handle
108
plugin_ref ha_resolve_by_name(THD *thd, const LEX_STRING *name)
110
const LEX_STRING *table_alias;
114
/* my_strnncoll is a macro and gcc doesn't do early expansion of macro */
115
if (thd && !my_charset_utf8_general_ci.coll->strnncoll(&my_charset_utf8_general_ci,
116
(const unsigned char *)name->str, name->length,
117
(const unsigned char *)STRING_WITH_LEN("DEFAULT"), 0))
118
return ha_default_plugin(thd);
120
if ((plugin= my_plugin_lock_by_name(thd, name, DRIZZLE_STORAGE_ENGINE_PLUGIN)))
122
handlerton *hton= plugin_data(plugin, handlerton *);
123
if (!(hton->flags & HTON_NOT_USER_SELECTABLE))
127
unlocking plugin immediately after locking is relatively low cost.
129
plugin_unlock(thd, plugin);
133
We check for the historical aliases.
135
for (table_alias= sys_table_aliases; table_alias->str; table_alias+= 2)
137
if (!my_strnncoll(&my_charset_utf8_general_ci,
138
(const unsigned char *)name->str, name->length,
139
(const unsigned char *)table_alias->str, table_alias->length))
141
name= table_alias + 1;
150
plugin_ref ha_lock_engine(THD *thd, handlerton *hton)
154
st_plugin_int **plugin= hton2plugin + hton->slot;
156
return my_plugin_lock(thd, &plugin);
162
handlerton *ha_resolve_by_legacy_type(THD *thd, enum legacy_db_type db_type)
166
case DB_TYPE_DEFAULT:
167
return ha_default_handlerton(thd);
169
if (db_type > DB_TYPE_UNKNOWN && db_type < DB_TYPE_DEFAULT &&
170
(plugin= ha_lock_engine(thd, installed_htons[db_type])))
171
return plugin_data(plugin, handlerton*);
173
case DB_TYPE_UNKNOWN:
180
Use other database handler if databasehandler is not compiled in.
182
handlerton *ha_checktype(THD *thd, enum legacy_db_type database_type,
183
bool no_substitute, bool report_error)
185
handlerton *hton= ha_resolve_by_legacy_type(thd, database_type);
186
if (ha_storage_engine_is_enabled(hton))
193
const char *engine_name= ha_resolve_storage_engine_name(hton);
194
my_error(ER_FEATURE_DISABLED,MYF(0),engine_name,engine_name);
199
return ha_default_handlerton(thd);
203
handler *get_new_handler(TABLE_SHARE *share, MEM_ROOT *alloc,
208
if (db_type && db_type->state == SHOW_OPTION_YES && db_type->create)
210
if ((file= db_type->create(db_type, share, alloc)))
215
Try the default table type
216
Here the call to current_thd() is ok as we call this function a lot of
217
times but we enter this branch very seldom.
219
return(get_new_handler(share, alloc, ha_default_handlerton(current_thd)));
66
tx_isolation_names, NULL};
311
int ha_finalize_handlerton(st_plugin_int *plugin)
313
handlerton *hton= (handlerton *)plugin->data;
318
case SHOW_OPTION_DISABLED:
320
case SHOW_OPTION_YES:
321
if (installed_htons[hton->db_type] == hton)
322
installed_htons[hton->db_type]= NULL;
326
if (hton && plugin->plugin->deinit)
327
(void)plugin->plugin->deinit(hton);
329
free((unsigned char*)hton);
335
int ha_initialize_handlerton(st_plugin_int *plugin)
339
hton= (handlerton *)my_malloc(sizeof(handlerton),
340
MYF(MY_WME | MY_ZEROFILL));
342
FIXME: the MY_ZEROFILL flag above doesn't zero all the bytes.
344
This was detected after adding get_backup_engine member to handlerton
345
structure. Apparently get_backup_engine was not NULL even though it was
348
memset(hton, 0, sizeof(hton));
349
/* Historical Requirement */
350
plugin->data= hton; // shortcut for the future
351
if (plugin->plugin->init)
353
if (plugin->plugin->init(hton))
355
sql_print_error(_("Plugin '%s' init function returned error."),
362
the switch below and hton->state should be removed when
363
command-line options for plugins will be implemented
365
switch (hton->state) {
368
case SHOW_OPTION_YES:
371
/* now check the db_type for conflict */
372
if (hton->db_type <= DB_TYPE_UNKNOWN ||
373
hton->db_type >= DB_TYPE_DEFAULT ||
374
installed_htons[hton->db_type])
376
int idx= (int) DB_TYPE_FIRST_DYNAMIC;
378
while (idx < (int) DB_TYPE_DEFAULT && installed_htons[idx])
381
if (idx == (int) DB_TYPE_DEFAULT)
383
sql_print_warning(_("Too many storage engines!"));
386
if (hton->db_type != DB_TYPE_UNKNOWN)
387
sql_print_warning(_("Storage engine '%s' has conflicting typecode. "
388
"Assigning value %d."), plugin->plugin->name, idx);
389
hton->db_type= (enum legacy_db_type) idx;
391
installed_htons[hton->db_type]= hton;
392
tmp= hton->savepoint_offset;
393
hton->savepoint_offset= savepoint_alloc_size;
394
savepoint_alloc_size+= tmp;
395
hton->slot= total_ha++;
396
hton2plugin[hton->slot]=plugin;
403
hton->state= SHOW_OPTION_DISABLED;
408
This is entirely for legacy. We will create a new "disk based" hton and a
409
"memory" hton which will be configurable longterm. We should be able to
410
remove partition and myisammrg.
412
if (strcmp(plugin->plugin->name, "MEMORY") == 0)
415
if (strcmp(plugin->plugin->name, "MyISAM") == 0)
453
static bool dropdb_handlerton(THD *unused1 __attribute__((unused)),
457
handlerton *hton= plugin_data(plugin, handlerton *);
458
if (hton->state == SHOW_OPTION_YES && hton->drop_database)
459
hton->drop_database(hton, (char *)path);
464
void ha_drop_database(char* path)
466
plugin_foreach(NULL, dropdb_handlerton, DRIZZLE_STORAGE_ENGINE_PLUGIN, path);
470
static bool closecon_handlerton(THD *thd, plugin_ref plugin,
471
void *unused __attribute__((unused)))
473
handlerton *hton= plugin_data(plugin, handlerton *);
475
there's no need to rollback here as all transactions must
476
be rolled back already
478
if (hton->state == SHOW_OPTION_YES && hton->close_connection &&
479
thd_get_ha_data(thd, hton))
480
hton->close_connection(hton, thd);
487
don't bother to rollback here, it's done already
489
void ha_close_connection(THD* thd)
491
plugin_foreach(thd, closecon_handlerton, DRIZZLE_STORAGE_ENGINE_PLUGIN, 0);
494
187
/* ========================================================================
495
188
======================= TRANSACTIONS ===================================*/
595
288
The server stores its transaction-related data in
596
thd->transaction. This structure has two members of type
597
THD_TRANS. These members correspond to the statement and
289
session->transaction. This structure has two members of type
290
Session_TRANS. These members correspond to the statement and
598
291
normal transactions respectively:
600
- thd->transaction.stmt contains a list of engines
293
- session->transaction.stmt contains a list of engines
601
294
that are participating in the given statement
602
- thd->transaction.all contains a list of engines that
295
- session->transaction.all contains a list of engines that
603
296
have participated in any of the statement transactions started
604
297
within the context of the normal transaction.
605
298
Each element of the list contains a pointer to the storage
606
299
engine, engine-specific transactional data, and engine-specific
607
300
transaction flags.
609
In autocommit mode thd->transaction.all is empty.
610
Instead, data of thd->transaction.stmt is
302
In autocommit mode session->transaction.all is empty.
303
Instead, data of session->transaction.stmt is
611
304
used to commit/rollback the normal transaction.
613
306
The list of registered engines has a few important properties:
797
490
times per transaction.
800
void trans_register_ha(THD *thd, bool all, handlerton *ht_arg)
493
void trans_register_ha(Session *session, bool all, StorageEngine *engine)
495
Session_TRANS *trans;
803
496
Ha_trx_info *ha_info;
807
trans= &thd->transaction.all;
808
thd->server_status|= SERVER_STATUS_IN_TRANS;
500
trans= &session->transaction.all;
501
session->server_status|= SERVER_STATUS_IN_TRANS;
811
trans= &thd->transaction.stmt;
504
trans= &session->transaction.stmt;
813
ha_info= thd->ha_data[ht_arg->slot].ha_info + static_cast<unsigned>(all);
506
ha_info= session->ha_data[engine->slot].ha_info + static_cast<unsigned>(all);
815
508
if (ha_info->is_started())
816
509
return; /* already registered, return */
818
ha_info->register_ha(trans, ht_arg);
511
ha_info->register_ha(trans, engine);
820
trans->no_2pc|=(ht_arg->prepare==0);
821
if (thd->transaction.xid_state.xid.is_null())
822
thd->transaction.xid_state.xid.set(thd->query_id);
513
trans->no_2pc|= not engine->has_2pc();
514
if (session->transaction.xid_state.xid.is_null())
515
session->transaction.xid_state.xid.set(session->query_id);
831
524
1 error, transaction was rolled back
833
int ha_prepare(THD *thd)
526
int ha_prepare(Session *session)
835
528
int error=0, all=1;
836
THD_TRANS *trans=all ? &thd->transaction.all : &thd->transaction.stmt;
529
Session_TRANS *trans=all ? &session->transaction.all : &session->transaction.stmt;
837
530
Ha_trx_info *ha_info= trans->ha_list;
840
533
for (; ha_info; ha_info= ha_info->next())
843
handlerton *ht= ha_info->ht();
844
status_var_increment(thd->status_var.ha_prepare_count);
536
StorageEngine *engine= ha_info->engine();
537
status_var_increment(session->status_var.ha_prepare_count);
538
if ((err= engine->prepare(session, all)))
847
if ((err= ht->prepare(ht, thd, all)))
849
my_error(ER_ERROR_DURING_COMMIT, MYF(0), err);
850
ha_rollback_trans(thd, all);
540
my_error(ER_ERROR_DURING_COMMIT, MYF(0), err);
541
ha_rollback_trans(session, all);
857
push_warning_printf(thd, DRIZZLE_ERROR::WARN_LEVEL_WARN,
547
push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_WARN,
858
548
ER_ILLEGAL_HA, ER(ER_ILLEGAL_HA),
859
ha_resolve_storage_engine_name(ht));
549
engine->getName().c_str());
951
640
flags will not get propagated to its normal transaction's
954
assert(thd->transaction.stmt.ha_list == NULL ||
955
trans == &thd->transaction.stmt);
643
assert(session->transaction.stmt.ha_list == NULL ||
644
trans == &session->transaction.stmt);
957
if (thd->in_sub_stmt)
960
Since we don't support nested statement transactions in 5.0,
961
we can't commit or rollback stmt transactions while we are inside
962
stored functions or triggers. So we simply do nothing now.
963
TODO: This should be fixed in later ( >= 5.1) releases.
968
We assume that all statements which commit or rollback main transaction
969
are prohibited inside of stored functions or triggers. So they should
970
bail out with error even before ha_commit_trans() call. To be 100% safe
971
let us throw error in non-debug builds.
974
my_error(ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG, MYF(0));
981
if (is_real_trans && wait_if_global_read_lock(thd, 0, 0))
650
if (is_real_trans && wait_if_global_read_lock(session, 0, 0))
983
ha_rollback_trans(thd, all);
652
ha_rollback_trans(session, all);
989
&& ! thd->slave_thread
992
my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--read-only");
993
ha_rollback_trans(thd, all);
998
must_2pc= ha_check_and_coalesce_trx_read_only(thd, ha_info, all);
656
must_2pc= ha_check_and_coalesce_trx_read_only(session, ha_info, all);
1000
658
if (!trans->no_2pc && must_2pc)
1002
660
for (; ha_info && !error; ha_info= ha_info->next())
1005
handlerton *ht= ha_info->ht();
663
StorageEngine *engine= ha_info->engine();
1007
665
Do not call two-phase commit if this particular
1008
666
transaction is read-only. This allows for simpler
1014
672
Sic: we know that prepare() is not NULL since otherwise
1015
673
trans->no_2pc would have been set.
1017
if ((err= ht->prepare(ht, thd, all)))
675
if ((err= engine->prepare(session, all)))
1019
677
my_error(ER_ERROR_DURING_COMMIT, MYF(0), err);
1022
status_var_increment(thd->status_var.ha_prepare_count);
680
status_var_increment(session->status_var.ha_prepare_count);
1024
if (error || (is_real_trans && xid &&
1025
(error= !(cookie= tc_log->log_xid(thd, xid)))))
1027
ha_rollback_trans(thd, all);
684
ha_rollback_trans(session, all);
1032
error=ha_commit_one_phase(thd, all) ? (cookie ? 2 : 1) : 0;
1034
tc_log->unlog(cookie, xid);
689
error=ha_commit_one_phase(session, all) ? (cookie ? 2 : 1) : 0;
1036
691
if (is_real_trans)
1037
start_waiting_global_read_lock(thd);
692
start_waiting_global_read_lock(session);
1044
699
This function does not care about global read lock. A caller should.
1046
int ha_commit_one_phase(THD *thd, bool all)
701
int ha_commit_one_phase(Session *session, bool all)
1049
THD_TRANS *trans=all ? &thd->transaction.all : &thd->transaction.stmt;
1050
bool is_real_trans=all || thd->transaction.all.ha_list == 0;
704
Session_TRANS *trans=all ? &session->transaction.all : &session->transaction.stmt;
705
bool is_real_trans=all || session->transaction.all.ha_list == 0;
1051
706
Ha_trx_info *ha_info= trans->ha_list, *ha_info_next;
1054
709
for (; ha_info; ha_info= ha_info_next)
1057
handlerton *ht= ha_info->ht();
1058
if ((err= ht->commit(ht, thd, all)))
712
StorageEngine *engine= ha_info->engine();
713
if ((err= engine->commit(session, all)))
1060
715
my_error(ER_ERROR_DURING_COMMIT, MYF(0), err);
1063
status_var_increment(thd->status_var.ha_commit_count);
718
status_var_increment(session->status_var.ha_commit_count);
1064
719
ha_info_next= ha_info->next();
1065
720
ha_info->reset(); /* keep it conveniently zero-filled */
1067
722
trans->ha_list= 0;
1068
723
trans->no_2pc=0;
1069
724
if (is_real_trans)
1070
thd->transaction.xid_state.xid.null();
725
session->transaction.xid_state.xid.null();
1073
thd->variables.tx_isolation=thd->session_tx_isolation;
1074
thd->transaction.cleanup();
728
session->variables.tx_isolation=session->session_tx_isolation;
729
session->transaction.cleanup();
1081
int ha_rollback_trans(THD *thd, bool all)
736
int ha_rollback_trans(Session *session, bool all)
1084
THD_TRANS *trans=all ? &thd->transaction.all : &thd->transaction.stmt;
739
Session_TRANS *trans=all ? &session->transaction.all : &session->transaction.stmt;
1085
740
Ha_trx_info *ha_info= trans->ha_list, *ha_info_next;
1086
bool is_real_trans=all || thd->transaction.all.ha_list == 0;
741
bool is_real_trans=all || session->transaction.all.ha_list == 0;
1089
744
We must not rollback the normal transaction if a statement
1090
745
transaction is pending.
1092
assert(thd->transaction.stmt.ha_list == NULL ||
1093
trans == &thd->transaction.stmt);
747
assert(session->transaction.stmt.ha_list == NULL ||
748
trans == &session->transaction.stmt);
1095
if (thd->in_sub_stmt)
1098
If we are inside stored function or trigger we should not commit or
1099
rollback current statement transaction. See comment in ha_commit_trans()
1100
call for more information.
1105
my_error(ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG, MYF(0));
1110
752
for (; ha_info; ha_info= ha_info_next)
1113
handlerton *ht= ha_info->ht();
1114
if ((err= ht->rollback(ht, thd, all)))
755
StorageEngine *engine= ha_info->engine();
756
if ((err= engine->rollback(session, all)))
1115
757
{ // cannot happen
1116
758
my_error(ER_ERROR_DURING_ROLLBACK, MYF(0), err);
1119
status_var_increment(thd->status_var.ha_rollback_count);
761
status_var_increment(session->status_var.ha_rollback_count);
1120
762
ha_info_next= ha_info->next();
1121
763
ha_info->reset(); /* keep it conveniently zero-filled */
1123
765
trans->ha_list= 0;
1124
766
trans->no_2pc=0;
1125
767
if (is_real_trans)
1126
thd->transaction.xid_state.xid.null();
768
session->transaction.xid_state.xid.null();
1129
thd->variables.tx_isolation=thd->session_tx_isolation;
1130
thd->transaction.cleanup();
771
session->variables.tx_isolation=session->session_tx_isolation;
772
session->transaction.cleanup();
1134
thd->transaction_rollback_request= false;
776
session->transaction_rollback_request= false;
1137
779
If a non-transactional table was updated, warn; don't warn if this is a
1161
802
the user has used LOCK TABLES then that mechanism does not know to do the
1164
int ha_autocommit_or_rollback(THD *thd, int error)
805
int ha_autocommit_or_rollback(Session *session, int error)
1166
if (thd->transaction.stmt.ha_list)
807
if (session->transaction.stmt.ha_list)
1170
if (ha_commit_trans(thd, 0))
811
if (ha_commit_trans(session, 0))
1175
(void) ha_rollback_trans(thd, 0);
1176
if (thd->transaction_rollback_request && !thd->in_sub_stmt)
1177
(void) ha_rollback(thd);
816
(void) ha_rollback_trans(session, 0);
817
if (session->transaction_rollback_request)
818
(void) ha_rollback(session);
1180
thd->variables.tx_isolation=thd->session_tx_isolation;
821
session->variables.tx_isolation=session->session_tx_isolation;
1191
static bool xacommit_handlerton(THD *unused1 __attribute__((unused)),
1195
handlerton *hton= plugin_data(plugin, handlerton *);
1196
if (hton->state == SHOW_OPTION_YES && hton->recover)
1198
hton->commit_by_xid(hton, ((struct xahton_st *)arg)->xid);
1199
((struct xahton_st *)arg)->result= 0;
1204
static bool xarollback_handlerton(THD *unused1 __attribute__((unused)),
1208
handlerton *hton= plugin_data(plugin, handlerton *);
1209
if (hton->state == SHOW_OPTION_YES && hton->recover)
1211
hton->rollback_by_xid(hton, ((struct xahton_st *)arg)->xid);
1212
((struct xahton_st *)arg)->result= 0;
1218
int ha_commit_or_rollback_by_xid(XID *xid, bool commit)
1220
struct xahton_st xaop;
1224
plugin_foreach(NULL, commit ? xacommit_handlerton : xarollback_handlerton,
1225
DRIZZLE_STORAGE_ENGINE_PLUGIN, &xaop);
1231
recover() step of xa.
1234
there are three modes of operation:
1235
- automatic recover after a crash
1236
in this case commit_list != 0, tc_heuristic_recover==0
1237
all xids from commit_list are committed, others are rolled back
1238
- manual (heuristic) recover
1239
in this case commit_list==0, tc_heuristic_recover != 0
1240
DBA has explicitly specified that all prepared transactions should
1241
be committed (or rolled back).
1242
- no recovery (MySQL did not detect a crash)
1243
in this case commit_list==0, tc_heuristic_recover == 0
1244
there should be no prepared transactions in this case.
1248
int len, found_foreign_xids, found_my_xids;
1254
static bool xarecover_handlerton(THD *unused __attribute__((unused)),
1258
handlerton *hton= plugin_data(plugin, handlerton *);
1259
struct xarecover_st *info= (struct xarecover_st *) arg;
1262
if (hton->state == SHOW_OPTION_YES && hton->recover)
1264
while ((got= hton->recover(hton, info->list, info->len)) > 0 )
1266
sql_print_information(_("Found %d prepared transaction(s) in %s"),
1267
got, ha_resolve_storage_engine_name(hton));
1268
for (int i=0; i < got; i ++)
1270
my_xid x=info->list[i].get_my_xid();
1271
if (!x) // not "mine" - that is generated by external TM
1273
xid_cache_insert(info->list+i, XA_PREPARED);
1274
info->found_foreign_xids++;
1279
info->found_my_xids++;
1283
if (info->commit_list ?
1284
hash_search(info->commit_list, (unsigned char *)&x, sizeof(x)) != 0 :
1285
tc_heuristic_recover == TC_HEURISTIC_RECOVER_COMMIT)
1287
hton->commit_by_xid(hton, info->list+i);
1291
hton->rollback_by_xid(hton, info->list+i);
1294
if (got < info->len)
1301
int ha_recover(HASH *commit_list)
1303
struct xarecover_st info;
1304
info.found_foreign_xids= info.found_my_xids= 0;
1305
info.commit_list= commit_list;
1306
info.dry_run= (info.commit_list==0 && tc_heuristic_recover==0);
1309
/* commit_list and tc_heuristic_recover cannot be set both */
1310
assert(info.commit_list==0 || tc_heuristic_recover==0);
1311
/* if either is set, total_ha_2pc must be set too */
1312
assert(info.dry_run || total_ha_2pc>(uint32_t)opt_bin_log);
1314
if (total_ha_2pc <= (uint32_t)opt_bin_log)
1317
if (info.commit_list)
1318
sql_print_information(_("Starting crash recovery..."));
1321
#ifndef WILL_BE_DELETED_LATER
1324
for now, only InnoDB supports 2pc. It means we can always safely
1325
rollback all pending transactions, without risking inconsistent data
1328
assert(total_ha_2pc == (uint32_t) opt_bin_log+1); // only InnoDB and binlog
1329
tc_heuristic_recover= TC_HEURISTIC_RECOVER_ROLLBACK; // forcing ROLLBACK
1334
for (info.len= MAX_XID_LIST_SIZE ;
1335
info.list==0 && info.len > MIN_XID_LIST_SIZE; info.len/=2)
1337
info.list=(XID *)my_malloc(info.len*sizeof(XID), MYF(0));
1341
sql_print_error(ER(ER_OUTOFMEMORY), info.len*sizeof(XID));
1345
plugin_foreach(NULL, xarecover_handlerton,
1346
DRIZZLE_STORAGE_ENGINE_PLUGIN, &info);
1348
free((unsigned char*)info.list);
1349
if (info.found_foreign_xids)
1350
sql_print_warning(_("Found %d prepared XA transactions"),
1351
info.found_foreign_xids);
1352
if (info.dry_run && info.found_my_xids)
1354
sql_print_error(_("Found %d prepared transactions! It means that drizzled "
1355
"was not shut down properly last time and critical "
1356
"recovery information (last binlog or %s file) was "
1357
"manually deleted after a crash. You have to start "
1358
"drizzled with the --tc-heuristic-recover switch to "
1359
"commit or rollback pending transactions."),
1360
info.found_my_xids, opt_tc_log_file);
1363
if (info.commit_list)
1364
sql_print_information(_("Crash recovery finished."));
1369
830
return the list of XID's to a client, the same way SHOW commands do.
1411
872
pthread_mutex_unlock(&LOCK_xid_cache);
1418
This function should be called when MySQL sends rows of a SELECT result set
1419
or the EOF mark to the client. It releases a possible adaptive hash index
1420
S-latch held by thd in InnoDB and also releases a possible InnoDB query
1421
FIFO ticket to enter InnoDB. To save CPU time, InnoDB allows a thd to
1422
keep them over several calls of the InnoDB handler interface when a join
1423
is executed. But when we let the control to pass to the client they have
1424
to be released because if the application program uses mysql_use_result(),
1425
it may deadlock on the S-latch if the application on another connection
1426
performs another SQL query. In MySQL-4.1 this is even more important because
1427
there a connection can have several SELECT queries open at the same time.
1429
@param thd the thread handle of the current connection
1434
static bool release_temporary_latches(THD *thd, plugin_ref plugin,
1435
void *unused __attribute__((unused)))
1437
handlerton *hton= plugin_data(plugin, handlerton *);
1439
if (hton->state == SHOW_OPTION_YES && hton->release_temporary_latches)
1440
hton->release_temporary_latches(hton, thd);
1446
int ha_release_temporary_latches(THD *thd)
1448
plugin_foreach(thd, release_temporary_latches, DRIZZLE_STORAGE_ENGINE_PLUGIN,
1454
int ha_rollback_to_savepoint(THD *thd, SAVEPOINT *sv)
878
int ha_rollback_to_savepoint(Session *session, SAVEPOINT *sv)
1457
THD_TRANS *trans= (thd->in_sub_stmt ? &thd->transaction.stmt :
1458
&thd->transaction.all);
881
Session_TRANS *trans= &session->transaction.all;
1459
882
Ha_trx_info *ha_info, *ha_info_next;
1461
884
trans->no_2pc=0;
1506
928
section "4.33.4 SQL-statements and transaction states",
1507
929
SAVEPOINT is *not* transaction-initiating SQL-statement
1509
int ha_savepoint(THD *thd, SAVEPOINT *sv)
931
int ha_savepoint(Session *session, SAVEPOINT *sv)
1512
THD_TRANS *trans= (thd->in_sub_stmt ? &thd->transaction.stmt :
1513
&thd->transaction.all);
934
Session_TRANS *trans= &session->transaction.all;
1514
935
Ha_trx_info *ha_info= trans->ha_list;
1515
936
for (; ha_info; ha_info= ha_info->next())
1518
handlerton *ht= ha_info->ht();
1520
if (! ht->savepoint_set)
939
StorageEngine *engine= ha_info->engine();
941
/* if (! engine->savepoint_set)
1522
943
my_error(ER_CHECK_NOT_IMPLEMENTED, MYF(0), "SAVEPOINT");
1526
if ((err= ht->savepoint_set(ht, thd, (unsigned char *)(sv+1)+ht->savepoint_offset)))
947
if ((err= engine->savepoint_set(session, (void *)(sv+1))))
1527
948
{ // cannot happen
1528
949
my_error(ER_GET_ERRNO, MYF(0), err);
1531
status_var_increment(thd->status_var.ha_savepoint_count);
952
status_var_increment(session->status_var.ha_savepoint_count);
1534
955
Remember the list of registered storage engines. All new
1565
static bool snapshot_handlerton(THD *thd, plugin_ref plugin, void *arg)
1567
handlerton *hton= plugin_data(plugin, handlerton *);
1568
if (hton->state == SHOW_OPTION_YES &&
1569
hton->start_consistent_snapshot)
1571
hton->start_consistent_snapshot(hton, thd);
1572
*((bool *)arg)= false;
1577
int ha_start_consistent_snapshot(THD *thd)
1581
plugin_foreach(thd, snapshot_handlerton, DRIZZLE_STORAGE_ENGINE_PLUGIN, &warn);
1584
Same idea as when one wants to CREATE TABLE in one engine which does not
1588
push_warning(thd, DRIZZLE_ERROR::WARN_LEVEL_WARN, ER_UNKNOWN_ERROR,
1589
"This MySQL server does not support any "
1590
"consistent-read capable storage engine");
1595
static bool flush_handlerton(THD *thd __attribute__((unused)),
1597
void *arg __attribute__((unused)))
1599
handlerton *hton= plugin_data(plugin, handlerton *);
1600
if (hton->state == SHOW_OPTION_YES && hton->flush_logs &&
1601
hton->flush_logs(hton))
1607
bool ha_flush_logs(handlerton *db_type)
1609
if (db_type == NULL)
1611
if (plugin_foreach(NULL, flush_handlerton,
1612
DRIZZLE_STORAGE_ENGINE_PLUGIN, 0))
1617
if (db_type->state != SHOW_OPTION_YES ||
1618
(db_type->flush_logs && db_type->flush_logs(db_type)))
1624
static const char *check_lowercase_names(handler *file, const char *path,
1627
if (lower_case_table_names != 2 || (file->ha_table_flags() & HA_FILE_BASED))
1630
/* Ensure that table handler get path in lower case */
1631
if (tmp_path != path)
1632
my_stpcpy(tmp_path, path);
1635
we only should turn into lowercase database/table part
1636
so start the process after homedirectory
1638
my_casedn_str(files_charset_info, tmp_path + mysql_data_home_len);
1644
An interceptor to hijack the text of the error message without
1645
setting an error in the thread. We need the text to present it
1646
in the form of a warning to the user.
1649
struct Ha_delete_table_error_handler: public Internal_error_handler
1652
virtual bool handle_error(uint32_t sql_errno,
1653
const char *message,
1654
DRIZZLE_ERROR::enum_warning_level level,
1656
char buff[DRIZZLE_ERRMSG_SIZE];
1661
Ha_delete_table_error_handler::
1662
handle_error(uint32_t sql_errno __attribute__((unused)),
1663
const char *message,
1664
DRIZZLE_ERROR::enum_warning_level level __attribute__((unused)),
1665
THD *thd __attribute__((unused)))
1667
/* Grab the error message */
1668
strmake(buff, message, sizeof(buff)-1);
1674
This should return ENOENT if the file doesn't exists.
1675
The .frm file will be deleted only if we return 0 or ENOENT
1677
int ha_delete_table(THD *thd, handlerton *table_type, const char *path,
1678
const char *db, const char *alias, bool generate_warning)
1681
char tmp_path[FN_REFLEN];
1684
TABLE_SHARE dummy_share;
1686
memset(&dummy_table, 0, sizeof(dummy_table));
1687
memset(&dummy_share, 0, sizeof(dummy_share));
1688
dummy_table.s= &dummy_share;
1690
/* DB_TYPE_UNKNOWN is used in ALTER Table when renaming only .frm files */
1691
if (table_type == NULL ||
1692
! (file=get_new_handler((TABLE_SHARE*)0, thd->mem_root, table_type)))
1695
path= check_lowercase_names(file, path, tmp_path);
1696
if ((error= file->ha_delete_table(path)) && generate_warning)
1699
Because file->print_error() use my_error() to generate the error message
1700
we use an internal error handler to intercept it and store the text
1701
in a temporary buffer. Later the message will be presented to user
1704
Ha_delete_table_error_handler ha_delete_table_error_handler;
1706
/* Fill up strucutures that print_error may need */
1707
dummy_share.path.str= (char*) path;
1708
dummy_share.path.length= strlen(path);
1709
dummy_share.db.str= (char*) db;
1710
dummy_share.db.length= strlen(db);
1711
dummy_share.table_name.str= (char*) alias;
1712
dummy_share.table_name.length= strlen(alias);
1713
dummy_table.alias= alias;
1715
file->change_table_ptr(&dummy_table, &dummy_share);
1717
thd->push_internal_handler(&ha_delete_table_error_handler);
1718
file->print_error(error, 0);
1720
thd->pop_internal_handler();
1723
XXX: should we convert *all* errors to warnings here?
1724
What if the error is fatal?
1726
push_warning(thd, DRIZZLE_ERROR::WARN_LEVEL_ERROR, error,
1727
ha_delete_table_error_handler.buff);
1733
987
/****************************************************************************
1734
988
** General handler functions
1008
int handler::ha_index_init(uint32_t idx, bool sorted)
1011
assert(inited==NONE);
1012
if (!(result= index_init(idx, sorted)))
1018
int handler::ha_index_end()
1020
assert(inited==INDEX);
1023
return(index_end());
1026
int handler::ha_rnd_init(bool scan)
1029
assert(inited==NONE || (inited==RND && scan));
1030
inited= (result= rnd_init(scan)) ? NONE: RND;
1034
int handler::ha_rnd_end()
1036
assert(inited==RND);
1041
int handler::ha_index_or_rnd_end()
1043
return inited == INDEX ? ha_index_end() : inited == RND ? ha_rnd_end() : 0;
1046
handler::Table_flags handler::ha_table_flags() const
1048
return cached_table_flags;
1051
void handler::ha_start_bulk_insert(ha_rows rows)
1053
estimation_rows_to_insert= rows;
1054
start_bulk_insert(rows);
1057
int handler::ha_end_bulk_insert()
1059
estimation_rows_to_insert= 0;
1060
return end_bulk_insert();
1063
void handler::change_table_ptr(Table *table_arg, TableShare *share)
1069
const key_map *handler::keys_to_use_for_scanning()
1071
return &key_map_empty;
1074
bool handler::has_transactions()
1076
return (ha_table_flags() & HA_NO_TRANSACTIONS) == 0;
1756
1079
void handler::ha_statistic_increment(ulong SSV::*offset) const
1758
1081
status_var_increment(table->in_use->status_var.*offset);
1761
void **handler::ha_data(THD *thd) const
1763
return thd_ha_data(thd, ht);
1766
THD *handler::ha_thd(void) const
1768
assert(!table || !table->in_use || table->in_use == current_thd);
1769
return (table && table->in_use) ? table->in_use : current_thd;
1084
void **handler::ha_data(Session *session) const
1086
return session_ha_data(session, engine);
1089
Session *handler::ha_session(void) const
1091
assert(!table || !table->in_use || table->in_use == current_session);
1092
return (table && table->in_use) ? table->in_use : current_session;
1096
bool handler::is_fatal_error(int error, uint32_t flags)
1099
((flags & HA_CHECK_DUP_KEY) &&
1100
(error == HA_ERR_FOUND_DUPP_KEY ||
1101
error == HA_ERR_FOUND_DUPP_UNIQUE)))
1107
ha_rows handler::records() { return stats.records; }
1773
1110
Open database-handler.
2545
static bool update_frm_version(Table *table)
2547
char path[FN_REFLEN];
2552
No need to update frm version in case table was created or checked
2553
by server with the same version. This also ensures that we do not
2554
update frm version for temporary tables as this code doesn't support
2557
if (table->s->mysql_version == DRIZZLE_VERSION_ID)
2560
strxmov(path, table->s->normalized_path.str, reg_ext, NULL);
2562
if ((file= my_open(path, O_RDWR|O_BINARY, MYF(MY_WME))) >= 0)
2564
unsigned char version[4];
2565
char *key= table->s->table_cache_key.str;
2566
uint32_t key_length= table->s->table_cache_key.length;
2568
HASH_SEARCH_STATE state;
2570
int4store(version, DRIZZLE_VERSION_ID);
2572
if (pwrite(file, (unsigned char*)version, 4, 51L) == 0)
2578
for (entry=(Table*) hash_first(&open_cache,(unsigned char*) key,key_length, &state);
2580
entry= (Table*) hash_next(&open_cache,(unsigned char*) key,key_length, &state))
2581
entry->s->mysql_version= DRIZZLE_VERSION_ID;
2585
my_close(file,MYF(MY_WME));
2593
1863
key if error because of duplicated keys
2595
1865
uint32_t handler::get_dup_key(int error)
2597
table->file->errkey = (uint) -1;
1867
table->file->errkey = (uint32_t) -1;
2598
1868
if (error == HA_ERR_FOUND_DUPP_KEY || error == HA_ERR_FOREIGN_DUPLICATE_KEY ||
2599
1869
error == HA_ERR_FOUND_DUPP_UNIQUE ||
2600
1870
error == HA_ERR_DROP_INDEX_FK)
3060
2325
** Some general functions that isn't in the handler class
3061
2326
****************************************************************************/
3064
Initiates table-file and calls appropriate database-creator.
3071
int ha_create_table(THD *thd, const char *path,
3072
const char *db, const char *table_name,
3073
HA_CREATE_INFO *create_info,
3074
bool update_create_info)
3078
char name_buff[FN_REFLEN];
3082
init_tmp_table_share(thd, &share, db, 0, table_name, path);
3083
if (open_table_def(thd, &share, 0) ||
3084
open_table_from_share(thd, &share, "", 0, (uint) READ_ALL, 0, &table,
3088
if (update_create_info)
3089
table.updateCreateInfo(create_info);
3091
name= check_lowercase_names(table.file, share.path.str, name_buff);
3093
error= table.file->ha_create(name, &table, create_info);
3094
closefrm(&table, 0);
3097
strxmov(name_buff, db, ".", table_name, NULL);
3098
my_error(ER_CANT_CREATE_TABLE, MYF(ME_BELL+ME_WAITTANG), name_buff, error);
3101
free_table_share(&share);
3106
Try to discover table from engine.
3109
If found, write the frm file to disk.
3112
-1 Table did not exists
3116
> 0 Error, table existed but could not be created
3118
int ha_create_table_from_engine(THD* thd, const char *db, const char *name)
3121
unsigned char *frmblob;
3123
char path[FN_REFLEN];
3124
HA_CREATE_INFO create_info;
3128
memset(&create_info, 0, sizeof(create_info));
3129
if ((error= ha_discover(thd, db, name, &frmblob, &frmlen)))
3131
/* Table could not be discovered and thus not created */
3136
Table exists in handler and could be discovered
3137
frmblob and frmlen are set, write the frm to disk
3140
build_table_filename(path, FN_REFLEN-1, db, name, "", 0);
3141
// Save the frm file
3142
error= writefrm(path, frmblob, frmlen);
3147
init_tmp_table_share(thd, &share, db, 0, name, path);
3148
if (open_table_def(thd, &share, 0))
3152
if (open_table_from_share(thd, &share, "" ,0, 0, 0, &table, OTM_OPEN))
3154
free_table_share(&share);
3158
table.updateCreateInfo(&create_info);
3159
create_info.table_options|= HA_OPTION_CREATE_FROM_ENGINE;
3161
check_lowercase_names(table.file, path, path);
3162
error=table.file->ha_create(path, &table, &create_info);
3163
closefrm(&table, 1);
3168
2329
void st_ha_check_opt::init()
3170
flags= sql_flags= 0;
3171
sort_buffer_size = current_thd->variables.myisam_sort_buff_size;
3266
Try to discover one table from handler(s).
3269
-1 Table did not exists
3271
0 OK. In this case *frmblob and *frmlen are set
3273
>0 error. frmblob and frmlen may not be set
3275
struct st_discover_args
3279
unsigned char **frmblob;
3283
static bool discover_handlerton(THD *thd, plugin_ref plugin,
3286
st_discover_args *vargs= (st_discover_args *)arg;
3287
handlerton *hton= plugin_data(plugin, handlerton *);
3288
if (hton->state == SHOW_OPTION_YES && hton->discover &&
3289
(!(hton->discover(hton, thd, vargs->db, vargs->name,
3297
int ha_discover(THD *thd, const char *db, const char *name,
3298
unsigned char **frmblob, size_t *frmlen)
3300
int error= -1; // Table does not exist in any handler
3301
st_discover_args args= {db, name, frmblob, frmlen};
3303
if (is_prefix(name,tmp_file_prefix)) /* skip temporary tables */
3306
if (plugin_foreach(thd, discover_handlerton,
3307
DRIZZLE_STORAGE_ENGINE_PLUGIN, &args))
3311
status_var_increment(thd->status_var.ha_discover_count);
3317
Call this function in order to give the handler the possiblity
3318
to ask engine if there are any new tables that should be written to disk
3319
or any dropped tables that need to be removed from disk
3321
struct st_find_files_args
3327
List<LEX_STRING> *files;
3331
Ask handler if the table exists in engine.
3333
HA_ERR_NO_SUCH_TABLE Table does not exist
3335
HA_ERR_TABLE_EXIST Table exists
3339
struct st_table_exists_in_engine_args
3346
static bool table_exists_in_engine_handlerton(THD *thd, plugin_ref plugin,
3349
st_table_exists_in_engine_args *vargs= (st_table_exists_in_engine_args *)arg;
3350
handlerton *hton= plugin_data(plugin, handlerton *);
3352
int err= HA_ERR_NO_SUCH_TABLE;
3354
if (hton->state == SHOW_OPTION_YES && hton->table_exists_in_engine)
3355
err = hton->table_exists_in_engine(hton, thd, vargs->db, vargs->name);
3358
if (vargs->err == HA_ERR_TABLE_EXIST)
3364
int ha_table_exists_in_engine(THD* thd, const char* db, const char* name)
3366
st_table_exists_in_engine_args args= {db, name, HA_ERR_NO_SUCH_TABLE};
3367
plugin_foreach(thd, table_exists_in_engine_handlerton,
3368
DRIZZLE_STORAGE_ENGINE_PLUGIN, &args);
3373
2427
Calculate cost of 'index only' scan for given index and number of records
3375
2429
@param keynr Index number
3698
2750
uint32_t keyno;
3699
2751
Item *pushed_cond= NULL;
3700
2752
handler *new_h2;
3701
keyno= h->active_index;
2753
keyno= h_in->active_index;
3702
2754
assert(h2 == NULL);
3703
2755
if (mode & HA_MRR_USE_DEFAULT_IMPL || mode & HA_MRR_SORTED)
3705
2757
use_default_impl= true;
3706
return(h->handler::multi_range_read_init(seq_funcs, seq_init_param,
2758
return(h_in->handler::multi_range_read_init(seq_funcs, seq_init_param,
3707
2759
n_ranges, mode, buf));
3709
2761
rowids_buf= buf->buffer;
3710
2762
//psergey-todo: don't add key_length as it is not needed anymore
3711
rowids_buf += key->key_length + h->ref_length;
2763
rowids_buf += key->key_length + h_in->ref_length;
3713
2765
is_mrr_assoc= !test(mode & HA_MRR_NO_ASSOCIATION);
3714
2766
rowids_buf_end= buf->buffer_end;
3716
elem_size= h->ref_length + (int)is_mrr_assoc * sizeof(void*);
3717
rowids_buf_last= rowids_buf +
2768
elem_size= h_in->ref_length + (int)is_mrr_assoc * sizeof(void*);
2769
rowids_buf_last= rowids_buf +
3718
2770
((rowids_buf_end - rowids_buf)/ elem_size)*
3720
2772
rowids_buf_end= rowids_buf_last;
3722
2774
/* Create a separate handler object to do rndpos() calls. */
3723
THD *thd= current_thd;
3724
if (!(new_h2= h->clone(thd->mem_root)) ||
3725
new_h2->ha_external_lock(thd, F_RDLCK))
2775
Session *session= current_session;
2776
if (!(new_h2= h_in->clone(session->mem_root)) ||
2777
new_h2->ha_external_lock(session, F_RDLCK))
3731
if (keyno == h->pushed_idx_cond_keyno)
3732
pushed_cond= h->pushed_idx_cond;
3733
if (h->ha_index_end())
2783
if (keyno == h_in->pushed_idx_cond_keyno)
2784
pushed_cond= h_in->pushed_idx_cond;
2785
if (h_in->ha_index_end())
4016
3068
COST_VECT dsmrr_cost;
4018
THD *thd= current_thd;
4019
if ((thd->variables.optimizer_use_mrr == 2) ||
3070
Session *session= current_session;
3071
if ((session->variables.optimizer_use_mrr == 2) ||
4020
3072
(*flags & HA_MRR_INDEX_ONLY) || (*flags & HA_MRR_SORTED) ||
4021
(keyno == table->s->primary_key &&
4022
h->primary_key_is_clustered()) ||
3073
(keyno == table->s->primary_key &&
3074
h->primary_key_is_clustered()) ||
4023
3075
key_uses_partial_cols(keyno))
4025
3077
/* Use the default implementation */
4026
3078
*flags |= HA_MRR_USE_DEFAULT_IMPL;
4030
uint32_t add_len= table->key_info[keyno].key_length + h->ref_length;
3082
uint32_t add_len= table->key_info[keyno].key_length + h->ref_length;
4031
3083
*bufsz -= add_len;
4032
3084
if (get_disk_sweep_mrr_cost(keyno, rows, *flags, bufsz, &dsmrr_cost))
4034
3086
*bufsz += add_len;
4036
3088
bool force_dsmrr;
4038
3090
If @@optimizer_use_mrr==force, then set cost of DS-MRR to be minimum of
4039
3091
DS-MRR and Default implementations cost. This allows one to force use of
4040
3092
DS-MRR whenever it is applicable without affecting other cost-based
4043
if ((force_dsmrr= (thd->variables.optimizer_use_mrr == 1)) &&
3095
if ((force_dsmrr= (session->variables.optimizer_use_mrr == 1)) &&
4044
3096
dsmrr_cost.total_cost() > cost->total_cost())
4045
3097
dsmrr_cost= *cost;
4387
Returns a list of all known extensions.
4389
No mutexes, worst case race is a minor surplus memory allocation
4390
We have to recreate the extension map if mysqld is restarted (for example
4394
pointer pointer to TYPELIB structure
4396
static bool exts_handlerton(THD *unused __attribute__((unused)),
4400
List<char> *found_exts= (List<char> *) arg;
4401
handlerton *hton= plugin_data(plugin, handlerton *);
4403
if (hton->state == SHOW_OPTION_YES && hton->create &&
4404
(file= hton->create(hton, (TABLE_SHARE*) 0, current_thd->mem_root)))
4406
List_iterator_fast<char> it(*found_exts);
4407
const char **ext, *old_ext;
4409
for (ext= file->bas_ext(); *ext; ext++)
4411
while ((old_ext= it++))
4413
if (!strcmp(old_ext, *ext))
4417
found_exts->push_back((char *) *ext);
4426
TYPELIB *ha_known_exts(void)
4428
if (!known_extensions.type_names || mysys_usage_id != known_extensions_id)
4430
List<char> found_exts;
4431
const char **ext, *old_ext;
4433
known_extensions_id= mysys_usage_id;
4435
plugin_foreach(NULL, exts_handlerton,
4436
DRIZZLE_STORAGE_ENGINE_PLUGIN, &found_exts);
4438
ext= (const char **) my_once_alloc(sizeof(char *)*
4439
(found_exts.elements+1),
4440
MYF(MY_WME | MY_FAE));
4443
known_extensions.count= found_exts.elements;
4444
known_extensions.type_names= ext;
4446
List_iterator_fast<char> it(found_exts);
4447
while ((old_ext= it++))
4451
return &known_extensions;
4455
static bool stat_print(THD *thd, const char *type, uint32_t type_len,
3439
static bool stat_print(Session *session, const char *type, uint32_t type_len,
4456
3440
const char *file, uint32_t file_len,
4457
3441
const char *status, uint32_t status_len)
4459
Protocol *protocol= thd->protocol;
4460
protocol->prepare_for_resend();
3443
Protocol *protocol= session->protocol;
3444
protocol->prepareForResend();
4461
3445
protocol->store(type, type_len, system_charset_info);
4462
3446
protocol->store(file, file_len, system_charset_info);
4463
3447
protocol->store(status, status_len, system_charset_info);
4469
bool ha_show_status(THD *thd, handlerton *db_type, enum ha_stat_type stat)
3453
bool ha_show_status(Session *session, StorageEngine *engine, enum ha_stat_type stat)
4471
3455
List<Item> field_list;
4472
Protocol *protocol= thd->protocol;
3456
Protocol *protocol= session->protocol;
4475
3459
field_list.push_back(new Item_empty_string("Type",10));
4476
3460
field_list.push_back(new Item_empty_string("Name",FN_REFLEN));
4477
3461
field_list.push_back(new Item_empty_string("Status",10));
4479
if (protocol->send_fields(&field_list,
4480
Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
3463
if (protocol->sendFields(&field_list,
3464
Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
4483
result= db_type->show_status &&
4484
db_type->show_status(db_type, thd, stat_print, stat) ? 1 : 0;
3467
result= engine->show_status(session, stat_print, stat) ? 1 : 0;
4501
3484
- table is not mysql.event
4504
static bool check_table_binlog_row_based(THD *thd, Table *table)
4506
if (table->s->cached_row_logging_check == -1)
4508
int const check(table->s->tmp_table == NO_TMP_TABLE &&
4509
binlog_filter->db_ok(table->s->db.str));
4510
table->s->cached_row_logging_check= check;
4513
assert(table->s->cached_row_logging_check == 0 ||
4514
table->s->cached_row_logging_check == 1);
4516
return (thd->current_stmt_binlog_row_based &&
4517
table->s->cached_row_logging_check &&
4518
(thd->options & OPTION_BIN_LOG) &&
4519
mysql_bin_log.is_open());
4524
Write table maps for all (manually or automatically) locked tables
4527
This function will generate and write table maps for all tables
4528
that are locked by the thread 'thd'. Either manually locked
4529
(stored in THD::locked_tables) and automatically locked (stored
4530
in THD::lock) are considered.
4532
@param thd Pointer to THD structure
4535
@retval 1 Failed to write all table maps
4542
static int write_locked_table_maps(THD *thd)
4544
if (thd->get_binlog_table_maps() == 0)
4546
DRIZZLE_LOCK *locks[3];
4547
locks[0]= thd->extra_lock;
4548
locks[1]= thd->lock;
4549
locks[2]= thd->locked_tables;
4550
for (uint32_t i= 0 ; i < sizeof(locks)/sizeof(*locks) ; ++i )
4552
DRIZZLE_LOCK const *const lock= locks[i];
4556
Table **const end_ptr= lock->table + lock->table_count;
4557
for (Table **table_ptr= lock->table ;
4558
table_ptr != end_ptr ;
4561
Table *const table= *table_ptr;
4562
if (table->current_lock == F_WRLCK &&
4563
check_table_binlog_row_based(thd, table))
4565
int const has_trans= table->file->has_transactions();
4566
int const error= thd->binlog_write_table_map(table, has_trans);
4568
If an error occurs, it is the responsibility of the caller to
4569
roll back the transaction.
4571
if (unlikely(error))
4581
typedef bool Log_func(THD*, Table*, bool, const unsigned char*, const unsigned char*);
4583
static int binlog_log_row(Table* table,
4584
const unsigned char *before_record,
4585
const unsigned char *after_record,
4588
if (table->no_replicate)
4591
THD *const thd= table->in_use;
4593
if (check_table_binlog_row_based(thd, table))
3487
static bool binlog_log_row(Table* table,
3488
const unsigned char *before_record,
3489
const unsigned char *after_record)
3491
Session *const session= table->in_use;
3493
switch (session->lex->sql_command)
3495
case SQLCOM_REPLACE:
3497
case SQLCOM_REPLACE_SELECT:
3498
case SQLCOM_INSERT_SELECT:
3499
case SQLCOM_CREATE_TABLE:
3500
transaction_services.insertRecord(session, table);
3504
case SQLCOM_UPDATE_MULTI:
3505
transaction_services.updateRecord(session, table, before_record, after_record);
3509
case SQLCOM_DELETE_MULTI:
3510
transaction_services.deleteRecord(session, table);
4596
If there are no table maps written to the binary log, this is
4597
the first row handled in this statement. In that case, we need
4598
to write table maps for all locked tables to the binary log.
3514
For everything else we ignore the event (since it just involves a temp table)
4600
if (likely(!(error= write_locked_table_maps(thd))))
4602
bool const has_trans= table->file->has_transactions();
4603
error= (*log_func)(thd, table, has_trans, before_record, after_record);
4606
return error ? HA_ERR_RBR_LOGGING_FAILED : 0;
3520
return false; //error;
4609
int handler::ha_external_lock(THD *thd, int lock_type)
3523
int handler::ha_external_lock(Session *session, int lock_type)
4612
3526
Whether this is lock or unlock, this should be true, and is to verify that
4682
3605
if (unlikely(error= update_row(old_data, new_data)))
4684
if (unlikely(error= binlog_log_row(table, old_data, new_data, log_func)))
3608
if (unlikely(binlog_log_row(table, old_data, new_data)))
3609
return HA_ERR_RBR_LOGGING_FAILED;
4689
3614
int handler::ha_delete_row(const unsigned char *buf)
4692
Log_func *log_func= Delete_rows_log_event::binlog_row_logging_function;
4694
3618
mark_trx_read_write();
4696
3620
if (unlikely(error= delete_row(buf)))
4698
if (unlikely(error= binlog_log_row(table, buf, 0, log_func)))
3623
if (unlikely(binlog_log_row(table, buf, 0)))
3624
return HA_ERR_RBR_LOGGING_FAILED;
4707
use_hidden_primary_key() is called in case of an update/delete when
4708
(table_flags() and HA_PRIMARY_KEY_REQUIRED_FOR_DELETE) is defined
4709
but we don't have a primary key
4711
void handler::use_hidden_primary_key()
4713
/* fallback to use all columns in the table to identify row */
4714
table->use_all_columns();
3629
void table_case_convert(char * name, uint32_t length)
3631
if (lower_case_table_names)
3632
files_charset_info->cset->casedn(files_charset_info,
3633
name, length, name, length);
3636
const char *table_case_name(HA_CREATE_INFO *info, const char *name)
3638
return ((lower_case_table_names == 2 && info->alias) ? info->alias : name);