mirror of
https://github.com/MariaDB/server.git
synced 2025-08-08 11:22:35 +03:00
SQL, IB: various refactoring [#337]
This commit is contained in:
committed by
Aleksey Midenkov
parent
4dd8736c15
commit
0cdc1164dc
@@ -198,7 +198,7 @@ enum enum_indicator_type
|
||||
#define VERS_SYS_END_FLAG (1 << 28) /* autogenerated column declared with
|
||||
`generated always as row end`
|
||||
(see II.a SQL Standard).*/
|
||||
#define VERS_OPTIMIZED_UPDATE_FLAG (1 << 29) /* column that doesn't support
|
||||
#define VERS_UPDATE_UNVERSIONED_FLAG (1 << 29) /* column that doesn't support
|
||||
system versioning when table
|
||||
itself supports it*/
|
||||
#define HIDDEN_FLAG (1 << 31) /* hide from SELECT * */
|
||||
|
@@ -1455,6 +1455,11 @@ public:
|
||||
return flags & (VERS_SYS_START_FLAG | VERS_SYS_END_FLAG);
|
||||
}
|
||||
|
||||
bool vers_update_unversioned() const
|
||||
{
|
||||
return flags & VERS_UPDATE_UNVERSIONED_FLAG;
|
||||
}
|
||||
|
||||
virtual bool vers_trx_id() const
|
||||
{
|
||||
return false;
|
||||
|
@@ -6859,7 +6859,7 @@ bool Vers_parse_info::check_and_fix_implicit(
|
||||
!with_system_versioning) ||
|
||||
f->versioning == Column_definition::WITHOUT_VERSIONING)
|
||||
{
|
||||
f->flags|= VERS_OPTIMIZED_UPDATE_FLAG;
|
||||
f->flags|= VERS_UPDATE_UNVERSIONED_FLAG;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6999,7 +6999,7 @@ bool Vers_parse_info::check_and_fix_alter(THD *thd, Alter_info *alter_info,
|
||||
while (Create_field *f= it++)
|
||||
{
|
||||
if (f->versioning == Column_definition::WITHOUT_VERSIONING)
|
||||
f->flags|= VERS_OPTIMIZED_UPDATE_FLAG;
|
||||
f->flags|= VERS_UPDATE_UNVERSIONED_FLAG;
|
||||
|
||||
if (f->change.str && (start == f->change || end == f->change))
|
||||
{
|
||||
|
@@ -10384,7 +10384,7 @@ Item *Item_field::vers_optimized_fields_transformer(THD *thd, uchar *)
|
||||
if (!field)
|
||||
return this;
|
||||
|
||||
if (field->flags & VERS_OPTIMIZED_UPDATE_FLAG && context &&
|
||||
if (field->vers_update_unversioned() && context &&
|
||||
field->table->pos_in_table_list &&
|
||||
field->table->pos_in_table_list->vers_conditions)
|
||||
{
|
||||
|
@@ -710,12 +710,6 @@ extern "C" void thd_kill_timeout(THD* thd)
|
||||
mysql_mutex_unlock(&thd->LOCK_thd_data);
|
||||
}
|
||||
|
||||
Time_zone * thd_get_timezone(THD * thd)
|
||||
{
|
||||
DBUG_ASSERT(thd && thd->variables.time_zone);
|
||||
return thd->variables.time_zone;
|
||||
}
|
||||
|
||||
void thd_vers_update_trt(THD * thd, bool value)
|
||||
{
|
||||
thd->vers_update_trt= value;
|
||||
|
@@ -155,6 +155,7 @@ extern bool volatile shutdown_in_progress;
|
||||
|
||||
extern "C" LEX_STRING * thd_query_string (MYSQL_THD thd);
|
||||
extern "C" size_t thd_query_safe(MYSQL_THD thd, char *buf, size_t buflen);
|
||||
void thd_vers_update_trt(THD *thd, bool value);
|
||||
|
||||
/**
|
||||
@class CSET_STRING
|
||||
@@ -4564,6 +4565,8 @@ public:
|
||||
/* Handling of timeouts for commands */
|
||||
thr_timer_t query_timer;
|
||||
|
||||
// Storage engine may set this to true is we want to write a row to
|
||||
// transaction_registry table on transaction commit.
|
||||
bool vers_update_trt;
|
||||
|
||||
public:
|
||||
|
@@ -16743,7 +16743,7 @@ Field *create_tmp_field_from_field(THD *thd, Field *org_field,
|
||||
HIDDEN_FLAG |
|
||||
VERS_SYS_START_FLAG |
|
||||
VERS_SYS_END_FLAG |
|
||||
VERS_OPTIMIZED_UPDATE_FLAG));
|
||||
VERS_UPDATE_UNVERSIONED_FLAG));
|
||||
if (org_field->maybe_null() || (item && item->maybe_null))
|
||||
new_field->flags&= ~NOT_NULL_FLAG; // Because of outer join
|
||||
if (org_field->type() == MYSQL_TYPE_VAR_STRING ||
|
||||
|
@@ -2188,7 +2188,7 @@ int show_create_table(THD *thd, TABLE_LIST *table_list, String *packet,
|
||||
packet->append(def_value.ptr(), def_value.length(), system_charset_info);
|
||||
}
|
||||
|
||||
if (field->flags & VERS_OPTIMIZED_UPDATE_FLAG)
|
||||
if (field->vers_update_unversioned())
|
||||
{
|
||||
packet->append(STRING_WITH_LEN(" WITHOUT SYSTEM VERSIONING"));
|
||||
}
|
||||
|
@@ -161,7 +161,7 @@ static bool check_has_vers_fields(List<Item> &items)
|
||||
while (Item *item= it++)
|
||||
{
|
||||
if (Item_field *item_field= item->field_for_view_update())
|
||||
if (!(item_field->field->flags & VERS_OPTIMIZED_UPDATE_FLAG))
|
||||
if (!item_field->field->vers_update_unversioned())
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
@@ -2051,7 +2051,7 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write,
|
||||
{
|
||||
uchar flags= *extra2_field_flags++;
|
||||
if (flags & VERS_OPTIMIZED_UPDATE)
|
||||
reg_field->flags|= VERS_OPTIMIZED_UPDATE_FLAG;
|
||||
reg_field->flags|= VERS_UPDATE_UNVERSIONED_FLAG;
|
||||
if (flags & HIDDEN)
|
||||
reg_field->flags|= HIDDEN_FLAG;
|
||||
}
|
||||
@@ -8527,7 +8527,8 @@ void TR_table::store(uint field_id, timeval ts)
|
||||
|
||||
void TR_table::store_data(ulonglong trx_id, ulonglong commit_id, timeval commit_ts)
|
||||
{
|
||||
timeval start_time= {thd->start_time, thd->start_time_sec_part};
|
||||
timeval start_time= {static_cast<int>(thd->start_time),
|
||||
static_cast<int>(thd->start_time_sec_part)};
|
||||
store(FLD_TRX_ID, trx_id);
|
||||
store(FLD_COMMIT_ID, commit_id);
|
||||
store(FLD_BEGIN_TS, start_time);
|
||||
|
94
sql/table.h
94
sql/table.h
@@ -2930,14 +2930,14 @@ inline void mark_as_null_row(TABLE *table)
|
||||
|
||||
bool is_simple_order(ORDER *order);
|
||||
|
||||
class Open_tables_backup;
|
||||
|
||||
/** Transaction Registry Table (TRT)
|
||||
|
||||
This table holds transaction IDs, their corresponding times and other
|
||||
transaction-related data which is used for transaction order resolution.
|
||||
When versioned table marks its records lifetime with transaction IDs,
|
||||
TRT is used to get their actual timestamps. */
|
||||
|
||||
class Open_tables_backup;
|
||||
class TR_table: public TABLE_LIST
|
||||
{
|
||||
THD *thd;
|
||||
@@ -2952,33 +2952,111 @@ public:
|
||||
FLD_ISO_LEVEL,
|
||||
FIELD_COUNT
|
||||
};
|
||||
/**
|
||||
@param[in,out] Thread handle
|
||||
@param[in] Current transaction is read-write.
|
||||
*/
|
||||
TR_table(THD *_thd, bool rw= false);
|
||||
/**
|
||||
Opens a transaction_registry table.
|
||||
|
||||
@retval true on error, false otherwise.
|
||||
*/
|
||||
bool open();
|
||||
~TR_table();
|
||||
/**
|
||||
@retval current thd
|
||||
*/
|
||||
THD *get_thd() const { return thd; }
|
||||
/**
|
||||
Stores value to internal transaction_registry TABLE object.
|
||||
|
||||
@param[in] field number in a TABLE
|
||||
@param[in] value to store
|
||||
*/
|
||||
void store(uint field_id, ulonglong val);
|
||||
/**
|
||||
Stores value to internal transaction_registry TABLE object.
|
||||
|
||||
@param[in] field number in a TABLE
|
||||
@param[in] value to store
|
||||
*/
|
||||
void store(uint field_id, timeval ts);
|
||||
/**
|
||||
Stores value to internal transaction_registry TABLE object.
|
||||
|
||||
@param[in] current (InnoDB) transaction id
|
||||
@param[in] InnoDB transaction counter at the time of transaction commit
|
||||
@param[in] transaction commit timestamp
|
||||
*/
|
||||
void store_data(ulonglong trx_id, ulonglong commit_id, timeval commit_ts);
|
||||
/**
|
||||
Writes a row from internal TABLE object to transaction_registry table.
|
||||
|
||||
@retval true on error, false otherwise.
|
||||
*/
|
||||
bool update();
|
||||
// return true if found; false if not found or error
|
||||
/**
|
||||
Checks whether a row with specified transaction_id exists in a
|
||||
transaction_registry table.
|
||||
|
||||
@param[in] transacton_id value
|
||||
@retval true if exists, false it not exists or an error occured
|
||||
*/
|
||||
bool query(ulonglong trx_id);
|
||||
/**
|
||||
Gets a row from transaction_registry with the closest commit_timestamp to
|
||||
first argument. We can search for a value which a lesser or greater than
|
||||
first argument. Also loads a row into an internal TABLE object.
|
||||
|
||||
@param[in] timestamp
|
||||
@param[in] true if we search for a lesser timestamp, false if greater
|
||||
@retval true if exists, false it not exists or an error occured
|
||||
*/
|
||||
bool query(MYSQL_TIME &commit_time, bool backwards);
|
||||
// return true if error
|
||||
/**
|
||||
Checks whether transaction1 sees transaction0.
|
||||
|
||||
@param[out] true if transaction1 sees transaction0, undefined on error and
|
||||
when transaction1=transaction0 and false otherwise
|
||||
@param[in] transaction_id of transaction1
|
||||
@param[in] transaction_id of transaction0
|
||||
@param[in] commit time of transaction1 or 0 if we want it to be queried
|
||||
@param[in] isolation level (from handler.h) of transaction1
|
||||
@param[in] commit time of transaction0 or 0 if we want it to be queried
|
||||
@retval true on error, false otherwise
|
||||
*/
|
||||
bool query_sees(bool &result, ulonglong trx_id1, ulonglong trx_id0,
|
||||
ulonglong commit_id1= 0, enum_tx_isolation iso_level1= ISO_READ_UNCOMMITTED,
|
||||
ulonglong commit_id1= 0,
|
||||
enum_tx_isolation iso_level1= ISO_READ_UNCOMMITTED,
|
||||
ulonglong commit_id0= 0);
|
||||
|
||||
/**
|
||||
@retval transaction isolation level of a row from internal TABLE object.
|
||||
*/
|
||||
enum_tx_isolation iso_level() const;
|
||||
/**
|
||||
Stores transactioin isolation level to internal TABLE object.
|
||||
*/
|
||||
void store_iso_level(enum_tx_isolation iso_level)
|
||||
{
|
||||
DBUG_ASSERT(iso_level <= ISO_SERIALIZABLE);
|
||||
store(FLD_ISO_LEVEL, iso_level + 1);
|
||||
}
|
||||
|
||||
/**
|
||||
Writes a message to MariaDB log about incorrect transaction_registry schema.
|
||||
|
||||
@param[in] a message explained what's incorrect in schema
|
||||
*/
|
||||
void warn_schema_incorrect(const char *reason);
|
||||
/**
|
||||
Checks whether transaction_registry table has a correct schema.
|
||||
|
||||
@retval true if schema is incorrect and false otherwise
|
||||
*/
|
||||
bool check();
|
||||
|
||||
public:
|
||||
TABLE * operator-> () const
|
||||
{
|
||||
return table;
|
||||
@@ -2992,13 +3070,13 @@ public:
|
||||
{
|
||||
return table;
|
||||
}
|
||||
bool operator== (TABLE_LIST &subj) const
|
||||
bool operator== (const TABLE_LIST &subj) const
|
||||
{
|
||||
if (0 != strcmp(db, subj.db))
|
||||
return false;
|
||||
return (0 == strcmp(table_name, subj.table_name));
|
||||
}
|
||||
bool operator!= (TABLE_LIST &subj) const
|
||||
bool operator!= (const TABLE_LIST &subj) const
|
||||
{
|
||||
return !(*this == subj);
|
||||
}
|
||||
|
@@ -89,7 +89,5 @@ extern my_time_t sec_since_epoch_TIME(MYSQL_TIME *t);
|
||||
|
||||
static const int MY_TZ_TABLES_COUNT= 4;
|
||||
|
||||
extern Time_zone* thd_get_timezone(THD* thd);
|
||||
|
||||
#endif /* !defined(TESTTIME) && !defined(TZINFO2SQL) */
|
||||
#endif /* TZTIME_INCLUDED */
|
||||
|
@@ -121,7 +121,7 @@ bool has_extra2_field_flags(List<Create_field> &create_fields)
|
||||
List_iterator<Create_field> it(create_fields);
|
||||
while (Create_field *f= it++)
|
||||
{
|
||||
if (f->flags & (VERS_OPTIMIZED_UPDATE_FLAG | HIDDEN_FLAG))
|
||||
if (f->flags & (VERS_UPDATE_UNVERSIONED_FLAG | HIDDEN_FLAG))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -356,7 +356,7 @@ LEX_CUSTRING build_frm_image(THD *thd, const char *table,
|
||||
while (Create_field *field= it++)
|
||||
{
|
||||
uchar flags= 0;
|
||||
if (field->flags & VERS_OPTIMIZED_UPDATE_FLAG)
|
||||
if (field->flags & VERS_UPDATE_UNVERSIONED_FLAG)
|
||||
flags|= VERS_OPTIMIZED_UPDATE;
|
||||
if (field->flags & HIDDEN_FLAG)
|
||||
flags|= HIDDEN;
|
||||
|
@@ -861,3 +861,17 @@ dfield_t::clone(mem_heap_t* heap) const
|
||||
|
||||
return(obj);
|
||||
}
|
||||
|
||||
/** Assuming field is sys_trx_end checks whether its value is not SYS_TRX_MAX.
|
||||
@param dfield field to check
|
||||
@return true for historical rows and false otherwise*/
|
||||
bool
|
||||
dfield_is_historical_sys_trx_end(const dfield_t* dfield)
|
||||
{
|
||||
static const trx_id_t MAX = TRX_ID_MAX;
|
||||
ut_ad(dfield);
|
||||
ut_ad(dfield->type.prtype & DATA_VERS_END);
|
||||
const byte* data = static_cast<const byte*>(dfield_get_data(dfield));
|
||||
ut_ad(dfield_get_len(dfield) == 8);
|
||||
return(memcmp(data, &MAX, 8));
|
||||
}
|
||||
|
@@ -3623,10 +3623,9 @@ static const char* ha_innobase_exts[] = {
|
||||
NullS
|
||||
};
|
||||
|
||||
void innodb_get_trt_data(TR_table &trt)
|
||||
{
|
||||
THD *thd = trt.get_thd();
|
||||
trx_t *trx = thd_to_trx(thd);
|
||||
void innodb_get_trt_data(TR_table& trt) {
|
||||
THD* thd = trt.get_thd();
|
||||
trx_t* trx = thd_to_trx(thd);
|
||||
ut_a(trx);
|
||||
ut_a(trx->vers_update_trt);
|
||||
mutex_enter(&trx_sys->mutex);
|
||||
@@ -3637,8 +3636,7 @@ void innodb_get_trt_data(TR_table &trt)
|
||||
mutex_exit(&trx_sys->mutex);
|
||||
|
||||
// silent downgrade cast warning on win64
|
||||
timeval commit_ts = {static_cast<int>(sec),
|
||||
static_cast<int>(usec)};
|
||||
timeval commit_ts = {static_cast<int>(sec), static_cast<int>(usec)};
|
||||
trt.store_data(trx->id, commit_id, commit_ts);
|
||||
trx->vers_update_trt = false;
|
||||
}
|
||||
@@ -6521,6 +6519,10 @@ no_such_table:
|
||||
}
|
||||
}
|
||||
|
||||
if (table && m_prebuilt->table) {
|
||||
ut_ad(table->versioned() == m_prebuilt->table->versioned());
|
||||
}
|
||||
|
||||
info(HA_STATUS_NO_LOCK | HA_STATUS_VARIABLE | HA_STATUS_CONST);
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
@@ -8365,17 +8367,18 @@ no_commit:
|
||||
|
||||
innobase_srv_conc_enter_innodb(m_prebuilt);
|
||||
|
||||
vers_set_fields = (table->versioned_write() &&
|
||||
(sql_command != SQLCOM_CREATE_TABLE || table->s->vtmd))
|
||||
?
|
||||
ROW_INS_VERSIONED :
|
||||
ROW_INS_NORMAL;
|
||||
vers_set_fields =
|
||||
(table->versioned_write()
|
||||
&& (sql_command != SQLCOM_CREATE_TABLE || table->s->vtmd))
|
||||
? ROW_INS_VERSIONED
|
||||
: ROW_INS_NORMAL;
|
||||
|
||||
/* Step-5: Execute insert graph that will result in actual insert. */
|
||||
error = row_insert_for_mysql((byte*) record, m_prebuilt, vers_set_fields);
|
||||
|
||||
if (m_prebuilt->trx->vers_update_trt)
|
||||
if (m_prebuilt->trx->vers_update_trt) {
|
||||
thd_vers_update_trt(m_user_thd, true);
|
||||
}
|
||||
|
||||
DEBUG_SYNC(m_user_thd, "ib_after_row_insert");
|
||||
|
||||
@@ -8626,6 +8629,7 @@ calc_row_difference(
|
||||
doc_id_t doc_id = FTS_NULL_DOC_ID;
|
||||
ulint num_v = 0;
|
||||
uint n_fields = mysql_fields(table);
|
||||
bool table_versioned = prebuilt->table->versioned();
|
||||
|
||||
ut_ad(!srv_read_only_mode);
|
||||
|
||||
@@ -8876,9 +8880,8 @@ calc_row_difference(
|
||||
}
|
||||
n_changed++;
|
||||
|
||||
if (!prebuilt->upd_node->versioned &&
|
||||
prebuilt->table->versioned() &&
|
||||
!(field->flags & VERS_OPTIMIZED_UPDATE_FLAG)) {
|
||||
if (table_versioned
|
||||
&& !field->vers_update_unversioned()) {
|
||||
prebuilt->upd_node->versioned = true;
|
||||
}
|
||||
|
||||
@@ -8987,9 +8990,7 @@ calc_row_difference(
|
||||
|
||||
++n_changed;
|
||||
|
||||
if (!prebuilt->upd_node->versioned &&
|
||||
prebuilt->table->versioned() &&
|
||||
!(field->flags & VERS_OPTIMIZED_UPDATE_FLAG)) {
|
||||
if (table_versioned && !field->vers_update_unversioned()) {
|
||||
prebuilt->upd_node->versioned = true;
|
||||
}
|
||||
} else {
|
||||
@@ -9175,13 +9176,14 @@ ha_innobase::update_row(
|
||||
|
||||
innobase_srv_conc_enter_innodb(m_prebuilt);
|
||||
|
||||
if (!table->versioned_write())
|
||||
if (!table->versioned_write()) {
|
||||
m_prebuilt->upd_node->versioned = false;
|
||||
}
|
||||
|
||||
if (m_prebuilt->upd_node->versioned) {
|
||||
vers_set_fields = true;
|
||||
if (thd_sql_command(m_user_thd) == SQLCOM_ALTER_TABLE && !table->s->vtmd)
|
||||
{
|
||||
if (thd_sql_command(m_user_thd) == SQLCOM_ALTER_TABLE
|
||||
&& !table->s->vtmd) {
|
||||
m_prebuilt->upd_node->vers_delete = true;
|
||||
} else {
|
||||
m_prebuilt->upd_node->vers_delete = false;
|
||||
@@ -9192,12 +9194,14 @@ ha_innobase::update_row(
|
||||
error = row_update_for_mysql(m_prebuilt, vers_set_fields);
|
||||
|
||||
if (error == DB_SUCCESS && vers_ins_row) {
|
||||
if (trx->id != static_cast<trx_id_t>(table->vers_start_field()->val_int()))
|
||||
if (trx->id != static_cast<trx_id_t>(table->vers_start_field()->val_int())) {
|
||||
error = row_insert_for_mysql((byte*) old_row, m_prebuilt, ROW_INS_HISTORICAL);
|
||||
}
|
||||
}
|
||||
|
||||
if (m_prebuilt->trx->vers_update_trt)
|
||||
if (m_prebuilt->trx->vers_update_trt) {
|
||||
thd_vers_update_trt(m_user_thd, true);
|
||||
}
|
||||
|
||||
if (error == DB_SUCCESS && autoinc) {
|
||||
/* A value for an AUTO_INCREMENT column
|
||||
@@ -9313,13 +9317,13 @@ ha_innobase::delete_row(
|
||||
innobase_srv_conc_enter_innodb(m_prebuilt);
|
||||
|
||||
bool vers_set_fields =
|
||||
table->versioned_write() &&
|
||||
table->vers_end_field()->is_max();
|
||||
table->versioned_write() && table->vers_end_field()->is_max();
|
||||
|
||||
error = row_update_for_mysql(m_prebuilt, vers_set_fields);
|
||||
|
||||
if (m_prebuilt->trx->vers_update_trt)
|
||||
if (m_prebuilt->trx->vers_update_trt) {
|
||||
thd_vers_update_trt(m_user_thd, true);
|
||||
}
|
||||
|
||||
innobase_srv_conc_exit_innodb(m_prebuilt);
|
||||
|
||||
@@ -11407,6 +11411,7 @@ create_table_info_t::create_table_def()
|
||||
for (i = 0; i < n_cols; i++) {
|
||||
ulint is_virtual;
|
||||
bool is_stored = false;
|
||||
|
||||
Field* field = m_form->field[i];
|
||||
ulint vers_row_start = 0;
|
||||
ulint vers_row_end = 0;
|
||||
|
@@ -586,8 +586,6 @@ bool thd_is_strict_mode(const MYSQL_THD thd);
|
||||
*/
|
||||
extern void mysql_bin_log_commit_pos(THD *thd, ulonglong *out_pos, const char **out_file);
|
||||
|
||||
extern void thd_vers_update_trt(THD * thd, bool value);
|
||||
|
||||
/** Get the partition_info working copy.
|
||||
@param thd Thread object.
|
||||
@return NULL or pointer to partition_info working copy. */
|
||||
|
@@ -631,9 +631,10 @@ instant_alter_column_possible(
|
||||
const Alter_inplace_info* ha_alter_info,
|
||||
const TABLE* table)
|
||||
{
|
||||
if (ha_alter_info->create_info->vers_info.with_system_versioning)
|
||||
// Making table system-versioned instantly is not implemented yet.
|
||||
if (ha_alter_info->create_info->vers_info.with_system_versioning) {
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
if (~ha_alter_info->handler_flags
|
||||
& Alter_inplace_info::ADD_STORED_BASE_COLUMN) {
|
||||
@@ -7086,8 +7087,9 @@ ok_exit:
|
||||
ctx->m_stage, add_v, eval_table,
|
||||
ha_alter_info->handler_flags & Alter_inplace_info::ALTER_DROP_HISTORICAL);
|
||||
|
||||
if (m_prebuilt->trx->vers_update_trt)
|
||||
if (m_prebuilt->trx->vers_update_trt) {
|
||||
thd_vers_update_trt(m_user_thd, true);
|
||||
}
|
||||
|
||||
#ifndef DBUG_OFF
|
||||
oom:
|
||||
@@ -9753,7 +9755,6 @@ foreign_fail:
|
||||
DBUG_RETURN(false);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
@param thd the session
|
||||
@param start_value the lower bound
|
||||
|
@@ -508,6 +508,12 @@ dtuple_print(
|
||||
const dtuple_t* tuple) /*!< in: tuple */
|
||||
MY_ATTRIBUTE((nonnull));
|
||||
|
||||
/** Assuming field is sys_trx_end checks whether its value is not SYS_TRX_MAX.
|
||||
@param dfield field to check
|
||||
@return true for historical rows and false otherwise*/
|
||||
bool
|
||||
dfield_is_historical_sys_trx_end(const dfield_t* dfield);
|
||||
|
||||
/** Print the contents of a tuple.
|
||||
@param[out] o output stream
|
||||
@param[in] field array of data fields
|
||||
|
@@ -229,39 +229,4 @@ struct ins_node_t{
|
||||
#define INS_NODE_ALLOC_ROW_ID 2 /* row id should be allocated */
|
||||
#define INS_NODE_INSERT_ENTRIES 3 /* index entries should be built and
|
||||
inserted */
|
||||
|
||||
UNIV_INLINE
|
||||
void row_ins_set_tuple_col_8(
|
||||
dtuple_t* tuple,
|
||||
int col,
|
||||
ib_uint64_t data,
|
||||
byte* buf)
|
||||
{
|
||||
static const ulint fsize = sizeof(data);
|
||||
dfield_t* dfield = dtuple_get_nth_field(tuple, col);
|
||||
ut_ad(dfield->type.len == fsize);
|
||||
if (dfield->len == UNIV_SQL_NULL) {
|
||||
dfield_set_data(dfield, buf, fsize);
|
||||
}
|
||||
ut_ad(dfield->len == dfield->type.len && dfield->data);
|
||||
mach_write_to_8(dfield->data, data);
|
||||
}
|
||||
|
||||
UNIV_INLINE
|
||||
void row_ins_set_tuple_col_8(
|
||||
dtuple_t* tuple,
|
||||
int col,
|
||||
timeval& data,
|
||||
byte* buf)
|
||||
{
|
||||
dfield_t* dfield = dtuple_get_nth_field(tuple, col);
|
||||
ut_ad(dfield->type.len == 8);
|
||||
if (dfield->len == UNIV_SQL_NULL) {
|
||||
dfield_set_data(dfield, buf, 8);
|
||||
}
|
||||
ut_ad(dfield->len == dfield->type.len && dfield->data);
|
||||
mach_write_to_4(reinterpret_cast<byte*>(dfield->data), (ulint) data.tv_sec);
|
||||
mach_write_to_4(reinterpret_cast<byte*>(dfield->data) + 4, (ulint) data.tv_usec);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@@ -237,9 +237,12 @@ row_lock_table_for_mysql(
|
||||
|
||||
/** System Versioning: row_insert_for_mysql() modes */
|
||||
enum ins_mode_t {
|
||||
ROW_INS_NORMAL = 0, ///< plain row (without versioning)
|
||||
ROW_INS_VERSIONED, ///< sys_trx_start = TRX_ID, sys_trx_end = MAX
|
||||
ROW_INS_HISTORICAL ///< sys_trx_end = TRX_ID
|
||||
/* plain row (without versioning) */
|
||||
ROW_INS_NORMAL = 0,
|
||||
/* sys_trx_start = TRX_ID, sys_trx_end = MAX */
|
||||
ROW_INS_VERSIONED,
|
||||
/* sys_trx_end = TRX_ID */
|
||||
ROW_INS_HISTORICAL
|
||||
};
|
||||
|
||||
/** Does an insert for MySQL.
|
||||
|
@@ -429,7 +429,7 @@ row_ins_cascade_ancestor_updates_table(
|
||||
|
||||
upd_node = static_cast<upd_node_t*>(parent);
|
||||
|
||||
if (upd_node->table == table && upd_node->is_delete == FALSE
|
||||
if (upd_node->table == table && !upd_node->is_delete
|
||||
&& !upd_node->vers_delete) {
|
||||
|
||||
return(TRUE);
|
||||
@@ -1573,18 +1573,19 @@ private:
|
||||
ulint& counter;
|
||||
};
|
||||
|
||||
/*********************************************************************//**
|
||||
Reads sys_trx_end field from clustered index row.
|
||||
/** Reads sys_trx_end field from clustered index row.
|
||||
@param[in] rec clustered row
|
||||
@param[in] offsets offsets
|
||||
@param[in] index clustered index
|
||||
@return trx_id_t */
|
||||
static
|
||||
trx_id_t
|
||||
row_ins_get_sys_trx_end(
|
||||
/*===================================*/
|
||||
const rec_t *rec, /*!< in: clustered row */
|
||||
ulint *offsets, /*!< in: offsets */
|
||||
dict_index_t *index) /*!< in: clustered index */
|
||||
const rec_t* rec,
|
||||
const ulint* offsets,
|
||||
const dict_index_t* index)
|
||||
{
|
||||
ut_a(dict_index_is_clust(index));
|
||||
ut_a(index->is_clust());
|
||||
|
||||
ulint len;
|
||||
ulint nfield = dict_col_get_clust_pos(
|
||||
@@ -1594,51 +1595,46 @@ row_ins_get_sys_trx_end(
|
||||
return(mach_read_from_8(field));
|
||||
}
|
||||
|
||||
/**
|
||||
Performs search at clustered index and returns sys_trx_end if row was found.
|
||||
/** Performs search at clustered index and returns sys_trx_end if row was found.
|
||||
@param[in] index secondary index of record
|
||||
@param[in] rec record in a secondary index
|
||||
@param[out] end_trx_id value from clustered index
|
||||
@return DB_SUCCESS, DB_NO_REFERENCED_ROW */
|
||||
@return sys_trx_end on success or 0 at failure */
|
||||
static
|
||||
dberr_t
|
||||
trx_id_t
|
||||
row_ins_search_sys_trx_end(
|
||||
dict_index_t *index,
|
||||
const rec_t *rec,
|
||||
trx_id_t *end_trx_id)
|
||||
dict_index_t* index,
|
||||
const rec_t* rec)
|
||||
{
|
||||
ut_ad(!index->is_clust());
|
||||
|
||||
bool found = false;
|
||||
mem_heap_t *heap = mem_heap_create(256);
|
||||
dict_index_t *clust_index = NULL;
|
||||
trx_id_t result = 0;
|
||||
mem_heap_t* heap = NULL;
|
||||
dict_index_t* clust_index = NULL;
|
||||
ulint offsets_[REC_OFFS_NORMAL_SIZE];
|
||||
ulint *offsets = offsets_;
|
||||
ulint* offsets = offsets_;
|
||||
rec_offs_init(offsets_);
|
||||
|
||||
mtr_t mtr;
|
||||
mtr_start(&mtr);
|
||||
mtr.start();
|
||||
|
||||
rec_t *clust_rec =
|
||||
rec_t* clust_rec =
|
||||
row_get_clust_rec(BTR_SEARCH_LEAF, rec, index, &clust_index, &mtr);
|
||||
if (!clust_rec)
|
||||
goto not_found;
|
||||
|
||||
if (clust_rec) {
|
||||
offsets = rec_get_offsets(clust_rec, clust_index, offsets, true,
|
||||
ULINT_UNDEFINED, &heap);
|
||||
|
||||
*end_trx_id = row_ins_get_sys_trx_end(clust_rec, offsets, clust_index);
|
||||
found = true;
|
||||
not_found:
|
||||
mtr_commit(&mtr);
|
||||
mem_heap_free(heap);
|
||||
if (!found) {
|
||||
result =
|
||||
row_ins_get_sys_trx_end(clust_rec, offsets, clust_index);
|
||||
} else {
|
||||
ib::error() << "foreign constraints: secondary index is out of "
|
||||
"sync";
|
||||
ut_ad(false && "secondary index is out of sync");
|
||||
return(DB_NO_REFERENCED_ROW);
|
||||
ut_ad(!"secondary index is out of sync");
|
||||
}
|
||||
return(DB_SUCCESS);
|
||||
mtr.commit();
|
||||
if (heap) {
|
||||
mem_heap_free(heap);
|
||||
}
|
||||
return(result);
|
||||
}
|
||||
|
||||
/***************************************************************//**
|
||||
@@ -1705,15 +1701,13 @@ row_ins_check_foreign_constraint(
|
||||
}
|
||||
/* System Versioning: if sys_trx_end != Inf, we
|
||||
suppress the foreign key check */
|
||||
if (table->versioned() &&
|
||||
dfield_get_type(field)->prtype & DATA_VERS_END) {
|
||||
byte* data = static_cast<byte*>(dfield_get_data(field));
|
||||
ut_ad(data);
|
||||
trx_id_t end_trx_id = mach_read_from_8(data);
|
||||
if (end_trx_id != TRX_ID_MAX)
|
||||
if (dfield_get_type(field)->prtype & DATA_VERS_END) {
|
||||
ut_ad(table->versioned());
|
||||
if (dfield_is_historical_sys_trx_end(field)) {
|
||||
goto exit_func;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (que_node_get_type(thr->run_node) == QUE_NODE_UPDATE) {
|
||||
upd_node = static_cast<upd_node_t*>(thr->run_node);
|
||||
@@ -1844,19 +1838,20 @@ row_ins_check_foreign_constraint(
|
||||
if (check_table->versioned()) {
|
||||
trx_id_t end_trx_id = 0;
|
||||
|
||||
if (dict_index_is_clust(check_index)) {
|
||||
if (check_index->is_clust()) {
|
||||
end_trx_id =
|
||||
row_ins_get_sys_trx_end(
|
||||
rec, offsets, check_index);
|
||||
} else if (row_ins_search_sys_trx_end(
|
||||
check_index, rec, &end_trx_id) !=
|
||||
DB_SUCCESS) {
|
||||
} else if (!(end_trx_id =
|
||||
row_ins_search_sys_trx_end(
|
||||
check_index, rec))) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (end_trx_id != TRX_ID_MAX)
|
||||
if (end_trx_id != TRX_ID_MAX) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (rec_get_deleted_flag(rec,
|
||||
rec_offs_comp(offsets))) {
|
||||
|
@@ -1743,6 +1743,8 @@ row_merge_read_clustered_index(
|
||||
ib_uint64_t read_rows = 0;
|
||||
ib_uint64_t table_total_rows = 0;
|
||||
ulonglong historic_auto_decrement = 0xffffffffffffffff;
|
||||
char new_sys_trx_start[8];
|
||||
char new_sys_trx_end[8];
|
||||
|
||||
DBUG_ENTER("row_merge_read_clustered_index");
|
||||
|
||||
@@ -1917,6 +1919,9 @@ row_merge_read_clustered_index(
|
||||
prev_fields = NULL;
|
||||
}
|
||||
|
||||
mach_write_to_8(new_sys_trx_start, trx->id);
|
||||
mach_write_to_8(new_sys_trx_end, TRX_ID_MAX);
|
||||
|
||||
/* Scan the clustered index. */
|
||||
for (;;) {
|
||||
const rec_t* rec;
|
||||
@@ -2242,13 +2247,10 @@ end_of_index:
|
||||
|
||||
bool historical_row = false;
|
||||
if (new_table->versioned()) {
|
||||
const dfield_t *dfield = dtuple_get_nth_field(
|
||||
const dfield_t* dfield = dtuple_get_nth_field(
|
||||
row, new_table->vers_end);
|
||||
const byte *data = static_cast<const byte *>(
|
||||
dfield_get_data(dfield));
|
||||
ut_ad(dfield_get_len(dfield) == 8);
|
||||
historical_row =
|
||||
mach_read_from_8(data) != TRX_ID_MAX;
|
||||
dfield_is_historical_sys_trx_end(dfield);
|
||||
}
|
||||
|
||||
const dfield_t* dfield;
|
||||
@@ -2272,10 +2274,11 @@ end_of_index:
|
||||
}
|
||||
|
||||
ulonglong value;
|
||||
if (likely(!historical_row))
|
||||
if (likely(!historical_row)) {
|
||||
value = sequence++;
|
||||
else
|
||||
} else {
|
||||
value = historic_auto_decrement--;
|
||||
}
|
||||
|
||||
switch (dtype_get_mtype(dtype)) {
|
||||
case DATA_INT: {
|
||||
@@ -2305,30 +2308,27 @@ end_of_index:
|
||||
|
||||
if (old_table->versioned()) {
|
||||
if (!new_table->versioned() || drop_historical) {
|
||||
const dict_col_t *col =
|
||||
&old_table->cols
|
||||
[old_table->vers_end];
|
||||
const ulint nfield = dict_col_get_clust_pos(
|
||||
col, clust_index);
|
||||
const dict_col_t* col =
|
||||
&old_table->cols[old_table->vers_end];
|
||||
const ulint nfield =
|
||||
dict_col_get_clust_pos(col, clust_index);
|
||||
ulint len = 0;
|
||||
const rec_t *sys_trx_end = rec_get_nth_field(
|
||||
const rec_t* sys_trx_end = rec_get_nth_field(
|
||||
rec, offsets, nfield, &len);
|
||||
ut_ad(len == 8);
|
||||
if (mach_read_from_8(sys_trx_end) != TRX_ID_MAX)
|
||||
if (mach_read_from_8(sys_trx_end)
|
||||
!= TRX_ID_MAX) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
} else if (new_table->versioned()) {
|
||||
void *sys_trx_start = mem_heap_alloc(row_heap, 8);
|
||||
void *sys_trx_end = mem_heap_alloc(row_heap, 8);
|
||||
mach_write_to_8(sys_trx_start, trx->id);
|
||||
mach_write_to_8(sys_trx_end, TRX_ID_MAX);
|
||||
dfield_t *start = dtuple_get_nth_field(
|
||||
row, new_table->vers_start);
|
||||
dfield_t *end = dtuple_get_nth_field(
|
||||
row, new_table->vers_end);
|
||||
dfield_set_data(start, sys_trx_start, 8);
|
||||
dfield_set_data(end, sys_trx_end, 8);
|
||||
trx->vers_update_trt= true;
|
||||
dfield_t* start =
|
||||
dtuple_get_nth_field(row, new_table->vers_start);
|
||||
dfield_t* end =
|
||||
dtuple_get_nth_field(row, new_table->vers_end);
|
||||
dfield_set_data(start, new_sys_trx_start, 8);
|
||||
dfield_set_data(end, new_sys_trx_end, 8);
|
||||
trx->vers_update_trt = true;
|
||||
}
|
||||
|
||||
write_buffers:
|
||||
|
@@ -1420,6 +1420,23 @@ row_mysql_get_table_status(
|
||||
return(err);
|
||||
}
|
||||
|
||||
/** Writes 8 bytes to nth tuple field
|
||||
@param[in] tuple where to write
|
||||
@param[in] nth index in tuple
|
||||
@param[in] data what to write
|
||||
@param[in] buf field data buffer */
|
||||
static
|
||||
void
|
||||
set_tuple_col_8(dtuple_t* tuple, int col, uint64_t data, byte* buf) {
|
||||
dfield_t* dfield = dtuple_get_nth_field(tuple, col);
|
||||
ut_ad(dfield->type.len == 8);
|
||||
if (dfield->len == UNIV_SQL_NULL) {
|
||||
dfield_set_data(dfield, buf, 8);
|
||||
}
|
||||
ut_ad(dfield->len == dfield->type.len && dfield->data);
|
||||
mach_write_to_8(dfield->data, data);
|
||||
}
|
||||
|
||||
/** Does an insert for MySQL.
|
||||
@param[in] mysql_rec row in the MySQL format
|
||||
@param[in,out] prebuilt prebuilt struct in MySQL handle
|
||||
@@ -1504,14 +1521,14 @@ row_insert_for_mysql(
|
||||
ut_ad(t->mysql_col_len == 8);
|
||||
|
||||
if (ins_mode == ROW_INS_HISTORICAL) {
|
||||
row_ins_set_tuple_col_8(node->row, table->vers_end, trx->id, node->vers_end_buf);
|
||||
set_tuple_col_8(node->row, table->vers_end, trx->id, node->vers_end_buf);
|
||||
}
|
||||
else /* ROW_INS_VERSIONED */ {
|
||||
row_ins_set_tuple_col_8(node->row, table->vers_end, IB_UINT64_MAX, node->vers_end_buf);
|
||||
int8store(&mysql_rec[t->mysql_col_offset], IB_UINT64_MAX);
|
||||
set_tuple_col_8(node->row, table->vers_end, TRX_ID_MAX, node->vers_end_buf);
|
||||
int8store(&mysql_rec[t->mysql_col_offset], TRX_ID_MAX);
|
||||
t = &prebuilt->mysql_template[table->vers_start];
|
||||
ut_ad(t->mysql_col_len == 8);
|
||||
row_ins_set_tuple_col_8(node->row, table->vers_start, trx->id, node->vers_start_buf);
|
||||
set_tuple_col_8(node->row, table->vers_start, trx->id, node->vers_start_buf);
|
||||
int8store(&mysql_rec[t->mysql_col_offset], trx->id);
|
||||
}
|
||||
}
|
||||
@@ -2129,8 +2146,8 @@ run_again:
|
||||
node->cascade_upd_nodes = cascade_upd_nodes;
|
||||
cascade_upd_nodes->pop_front();
|
||||
thr->fk_cascade_depth++;
|
||||
vers_set_fields = node->table->versioned() &&
|
||||
(node->is_delete || node->versioned);
|
||||
vers_set_fields = node->table->versioned()
|
||||
&& (node->is_delete || node->versioned);
|
||||
|
||||
goto run_again;
|
||||
}
|
||||
@@ -2210,11 +2227,12 @@ run_again:
|
||||
prebuilt->table->stat_modified_counter++;
|
||||
}
|
||||
|
||||
if (node->table->versioned() &&
|
||||
(node->versioned || node->vers_delete ||
|
||||
if (node->table->versioned()
|
||||
&& (node->versioned
|
||||
|| node->vers_delete
|
||||
// TODO: improve this check (check if we touch only
|
||||
// unversioned fields in foreigh table)
|
||||
node->foreign)) {
|
||||
|| node->foreign)) {
|
||||
trx->vers_update_trt = true;
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user