Commit 03fbfeef authored by Marko Mäkelä's avatar Marko Mäkelä Committed by Aleksey Midenkov

Identify system-versioned columns in the InnoDB dictionary

Both bits DATA_VERSIONED will be set in prtype if the column
is system-versioned. The bits will be 0 for normal unversioned
columns. For the special columns identifying the logical start
and end times of versions, only one bit will be set:
DATA_VERS_START or DATA_VERS_END.

create_table_info_t::create_table_def(),
prepare_inplace_alter_table_dict(): Set prtype |= DATA_VERSIONED
for system-versioned columns.

dfield_t::is_version_historical_end(): Determine if a data tuple
field is_version_end() and contains a timestamp in the past
(not TRX_ID_MAX).

dtype_t, dict_col_t: Add the accessors
is_versioned(), is_version_start(), is_version_end().

trx_id_max_bytes[]: The bit pattern of TRX_ID_MAX, for use with
memcmp().
parent 0cdc1164
......@@ -861,17 +861,3 @@ 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));
}
......@@ -312,11 +312,13 @@ dict_mem_table_add_col(
dict_mem_fill_column_struct(col, i, mtype, prtype, len);
if (prtype & DATA_VERS_START) {
ut_ad(!(prtype & DATA_VERS_END));
switch (prtype & DATA_VERSIONED) {
case DATA_VERS_START:
ut_ad(!table->vers_start);
table->vers_start = i;
} else if (prtype & DATA_VERS_END) {
ut_ad(!(prtype & DATA_VERS_START));
break;
case DATA_VERS_END:
ut_ad(!table->vers_end);
table->vers_end = i;
}
}
......
......@@ -11413,14 +11413,16 @@ create_table_info_t::create_table_def()
bool is_stored = false;
Field* field = m_form->field[i];
ulint vers_row_start = 0;
ulint vers_row_end = 0;
ulint vers_row = 0;
if (m_form->versioned()) {
if (i == m_form->s->row_start_field) {
vers_row_start = DATA_VERS_START;
vers_row = DATA_VERS_START;
} else if (i == m_form->s->row_end_field) {
vers_row_end = DATA_VERS_END;
vers_row = DATA_VERS_END;
} else if (!(field->flags
& VERS_UPDATE_UNVERSIONED_FLAG)) {
vers_row = DATA_VERSIONED;
}
}
......@@ -11514,7 +11516,7 @@ create_table_info_t::create_table_def()
(ulint) field->type()
| nulls_allowed | unsigned_type
| binary_type | long_true_varchar
| vers_row_start | vers_row_end,
| vers_row,
charset_no),
col_len);
} else {
......@@ -11524,7 +11526,7 @@ create_table_info_t::create_table_def()
(ulint) field->type()
| nulls_allowed | unsigned_type
| binary_type | long_true_varchar
| vers_row_start | vers_row_end
| vers_row
| is_virtual,
charset_no),
col_len, i, 0);
......
......@@ -4983,6 +4983,9 @@ prepare_inplace_alter_table_dict(
} else if (i ==
altered_table->s->row_end_field) {
field_type |= DATA_VERS_END;
} else if (!(field->flags
& VERS_UPDATE_UNVERSIONED_FLAG)) {
field_type |= DATA_VERSIONED;
}
}
......
......@@ -508,12 +508,6 @@ 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
......@@ -597,6 +591,19 @@ struct dfield_t{
@param[in,out] heap memory heap in which the clone will be created
@return the cloned object */
dfield_t* clone(mem_heap_t* heap) const;
/** @return whether this column is the end of the system
version history and points to the past, that is, this record
does not exist in the current time */
bool is_version_historical_end() const
{
if (!type.is_version_end()) {
return false;
}
ut_ad(len == sizeof trx_id_max_bytes);
return memcmp(data, trx_id_max_bytes, sizeof trx_id_max_bytes);
}
};
/** Structure for an SQL data tuple of fields (logical record) */
......
......@@ -192,6 +192,8 @@ be less than 256 */
/** System Versioning */
#define DATA_VERS_START 16384U /* start system field */
#define DATA_VERS_END 32768U /* end system field */
/** system-versioned user data column */
#define DATA_VERSIONED (DATA_VERS_START|DATA_VERS_END)
/** Check whether locking is disabled (never). */
#define dict_table_is_locking_disabled(table) false
......@@ -558,6 +560,19 @@ struct dtype_t{
DATA_MBMINMAXLEN(mbminlen,mbmaxlen);
mbminlen=DATA_MBMINLEN(mbminmaxlen);
mbmaxlen=DATA_MBMINLEN(mbminmaxlen) */
/** @return whether this is system versioned */
bool is_versioned() const { return !(~prtype & DATA_VERSIONED); }
/** @return whether this is the system version start */
bool is_version_start() const
{
return (prtype & DATA_VERSIONED) == DATA_VERS_START;
}
/** @return whether this is the system version end */
bool is_version_end() const
{
return (prtype & DATA_VERSIONED) == DATA_VERS_END;
}
};
#include "data0type.ic"
......
......@@ -652,6 +652,20 @@ struct dict_col_t{
bool is_virtual() const { return prtype & DATA_VIRTUAL; }
/** @return whether NULL is an allowed value for this column */
bool is_nullable() const { return !(prtype & DATA_NOT_NULL); }
/** @return whether this is system versioned */
bool is_versioned() const { return !(~prtype & DATA_VERSIONED); }
/** @return whether this is the system version start */
bool is_version_start() const
{
return (prtype & DATA_VERSIONED) == DATA_VERS_START;
}
/** @return whether this is the system version end */
bool is_version_end() const
{
return (prtype & DATA_VERSIONED) == DATA_VERS_END;
}
/** @return whether this is an instantly-added column */
bool is_instant() const
{
......
......@@ -52,6 +52,12 @@ DICT_IBUF_ID_MIN plus the space id */
typedef ib_id_t table_id_t;
typedef ib_id_t index_id_t;
/** Maximum transaction identifier */
#define TRX_ID_MAX IB_ID_MAX
/** The bit pattern corresponding to TRX_ID_MAX */
extern const char trx_id_max_bytes[8];
/** Error to ignore when we load table dictionary into memory. However,
the table and index will be marked as "corrupted", and caller will
be responsible to deal with corrupted table or index.
......
......@@ -140,9 +140,6 @@ typedef ib_id_t roll_ptr_t;
/** Undo number */
typedef ib_id_t undo_no_t;
/** Maximum transaction identifier */
#define TRX_ID_MAX IB_ID_MAX
/** Transaction savepoint */
struct trx_savept_t{
undo_no_t least_undo_no; /*!< least undo number to undo */
......
......@@ -1701,11 +1701,8 @@ row_ins_check_foreign_constraint(
}
/* System Versioning: if sys_trx_end != Inf, we
suppress the foreign key check */
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 (field->is_version_historical_end()) {
goto exit_func;
}
}
......
......@@ -2249,8 +2249,8 @@ row_merge_read_clustered_index(
if (new_table->versioned()) {
const dfield_t* dfield = dtuple_get_nth_field(
row, new_table->vers_end);
historical_row =
dfield_is_historical_sys_trx_end(dfield);
historical_row
= dfield->is_version_historical_end();
}
const dfield_t* dfield;
......
......@@ -62,6 +62,11 @@ Created 3/26/1996 Heikki Tuuri
extern "C"
int thd_deadlock_victim_preference(const MYSQL_THD thd1, const MYSQL_THD thd2);
/** The bit pattern corresponding to TRX_ID_MAX */
const char trx_id_max_bytes[8] = {
'\377', '\377', '\377', '\377', '\377', '\377', '\377', '\377'
};
static const ulint MAX_DETAILED_ERROR_LEN = 256;
/** Set of table_id */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment