1
0
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:
Eugene Kosov
2017-11-24 15:34:57 +03:00
committed by Aleksey Midenkov
parent 4dd8736c15
commit 0cdc1164dc
23 changed files with 267 additions and 183 deletions

View File

@@ -198,7 +198,7 @@ enum enum_indicator_type
#define VERS_SYS_END_FLAG (1 << 28) /* autogenerated column declared with #define VERS_SYS_END_FLAG (1 << 28) /* autogenerated column declared with
`generated always as row end` `generated always as row end`
(see II.a SQL Standard).*/ (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 system versioning when table
itself supports it*/ itself supports it*/
#define HIDDEN_FLAG (1 << 31) /* hide from SELECT * */ #define HIDDEN_FLAG (1 << 31) /* hide from SELECT * */

View File

@@ -1455,6 +1455,11 @@ public:
return flags & (VERS_SYS_START_FLAG | VERS_SYS_END_FLAG); 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 virtual bool vers_trx_id() const
{ {
return false; return false;

View File

@@ -6859,7 +6859,7 @@ bool Vers_parse_info::check_and_fix_implicit(
!with_system_versioning) || !with_system_versioning) ||
f->versioning == Column_definition::WITHOUT_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++) while (Create_field *f= it++)
{ {
if (f->versioning == Column_definition::WITHOUT_VERSIONING) 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)) if (f->change.str && (start == f->change || end == f->change))
{ {

View File

@@ -10384,7 +10384,7 @@ Item *Item_field::vers_optimized_fields_transformer(THD *thd, uchar *)
if (!field) if (!field)
return this; 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 &&
field->table->pos_in_table_list->vers_conditions) field->table->pos_in_table_list->vers_conditions)
{ {

View File

@@ -710,12 +710,6 @@ extern "C" void thd_kill_timeout(THD* thd)
mysql_mutex_unlock(&thd->LOCK_thd_data); 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) void thd_vers_update_trt(THD * thd, bool value)
{ {
thd->vers_update_trt= value; thd->vers_update_trt= value;

View File

@@ -155,6 +155,7 @@ extern bool volatile shutdown_in_progress;
extern "C" LEX_STRING * thd_query_string (MYSQL_THD thd); 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); 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 @class CSET_STRING
@@ -4564,6 +4565,8 @@ public:
/* Handling of timeouts for commands */ /* Handling of timeouts for commands */
thr_timer_t query_timer; 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; bool vers_update_trt;
public: public:

View File

@@ -16743,7 +16743,7 @@ Field *create_tmp_field_from_field(THD *thd, Field *org_field,
HIDDEN_FLAG | HIDDEN_FLAG |
VERS_SYS_START_FLAG | VERS_SYS_START_FLAG |
VERS_SYS_END_FLAG | VERS_SYS_END_FLAG |
VERS_OPTIMIZED_UPDATE_FLAG)); VERS_UPDATE_UNVERSIONED_FLAG));
if (org_field->maybe_null() || (item && item->maybe_null)) if (org_field->maybe_null() || (item && item->maybe_null))
new_field->flags&= ~NOT_NULL_FLAG; // Because of outer join new_field->flags&= ~NOT_NULL_FLAG; // Because of outer join
if (org_field->type() == MYSQL_TYPE_VAR_STRING || if (org_field->type() == MYSQL_TYPE_VAR_STRING ||

View File

@@ -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); 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")); packet->append(STRING_WITH_LEN(" WITHOUT SYSTEM VERSIONING"));
} }

View File

@@ -161,7 +161,7 @@ static bool check_has_vers_fields(List<Item> &items)
while (Item *item= it++) while (Item *item= it++)
{ {
if (Item_field *item_field= item->field_for_view_update()) 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 true;
} }
return false; return false;

View File

@@ -2051,7 +2051,7 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write,
{ {
uchar flags= *extra2_field_flags++; uchar flags= *extra2_field_flags++;
if (flags & VERS_OPTIMIZED_UPDATE) if (flags & VERS_OPTIMIZED_UPDATE)
reg_field->flags|= VERS_OPTIMIZED_UPDATE_FLAG; reg_field->flags|= VERS_UPDATE_UNVERSIONED_FLAG;
if (flags & HIDDEN) if (flags & HIDDEN)
reg_field->flags|= HIDDEN_FLAG; 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) 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_TRX_ID, trx_id);
store(FLD_COMMIT_ID, commit_id); store(FLD_COMMIT_ID, commit_id);
store(FLD_BEGIN_TS, start_time); store(FLD_BEGIN_TS, start_time);

View File

@@ -2930,14 +2930,14 @@ inline void mark_as_null_row(TABLE *table)
bool is_simple_order(ORDER *order); bool is_simple_order(ORDER *order);
class Open_tables_backup;
/** Transaction Registry Table (TRT) /** Transaction Registry Table (TRT)
This table holds transaction IDs, their corresponding times and other This table holds transaction IDs, their corresponding times and other
transaction-related data which is used for transaction order resolution. transaction-related data which is used for transaction order resolution.
When versioned table marks its records lifetime with transaction IDs, When versioned table marks its records lifetime with transaction IDs,
TRT is used to get their actual timestamps. */ TRT is used to get their actual timestamps. */
class Open_tables_backup;
class TR_table: public TABLE_LIST class TR_table: public TABLE_LIST
{ {
THD *thd; THD *thd;
@@ -2952,33 +2952,111 @@ public:
FLD_ISO_LEVEL, FLD_ISO_LEVEL,
FIELD_COUNT FIELD_COUNT
}; };
/**
@param[in,out] Thread handle
@param[in] Current transaction is read-write.
*/
TR_table(THD *_thd, bool rw= false); TR_table(THD *_thd, bool rw= false);
/**
Opens a transaction_registry table.
@retval true on error, false otherwise.
*/
bool open(); bool open();
~TR_table(); ~TR_table();
/**
@retval current thd
*/
THD *get_thd() const { return 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); 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); 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); 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(); 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); 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); 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, 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); ulonglong commit_id0= 0);
/**
@retval transaction isolation level of a row from internal TABLE object.
*/
enum_tx_isolation iso_level() const; enum_tx_isolation iso_level() const;
/**
Stores transactioin isolation level to internal TABLE object.
*/
void store_iso_level(enum_tx_isolation iso_level) void store_iso_level(enum_tx_isolation iso_level)
{ {
DBUG_ASSERT(iso_level <= ISO_SERIALIZABLE); DBUG_ASSERT(iso_level <= ISO_SERIALIZABLE);
store(FLD_ISO_LEVEL, iso_level + 1); 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); 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(); bool check();
public:
TABLE * operator-> () const TABLE * operator-> () const
{ {
return table; return table;
@@ -2992,13 +3070,13 @@ public:
{ {
return table; return table;
} }
bool operator== (TABLE_LIST &subj) const bool operator== (const TABLE_LIST &subj) const
{ {
if (0 != strcmp(db, subj.db)) if (0 != strcmp(db, subj.db))
return false; return false;
return (0 == strcmp(table_name, subj.table_name)); return (0 == strcmp(table_name, subj.table_name));
} }
bool operator!= (TABLE_LIST &subj) const bool operator!= (const TABLE_LIST &subj) const
{ {
return !(*this == subj); return !(*this == subj);
} }

View File

@@ -89,7 +89,5 @@ extern my_time_t sec_since_epoch_TIME(MYSQL_TIME *t);
static const int MY_TZ_TABLES_COUNT= 4; static const int MY_TZ_TABLES_COUNT= 4;
extern Time_zone* thd_get_timezone(THD* thd);
#endif /* !defined(TESTTIME) && !defined(TZINFO2SQL) */ #endif /* !defined(TESTTIME) && !defined(TZINFO2SQL) */
#endif /* TZTIME_INCLUDED */ #endif /* TZTIME_INCLUDED */

View File

@@ -121,7 +121,7 @@ bool has_extra2_field_flags(List<Create_field> &create_fields)
List_iterator<Create_field> it(create_fields); List_iterator<Create_field> it(create_fields);
while (Create_field *f= it++) 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 true;
} }
return false; return false;
@@ -356,7 +356,7 @@ LEX_CUSTRING build_frm_image(THD *thd, const char *table,
while (Create_field *field= it++) while (Create_field *field= it++)
{ {
uchar flags= 0; uchar flags= 0;
if (field->flags & VERS_OPTIMIZED_UPDATE_FLAG) if (field->flags & VERS_UPDATE_UNVERSIONED_FLAG)
flags|= VERS_OPTIMIZED_UPDATE; flags|= VERS_OPTIMIZED_UPDATE;
if (field->flags & HIDDEN_FLAG) if (field->flags & HIDDEN_FLAG)
flags|= HIDDEN; flags|= HIDDEN;

View File

@@ -861,3 +861,17 @@ dfield_t::clone(mem_heap_t* heap) const
return(obj); 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));
}

View File

@@ -3623,10 +3623,9 @@ static const char* ha_innobase_exts[] = {
NullS NullS
}; };
void innodb_get_trt_data(TR_table &trt) void innodb_get_trt_data(TR_table& trt) {
{ THD* thd = trt.get_thd();
THD *thd = trt.get_thd(); trx_t* trx = thd_to_trx(thd);
trx_t *trx = thd_to_trx(thd);
ut_a(trx); ut_a(trx);
ut_a(trx->vers_update_trt); ut_a(trx->vers_update_trt);
mutex_enter(&trx_sys->mutex); mutex_enter(&trx_sys->mutex);
@@ -3637,8 +3636,7 @@ void innodb_get_trt_data(TR_table &trt)
mutex_exit(&trx_sys->mutex); mutex_exit(&trx_sys->mutex);
// silent downgrade cast warning on win64 // silent downgrade cast warning on win64
timeval commit_ts = {static_cast<int>(sec), timeval commit_ts = {static_cast<int>(sec), static_cast<int>(usec)};
static_cast<int>(usec)};
trt.store_data(trx->id, commit_id, commit_ts); trt.store_data(trx->id, commit_id, commit_ts);
trx->vers_update_trt = false; 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); info(HA_STATUS_NO_LOCK | HA_STATUS_VARIABLE | HA_STATUS_CONST);
DBUG_RETURN(0); DBUG_RETURN(0);
} }
@@ -8365,17 +8367,18 @@ no_commit:
innobase_srv_conc_enter_innodb(m_prebuilt); innobase_srv_conc_enter_innodb(m_prebuilt);
vers_set_fields = (table->versioned_write() && vers_set_fields =
(sql_command != SQLCOM_CREATE_TABLE || table->s->vtmd)) (table->versioned_write()
? && (sql_command != SQLCOM_CREATE_TABLE || table->s->vtmd))
ROW_INS_VERSIONED : ? ROW_INS_VERSIONED
ROW_INS_NORMAL; : ROW_INS_NORMAL;
/* Step-5: Execute insert graph that will result in actual insert. */ /* Step-5: Execute insert graph that will result in actual insert. */
error = row_insert_for_mysql((byte*) record, m_prebuilt, vers_set_fields); 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); thd_vers_update_trt(m_user_thd, true);
}
DEBUG_SYNC(m_user_thd, "ib_after_row_insert"); 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; doc_id_t doc_id = FTS_NULL_DOC_ID;
ulint num_v = 0; ulint num_v = 0;
uint n_fields = mysql_fields(table); uint n_fields = mysql_fields(table);
bool table_versioned = prebuilt->table->versioned();
ut_ad(!srv_read_only_mode); ut_ad(!srv_read_only_mode);
@@ -8876,9 +8880,8 @@ calc_row_difference(
} }
n_changed++; n_changed++;
if (!prebuilt->upd_node->versioned && if (table_versioned
prebuilt->table->versioned() && && !field->vers_update_unversioned()) {
!(field->flags & VERS_OPTIMIZED_UPDATE_FLAG)) {
prebuilt->upd_node->versioned = true; prebuilt->upd_node->versioned = true;
} }
@@ -8987,9 +8990,7 @@ calc_row_difference(
++n_changed; ++n_changed;
if (!prebuilt->upd_node->versioned && if (table_versioned && !field->vers_update_unversioned()) {
prebuilt->table->versioned() &&
!(field->flags & VERS_OPTIMIZED_UPDATE_FLAG)) {
prebuilt->upd_node->versioned = true; prebuilt->upd_node->versioned = true;
} }
} else { } else {
@@ -9175,13 +9176,14 @@ ha_innobase::update_row(
innobase_srv_conc_enter_innodb(m_prebuilt); innobase_srv_conc_enter_innodb(m_prebuilt);
if (!table->versioned_write()) if (!table->versioned_write()) {
m_prebuilt->upd_node->versioned = false; m_prebuilt->upd_node->versioned = false;
}
if (m_prebuilt->upd_node->versioned) { if (m_prebuilt->upd_node->versioned) {
vers_set_fields = true; 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; m_prebuilt->upd_node->vers_delete = true;
} else { } else {
m_prebuilt->upd_node->vers_delete = false; 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); error = row_update_for_mysql(m_prebuilt, vers_set_fields);
if (error == DB_SUCCESS && vers_ins_row) { 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); 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); thd_vers_update_trt(m_user_thd, true);
}
if (error == DB_SUCCESS && autoinc) { if (error == DB_SUCCESS && autoinc) {
/* A value for an AUTO_INCREMENT column /* A value for an AUTO_INCREMENT column
@@ -9313,13 +9317,13 @@ ha_innobase::delete_row(
innobase_srv_conc_enter_innodb(m_prebuilt); innobase_srv_conc_enter_innodb(m_prebuilt);
bool vers_set_fields = bool vers_set_fields =
table->versioned_write() && table->versioned_write() && table->vers_end_field()->is_max();
table->vers_end_field()->is_max();
error = row_update_for_mysql(m_prebuilt, vers_set_fields); 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); thd_vers_update_trt(m_user_thd, true);
}
innobase_srv_conc_exit_innodb(m_prebuilt); 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++) { for (i = 0; i < n_cols; i++) {
ulint is_virtual; ulint is_virtual;
bool is_stored = false; bool is_stored = false;
Field* field = m_form->field[i]; Field* field = m_form->field[i];
ulint vers_row_start = 0; ulint vers_row_start = 0;
ulint vers_row_end = 0; ulint vers_row_end = 0;

View File

@@ -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 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. /** Get the partition_info working copy.
@param thd Thread object. @param thd Thread object.
@return NULL or pointer to partition_info working copy. */ @return NULL or pointer to partition_info working copy. */

View File

@@ -631,9 +631,10 @@ instant_alter_column_possible(
const Alter_inplace_info* ha_alter_info, const Alter_inplace_info* ha_alter_info,
const TABLE* table) 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; return false;
}
if (~ha_alter_info->handler_flags if (~ha_alter_info->handler_flags
& Alter_inplace_info::ADD_STORED_BASE_COLUMN) { & Alter_inplace_info::ADD_STORED_BASE_COLUMN) {
@@ -7086,8 +7087,9 @@ ok_exit:
ctx->m_stage, add_v, eval_table, ctx->m_stage, add_v, eval_table,
ha_alter_info->handler_flags & Alter_inplace_info::ALTER_DROP_HISTORICAL); 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); thd_vers_update_trt(m_user_thd, true);
}
#ifndef DBUG_OFF #ifndef DBUG_OFF
oom: oom:
@@ -9753,7 +9755,6 @@ foreign_fail:
DBUG_RETURN(false); DBUG_RETURN(false);
} }
/** /**
@param thd the session @param thd the session
@param start_value the lower bound @param start_value the lower bound

View File

@@ -508,6 +508,12 @@ dtuple_print(
const dtuple_t* tuple) /*!< in: tuple */ const dtuple_t* tuple) /*!< in: tuple */
MY_ATTRIBUTE((nonnull)); 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. /** Print the contents of a tuple.
@param[out] o output stream @param[out] o output stream
@param[in] field array of data fields @param[in] field array of data fields

View File

@@ -229,39 +229,4 @@ struct ins_node_t{
#define INS_NODE_ALLOC_ROW_ID 2 /* row id should be allocated */ #define INS_NODE_ALLOC_ROW_ID 2 /* row id should be allocated */
#define INS_NODE_INSERT_ENTRIES 3 /* index entries should be built and #define INS_NODE_INSERT_ENTRIES 3 /* index entries should be built and
inserted */ 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 #endif

View File

@@ -237,9 +237,12 @@ row_lock_table_for_mysql(
/** System Versioning: row_insert_for_mysql() modes */ /** System Versioning: row_insert_for_mysql() modes */
enum ins_mode_t { enum ins_mode_t {
ROW_INS_NORMAL = 0, ///< plain row (without versioning) /* plain row (without versioning) */
ROW_INS_VERSIONED, ///< sys_trx_start = TRX_ID, sys_trx_end = MAX ROW_INS_NORMAL = 0,
ROW_INS_HISTORICAL ///< sys_trx_end = TRX_ID /* 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. /** Does an insert for MySQL.

View File

@@ -429,7 +429,7 @@ row_ins_cascade_ancestor_updates_table(
upd_node = static_cast<upd_node_t*>(parent); 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) { && !upd_node->vers_delete) {
return(TRUE); return(TRUE);
@@ -1573,18 +1573,19 @@ private:
ulint& counter; 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 */ @return trx_id_t */
static static
trx_id_t trx_id_t
row_ins_get_sys_trx_end( row_ins_get_sys_trx_end(
/*===================================*/ const rec_t* rec,
const rec_t *rec, /*!< in: clustered row */ const ulint* offsets,
ulint *offsets, /*!< in: offsets */ const dict_index_t* index)
dict_index_t *index) /*!< in: clustered index */
{ {
ut_a(dict_index_is_clust(index)); ut_a(index->is_clust());
ulint len; ulint len;
ulint nfield = dict_col_get_clust_pos( ulint nfield = dict_col_get_clust_pos(
@@ -1594,51 +1595,46 @@ row_ins_get_sys_trx_end(
return(mach_read_from_8(field)); 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] index secondary index of record
@param[in] rec record in a secondary index @param[in] rec record in a secondary index
@param[out] end_trx_id value from clustered index @return sys_trx_end on success or 0 at failure */
@return DB_SUCCESS, DB_NO_REFERENCED_ROW */
static static
dberr_t trx_id_t
row_ins_search_sys_trx_end( row_ins_search_sys_trx_end(
dict_index_t *index, dict_index_t* index,
const rec_t *rec, const rec_t* rec)
trx_id_t *end_trx_id)
{ {
ut_ad(!index->is_clust()); ut_ad(!index->is_clust());
bool found = false; trx_id_t result = 0;
mem_heap_t *heap = mem_heap_create(256); mem_heap_t* heap = NULL;
dict_index_t *clust_index = NULL; dict_index_t* clust_index = NULL;
ulint offsets_[REC_OFFS_NORMAL_SIZE]; ulint offsets_[REC_OFFS_NORMAL_SIZE];
ulint *offsets = offsets_; ulint* offsets = offsets_;
rec_offs_init(offsets_); rec_offs_init(offsets_);
mtr_t mtr; 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); row_get_clust_rec(BTR_SEARCH_LEAF, rec, index, &clust_index, &mtr);
if (!clust_rec) if (clust_rec) {
goto not_found;
offsets = rec_get_offsets(clust_rec, clust_index, offsets, true, offsets = rec_get_offsets(clust_rec, clust_index, offsets, true,
ULINT_UNDEFINED, &heap); ULINT_UNDEFINED, &heap);
*end_trx_id = row_ins_get_sys_trx_end(clust_rec, offsets, clust_index); result =
found = true; row_ins_get_sys_trx_end(clust_rec, offsets, clust_index);
not_found: } else {
mtr_commit(&mtr);
mem_heap_free(heap);
if (!found) {
ib::error() << "foreign constraints: secondary index is out of " ib::error() << "foreign constraints: secondary index is out of "
"sync"; "sync";
ut_ad(false && "secondary index is out of sync"); ut_ad(!"secondary index is out of sync");
return(DB_NO_REFERENCED_ROW);
} }
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 /* System Versioning: if sys_trx_end != Inf, we
suppress the foreign key check */ suppress the foreign key check */
if (table->versioned() && if (dfield_get_type(field)->prtype & DATA_VERS_END) {
dfield_get_type(field)->prtype & DATA_VERS_END) { ut_ad(table->versioned());
byte* data = static_cast<byte*>(dfield_get_data(field)); if (dfield_is_historical_sys_trx_end(field)) {
ut_ad(data);
trx_id_t end_trx_id = mach_read_from_8(data);
if (end_trx_id != TRX_ID_MAX)
goto exit_func; goto exit_func;
} }
} }
}
if (que_node_get_type(thr->run_node) == QUE_NODE_UPDATE) { if (que_node_get_type(thr->run_node) == QUE_NODE_UPDATE) {
upd_node = static_cast<upd_node_t*>(thr->run_node); upd_node = static_cast<upd_node_t*>(thr->run_node);
@@ -1844,19 +1838,20 @@ row_ins_check_foreign_constraint(
if (check_table->versioned()) { if (check_table->versioned()) {
trx_id_t end_trx_id = 0; trx_id_t end_trx_id = 0;
if (dict_index_is_clust(check_index)) { if (check_index->is_clust()) {
end_trx_id = end_trx_id =
row_ins_get_sys_trx_end( row_ins_get_sys_trx_end(
rec, offsets, check_index); rec, offsets, check_index);
} else if (row_ins_search_sys_trx_end( } else if (!(end_trx_id =
check_index, rec, &end_trx_id) != row_ins_search_sys_trx_end(
DB_SUCCESS) { check_index, rec))) {
break; break;
} }
if (end_trx_id != TRX_ID_MAX) if (end_trx_id != TRX_ID_MAX) {
continue; continue;
} }
}
if (rec_get_deleted_flag(rec, if (rec_get_deleted_flag(rec,
rec_offs_comp(offsets))) { rec_offs_comp(offsets))) {

View File

@@ -1743,6 +1743,8 @@ row_merge_read_clustered_index(
ib_uint64_t read_rows = 0; ib_uint64_t read_rows = 0;
ib_uint64_t table_total_rows = 0; ib_uint64_t table_total_rows = 0;
ulonglong historic_auto_decrement = 0xffffffffffffffff; ulonglong historic_auto_decrement = 0xffffffffffffffff;
char new_sys_trx_start[8];
char new_sys_trx_end[8];
DBUG_ENTER("row_merge_read_clustered_index"); DBUG_ENTER("row_merge_read_clustered_index");
@@ -1917,6 +1919,9 @@ row_merge_read_clustered_index(
prev_fields = NULL; 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. */ /* Scan the clustered index. */
for (;;) { for (;;) {
const rec_t* rec; const rec_t* rec;
@@ -2242,13 +2247,10 @@ end_of_index:
bool historical_row = false; bool historical_row = false;
if (new_table->versioned()) { 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); 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 = historical_row =
mach_read_from_8(data) != TRX_ID_MAX; dfield_is_historical_sys_trx_end(dfield);
} }
const dfield_t* dfield; const dfield_t* dfield;
@@ -2272,10 +2274,11 @@ end_of_index:
} }
ulonglong value; ulonglong value;
if (likely(!historical_row)) if (likely(!historical_row)) {
value = sequence++; value = sequence++;
else } else {
value = historic_auto_decrement--; value = historic_auto_decrement--;
}
switch (dtype_get_mtype(dtype)) { switch (dtype_get_mtype(dtype)) {
case DATA_INT: { case DATA_INT: {
@@ -2305,30 +2308,27 @@ end_of_index:
if (old_table->versioned()) { if (old_table->versioned()) {
if (!new_table->versioned() || drop_historical) { if (!new_table->versioned() || drop_historical) {
const dict_col_t *col = const dict_col_t* col =
&old_table->cols &old_table->cols[old_table->vers_end];
[old_table->vers_end]; const ulint nfield =
const ulint nfield = dict_col_get_clust_pos( dict_col_get_clust_pos(col, clust_index);
col, clust_index);
ulint len = 0; 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); rec, offsets, nfield, &len);
ut_ad(len == 8); 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; continue;
} }
}
} else if (new_table->versioned()) { } else if (new_table->versioned()) {
void *sys_trx_start = mem_heap_alloc(row_heap, 8); dfield_t* start =
void *sys_trx_end = mem_heap_alloc(row_heap, 8); dtuple_get_nth_field(row, new_table->vers_start);
mach_write_to_8(sys_trx_start, trx->id); dfield_t* end =
mach_write_to_8(sys_trx_end, TRX_ID_MAX); dtuple_get_nth_field(row, new_table->vers_end);
dfield_t *start = dtuple_get_nth_field( dfield_set_data(start, new_sys_trx_start, 8);
row, new_table->vers_start); dfield_set_data(end, new_sys_trx_end, 8);
dfield_t *end = dtuple_get_nth_field( trx->vers_update_trt = true;
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;
} }
write_buffers: write_buffers:

View File

@@ -1420,6 +1420,23 @@ row_mysql_get_table_status(
return(err); 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. /** Does an insert for MySQL.
@param[in] mysql_rec row in the MySQL format @param[in] mysql_rec row in the MySQL format
@param[in,out] prebuilt prebuilt struct in MySQL handle @param[in,out] prebuilt prebuilt struct in MySQL handle
@@ -1504,14 +1521,14 @@ row_insert_for_mysql(
ut_ad(t->mysql_col_len == 8); ut_ad(t->mysql_col_len == 8);
if (ins_mode == ROW_INS_HISTORICAL) { 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 */ { else /* ROW_INS_VERSIONED */ {
row_ins_set_tuple_col_8(node->row, table->vers_end, IB_UINT64_MAX, node->vers_end_buf); set_tuple_col_8(node->row, table->vers_end, TRX_ID_MAX, node->vers_end_buf);
int8store(&mysql_rec[t->mysql_col_offset], IB_UINT64_MAX); int8store(&mysql_rec[t->mysql_col_offset], TRX_ID_MAX);
t = &prebuilt->mysql_template[table->vers_start]; t = &prebuilt->mysql_template[table->vers_start];
ut_ad(t->mysql_col_len == 8); 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); int8store(&mysql_rec[t->mysql_col_offset], trx->id);
} }
} }
@@ -2129,8 +2146,8 @@ run_again:
node->cascade_upd_nodes = cascade_upd_nodes; node->cascade_upd_nodes = cascade_upd_nodes;
cascade_upd_nodes->pop_front(); cascade_upd_nodes->pop_front();
thr->fk_cascade_depth++; thr->fk_cascade_depth++;
vers_set_fields = node->table->versioned() && vers_set_fields = node->table->versioned()
(node->is_delete || node->versioned); && (node->is_delete || node->versioned);
goto run_again; goto run_again;
} }
@@ -2210,11 +2227,12 @@ run_again:
prebuilt->table->stat_modified_counter++; prebuilt->table->stat_modified_counter++;
} }
if (node->table->versioned() && if (node->table->versioned()
(node->versioned || node->vers_delete || && (node->versioned
|| node->vers_delete
// TODO: improve this check (check if we touch only // TODO: improve this check (check if we touch only
// unversioned fields in foreigh table) // unversioned fields in foreigh table)
node->foreign)) { || node->foreign)) {
trx->vers_update_trt = true; trx->vers_update_trt = true;
} }