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)
41
KEY_CREATE_INFO default_key_create_info= { HA_KEY_ALG_UNDEF, 0, {NULL,0}, {NULL,0} };
43
/* number of entries in handlertons[] */
26
#include "drizzled/server_includes.h"
27
#include "mysys/hash.h"
28
#include "drizzled/error.h"
29
#include "drizzled/gettext.h"
30
#include "drizzled/probes.h"
31
#include "drizzled/sql_parse.h"
32
#include "drizzled/cost_vect.h"
33
#include "drizzled/session.h"
34
#include "drizzled/sql_base.h"
35
#include "drizzled/replication_services.h"
36
#include "drizzled/lock.h"
37
#include "drizzled/item/int.h"
38
#include "drizzled/item/empty_string.h"
39
#include "drizzled/unireg.h" // for mysql_frm_type
40
#include "drizzled/field/timestamp.h"
41
#include "drizzled/message/table.pb.h"
42
#include "drizzled/plugin/client.h"
45
using namespace drizzled;
47
extern drizzled::ReplicationServices replication_services;
49
KEY_CREATE_INFO default_key_create_info= { HA_KEY_ALG_UNDEF, 0, {NULL,0} };
51
/* number of entries in storage_engines[] */
44
52
uint32_t total_ha= 0;
45
/* number of storage engines (from handlertons[]) that support 2pc */
53
/* number of storage engines (from storage_engines[]) that support 2pc */
46
54
uint32_t total_ha_2pc= 0;
47
55
/* size of savepoint storage area (see ha_init) */
48
56
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
58
const char *ha_row_type[] = {
58
59
"", "FIXED", "DYNAMIC", "COMPRESSED", "REDUNDANT", "COMPACT", "PAGE", "?","?","?"
61
62
const char *tx_isolation_names[] =
62
63
{ "READ-UNCOMMITTED", "READ-COMMITTED", "REPEATABLE-READ", "SERIALIZABLE",
64
66
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)));
67
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)
1014
635
Sic: we know that prepare() is not NULL since otherwise
1015
636
trans->no_2pc would have been set.
1017
if ((err= ht->prepare(ht, thd, all)))
638
if ((err= engine->prepare(session, all)))
1019
640
my_error(ER_ERROR_DURING_COMMIT, MYF(0), err);
1022
status_var_increment(thd->status_var.ha_prepare_count);
643
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);
647
ha_rollback_trans(session, all);
1032
error=ha_commit_one_phase(thd, all) ? (cookie ? 2 : 1) : 0;
1034
tc_log->unlog(cookie, xid);
652
error=ha_commit_one_phase(session, all) ? (cookie ? 2 : 1) : 0;
1036
654
if (is_real_trans)
1037
start_waiting_global_read_lock(thd);
655
start_waiting_global_read_lock(session);
1044
662
This function does not care about global read lock. A caller should.
1046
int ha_commit_one_phase(THD *thd, bool all)
664
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;
667
Session_TRANS *trans=all ? &session->transaction.all : &session->transaction.stmt;
668
bool is_real_trans=all || session->transaction.all.ha_list == 0;
1051
669
Ha_trx_info *ha_info= trans->ha_list, *ha_info_next;
1054
672
for (; ha_info; ha_info= ha_info_next)
1057
handlerton *ht= ha_info->ht();
1058
if ((err= ht->commit(ht, thd, all)))
675
StorageEngine *engine= ha_info->engine();
676
if ((err= engine->commit(session, all)))
1060
678
my_error(ER_ERROR_DURING_COMMIT, MYF(0), err);
1063
status_var_increment(thd->status_var.ha_commit_count);
681
status_var_increment(session->status_var.ha_commit_count);
1064
682
ha_info_next= ha_info->next();
1065
683
ha_info->reset(); /* keep it conveniently zero-filled */
1067
685
trans->ha_list= 0;
1068
686
trans->no_2pc=0;
1069
687
if (is_real_trans)
1070
thd->transaction.xid_state.xid.null();
688
session->transaction.xid_state.xid.null();
1073
thd->variables.tx_isolation=thd->session_tx_isolation;
1074
thd->transaction.cleanup();
691
session->variables.tx_isolation=session->session_tx_isolation;
692
session->transaction.cleanup();
1081
int ha_rollback_trans(THD *thd, bool all)
699
int ha_rollback_trans(Session *session, bool all)
1084
THD_TRANS *trans=all ? &thd->transaction.all : &thd->transaction.stmt;
702
Session_TRANS *trans=all ? &session->transaction.all : &session->transaction.stmt;
1085
703
Ha_trx_info *ha_info= trans->ha_list, *ha_info_next;
1086
bool is_real_trans=all || thd->transaction.all.ha_list == 0;
704
bool is_real_trans=all || session->transaction.all.ha_list == 0;
1089
707
We must not rollback the normal transaction if a statement
1090
708
transaction is pending.
1092
assert(thd->transaction.stmt.ha_list == NULL ||
1093
trans == &thd->transaction.stmt);
710
assert(session->transaction.stmt.ha_list == NULL ||
711
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
715
for (; ha_info; ha_info= ha_info_next)
1113
handlerton *ht= ha_info->ht();
1114
if ((err= ht->rollback(ht, thd, all)))
718
StorageEngine *engine= ha_info->engine();
719
if ((err= engine->rollback(session, all)))
1115
720
{ // cannot happen
1116
721
my_error(ER_ERROR_DURING_ROLLBACK, MYF(0), err);
1119
status_var_increment(thd->status_var.ha_rollback_count);
724
status_var_increment(session->status_var.ha_rollback_count);
1120
725
ha_info_next= ha_info->next();
1121
726
ha_info->reset(); /* keep it conveniently zero-filled */
1123
728
trans->ha_list= 0;
1124
729
trans->no_2pc=0;
1125
730
if (is_real_trans)
1126
thd->transaction.xid_state.xid.null();
731
session->transaction.xid_state.xid.null();
1129
thd->variables.tx_isolation=thd->session_tx_isolation;
1130
thd->transaction.cleanup();
734
session->variables.tx_isolation=session->session_tx_isolation;
735
session->transaction.cleanup();
1134
thd->transaction_rollback_request= false;
739
session->transaction_rollback_request= false;
1137
742
If a non-transactional table was updated, warn; don't warn if this is a
1161
765
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)
768
int ha_autocommit_or_rollback(Session *session, int error)
1166
if (thd->transaction.stmt.ha_list)
770
if (session->transaction.stmt.ha_list)
1170
if (ha_commit_trans(thd, 0))
1175
(void) ha_rollback_trans(thd, 0);
1176
if (thd->transaction_rollback_request && !thd->in_sub_stmt)
1177
(void) ha_rollback(thd);
1180
thd->variables.tx_isolation=thd->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."));
774
if (ha_commit_trans(session, 0))
779
(void) ha_rollback_trans(session, 0);
780
if (session->transaction_rollback_request)
781
(void) ha_rollback(session);
784
session->variables.tx_isolation=session->session_tx_isolation;
1385
806
field_list.push_back(new Item_int("bqual_length", 0, MY_INT32_NUM_DECIMAL_DIGITS));
1386
807
field_list.push_back(new Item_empty_string("data",XIDDATASIZE));
1388
if (protocol->send_fields(&field_list,
1389
Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
809
if (session->client->sendFields(&field_list))
1392
812
pthread_mutex_lock(&LOCK_xid_cache);
1393
813
while ((xs= (XID_STATE*)hash_element(&xid_cache, i++)))
1395
815
if (xs->xa_state==XA_PREPARED)
1397
protocol->prepare_for_resend();
1398
protocol->store_int64_t((int64_t)xs->xid.formatID, false);
1399
protocol->store_int64_t((int64_t)xs->xid.gtrid_length, false);
1400
protocol->store_int64_t((int64_t)xs->xid.bqual_length, false);
1401
protocol->store(xs->xid.data, xs->xid.gtrid_length+xs->xid.bqual_length,
1403
if (protocol->write())
817
session->client->store((int64_t)xs->xid.formatID);
818
session->client->store((int64_t)xs->xid.gtrid_length);
819
session->client->store((int64_t)xs->xid.bqual_length);
820
session->client->store(xs->xid.data,
821
xs->xid.gtrid_length+xs->xid.bqual_length);
822
if (session->client->flush())
1405
824
pthread_mutex_unlock(&LOCK_xid_cache);
1411
830
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)
836
int ha_rollback_to_savepoint(Session *session, SAVEPOINT *sv)
1457
THD_TRANS *trans= (thd->in_sub_stmt ? &thd->transaction.stmt :
1458
&thd->transaction.all);
839
Session_TRANS *trans= &session->transaction.all;
1459
840
Ha_trx_info *ha_info, *ha_info_next;
1461
842
trans->no_2pc=0;
1506
886
section "4.33.4 SQL-statements and transaction states",
1507
887
SAVEPOINT is *not* transaction-initiating SQL-statement
1509
int ha_savepoint(THD *thd, SAVEPOINT *sv)
889
int ha_savepoint(Session *session, SAVEPOINT *sv)
1512
THD_TRANS *trans= (thd->in_sub_stmt ? &thd->transaction.stmt :
1513
&thd->transaction.all);
892
Session_TRANS *trans= &session->transaction.all;
1514
893
Ha_trx_info *ha_info= trans->ha_list;
1515
894
for (; ha_info; ha_info= ha_info->next())
1518
handlerton *ht= ha_info->ht();
1520
if (! ht->savepoint_set)
897
StorageEngine *engine= ha_info->engine();
899
#ifdef NOT_IMPLEMENTED /*- TODO (examine this againt the original code base) */
900
if (! engine->savepoint_set)
1522
902
my_error(ER_CHECK_NOT_IMPLEMENTED, MYF(0), "SAVEPOINT");
1526
if ((err= ht->savepoint_set(ht, thd, (unsigned char *)(sv+1)+ht->savepoint_offset)))
907
if ((err= engine->savepoint_set(session, (void *)(sv+1))))
1527
908
{ // cannot happen
1528
909
my_error(ER_GET_ERRNO, MYF(0), err);
1531
status_var_increment(thd->status_var.ha_savepoint_count);
912
status_var_increment(session->status_var.ha_savepoint_count);
1534
915
Remember the list of registered storage engines. All new
1535
916
engines are prepended to the beginning of the list.
1537
918
sv->ha_list= trans->ha_list;
1541
int ha_release_savepoint(THD *thd, SAVEPOINT *sv)
922
int ha_release_savepoint(Session *session, SAVEPOINT *sv)
1544
925
Ha_trx_info *ha_info= sv->ha_list;
1546
927
for (; ha_info; ha_info= ha_info->next())
1549
handlerton *ht= ha_info->ht();
930
StorageEngine *engine= ha_info->engine();
1550
931
/* Savepoint life time is enclosed into transaction life time. */
1552
if (!ht->savepoint_release)
1554
if ((err= ht->savepoint_release(ht, thd,
1555
(unsigned char *)(sv+1) + ht->savepoint_offset)))
933
if ((err= engine->savepoint_release(session,
1556
935
{ // cannot happen
1557
936
my_error(ER_GET_ERRNO, MYF(0), err);
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
947
/****************************************************************************
1734
948
** General handler functions
1735
949
****************************************************************************/
950
handler::~handler(void)
952
assert(locked == false);
953
/* TODO: assert(inited == NONE); */
1736
957
handler *handler::clone(MEM_ROOT *mem_root)
1738
959
handler *new_handler= get_new_handler(table->s, mem_root, table->s->db_type());
1740
961
Allocate handler->ref here because otherwise ha_open will allocate it
1741
on this->table->mem_root and we will not be able to reclaim that memory
962
on this->table->mem_root and we will not be able to reclaim that memory
1742
963
when the clone handler object is destroyed.
1744
965
if (!(new_handler->ref= (unsigned char*) alloc_root(mem_root, ALIGN_SIZE(ref_length)*2)))
2497
1783
Returns true if this is a temporary error
2499
bool handler::get_error_message(int error __attribute__((unused)),
2500
String* buf __attribute__((unused)))
1785
bool handler::get_error_message(int , String* )
2506
int handler::ha_check_for_upgrade(HA_CHECK_OPT *check_opt)
2508
KEY *keyinfo, *keyend;
2509
KEY_PART_INFO *keypart, *keypartend;
2511
if (!table->s->mysql_version)
2513
/* check for blob-in-key error */
2514
keyinfo= table->key_info;
2515
keyend= table->key_info + table->s->keys;
2516
for (; keyinfo < keyend; keyinfo++)
2518
keypart= keyinfo->key_part;
2519
keypartend= keypart + keyinfo->key_parts;
2520
for (; keypart < keypartend; keypart++)
2522
if (!keypart->fieldnr)
2524
Field *field= table->field[keypart->fieldnr-1];
2525
if (field->type() == DRIZZLE_TYPE_BLOB)
2527
if (check_opt->sql_flags & TT_FOR_UPGRADE)
2528
check_opt->flags= T_MEDIUM;
2529
return HA_ADMIN_NEEDS_CHECK;
2534
return check_for_upgrade(check_opt);
2538
1791
/* Code left, but Drizzle has no legacy yet (while MySQL did) */
2539
1792
int handler::check_old_types()
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
1799
key if error because of duplicated keys
2595
1801
uint32_t handler::get_dup_key(int error)
2597
table->file->errkey = (uint) -1;
1803
table->file->errkey = (uint32_t) -1;
2598
1804
if (error == HA_ERR_FOUND_DUPP_KEY || error == HA_ERR_FOREIGN_DUPLICATE_KEY ||
2599
1805
error == HA_ERR_FOUND_DUPP_UNIQUE ||
2600
1806
error == HA_ERR_DROP_INDEX_FK)
3060
2080
** Some general functions that isn't in the handler class
3061
2081
****************************************************************************/
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
2084
void st_ha_check_opt::init()
3170
flags= sql_flags= 0;
3171
sort_buffer_size = current_thd->variables.myisam_sort_buff_size;
3175
/*****************************************************************************
3178
This code is only relevant for ISAM/MyISAM tables
3180
key_cache->cache may be 0 only in the case where a key cache is not
3181
initialized or when we where not able to init the key cache in a previous
3182
call to ha_init_key_cache() (probably out of memory)
3183
*****************************************************************************/
3186
Init a key cache if it has not been initied before.
3188
int ha_init_key_cache(const char *name __attribute__((unused)),
3189
KEY_CACHE *key_cache)
3191
if (!key_cache->key_cache_inited)
3193
pthread_mutex_lock(&LOCK_global_system_variables);
3194
uint32_t tmp_buff_size= (uint32_t) key_cache->param_buff_size;
3195
uint32_t tmp_block_size= (uint) key_cache->param_block_size;
3196
uint32_t division_limit= key_cache->param_division_limit;
3197
uint32_t age_threshold= key_cache->param_age_threshold;
3198
pthread_mutex_unlock(&LOCK_global_system_variables);
3199
return(!init_key_cache(key_cache,
3202
division_limit, age_threshold));
3211
int ha_resize_key_cache(KEY_CACHE *key_cache)
3213
if (key_cache->key_cache_inited)
3215
pthread_mutex_lock(&LOCK_global_system_variables);
3216
long tmp_buff_size= (long) key_cache->param_buff_size;
3217
long tmp_block_size= (long) key_cache->param_block_size;
3218
uint32_t division_limit= key_cache->param_division_limit;
3219
uint32_t age_threshold= key_cache->param_age_threshold;
3220
pthread_mutex_unlock(&LOCK_global_system_variables);
3221
return(!resize_key_cache(key_cache, tmp_block_size,
3223
division_limit, age_threshold));
3230
Change parameters for key cache (like size)
3232
int ha_change_key_cache_param(KEY_CACHE *key_cache)
3234
if (key_cache->key_cache_inited)
3236
pthread_mutex_lock(&LOCK_global_system_variables);
3237
uint32_t division_limit= key_cache->param_division_limit;
3238
uint32_t age_threshold= key_cache->param_age_threshold;
3239
pthread_mutex_unlock(&LOCK_global_system_variables);
3240
change_key_cache_param(key_cache, division_limit, age_threshold);
3246
Free memory allocated by a key cache.
3248
int ha_end_key_cache(KEY_CACHE *key_cache)
3250
end_key_cache(key_cache, 1); // Can never fail
3255
Move all tables from one key cache to another one.
3257
int ha_change_key_cache(KEY_CACHE *old_key_cache,
3258
KEY_CACHE *new_key_cache)
3260
mi_change_key_cache(old_key_cache, new_key_cache);
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);
3664
2380
while ((result == HA_ERR_END_OF_FILE) && !range_res);
3666
2382
*range_info= mrr_cur_range.ptr;
3671
/* **************************************************************************
3672
* DS-MRR implementation
3673
***************************************************************************/
3676
DS-MRR: Initialize and start MRR scan
3678
Initialize and start the MRR scan. Depending on the mode parameter, this
3679
may use default or DS-MRR implementation.
3681
@param h Table handler to be used
3682
@param key Index to be used
3683
@param seq_funcs Interval sequence enumeration functions
3684
@param seq_init_param Interval sequence enumeration parameter
3685
@param n_ranges Number of ranges in the sequence.
3686
@param mode HA_MRR_* modes to use
3687
@param buf INOUT Buffer to use
3689
@retval 0 Ok, Scan started.
3693
int DsMrr_impl::dsmrr_init(handler *h, KEY *key,
3694
RANGE_SEQ_IF *seq_funcs, void *seq_init_param,
3695
uint32_t n_ranges, uint32_t mode, HANDLER_BUFFER *buf)
3699
Item *pushed_cond= NULL;
3701
keyno= h->active_index;
3703
if (mode & HA_MRR_USE_DEFAULT_IMPL || mode & HA_MRR_SORTED)
3705
use_default_impl= true;
3706
return(h->handler::multi_range_read_init(seq_funcs, seq_init_param,
3707
n_ranges, mode, buf));
3709
rowids_buf= buf->buffer;
3710
//psergey-todo: don't add key_length as it is not needed anymore
3711
rowids_buf += key->key_length + h->ref_length;
3713
is_mrr_assoc= !test(mode & HA_MRR_NO_ASSOCIATION);
3714
rowids_buf_end= buf->buffer_end;
3716
elem_size= h->ref_length + (int)is_mrr_assoc * sizeof(void*);
3717
rowids_buf_last= rowids_buf +
3718
((rowids_buf_end - rowids_buf)/ elem_size)*
3720
rowids_buf_end= rowids_buf_last;
3722
/* 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))
3731
if (keyno == h->pushed_idx_cond_keyno)
3732
pushed_cond= h->pushed_idx_cond;
3733
if (h->ha_index_end())
3740
table->prepare_for_position();
3741
new_h2->extra(HA_EXTRA_KEYREAD);
3743
if (h2->ha_index_init(keyno, false) ||
3744
h2->handler::multi_range_read_init(seq_funcs, seq_init_param, n_ranges,
3747
use_default_impl= false;
3750
h2->idx_cond_push(keyno, pushed_cond);
3751
if (dsmrr_fill_buffer(new_h2))
3755
If the above call has scanned through all intervals in *seq, then
3756
adjust *buf to indicate that the remaining buffer space will not be used.
3759
buf->end_of_used_area= rowids_buf_last;
3761
if (h->ha_rnd_init(false))
3766
h2->ha_index_or_rnd_end();
3767
h2->ha_external_lock(thd, F_UNLCK);
3774
void DsMrr_impl::dsmrr_close()
3778
h2->ha_external_lock(current_thd, F_UNLCK);
3783
use_default_impl= true;
3788
static int rowid_cmp(void *h, unsigned char *a, unsigned char *b)
3790
return ((handler*)h)->cmp_ref(a, b);
3795
DS-MRR: Fill the buffer with rowids and sort it by rowid
3797
{This is an internal function of DiskSweep MRR implementation}
3798
Scan the MRR ranges and collect ROWIDs (or {ROWID, range_id} pairs) into
3799
buffer. When the buffer is full or scan is completed, sort the buffer by
3802
The function assumes that rowids buffer is empty when it is invoked.
3804
@param h Table handler
3806
@retval 0 OK, the next portion of rowids is in the buffer,
3811
int DsMrr_impl::dsmrr_fill_buffer(handler *unused __attribute__((unused)))
3816
rowids_buf_cur= rowids_buf;
3817
while ((rowids_buf_cur < rowids_buf_end) &&
3818
!(res= h2->handler::multi_range_read_next(&range_info)))
3820
/* Put rowid, or {rowid, range_id} pair into the buffer */
3821
h2->position(table->record[0]);
3822
memcpy(rowids_buf_cur, h2->ref, h2->ref_length);
3823
rowids_buf_cur += h->ref_length;
3827
memcpy(rowids_buf_cur, &range_info, sizeof(void*));
3828
rowids_buf_cur += sizeof(void*);
3832
if (res && res != HA_ERR_END_OF_FILE)
3834
dsmrr_eof= test(res == HA_ERR_END_OF_FILE);
3836
/* Sort the buffer contents by rowid */
3837
uint32_t elem_size= h->ref_length + (int)is_mrr_assoc * sizeof(void*);
3838
uint32_t n_rowids= (rowids_buf_cur - rowids_buf) / elem_size;
3840
my_qsort2(rowids_buf, n_rowids, elem_size, (qsort2_cmp)rowid_cmp,
3842
rowids_buf_last= rowids_buf_cur;
3843
rowids_buf_cur= rowids_buf;
3849
DS-MRR implementation: multi_range_read_next() function
3852
int DsMrr_impl::dsmrr_next(handler *h, char **range_info)
3856
if (use_default_impl)
3857
return h->handler::multi_range_read_next(range_info);
3859
if (rowids_buf_cur == rowids_buf_last)
3863
res= HA_ERR_END_OF_FILE;
3866
res= dsmrr_fill_buffer(h);
3871
/* Return EOF if there are no rowids in the buffer after re-fill attempt */
3872
if (rowids_buf_cur == rowids_buf_last)
3874
res= HA_ERR_END_OF_FILE;
3878
res= h->rnd_pos(table->record[0], rowids_buf_cur);
3879
rowids_buf_cur += h->ref_length;
3882
memcpy(range_info, rowids_buf_cur, sizeof(void*));
3883
rowids_buf_cur += sizeof(void*);
3894
DS-MRR implementation: multi_range_read_info() function
3896
int DsMrr_impl::dsmrr_info(uint32_t keyno, uint32_t n_ranges, uint32_t rows, uint32_t *bufsz,
3897
uint32_t *flags, COST_VECT *cost)
3900
uint32_t def_flags= *flags;
3901
uint32_t def_bufsz= *bufsz;
3903
/* Get cost/flags/mem_usage of default MRR implementation */
3904
res= h->handler::multi_range_read_info(keyno, n_ranges, rows, &def_bufsz,
3908
if ((*flags & HA_MRR_USE_DEFAULT_IMPL) ||
3909
choose_mrr_impl(keyno, rows, &def_flags, &def_bufsz, cost))
3911
/* Default implementation is choosen */
3920
DS-MRR Implementation: multi_range_read_info_const() function
3923
ha_rows DsMrr_impl::dsmrr_info_const(uint32_t keyno, RANGE_SEQ_IF *seq,
3924
void *seq_init_param, uint32_t n_ranges,
3925
uint32_t *bufsz, uint32_t *flags, COST_VECT *cost)
3928
uint32_t def_flags= *flags;
3929
uint32_t def_bufsz= *bufsz;
3930
/* Get cost/flags/mem_usage of default MRR implementation */
3931
rows= h->handler::multi_range_read_info_const(keyno, seq, seq_init_param,
3932
n_ranges, &def_bufsz,
3934
if (rows == HA_POS_ERROR)
3936
/* Default implementation can't perform MRR scan => we can't either */
3941
If HA_MRR_USE_DEFAULT_IMPL has been passed to us, that is an order to
3942
use the default MRR implementation (we need it for UPDATE/DELETE).
3943
Otherwise, make a choice based on cost and @@optimizer_use_mrr.
3945
if ((*flags & HA_MRR_USE_DEFAULT_IMPL) ||
3946
choose_mrr_impl(keyno, rows, flags, bufsz, cost))
3953
*flags &= ~HA_MRR_USE_DEFAULT_IMPL;
3960
Check if key has partially-covered columns
3962
We can't use DS-MRR to perform range scans when the ranges are over
3963
partially-covered keys, because we'll not have full key part values
3964
(we'll have their prefixes from the index) and will not be able to check
3965
if we've reached the end the range.
3967
@param keyno Key to check
3970
Allow use of DS-MRR in cases where the index has partially-covered
3971
components but they are not used for scanning.
3977
bool DsMrr_impl::key_uses_partial_cols(uint32_t keyno)
3979
KEY_PART_INFO *kp= table->key_info[keyno].key_part;
3980
KEY_PART_INFO *kp_end= kp + table->key_info[keyno].key_parts;
3981
for (; kp != kp_end; kp++)
3983
if (!kp->field->part_of_key.is_set(keyno))
3991
DS-MRR Internals: Choose between Default MRR implementation and DS-MRR
3993
Make the choice between using Default MRR implementation and DS-MRR.
3994
This function contains common functionality factored out of dsmrr_info()
3995
and dsmrr_info_const(). The function assumes that the default MRR
3996
implementation's applicability requirements are satisfied.
3998
@param keyno Index number
3999
@param rows E(full rows to be retrieved)
4000
@param flags IN MRR flags provided by the MRR user
4001
OUT If DS-MRR is choosen, flags of DS-MRR implementation
4002
else the value is not modified
4003
@param bufsz IN If DS-MRR is choosen, buffer use of DS-MRR implementation
4004
else the value is not modified
4005
@param cost IN Cost of default MRR implementation
4006
OUT If DS-MRR is choosen, cost of DS-MRR scan
4007
else the value is not modified
4009
@retval true Default MRR implementation should be used
4010
@retval false DS-MRR implementation should be used
4013
bool DsMrr_impl::choose_mrr_impl(uint32_t keyno, ha_rows rows, uint32_t *flags,
4014
uint32_t *bufsz, COST_VECT *cost)
4016
COST_VECT dsmrr_cost;
4018
THD *thd= current_thd;
4019
if ((thd->variables.optimizer_use_mrr == 2) ||
4020
(*flags & HA_MRR_INDEX_ONLY) || (*flags & HA_MRR_SORTED) ||
4021
(keyno == table->s->primary_key &&
4022
h->primary_key_is_clustered()) ||
4023
key_uses_partial_cols(keyno))
4025
/* Use the default implementation */
4026
*flags |= HA_MRR_USE_DEFAULT_IMPL;
4030
uint32_t add_len= table->key_info[keyno].key_length + h->ref_length;
4032
if (get_disk_sweep_mrr_cost(keyno, rows, *flags, bufsz, &dsmrr_cost))
4038
If @@optimizer_use_mrr==force, then set cost of DS-MRR to be minimum of
4039
DS-MRR and Default implementations cost. This allows one to force use of
4040
DS-MRR whenever it is applicable without affecting other cost-based
4043
if ((force_dsmrr= (thd->variables.optimizer_use_mrr == 1)) &&
4044
dsmrr_cost.total_cost() > cost->total_cost())
4047
if (force_dsmrr || dsmrr_cost.total_cost() <= cost->total_cost())
4049
*flags &= ~HA_MRR_USE_DEFAULT_IMPL; /* Use the DS-MRR implementation */
4050
*flags &= ~HA_MRR_SORTED; /* We will return unordered output */
4056
/* Use the default MRR implementation */
4063
static void get_sort_and_sweep_cost(Table *table, ha_rows nrows, COST_VECT *cost);
4067
Get cost of DS-MRR scan
4069
@param keynr Index to be used
4070
@param rows E(Number of rows to be scanned)
4071
@param flags Scan parameters (HA_MRR_* flags)
4072
@param buffer_size INOUT Buffer size
4073
@param cost OUT The cost
4076
@retval true Error, DS-MRR cannot be used (the buffer is too small
4080
bool DsMrr_impl::get_disk_sweep_mrr_cost(uint32_t keynr, ha_rows rows, uint32_t flags,
4081
uint32_t *buffer_size, COST_VECT *cost)
4083
uint32_t max_buff_entries, elem_size;
4084
ha_rows rows_in_full_step, rows_in_last_step;
4085
uint32_t n_full_steps;
4086
double index_read_cost;
4088
elem_size= h->ref_length + sizeof(void*) * (!test(flags & HA_MRR_NO_ASSOCIATION));
4089
max_buff_entries = *buffer_size / elem_size;
4091
if (!max_buff_entries)
4092
return true; /* Buffer has not enough space for even 1 rowid */
4094
/* Number of iterations we'll make with full buffer */
4095
n_full_steps= (uint)floor(rows2double(rows) / max_buff_entries);
4098
Get numbers of rows we'll be processing in
4099
- non-last sweep, with full buffer
4100
- last iteration, with non-full buffer
4102
rows_in_full_step= max_buff_entries;
4103
rows_in_last_step= rows % max_buff_entries;
4105
/* Adjust buffer size if we expect to use only part of the buffer */
4108
get_sort_and_sweep_cost(table, rows, cost);
4109
cost->multiply(n_full_steps);
4114
*buffer_size= cmax((ulong)*buffer_size,
4115
(size_t)(1.2*rows_in_last_step) * elem_size +
4116
h->ref_length + table->key_info[keynr].key_length);
4119
COST_VECT last_step_cost;
4120
get_sort_and_sweep_cost(table, rows_in_last_step, &last_step_cost);
4121
cost->add(&last_step_cost);
4123
if (n_full_steps != 0)
4124
cost->mem_cost= *buffer_size;
4126
cost->mem_cost= (double)rows_in_last_step * elem_size;
4128
/* Total cost of all index accesses */
4129
index_read_cost= h->index_only_read_time(keynr, (double)rows);
4130
cost->add_io(index_read_cost, 1 /* Random seeks */);
4136
Get cost of one sort-and-sweep step
4139
get_sort_and_sweep_cost()
4140
table Table being accessed
4141
nrows Number of rows to be sorted and retrieved
4145
Get cost of these operations:
4146
- sort an array of #nrows ROWIDs using qsort
4147
- read #nrows records from table in a sweep.
4151
void get_sort_and_sweep_cost(Table *table, ha_rows nrows, COST_VECT *cost)
4155
get_sweep_read_cost(table, nrows, false, cost);
4156
/* Add cost of qsort call: n * log2(n) * cost(rowid_comparison) */
4157
double cmp_op= rows2double(nrows) * (1.0 / TIME_FOR_COMPARE_ROWID);
4160
cost->cpu_cost += cmp_op * log2(cmp_op);
4382
2602
return error ? error : error1;
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,
2605
static bool stat_print(Session *session, const char *type, uint32_t type_len,
4456
2606
const char *file, uint32_t file_len,
4457
2607
const char *status, uint32_t status_len)
4459
Protocol *protocol= thd->protocol;
4460
protocol->prepare_for_resend();
4461
protocol->store(type, type_len, system_charset_info);
4462
protocol->store(file, file_len, system_charset_info);
4463
protocol->store(status, status_len, system_charset_info);
4464
if (protocol->write())
2609
session->client->store(type, type_len);
2610
session->client->store(file, file_len);
2611
session->client->store(status, status_len);
2612
if (session->client->flush())
4469
bool ha_show_status(THD *thd, handlerton *db_type, enum ha_stat_type stat)
2617
bool ha_show_status(Session *session, StorageEngine *engine, enum ha_stat_type stat)
4471
2619
List<Item> field_list;
4472
Protocol *protocol= thd->protocol;
4475
2622
field_list.push_back(new Item_empty_string("Type",10));
4476
2623
field_list.push_back(new Item_empty_string("Name",FN_REFLEN));
4477
2624
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))
2626
if (session->client->sendFields(&field_list))
4483
result= db_type->show_status &&
4484
db_type->show_status(db_type, thd, stat_print, stat) ? 1 : 0;
2629
result= engine->show_status(session, stat_print, stat) ? 1 : 0;
4501
2646
- 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))
2649
static bool log_row_for_replication(Table* table,
2650
const unsigned char *before_record,
2651
const unsigned char *after_record)
2653
Session *const session= table->in_use;
2655
switch (session->lex->sql_command)
2657
case SQLCOM_REPLACE:
2659
case SQLCOM_REPLACE_SELECT:
2660
case SQLCOM_INSERT_SELECT:
2661
case SQLCOM_CREATE_TABLE:
2662
replication_services.insertRecord(session, table);
2666
replication_services.updateRecord(session, table, before_record, after_record);
2670
replication_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.
2674
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;
2680
return false; //error;
4609
int handler::ha_external_lock(THD *thd, int lock_type)
2683
int handler::ha_external_lock(Session *session, int lock_type)
4612
2686
Whether this is lock or unlock, this should be true, and is to verify that