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
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 */
23
19
Handler-calling-functions
26
#include <drizzled/server_includes.h>
27
#include <drizzled/replication/filter.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>
35
#include <drizzled/session.h>
36
#include <drizzled/sql_base.h>
38
#if defined(CMATH_NAMESPACE)
39
using namespace CMATH_NAMESPACE;
22
#ifdef USE_PRAGMA_IMPLEMENTATION
23
#pragma implementation // gcc: Class implementation
43
extern HASH open_cache;
45
KEY_CREATE_INFO default_key_create_info= { HA_KEY_ALG_UNDEF, 0, {NULL,0}, {NULL,0} };
26
#include "mysql_priv.h"
27
#include "rpl_filter.h"
29
#include <drizzled/drizzled_error_messages.h>
32
While we have legacy_db_type, we have this array to
33
check for dups and to find handlerton from legacy_db_type.
34
Remove when legacy_db_type is finally gone
36
st_plugin_int *hton2plugin[MAX_HA];
38
static handlerton *installed_htons[128];
40
#define BITMAP_STACKBUF_SIZE (128/8)
42
KEY_CREATE_INFO default_key_create_info= { HA_KEY_ALG_UNDEF, 0, {NullS,0}, {NullS,0} };
47
44
/* number of entries in handlertons[] */
48
45
uint32_t total_ha= 0;
51
48
/* size of savepoint storage area (see ha_init) */
52
49
uint32_t savepoint_alloc_size= 0;
51
static const LEX_STRING sys_table_aliases[]=
53
{ C_STRING_WITH_LEN("INNOBASE") }, { C_STRING_WITH_LEN("INNODB") },
54
{ C_STRING_WITH_LEN("HEAP") }, { C_STRING_WITH_LEN("MEMORY") },
54
58
const char *ha_row_type[] = {
55
59
"", "FIXED", "DYNAMIC", "COMPRESSED", "REDUNDANT", "COMPACT", "PAGE", "?","?","?"
58
62
const char *tx_isolation_names[] =
59
63
{ "READ-UNCOMMITTED", "READ-COMMITTED", "REPEATABLE-READ", "SERIALIZABLE",
62
65
TYPELIB tx_isolation_typelib= {array_elements(tx_isolation_names)-1,"",
63
tx_isolation_names, NULL};
66
tx_isolation_names, NULL};
65
68
static TYPELIB known_extensions= {0,"known_exts", NULL, NULL};
66
uint32_t known_extensions_id= 0;
69
uint known_extensions_id= 0;
73
static plugin_ref ha_default_plugin(THD *thd)
75
if (thd->variables.table_plugin)
76
return thd->variables.table_plugin;
77
return my_plugin_lock(thd, &global_system_variables.table_plugin);
82
Return the default storage engine handlerton for thread
84
@param ha_default_handlerton(thd)
85
@param thd current thread
90
handlerton *ha_default_handlerton(THD *thd)
92
plugin_ref plugin= ha_default_plugin(thd);
94
handlerton *hton= plugin_data(plugin, handlerton*);
101
Return the storage engine handlerton for the supplied name
103
@param thd current thread
104
@param name name of storage engine
107
pointer to storage engine plugin handle
109
plugin_ref ha_resolve_by_name(THD *thd, const LEX_STRING *name)
111
const LEX_STRING *table_alias;
115
/* my_strnncoll is a macro and gcc doesn't do early expansion of macro */
116
if (thd && !my_charset_latin1.coll->strnncoll(&my_charset_latin1,
117
(const uchar *)name->str, name->length,
118
(const uchar *)STRING_WITH_LEN("DEFAULT"), 0))
119
return ha_default_plugin(thd);
121
if ((plugin= my_plugin_lock_by_name(thd, name, MYSQL_STORAGE_ENGINE_PLUGIN)))
123
handlerton *hton= plugin_data(plugin, handlerton *);
124
if (!(hton->flags & HTON_NOT_USER_SELECTABLE))
128
unlocking plugin immediately after locking is relatively low cost.
130
plugin_unlock(thd, plugin);
134
We check for the historical aliases.
136
for (table_alias= sys_table_aliases; table_alias->str; table_alias+= 2)
138
if (!my_strnncoll(&my_charset_latin1,
139
(const uchar *)name->str, name->length,
140
(const uchar *)table_alias->str, table_alias->length))
142
name= table_alias + 1;
151
plugin_ref ha_lock_engine(THD *thd, handlerton *hton)
155
st_plugin_int **plugin= hton2plugin + hton->slot;
157
return my_plugin_lock(thd, &plugin);
163
handlerton *ha_resolve_by_legacy_type(THD *thd, enum legacy_db_type db_type)
167
case DB_TYPE_DEFAULT:
168
return ha_default_handlerton(thd);
170
if (db_type > DB_TYPE_UNKNOWN && db_type < DB_TYPE_DEFAULT &&
171
(plugin= ha_lock_engine(thd, installed_htons[db_type])))
172
return plugin_data(plugin, handlerton*);
174
case DB_TYPE_UNKNOWN:
181
Use other database handler if databasehandler is not compiled in.
183
handlerton *ha_checktype(THD *thd, enum legacy_db_type database_type,
184
bool no_substitute, bool report_error)
186
handlerton *hton= ha_resolve_by_legacy_type(thd, database_type);
187
if (ha_storage_engine_is_enabled(hton))
194
const char *engine_name= ha_resolve_storage_engine_name(hton);
195
my_error(ER_FEATURE_DISABLED,MYF(0),engine_name,engine_name);
200
switch (database_type) {
202
return ha_resolve_by_legacy_type(thd, DB_TYPE_HASH);
207
return ha_default_handlerton(thd);
211
handler *get_new_handler(TABLE_SHARE *share, MEM_ROOT *alloc,
216
if (db_type && db_type->state == SHOW_OPTION_YES && db_type->create)
218
if ((file= db_type->create(db_type, share, alloc)))
223
Try the default table type
224
Here the call to current_thd() is ok as we call this function a lot of
225
times but we enter this branch very seldom.
227
return(get_new_handler(share, alloc, ha_default_handlerton(current_thd)));
149
311
/* Allocate a pointer array for the error message strings. */
150
312
if (! (errmsgs= my_error_unregister(HA_ERR_FIRST, HA_ERR_LAST)))
152
free((unsigned char*) errmsgs);
314
my_free((uchar*) errmsgs, MYF(0));
319
int ha_finalize_handlerton(st_plugin_int *plugin)
321
handlerton *hton= (handlerton *)plugin->data;
326
case SHOW_OPTION_DISABLED:
328
case SHOW_OPTION_YES:
329
if (installed_htons[hton->db_type] == hton)
330
installed_htons[hton->db_type]= NULL;
334
if (hton && plugin->plugin->deinit)
335
(void)plugin->plugin->deinit(hton);
337
my_free((uchar*)hton, MYF(0));
343
int ha_initialize_handlerton(st_plugin_int *plugin)
347
hton= (handlerton *)my_malloc(sizeof(handlerton),
348
MYF(MY_WME | MY_ZEROFILL));
350
FIXME: the MY_ZEROFILL flag above doesn't zero all the bytes.
352
This was detected after adding get_backup_engine member to handlerton
353
structure. Apparently get_backup_engine was not NULL even though it was
356
memset(hton, 0, sizeof(hton));
357
/* Historical Requirement */
358
plugin->data= hton; // shortcut for the future
359
if (plugin->plugin->init)
361
if (plugin->plugin->init(hton))
363
sql_print_error("Plugin '%s' init function returned error.",
370
the switch below and hton->state should be removed when
371
command-line options for plugins will be implemented
373
switch (hton->state) {
376
case SHOW_OPTION_YES:
379
/* now check the db_type for conflict */
380
if (hton->db_type <= DB_TYPE_UNKNOWN ||
381
hton->db_type >= DB_TYPE_DEFAULT ||
382
installed_htons[hton->db_type])
384
int idx= (int) DB_TYPE_FIRST_DYNAMIC;
386
while (idx < (int) DB_TYPE_DEFAULT && installed_htons[idx])
389
if (idx == (int) DB_TYPE_DEFAULT)
391
sql_print_warning("Too many storage engines!");
394
if (hton->db_type != DB_TYPE_UNKNOWN)
395
sql_print_warning("Storage engine '%s' has conflicting typecode. "
396
"Assigning value %d.", plugin->plugin->name, idx);
397
hton->db_type= (enum legacy_db_type) idx;
399
installed_htons[hton->db_type]= hton;
400
tmp= hton->savepoint_offset;
401
hton->savepoint_offset= savepoint_alloc_size;
402
savepoint_alloc_size+= tmp;
403
hton->slot= total_ha++;
404
hton2plugin[hton->slot]=plugin;
411
hton->state= SHOW_OPTION_DISABLED;
416
This is entirely for legacy. We will create a new "disk based" hton and a
417
"memory" hton which will be configurable longterm. We should be able to
418
remove partition and myisammrg.
420
switch (hton->db_type) {
328
608
The server stores its transaction-related data in
329
session->transaction. This structure has two members of type
330
Session_TRANS. These members correspond to the statement and
609
thd->transaction. This structure has two members of type
610
THD_TRANS. These members correspond to the statement and
331
611
normal transactions respectively:
333
- session->transaction.stmt contains a list of engines
613
- thd->transaction.stmt contains a list of engines
334
614
that are participating in the given statement
335
- session->transaction.all contains a list of engines that
615
- thd->transaction.all contains a list of engines that
336
616
have participated in any of the statement transactions started
337
617
within the context of the normal transaction.
338
618
Each element of the list contains a pointer to the storage
339
619
engine, engine-specific transactional data, and engine-specific
340
620
transaction flags.
342
In autocommit mode session->transaction.all is empty.
343
Instead, data of session->transaction.stmt is
622
In autocommit mode thd->transaction.all is empty.
623
Instead, data of thd->transaction.stmt is
344
624
used to commit/rollback the normal transaction.
346
626
The list of registered engines has a few important properties:
576
856
handlerton *ht= ha_info->ht();
577
status_var_increment(session->status_var.ha_prepare_count);
857
status_var_increment(thd->status_var.ha_prepare_count);
580
if ((err= ht->prepare(ht, session, all)))
860
if ((err= ht->prepare(ht, thd, all)))
582
862
my_error(ER_ERROR_DURING_COMMIT, MYF(0), err);
583
ha_rollback_trans(session, all);
863
ha_rollback_trans(thd, all);
590
push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_WARN,
870
push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
591
871
ER_ILLEGAL_HA, ER(ER_ILLEGAL_HA),
592
872
ha_resolve_storage_engine_name(ht));
666
946
stored functions or triggers. So we simply do nothing now.
667
947
TODO: This should be fixed in later ( >= 5.1) releases.
669
int ha_commit_trans(Session *session, bool all)
949
int ha_commit_trans(THD *thd, bool all)
671
951
int error= 0, cookie= 0;
673
953
'all' means that this is either an explicit commit issued by
674
954
user, or an implicit commit issued by a DDL.
676
Session_TRANS *trans= all ? &session->transaction.all : &session->transaction.stmt;
677
bool is_real_trans= all || session->transaction.all.ha_list == 0;
956
THD_TRANS *trans= all ? &thd->transaction.all : &thd->transaction.stmt;
957
bool is_real_trans= all || thd->transaction.all.ha_list == 0;
678
958
Ha_trx_info *ha_info= trans->ha_list;
679
my_xid xid= session->transaction.xid_state.xid.get_my_xid();
959
my_xid xid= thd->transaction.xid_state.xid.get_my_xid();
682
962
We must not commit the normal transaction if a statement
684
964
flags will not get propagated to its normal transaction's
687
assert(session->transaction.stmt.ha_list == NULL ||
688
trans == &session->transaction.stmt);
967
assert(thd->transaction.stmt.ha_list == NULL ||
968
trans == &thd->transaction.stmt);
970
if (thd->in_sub_stmt)
973
Since we don't support nested statement transactions in 5.0,
974
we can't commit or rollback stmt transactions while we are inside
975
stored functions or triggers. So we simply do nothing now.
976
TODO: This should be fixed in later ( >= 5.1) releases.
981
We assume that all statements which commit or rollback main transaction
982
are prohibited inside of stored functions or triggers. So they should
983
bail out with error even before ha_commit_trans() call. To be 100% safe
984
let us throw error in non-debug builds.
987
my_error(ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG, MYF(0));
694
if (is_real_trans && wait_if_global_read_lock(session, 0, 0))
994
if (is_real_trans && wait_if_global_read_lock(thd, 0, 0))
696
ha_rollback_trans(session, all);
996
ha_rollback_trans(thd, all);
700
1000
if ( is_real_trans
702
&& ! session->slave_thread
1002
&& ! thd->slave_thread
705
1005
my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--read-only");
706
ha_rollback_trans(session, all);
1006
ha_rollback_trans(thd, all);
711
must_2pc= ha_check_and_coalesce_trx_read_only(session, ha_info, all);
1011
must_2pc= ha_check_and_coalesce_trx_read_only(thd, ha_info, all);
713
1013
if (!trans->no_2pc && must_2pc)
727
1027
Sic: we know that prepare() is not NULL since otherwise
728
1028
trans->no_2pc would have been set.
730
if ((err= ht->prepare(ht, session, all)))
1030
if ((err= ht->prepare(ht, thd, all)))
732
1032
my_error(ER_ERROR_DURING_COMMIT, MYF(0), err);
735
status_var_increment(session->status_var.ha_prepare_count);
1035
status_var_increment(thd->status_var.ha_prepare_count);
737
1037
if (error || (is_real_trans && xid &&
738
(error= !(cookie= tc_log->log_xid(session, xid)))))
1038
(error= !(cookie= tc_log->log_xid(thd, xid)))))
740
ha_rollback_trans(session, all);
1040
ha_rollback_trans(thd, all);
745
error=ha_commit_one_phase(session, all) ? (cookie ? 2 : 1) : 0;
1045
error=ha_commit_one_phase(thd, all) ? (cookie ? 2 : 1) : 0;
747
1047
tc_log->unlog(cookie, xid);
749
1049
if (is_real_trans)
750
start_waiting_global_read_lock(session);
1050
start_waiting_global_read_lock(thd);
770
1070
handlerton *ht= ha_info->ht();
771
if ((err= ht->commit(ht, session, all)))
1071
if ((err= ht->commit(ht, thd, all)))
773
1073
my_error(ER_ERROR_DURING_COMMIT, MYF(0), err);
776
status_var_increment(session->status_var.ha_commit_count);
1076
status_var_increment(thd->status_var.ha_commit_count);
777
1077
ha_info_next= ha_info->next();
778
1078
ha_info->reset(); /* keep it conveniently zero-filled */
780
1080
trans->ha_list= 0;
781
1081
trans->no_2pc=0;
782
1082
if (is_real_trans)
783
session->transaction.xid_state.xid.null();
1083
thd->transaction.xid_state.xid.null();
786
session->variables.tx_isolation=session->session_tx_isolation;
787
session->transaction.cleanup();
1086
thd->variables.tx_isolation=thd->session_tx_isolation;
1087
thd->transaction.cleanup();
794
int ha_rollback_trans(Session *session, bool all)
1094
int ha_rollback_trans(THD *thd, bool all)
797
Session_TRANS *trans=all ? &session->transaction.all : &session->transaction.stmt;
1097
THD_TRANS *trans=all ? &thd->transaction.all : &thd->transaction.stmt;
798
1098
Ha_trx_info *ha_info= trans->ha_list, *ha_info_next;
799
bool is_real_trans=all || session->transaction.all.ha_list == 0;
1099
bool is_real_trans=all || thd->transaction.all.ha_list == 0;
802
1102
We must not rollback the normal transaction if a statement
803
1103
transaction is pending.
805
assert(session->transaction.stmt.ha_list == NULL ||
806
trans == &session->transaction.stmt);
1105
assert(thd->transaction.stmt.ha_list == NULL ||
1106
trans == &thd->transaction.stmt);
1108
if (thd->in_sub_stmt)
1111
If we are inside stored function or trigger we should not commit or
1112
rollback current statement transaction. See comment in ha_commit_trans()
1113
call for more information.
1118
my_error(ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG, MYF(0));
810
1123
for (; ha_info; ha_info= ha_info_next)
813
1126
handlerton *ht= ha_info->ht();
814
if ((err= ht->rollback(ht, session, all)))
1127
if ((err= ht->rollback(ht, thd, all)))
815
1128
{ // cannot happen
816
1129
my_error(ER_ERROR_DURING_ROLLBACK, MYF(0), err);
819
status_var_increment(session->status_var.ha_rollback_count);
1132
status_var_increment(thd->status_var.ha_rollback_count);
820
1133
ha_info_next= ha_info->next();
821
1134
ha_info->reset(); /* keep it conveniently zero-filled */
823
1136
trans->ha_list= 0;
824
1137
trans->no_2pc=0;
825
1138
if (is_real_trans)
826
session->transaction.xid_state.xid.null();
1139
thd->transaction.xid_state.xid.null();
829
session->variables.tx_isolation=session->session_tx_isolation;
830
session->transaction.cleanup();
1142
thd->variables.tx_isolation=thd->session_tx_isolation;
1143
thd->transaction.cleanup();
834
session->transaction_rollback_request= false;
1147
thd->transaction_rollback_request= false;
837
1150
If a non-transactional table was updated, warn; don't warn if this is a
861
1174
the user has used LOCK TABLES then that mechanism does not know to do the
864
int ha_autocommit_or_rollback(Session *session, int error)
1177
int ha_autocommit_or_rollback(THD *thd, int error)
866
if (session->transaction.stmt.ha_list)
1179
if (thd->transaction.stmt.ha_list)
870
if (ha_commit_trans(session, 0))
1183
if (ha_commit_trans(thd, 0))
875
(void) ha_rollback_trans(session, 0);
876
if (session->transaction_rollback_request)
877
(void) ha_rollback(session);
1188
(void) ha_rollback_trans(thd, 0);
1189
if (thd->transaction_rollback_request && !thd->in_sub_stmt)
1190
(void) ha_rollback(thd);
880
session->variables.tx_isolation=session->session_tx_isolation;
1193
thd->variables.tx_isolation=thd->session_tx_isolation;
1045
plugin_foreach(NULL, xarecover_handlerton,
1046
DRIZZLE_STORAGE_ENGINE_PLUGIN, &info);
1358
plugin_foreach(NULL, xarecover_handlerton,
1359
MYSQL_STORAGE_ENGINE_PLUGIN, &info);
1048
free((unsigned char*)info.list);
1361
my_free((uchar*)info.list, MYF(0));
1049
1362
if (info.found_foreign_xids)
1050
sql_print_warning(_("Found %d prepared XA transactions"),
1363
sql_print_warning("Found %d prepared XA transactions",
1051
1364
info.found_foreign_xids);
1052
1365
if (info.dry_run && info.found_my_xids)
1054
sql_print_error(_("Found %d prepared transactions! It means that drizzled "
1055
"was not shut down properly last time and critical "
1056
"recovery information (last binlog or %s file) was "
1057
"manually deleted after a crash. You have to start "
1058
"drizzled with the --tc-heuristic-recover switch to "
1059
"commit or rollback pending transactions."),
1367
sql_print_error("Found %d prepared transactions! It means that mysqld was "
1368
"not shut down properly last time and critical recovery "
1369
"information (last binlog or %s file) was manually deleted "
1370
"after a crash. You have to start mysqld with "
1371
"--tc-heuristic-recover switch to commit or rollback "
1372
"pending transactions.",
1060
1373
info.found_my_xids, opt_tc_log_file);
1063
1376
if (info.commit_list)
1064
sql_print_information(_("Crash recovery finished."));
1377
sql_print_information("Crash recovery finished.");
1126
1439
performs another SQL query. In MySQL-4.1 this is even more important because
1127
1440
there a connection can have several SELECT queries open at the same time.
1129
@param session the thread handle of the current connection
1442
@param thd the thread handle of the current connection
1134
static bool release_temporary_latches(Session *session, plugin_ref plugin,
1447
static bool release_temporary_latches(THD *thd, plugin_ref plugin,
1135
1448
void *unused __attribute__((unused)))
1137
1450
handlerton *hton= plugin_data(plugin, handlerton *);
1139
1452
if (hton->state == SHOW_OPTION_YES && hton->release_temporary_latches)
1140
hton->release_temporary_latches(hton, session);
1453
hton->release_temporary_latches(hton, thd);
1146
int ha_release_temporary_latches(Session *session)
1459
int ha_release_temporary_latches(THD *thd)
1148
plugin_foreach(session, release_temporary_latches, DRIZZLE_STORAGE_ENGINE_PLUGIN,
1461
plugin_foreach(thd, release_temporary_latches, MYSQL_STORAGE_ENGINE_PLUGIN,
1154
int ha_rollback_to_savepoint(Session *session, SAVEPOINT *sv)
1467
int ha_rollback_to_savepoint(THD *thd, SAVEPOINT *sv)
1157
Session_TRANS *trans= &session->transaction.all;
1470
THD_TRANS *trans= (thd->in_sub_stmt ? &thd->transaction.stmt :
1471
&thd->transaction.all);
1158
1472
Ha_trx_info *ha_info, *ha_info_next;
1160
1474
trans->no_2pc=0;
1263
static bool snapshot_handlerton(Session *session, plugin_ref plugin, void *arg)
1578
static bool snapshot_handlerton(THD *thd, plugin_ref plugin, void *arg)
1265
1580
handlerton *hton= plugin_data(plugin, handlerton *);
1266
1581
if (hton->state == SHOW_OPTION_YES &&
1267
1582
hton->start_consistent_snapshot)
1269
hton->start_consistent_snapshot(hton, session);
1584
hton->start_consistent_snapshot(hton, thd);
1270
1585
*((bool *)arg)= false;
1275
int ha_start_consistent_snapshot(Session *session)
1590
int ha_start_consistent_snapshot(THD *thd)
1277
1592
bool warn= true;
1279
plugin_foreach(session, snapshot_handlerton, DRIZZLE_STORAGE_ENGINE_PLUGIN, &warn);
1594
plugin_foreach(thd, snapshot_handlerton, MYSQL_STORAGE_ENGINE_PLUGIN, &warn);
1282
1597
Same idea as when one wants to CREATE TABLE in one engine which does not
1286
push_warning(session, DRIZZLE_ERROR::WARN_LEVEL_WARN, ER_UNKNOWN_ERROR,
1601
push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_UNKNOWN_ERROR,
1287
1602
"This MySQL server does not support any "
1288
1603
"consistent-read capable storage engine");
1293
static bool flush_handlerton(Session *session __attribute__((unused)),
1608
static bool flush_handlerton(THD *thd __attribute__((unused)),
1294
1609
plugin_ref plugin,
1295
1610
void *arg __attribute__((unused)))
1297
1612
handlerton *hton= plugin_data(plugin, handlerton *);
1298
if (hton->state == SHOW_OPTION_YES && hton->flush_logs &&
1613
if (hton->state == SHOW_OPTION_YES && hton->flush_logs &&
1299
1614
hton->flush_logs(hton))
1347
1662
struct Ha_delete_table_error_handler: public Internal_error_handler
1350
virtual bool handle_error(uint32_t sql_errno,
1665
virtual bool handle_error(uint sql_errno,
1351
1666
const char *message,
1352
DRIZZLE_ERROR::enum_warning_level level,
1354
char buff[DRIZZLE_ERRMSG_SIZE];
1667
MYSQL_ERROR::enum_warning_level level,
1669
char buff[MYSQL_ERRMSG_SIZE];
1359
1674
Ha_delete_table_error_handler::
1360
handle_error(uint32_t sql_errno __attribute__((unused)),
1675
handle_error(uint sql_errno __attribute__((unused)),
1361
1676
const char *message,
1362
DRIZZLE_ERROR::enum_warning_level level __attribute__((unused)),
1363
Session *session __attribute__((unused)))
1677
MYSQL_ERROR::enum_warning_level level __attribute__((unused)),
1678
THD *thd __attribute__((unused)))
1365
1680
/* Grab the error message */
1366
1681
strmake(buff, message, sizeof(buff)-1);
1371
struct handlerton_delete_table_args {
1378
static bool deletetable_handlerton(Session *unused1 __attribute__((unused)),
1382
struct handlerton_delete_table_args *dtargs= (struct handlerton_delete_table_args *) args;
1384
Session *session= dtargs->session;
1385
const char *path= dtargs->path;
1388
char tmp_path[FN_REFLEN];
1390
if(dtargs->error!=ENOENT) /* already deleted table */
1393
handlerton *table_type= plugin_data(plugin, handlerton *);
1398
if(!(table_type->state == SHOW_OPTION_YES && table_type->create))
1401
if ((file= table_type->create(table_type, NULL, session->mem_root)))
1406
path= check_lowercase_names(file, path, tmp_path);
1407
int error= file->ha_delete_table(path);
1411
dtargs->error= error;
1413
delete dtargs->file;
1422
1687
This should return ENOENT if the file doesn't exists.
1423
1688
The .frm file will be deleted only if we return 0 or ENOENT
1425
int ha_delete_table(Session *session, const char *path,
1690
int ha_delete_table(THD *thd, handlerton *table_type, const char *path,
1426
1691
const char *db, const char *alias, bool generate_warning)
1694
char tmp_path[FN_REFLEN];
1428
1697
TABLE_SHARE dummy_share;
1431
struct handlerton_delete_table_args dtargs;
1432
dtargs.error= ENOENT;
1433
dtargs.session= session;
1437
plugin_foreach(NULL, deletetable_handlerton, DRIZZLE_STORAGE_ENGINE_PLUGIN,
1440
memset(&dummy_table, 0, sizeof(dummy_table));
1441
memset(&dummy_share, 0, sizeof(dummy_share));
1699
memset((char*) &dummy_table, 0, sizeof(dummy_table));
1700
memset((char*) &dummy_share, 0, sizeof(dummy_share));
1442
1701
dummy_table.s= &dummy_share;
1444
if (dtargs.error && generate_warning)
1703
/* DB_TYPE_UNKNOWN is used in ALTER TABLE when renaming only .frm files */
1704
if (table_type == NULL ||
1705
! (file=get_new_handler((TABLE_SHARE*)0, thd->mem_root, table_type)))
1708
path= check_lowercase_names(file, path, tmp_path);
1709
if ((error= file->ha_delete_table(path)) && generate_warning)
1447
1712
Because file->print_error() use my_error() to generate the error message
1460
1725
dummy_share.table_name.length= strlen(alias);
1461
1726
dummy_table.alias= alias;
1463
handler *file= dtargs.file;
1464
1728
file->change_table_ptr(&dummy_table, &dummy_share);
1466
session->push_internal_handler(&ha_delete_table_error_handler);
1467
file->print_error(dtargs.error, 0);
1730
thd->push_internal_handler(&ha_delete_table_error_handler);
1731
file->print_error(error, 0);
1469
session->pop_internal_handler();
1733
thd->pop_internal_handler();
1472
1736
XXX: should we convert *all* errors to warnings here?
1473
1737
What if the error is fatal?
1475
push_warning(session, DRIZZLE_ERROR::WARN_LEVEL_ERROR, dtargs.error,
1739
push_warning(thd, MYSQL_ERROR::WARN_LEVEL_ERROR, error,
1476
1740
ha_delete_table_error_handler.buff);
1482
return dtargs.error;
1485
1746
/****************************************************************************
1490
1751
handler *new_handler= get_new_handler(table->s, mem_root, table->s->db_type());
1492
1753
Allocate handler->ref here because otherwise ha_open will allocate it
1493
on this->table->mem_root and we will not be able to reclaim that memory
1754
on this->table->mem_root and we will not be able to reclaim that memory
1494
1755
when the clone handler object is destroyed.
1496
if (!(new_handler->ref= (unsigned char*) alloc_root(mem_root, ALIGN_SIZE(ref_length)*2)))
1757
if (!(new_handler->ref= (uchar*) alloc_root(mem_root, ALIGN_SIZE(ref_length)*2)))
1498
1759
if (new_handler && !new_handler->ha_open(table,
1499
1760
table->s->normalized_path.str,
1501
1762
HA_OPEN_IGNORE_IF_LOCKED))
1502
1763
return new_handler;
1506
int handler::ha_index_init(uint32_t idx, bool sorted)
1509
assert(inited==NONE);
1510
if (!(result= index_init(idx, sorted)))
1516
int handler::ha_index_end()
1518
assert(inited==INDEX);
1521
return(index_end());
1524
int handler::ha_rnd_init(bool scan)
1527
assert(inited==NONE || (inited==RND && scan));
1528
inited= (result= rnd_init(scan)) ? NONE: RND;
1532
int handler::ha_rnd_end()
1534
assert(inited==RND);
1539
int handler::ha_index_or_rnd_end()
1541
return inited == INDEX ? ha_index_end() : inited == RND ? ha_rnd_end() : 0;
1544
handler::Table_flags handler::ha_table_flags() const
1546
return cached_table_flags;
1549
void handler::ha_start_bulk_insert(ha_rows rows)
1551
estimation_rows_to_insert= rows;
1552
start_bulk_insert(rows);
1555
int handler::ha_end_bulk_insert()
1557
estimation_rows_to_insert= 0;
1558
return end_bulk_insert();
1561
void handler::change_table_ptr(Table *table_arg, TABLE_SHARE *share)
1567
const key_map *handler::keys_to_use_for_scanning()
1569
return &key_map_empty;
1572
bool handler::has_transactions()
1574
return (ha_table_flags() & HA_NO_TRANSACTIONS) == 0;
1577
1769
void handler::ha_statistic_increment(ulong SSV::*offset) const
1579
1771
status_var_increment(table->in_use->status_var.*offset);
1582
void **handler::ha_data(Session *session) const
1584
return session_ha_data(session, ht);
1587
Session *handler::ha_session(void) const
1589
assert(!table || !table->in_use || table->in_use == current_session);
1590
return (table && table->in_use) ? table->in_use : current_session;
1594
bool handler::is_fatal_error(int error, uint32_t flags)
1597
((flags & HA_CHECK_DUP_KEY) &&
1598
(error == HA_ERR_FOUND_DUPP_KEY ||
1599
error == HA_ERR_FOUND_DUPP_UNIQUE)))
1605
ha_rows handler::records() { return stats.records; }
1774
void **handler::ha_data(THD *thd) const
1776
return thd_ha_data(thd, ht);
1779
THD *handler::ha_thd(void) const
1781
assert(!table || !table->in_use || table->in_use == current_thd);
1782
return (table && table->in_use) ? table->in_use : current_thd;
1608
1786
Open database-handler.
2559
static bool update_frm_version(TABLE *table)
2561
char path[FN_REFLEN];
2566
No need to update frm version in case table was created or checked
2567
by server with the same version. This also ensures that we do not
2568
update frm version for temporary tables as this code doesn't support
2571
if (table->s->mysql_version == MYSQL_VERSION_ID)
2574
strxmov(path, table->s->normalized_path.str, reg_ext, NullS);
2576
if ((file= my_open(path, O_RDWR|O_BINARY, MYF(MY_WME))) >= 0)
2579
char *key= table->s->table_cache_key.str;
2580
uint key_length= table->s->table_cache_key.length;
2582
HASH_SEARCH_STATE state;
2584
int4store(version, MYSQL_VERSION_ID);
2586
if (pwrite(file, (uchar*)version, 4, 51L) == 0)
2592
for (entry=(TABLE*) hash_first(&open_cache,(uchar*) key,key_length, &state);
2594
entry= (TABLE*) hash_next(&open_cache,(uchar*) key,key_length, &state))
2595
entry->s->mysql_version= MYSQL_VERSION_ID;
2599
VOID(my_close(file,MYF(MY_WME)));
2376
2607
key if error because of duplicated keys
2378
uint32_t handler::get_dup_key(int error)
2609
uint handler::get_dup_key(int error)
2380
2611
table->file->errkey = (uint) -1;
2381
2612
if (error == HA_ERR_FOUND_DUPP_KEY || error == HA_ERR_FOREIGN_DUPLICATE_KEY ||
2782
3013
is an optimization hint that storage engine is free to ignore.
2783
3014
So, let's commit an open transaction (if any) now.
2785
if (!(error= ha_commit_trans(session, 0)))
2786
error= end_trans(session, COMMIT);
3016
if (!(error= ha_commit_trans(thd, 0)))
3017
error= end_trans(thd, COMMIT);
2791
int handler::index_next_same(unsigned char *buf, const unsigned char *key, uint32_t keylen)
3022
int handler::index_next_same(uchar *buf, const uchar *key, uint keylen)
2794
3025
if (!(error=index_next(buf)))
2796
3027
my_ptrdiff_t ptrdiff= buf - table->record[0];
2797
unsigned char *save_record_0= NULL;
3028
uchar *save_record_0= NULL;
2798
3029
KEY *key_info= NULL;
2799
3030
KEY_PART_INFO *key_part;
2800
3031
KEY_PART_INFO *key_part_end= NULL;
2854
int ha_create_table(Session *session, const char *path,
3085
int ha_create_table(THD *thd, const char *path,
2855
3086
const char *db, const char *table_name,
2856
3087
HA_CREATE_INFO *create_info,
2857
3088
bool update_create_info)
2861
3092
char name_buff[FN_REFLEN];
2862
3093
const char *name;
2863
3094
TABLE_SHARE share;
2865
init_tmp_table_share(session, &share, db, 0, table_name, path);
2866
if (open_table_def(session, &share, 0) ||
2867
open_table_from_share(session, &share, "", 0, (uint) READ_ALL, 0, &table,
3096
init_tmp_table_share(thd, &share, db, 0, table_name, path);
3097
if (open_table_def(thd, &share, 0) ||
3098
open_table_from_share(thd, &share, "", 0, (uint) READ_ALL, 0, &table,
2871
3102
if (update_create_info)
2872
table.updateCreateInfo(create_info);
3103
update_create_info_from_table(create_info, &table);
2874
3105
name= check_lowercase_names(table.file, share.path.str, name_buff);
2876
3107
error= table.file->ha_create(name, &table, create_info);
2877
closefrm(&table, 0);
3108
VOID(closefrm(&table, 0));
2880
strxmov(name_buff, db, ".", table_name, NULL);
3111
strxmov(name_buff, db, ".", table_name, NullS);
2881
3112
my_error(ER_CANT_CREATE_TABLE, MYF(ME_BELL+ME_WAITTANG), name_buff, error);
2899
3130
> 0 Error, table existed but could not be created
2901
int ha_create_table_from_engine(Session* session, const char *db, const char *name)
3132
int ha_create_table_from_engine(THD* thd, const char *db, const char *name)
2904
unsigned char *frmblob;
2906
3137
char path[FN_REFLEN];
2907
3138
HA_CREATE_INFO create_info;
2909
3140
TABLE_SHARE share;
2911
memset(&create_info, 0, sizeof(create_info));
2912
if ((error= ha_discover(session, db, name, &frmblob, &frmlen)))
3142
memset((uchar*) &create_info, 0, sizeof(create_info));
3143
if ((error= ha_discover(thd, db, name, &frmblob, &frmlen)))
2914
3145
/* Table could not be discovered and thus not created */
2923
3154
build_table_filename(path, FN_REFLEN-1, db, name, "", 0);
2924
3155
// Save the frm file
2925
3156
error= writefrm(path, frmblob, frmlen);
3157
my_free(frmblob, MYF(0));
2930
init_tmp_table_share(session, &share, db, 0, name, path);
2931
if (open_table_def(session, &share, 0))
3161
init_tmp_table_share(thd, &share, db, 0, name, path);
3162
if (open_table_def(thd, &share, 0))
2935
if (open_table_from_share(session, &share, "" ,0, 0, 0, &table, OTM_OPEN))
3166
if (open_table_from_share(thd, &share, "" ,0, 0, 0, &table, OTM_OPEN))
2937
3168
free_table_share(&share);
2941
table.updateCreateInfo(&create_info);
3172
update_create_info_from_table(&create_info, &table);
2942
3173
create_info.table_options|= HA_OPTION_CREATE_FROM_ENGINE;
2944
3175
check_lowercase_names(table.file, path, path);
2945
3176
error=table.file->ha_create(path, &table, &create_info);
2946
closefrm(&table, 1);
3177
VOID(closefrm(&table, 1));
2948
3179
return(error != 0);
3060
3291
const char *db;
3061
3292
const char *name;
3062
unsigned char **frmblob;
3063
3294
size_t *frmlen;
3066
static bool discover_handlerton(Session *session, plugin_ref plugin,
3297
static bool discover_handlerton(THD *thd, plugin_ref plugin,
3069
3300
st_discover_args *vargs= (st_discover_args *)arg;
3070
3301
handlerton *hton= plugin_data(plugin, handlerton *);
3071
3302
if (hton->state == SHOW_OPTION_YES && hton->discover &&
3072
(!(hton->discover(hton, session, vargs->db, vargs->name,
3303
(!(hton->discover(hton, thd, vargs->db, vargs->name,
3074
3305
vargs->frmlen))))
3080
int ha_discover(Session *session, const char *db, const char *name,
3081
unsigned char **frmblob, size_t *frmlen)
3311
int ha_discover(THD *thd, const char *db, const char *name,
3312
uchar **frmblob, size_t *frmlen)
3083
3314
int error= -1; // Table does not exist in any handler
3084
3315
st_discover_args args= {db, name, frmblob, frmlen};
3086
if (is_prefix(name, TMP_FILE_PREFIX)) /* skip temporary tables */
3317
if (is_prefix(name,tmp_file_prefix)) /* skip temporary tables */
3089
if (plugin_foreach(session, discover_handlerton,
3090
DRIZZLE_STORAGE_ENGINE_PLUGIN, &args))
3320
if (plugin_foreach(thd, discover_handlerton,
3321
MYSQL_STORAGE_ENGINE_PLUGIN, &args))
3094
status_var_increment(session->status_var.ha_discover_count);
3325
status_var_increment(thd->status_var.ha_discover_count);
3223
handler::multi_range_read_info_const(uint32_t keyno, RANGE_SEQ_IF *seq,
3454
handler::multi_range_read_info_const(uint keyno, RANGE_SEQ_IF *seq,
3224
3455
void *seq_init_param,
3225
uint32_t n_ranges_arg __attribute__((unused)),
3226
uint32_t *bufsz, uint32_t *flags, COST_VECT *cost)
3456
uint n_ranges_arg __attribute__((unused)),
3457
uint *bufsz, uint *flags, COST_VECT *cost)
3228
3459
KEY_MULTI_RANGE range;
3229
3460
range_seq_t seq_it;
3230
3461
ha_rows rows, total_rows= 0;
3231
uint32_t n_ranges=0;
3232
Session *session= current_session;
3463
THD *thd= current_thd;
3234
3465
/* Default MRR implementation doesn't need buffer */
3237
3468
seq_it= seq->init(seq_init_param, n_ranges, *flags);
3238
3469
while (!seq->next(seq_it, &range))
3240
if (unlikely(session->killed != 0))
3471
if (unlikely(thd->killed != 0))
3241
3472
return HA_POS_ERROR;
3244
3475
key_range *min_endp, *max_endp;
3677
3908
DS-MRR implementation: multi_range_read_info() function
3679
int DsMrr_impl::dsmrr_info(uint32_t keyno, uint32_t n_ranges, uint32_t rows, uint32_t *bufsz,
3680
uint32_t *flags, COST_VECT *cost)
3910
int DsMrr_impl::dsmrr_info(uint keyno, uint n_ranges, uint rows, uint *bufsz,
3911
uint *flags, COST_VECT *cost)
3683
uint32_t def_flags= *flags;
3684
uint32_t def_bufsz= *bufsz;
3914
uint def_flags= *flags;
3915
uint def_bufsz= *bufsz;
3686
3917
/* Get cost/flags/mem_usage of default MRR implementation */
3687
3918
res= h->handler::multi_range_read_info(keyno, n_ranges, rows, &def_bufsz,
3688
3919
&def_flags, cost);
3691
if ((*flags & HA_MRR_USE_DEFAULT_IMPL) ||
3922
if ((*flags & HA_MRR_USE_DEFAULT_IMPL) ||
3692
3923
choose_mrr_impl(keyno, rows, &def_flags, &def_bufsz, cost))
3694
3925
/* Default implementation is choosen */
3703
3934
DS-MRR Implementation: multi_range_read_info_const() function
3706
ha_rows DsMrr_impl::dsmrr_info_const(uint32_t keyno, RANGE_SEQ_IF *seq,
3707
void *seq_init_param, uint32_t n_ranges,
3708
uint32_t *bufsz, uint32_t *flags, COST_VECT *cost)
3937
ha_rows DsMrr_impl::dsmrr_info_const(uint keyno, RANGE_SEQ_IF *seq,
3938
void *seq_init_param, uint n_ranges,
3939
uint *bufsz, uint *flags, COST_VECT *cost)
3711
uint32_t def_flags= *flags;
3712
uint32_t def_bufsz= *bufsz;
3942
uint def_flags= *flags;
3943
uint def_bufsz= *bufsz;
3713
3944
/* Get cost/flags/mem_usage of default MRR implementation */
3714
3945
rows= h->handler::multi_range_read_info_const(keyno, seq, seq_init_param,
3715
n_ranges, &def_bufsz,
3946
n_ranges, &def_bufsz,
3716
3947
&def_flags, cost);
3717
3948
if (rows == HA_POS_ERROR)
3793
4024
@retval false DS-MRR implementation should be used
3796
bool DsMrr_impl::choose_mrr_impl(uint32_t keyno, ha_rows rows, uint32_t *flags,
3797
uint32_t *bufsz, COST_VECT *cost)
4027
bool DsMrr_impl::choose_mrr_impl(uint keyno, ha_rows rows, uint *flags,
4028
uint *bufsz, COST_VECT *cost)
3799
4030
COST_VECT dsmrr_cost;
3801
Session *session= current_session;
3802
if ((session->variables.optimizer_use_mrr == 2) ||
4032
THD *thd= current_thd;
4033
if ((thd->variables.optimizer_use_mrr == 2) ||
3803
4034
(*flags & HA_MRR_INDEX_ONLY) || (*flags & HA_MRR_SORTED) ||
3804
(keyno == table->s->primary_key &&
3805
h->primary_key_is_clustered()) ||
4035
(keyno == table->s->primary_key &&
4036
h->primary_key_is_clustered()) ||
3806
4037
key_uses_partial_cols(keyno))
3808
4039
/* Use the default implementation */
3809
4040
*flags |= HA_MRR_USE_DEFAULT_IMPL;
3813
uint32_t add_len= table->key_info[keyno].key_length + h->ref_length;
4044
uint add_len= table->key_info[keyno].key_length + h->ref_length;
3814
4045
*bufsz -= add_len;
3815
4046
if (get_disk_sweep_mrr_cost(keyno, rows, *flags, bufsz, &dsmrr_cost))
3817
4048
*bufsz += add_len;
3819
4050
bool force_dsmrr;
3821
4052
If @@optimizer_use_mrr==force, then set cost of DS-MRR to be minimum of
3822
4053
DS-MRR and Default implementations cost. This allows one to force use of
3823
4054
DS-MRR whenever it is applicable without affecting other cost-based
3826
if ((force_dsmrr= (session->variables.optimizer_use_mrr == 1)) &&
4057
if ((force_dsmrr= (thd->variables.optimizer_use_mrr == 1)) &&
3827
4058
dsmrr_cost.total_cost() > cost->total_cost())
3828
4059
dsmrr_cost= *cost;
4238
static bool stat_print(Session *session, const char *type, uint32_t type_len,
4239
const char *file, uint32_t file_len,
4240
const char *status, uint32_t status_len)
4469
static bool stat_print(THD *thd, const char *type, uint type_len,
4470
const char *file, uint file_len,
4471
const char *status, uint status_len)
4242
Protocol *protocol= session->protocol;
4473
Protocol *protocol= thd->protocol;
4243
4474
protocol->prepare_for_resend();
4244
4475
protocol->store(type, type_len, system_charset_info);
4245
4476
protocol->store(file, file_len, system_charset_info);
4307
4539
to the binary log.
4309
4541
This function will generate and write table maps for all tables
4310
that are locked by the thread 'session'. Either manually locked
4311
(stored in Session::locked_tables) and automatically locked (stored
4312
in Session::lock) are considered.
4542
that are locked by the thread 'thd'. Either manually locked
4543
(stored in THD::locked_tables) and automatically locked (stored
4544
in THD::lock) are considered.
4314
@param session Pointer to Session structure
4546
@param thd Pointer to THD structure
4316
4548
@retval 0 All OK
4317
4549
@retval 1 Failed to write all table maps
4321
Session::locked_tables
4324
static int write_locked_table_maps(Session *session)
4556
static int write_locked_table_maps(THD *thd)
4326
if (session->get_binlog_table_maps() == 0)
4558
if (thd->get_binlog_table_maps() == 0)
4328
DRIZZLE_LOCK *locks[3];
4329
locks[0]= session->extra_lock;
4330
locks[1]= session->lock;
4331
locks[2]= session->locked_tables;
4332
for (uint32_t i= 0 ; i < sizeof(locks)/sizeof(*locks) ; ++i )
4560
MYSQL_LOCK *locks[3];
4561
locks[0]= thd->extra_lock;
4562
locks[1]= thd->lock;
4563
locks[2]= thd->locked_tables;
4564
for (uint i= 0 ; i < sizeof(locks)/sizeof(*locks) ; ++i )
4334
DRIZZLE_LOCK const *const lock= locks[i];
4566
MYSQL_LOCK const *const lock= locks[i];
4335
4567
if (lock == NULL)
4338
Table **const end_ptr= lock->table + lock->table_count;
4339
for (Table **table_ptr= lock->table ;
4570
TABLE **const end_ptr= lock->table + lock->table_count;
4571
for (TABLE **table_ptr= lock->table ;
4340
4572
table_ptr != end_ptr ;
4343
Table *const table= *table_ptr;
4575
TABLE *const table= *table_ptr;
4344
4576
if (table->current_lock == F_WRLCK &&
4345
check_table_binlog_row_based(session, table))
4577
check_table_binlog_row_based(thd, table))
4347
4579
int const has_trans= table->file->has_transactions();
4348
int const error= session->binlog_write_table_map(table, has_trans);
4580
int const error= thd->binlog_write_table_map(table, has_trans);
4350
4582
If an error occurs, it is the responsibility of the caller to
4351
4583
roll back the transaction.
4363
typedef bool Log_func(Session*, Table*, bool, const unsigned char*, const unsigned char*);
4595
typedef bool Log_func(THD*, TABLE*, bool, const uchar*, const uchar*);
4365
static int binlog_log_row(Table* table,
4366
const unsigned char *before_record,
4367
const unsigned char *after_record,
4597
static int binlog_log_row(TABLE* table,
4598
const uchar *before_record,
4599
const uchar *after_record,
4368
4600
Log_func *log_func)
4370
4602
if (table->no_replicate)
4374
Session *const session= table->in_use;
4605
THD *const thd= table->in_use;
4376
if (check_table_binlog_row_based(session, table))
4607
if (check_table_binlog_row_based(thd, table))
4379
4610
If there are no table maps written to the binary log, this is
4380
4611
the first row handled in this statement. In that case, we need
4381
4612
to write table maps for all locked tables to the binary log.
4383
if (likely(!(error= write_locked_table_maps(session))))
4614
if (likely(!(error= write_locked_table_maps(thd))))
4385
4616
bool const has_trans= table->file->has_transactions();
4386
error= (*log_func)(session, table, has_trans, before_record, after_record);
4617
error= (*log_func)(thd, table, has_trans, before_record, after_record);
4390
4620
return error ? HA_ERR_RBR_LOGGING_FAILED : 0;
4393
int handler::ha_external_lock(Session *session, int lock_type)
4623
int handler::ha_external_lock(THD *thd, int lock_type)
4396
4626
Whether this is lock or unlock, this should be true, and is to verify that