Merge 10.2 into 10.3
This commit is contained in:
commit
934d5f95d3
@ -3306,27 +3306,6 @@ SELECT func();
|
|||||||
func()
|
func()
|
||||||
1
|
1
|
||||||
DROP FUNCTION func;
|
DROP FUNCTION func;
|
||||||
#
|
|
||||||
# MDEV-15151: function with recursive CTE using no base tables
|
|
||||||
# (duplicate of MDEV-16661)
|
|
||||||
#
|
|
||||||
connection default;
|
|
||||||
CREATE TABLE t1 (id int KEY);
|
|
||||||
INSERT INTO t1 VALUES (0), (1),(2);
|
|
||||||
CREATE OR REPLACE FUNCTION func() RETURNS int
|
|
||||||
RETURN
|
|
||||||
(
|
|
||||||
WITH recursive cte AS
|
|
||||||
(SELECT 1 a UNION SELECT cte.* FROM cte natural join t1)
|
|
||||||
SELECT * FROM cte limit 1
|
|
||||||
);
|
|
||||||
connect con1,localhost,root,,;
|
|
||||||
SELECT func();
|
|
||||||
connection default;
|
|
||||||
KILL QUERY 5;
|
|
||||||
DROP FUNCTION func;
|
|
||||||
DROP TABLE t1;
|
|
||||||
disconnect con1;
|
|
||||||
# Start of 10.3 tests
|
# Start of 10.3 tests
|
||||||
#
|
#
|
||||||
# MDEV-14217 [db crash] Recursive CTE when SELECT includes new field
|
# MDEV-14217 [db crash] Recursive CTE when SELECT includes new field
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
--source include/not_embedded.inc
|
|
||||||
create table t1 (a int, b varchar(32));
|
create table t1 (a int, b varchar(32));
|
||||||
insert into t1 values
|
insert into t1 values
|
||||||
(4,'aaaa' ), (7,'bb'), (1,'ccc'), (4,'dd');
|
(4,'aaaa' ), (7,'bb'), (1,'ccc'), (4,'dd');
|
||||||
@ -2325,36 +2324,6 @@ SELECT func();
|
|||||||
|
|
||||||
DROP FUNCTION func;
|
DROP FUNCTION func;
|
||||||
|
|
||||||
--echo #
|
|
||||||
--echo # MDEV-15151: function with recursive CTE using no base tables
|
|
||||||
--echo # (duplicate of MDEV-16661)
|
|
||||||
--echo #
|
|
||||||
|
|
||||||
--connection default
|
|
||||||
|
|
||||||
CREATE TABLE t1 (id int KEY);
|
|
||||||
INSERT INTO t1 VALUES (0), (1),(2);
|
|
||||||
|
|
||||||
CREATE OR REPLACE FUNCTION func() RETURNS int
|
|
||||||
RETURN
|
|
||||||
(
|
|
||||||
WITH recursive cte AS
|
|
||||||
(SELECT 1 a UNION SELECT cte.* FROM cte natural join t1)
|
|
||||||
SELECT * FROM cte limit 1
|
|
||||||
);
|
|
||||||
|
|
||||||
--connect (con1,localhost,root,,)
|
|
||||||
--let $conid= `SELECT CONNECTION_ID()`
|
|
||||||
--send SELECT func()
|
|
||||||
|
|
||||||
--connection default
|
|
||||||
--eval KILL QUERY $conid
|
|
||||||
--source include/restart_mysqld.inc
|
|
||||||
|
|
||||||
DROP FUNCTION func;
|
|
||||||
DROP TABLE t1;
|
|
||||||
--disconnect con1
|
|
||||||
|
|
||||||
--echo # Start of 10.3 tests
|
--echo # Start of 10.3 tests
|
||||||
|
|
||||||
--echo #
|
--echo #
|
||||||
|
@ -175,8 +175,38 @@ SET DEBUG_SYNC='now WAIT_FOR halfway';
|
|||||||
COMMIT;
|
COMMIT;
|
||||||
InnoDB 0 transactions not purged
|
InnoDB 0 transactions not purged
|
||||||
SET DEBUG_SYNC='now SIGNAL purged';
|
SET DEBUG_SYNC='now SIGNAL purged';
|
||||||
disconnect prevent_purge;
|
|
||||||
connection default;
|
connection default;
|
||||||
DROP TABLE t1;
|
DROP TABLE t1;
|
||||||
|
CREATE TABLE t1 (y YEAR, vy YEAR AS (y) VIRTUAL UNIQUE, pk INT PRIMARY KEY)
|
||||||
|
ENGINE=InnoDB;
|
||||||
|
INSERT INTO t1 (pk,y) VALUES (1,2022);
|
||||||
|
CREATE TABLE t2(f1 INT NOT NULL, PRIMARY KEY(f1))ENGINE=InnoDB;
|
||||||
|
SET GLOBAL debug_dbug = '+d,ib_purge_virtual_index_callback';
|
||||||
|
BEGIN;
|
||||||
|
INSERT INTO t2(f1) VALUES(1);
|
||||||
|
connection prevent_purge;
|
||||||
|
SET DEBUG_SYNC=RESET;
|
||||||
|
start transaction with consistent snapshot;
|
||||||
|
connection default;
|
||||||
|
COMMIT;
|
||||||
|
connect truncate,localhost,root,,;
|
||||||
|
REPLACE INTO t1(pk, y) SELECT pk,y FROM t1;
|
||||||
|
SET DEBUG_SYNC='row_trunc_before_dict_lock SIGNAL commit WAIT_FOR release';
|
||||||
|
TRUNCATE TABLE t1;
|
||||||
|
connection prevent_purge;
|
||||||
|
SET DEBUG_SYNC='now WAIT_FOR commit';
|
||||||
|
COMMIT;
|
||||||
|
SET DEBUG_SYNC='now SIGNAL purge_start';
|
||||||
|
disconnect prevent_purge;
|
||||||
|
connection default;
|
||||||
|
SET DEBUG_SYNC='now WAIT_FOR purge_start';
|
||||||
|
InnoDB 2 transactions not purged
|
||||||
|
SET DEBUG_SYNC='now SIGNAL release';
|
||||||
|
SET GLOBAL debug_dbug=@old_dbug;
|
||||||
|
connection truncate;
|
||||||
|
disconnect truncate;
|
||||||
|
connection default;
|
||||||
|
InnoDB 0 transactions not purged
|
||||||
|
DROP TABLE t1, t2;
|
||||||
set debug_sync=reset;
|
set debug_sync=reset;
|
||||||
SET GLOBAL innodb_purge_rseg_truncate_frequency = @saved_frequency;
|
SET GLOBAL innodb_purge_rseg_truncate_frequency = @saved_frequency;
|
||||||
|
@ -156,7 +156,7 @@ INSERT INTO t1(a, b) VALUES (8, 8);
|
|||||||
COMMIT;
|
COMMIT;
|
||||||
|
|
||||||
--echo # wait for purge to process the deleted/updated records.
|
--echo # wait for purge to process the deleted/updated records.
|
||||||
let $wait_all_purged=1;
|
let $wait_all_purged=2;
|
||||||
--source ../../innodb/include/wait_all_purged.inc
|
--source ../../innodb/include/wait_all_purged.inc
|
||||||
let $wait_all_purged=0;
|
let $wait_all_purged=0;
|
||||||
|
|
||||||
@ -217,12 +217,54 @@ SET DEBUG_SYNC='now WAIT_FOR halfway';
|
|||||||
COMMIT;
|
COMMIT;
|
||||||
--source ../../innodb/include/wait_all_purged.inc
|
--source ../../innodb/include/wait_all_purged.inc
|
||||||
SET DEBUG_SYNC='now SIGNAL purged';
|
SET DEBUG_SYNC='now SIGNAL purged';
|
||||||
disconnect prevent_purge;
|
|
||||||
|
|
||||||
connection default;
|
connection default;
|
||||||
reap;
|
reap;
|
||||||
DROP TABLE t1;
|
DROP TABLE t1;
|
||||||
|
|
||||||
|
CREATE TABLE t1 (y YEAR, vy YEAR AS (y) VIRTUAL UNIQUE, pk INT PRIMARY KEY)
|
||||||
|
ENGINE=InnoDB;
|
||||||
|
|
||||||
|
INSERT INTO t1 (pk,y) VALUES (1,2022);
|
||||||
|
CREATE TABLE t2(f1 INT NOT NULL, PRIMARY KEY(f1))ENGINE=InnoDB;
|
||||||
|
|
||||||
|
SET GLOBAL debug_dbug = '+d,ib_purge_virtual_index_callback';
|
||||||
|
|
||||||
|
BEGIN;
|
||||||
|
INSERT INTO t2(f1) VALUES(1);
|
||||||
|
connection prevent_purge;
|
||||||
|
SET DEBUG_SYNC=RESET;
|
||||||
|
start transaction with consistent snapshot;
|
||||||
|
connection default;
|
||||||
|
COMMIT;
|
||||||
|
|
||||||
|
connect(truncate,localhost,root,,);
|
||||||
|
REPLACE INTO t1(pk, y) SELECT pk,y FROM t1;
|
||||||
|
SET DEBUG_SYNC='row_trunc_before_dict_lock SIGNAL commit WAIT_FOR release';
|
||||||
|
send TRUNCATE TABLE t1;
|
||||||
|
|
||||||
|
connection prevent_purge;
|
||||||
|
SET DEBUG_SYNC='now WAIT_FOR commit';
|
||||||
|
COMMIT;
|
||||||
|
SET DEBUG_SYNC='now SIGNAL purge_start';
|
||||||
|
disconnect prevent_purge;
|
||||||
|
|
||||||
|
connection default;
|
||||||
|
SET DEBUG_SYNC='now WAIT_FOR purge_start';
|
||||||
|
let $wait_all_purged=2;
|
||||||
|
--source ../../innodb/include/wait_all_purged.inc
|
||||||
|
let $wait_all_purged=0;
|
||||||
|
SET DEBUG_SYNC='now SIGNAL release';
|
||||||
|
SET GLOBAL debug_dbug=@old_dbug;
|
||||||
|
|
||||||
|
connection truncate;
|
||||||
|
reap;
|
||||||
|
disconnect truncate;
|
||||||
|
|
||||||
|
connection default;
|
||||||
|
--source ../../innodb/include/wait_all_purged.inc
|
||||||
|
DROP TABLE t1, t2;
|
||||||
|
|
||||||
--source include/wait_until_count_sessions.inc
|
--source include/wait_until_count_sessions.inc
|
||||||
set debug_sync=reset;
|
set debug_sync=reset;
|
||||||
SET GLOBAL innodb_purge_rseg_truncate_frequency = @saved_frequency;
|
SET GLOBAL innodb_purge_rseg_truncate_frequency = @saved_frequency;
|
||||||
|
@ -2,6 +2,7 @@ call mtr.add_suppression("InnoDB: New log files created");
|
|||||||
CREATE TABLE t(i INT) ENGINE INNODB ENCRYPTED=YES;
|
CREATE TABLE t(i INT) ENGINE INNODB ENCRYPTED=YES;
|
||||||
INSERT INTO t VALUES(1);
|
INSERT INTO t VALUES(1);
|
||||||
# Create full backup , modify table, then create incremental/differential backup
|
# Create full backup , modify table, then create incremental/differential backup
|
||||||
|
SET GLOBAL innodb_flush_log_at_trx_commit = 1;
|
||||||
INSERT INTO t VALUES(2);
|
INSERT INTO t VALUES(2);
|
||||||
SELECT * FROM t;
|
SELECT * FROM t;
|
||||||
i
|
i
|
||||||
|
@ -20,6 +20,7 @@ echo # Create full backup , modify table, then create incremental/differential b
|
|||||||
exec $XTRABACKUP --defaults-file=$MYSQLTEST_VARDIR/my.cnf --backup --target-dir=$basedir;
|
exec $XTRABACKUP --defaults-file=$MYSQLTEST_VARDIR/my.cnf --backup --target-dir=$basedir;
|
||||||
--enable_result_log
|
--enable_result_log
|
||||||
|
|
||||||
|
SET GLOBAL innodb_flush_log_at_trx_commit = 1;
|
||||||
INSERT INTO t VALUES(2);
|
INSERT INTO t VALUES(2);
|
||||||
SELECT * FROM t;
|
SELECT * FROM t;
|
||||||
|
|
||||||
|
@ -4677,13 +4677,6 @@ TABLE *open_purge_table(THD *thd, const char *db, size_t dblen,
|
|||||||
DBUG_RETURN(error ? NULL : tl->table);
|
DBUG_RETURN(error ? NULL : tl->table);
|
||||||
}
|
}
|
||||||
|
|
||||||
TABLE *get_purge_table(THD *thd)
|
|
||||||
{
|
|
||||||
/* see above, at most one table can be opened */
|
|
||||||
DBUG_ASSERT(thd->open_tables == NULL || thd->open_tables->next == NULL);
|
|
||||||
return thd->open_tables;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/** Find an open table in the list of prelocked tabled
|
/** Find an open table in the list of prelocked tabled
|
||||||
|
|
||||||
|
@ -128,7 +128,7 @@ void destroy_thd(MYSQL_THD thd);
|
|||||||
void reset_thd(MYSQL_THD thd);
|
void reset_thd(MYSQL_THD thd);
|
||||||
TABLE *open_purge_table(THD *thd, const char *db, size_t dblen,
|
TABLE *open_purge_table(THD *thd, const char *db, size_t dblen,
|
||||||
const char *tb, size_t tblen);
|
const char *tb, size_t tblen);
|
||||||
TABLE *get_purge_table(THD *thd);
|
void close_thread_tables(THD* thd);
|
||||||
|
|
||||||
#ifdef MYSQL_DYNAMIC_PLUGIN
|
#ifdef MYSQL_DYNAMIC_PLUGIN
|
||||||
#define tc_size 400
|
#define tc_size 400
|
||||||
@ -20622,63 +20622,154 @@ innobase_index_cond(
|
|||||||
return handler_index_cond_check(file);
|
return handler_index_cond_check(file);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Parse the table file name into table name and database name.
|
||||||
/** Find or open a mysql table for the virtual column template
|
@param[in] tbl_name InnoDB table name
|
||||||
@param[in] thd mysql thread handle
|
@param[out] dbname database name buffer (NAME_LEN + 1 bytes)
|
||||||
@param[in,out] table InnoDB table whose virtual column template is to be updated
|
@param[out] tblname table name buffer (NAME_LEN + 1 bytes)
|
||||||
@return TABLE if successful or NULL */
|
@param[out] dbnamelen database name length
|
||||||
static TABLE *
|
@param[out] tblnamelen table name length
|
||||||
innobase_find_mysql_table_for_vc(
|
@return true if the table name is parsed properly. */
|
||||||
/*=============================*/
|
static bool table_name_parse(
|
||||||
THD* thd,
|
const table_name_t& tbl_name,
|
||||||
dict_table_t* table)
|
char* dbname,
|
||||||
|
char* tblname,
|
||||||
|
ulint& dbnamelen,
|
||||||
|
ulint& tblnamelen)
|
||||||
{
|
{
|
||||||
TABLE *mysql_table;
|
dbnamelen = dict_get_db_name_len(tbl_name.m_name);
|
||||||
bool bg_thread = THDVAR(thd, background_thread);
|
char db_buf[MAX_DATABASE_NAME_LEN + 1];
|
||||||
|
char tbl_buf[MAX_TABLE_NAME_LEN + 1];
|
||||||
|
|
||||||
if (bg_thread) {
|
ut_ad(dbnamelen > 0);
|
||||||
if ((mysql_table = get_purge_table(thd))) {
|
ut_ad(dbnamelen <= MAX_DATABASE_NAME_LEN);
|
||||||
return mysql_table;
|
|
||||||
|
memcpy(db_buf, tbl_name.m_name, dbnamelen);
|
||||||
|
db_buf[dbnamelen] = 0;
|
||||||
|
|
||||||
|
tblnamelen = strlen(tbl_name.m_name + dbnamelen + 1);
|
||||||
|
memcpy(tbl_buf, tbl_name.m_name + dbnamelen + 1, tblnamelen);
|
||||||
|
tbl_buf[tblnamelen] = 0;
|
||||||
|
|
||||||
|
filename_to_tablename(db_buf, dbname, MAX_DATABASE_NAME_LEN + 1, true);
|
||||||
|
|
||||||
|
if (tblnamelen > TEMP_FILE_PREFIX_LENGTH
|
||||||
|
&& !strncmp(tbl_buf, TEMP_FILE_PREFIX, TEMP_FILE_PREFIX_LENGTH)) {
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (char *is_part = strchr(tbl_buf, '#')) {
|
||||||
|
*is_part = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
filename_to_tablename(tbl_buf, tblname, MAX_TABLE_NAME_LEN + 1, true);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** Acquire metadata lock and MariaDB table handle for an InnoDB table.
|
||||||
|
@param[in,out] thd thread handle
|
||||||
|
@param[in,out] table InnoDB table
|
||||||
|
@return MariaDB table handle
|
||||||
|
@retval NULL if the table does not exist, is unaccessible or corrupted. */
|
||||||
|
static TABLE* innodb_acquire_mdl(THD* thd, dict_table_t* table)
|
||||||
|
{
|
||||||
|
char db_buf[NAME_LEN + 1], db_buf1[NAME_LEN + 1];
|
||||||
|
char tbl_buf[NAME_LEN + 1], tbl_buf1[NAME_LEN + 1];
|
||||||
|
ulint db_buf_len, db_buf1_len;
|
||||||
|
ulint tbl_buf_len, tbl_buf1_len;
|
||||||
|
|
||||||
|
if (!table_name_parse(table->name, db_buf, tbl_buf,
|
||||||
|
db_buf_len, tbl_buf_len)) {
|
||||||
|
ut_ad(!"invalid table name");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
const table_id_t table_id = table->id;
|
||||||
|
retry_mdl:
|
||||||
|
const bool unaccessible = !table->is_readable() || table->corrupted;
|
||||||
|
table->release();
|
||||||
|
|
||||||
|
if (unaccessible) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
TABLE* mariadb_table = open_purge_table(thd, db_buf, db_buf_len,
|
||||||
|
tbl_buf, tbl_buf_len);
|
||||||
|
|
||||||
|
table = dict_table_open_on_id(table_id, false, DICT_TABLE_OP_NORMAL);
|
||||||
|
|
||||||
|
if (table == NULL) {
|
||||||
|
/* Table is dropped. */
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!fil_table_accessible(table)) {
|
||||||
|
release_fail:
|
||||||
|
table->release();
|
||||||
|
fail:
|
||||||
|
if (mariadb_table) {
|
||||||
|
close_thread_tables(thd);
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!table_name_parse(table->name, db_buf1, tbl_buf1,
|
||||||
|
db_buf1_len, tbl_buf1_len)) {
|
||||||
|
ut_ad(!"invalid table name");
|
||||||
|
goto release_fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!mariadb_table) {
|
||||||
|
} else if (!strcmp(db_buf, db_buf1) && !strcmp(tbl_buf, tbl_buf1)) {
|
||||||
|
return mariadb_table;
|
||||||
} else {
|
} else {
|
||||||
if (table->vc_templ->mysql_table_query_id == thd_get_query_id(thd)) {
|
/* Table is renamed. So release MDL for old name and try
|
||||||
|
to acquire the MDL for new table name. */
|
||||||
|
close_thread_tables(thd);
|
||||||
|
}
|
||||||
|
|
||||||
|
strcpy(tbl_buf, tbl_buf1);
|
||||||
|
strcpy(db_buf, db_buf1);
|
||||||
|
tbl_buf_len = tbl_buf1_len;
|
||||||
|
db_buf_len = db_buf1_len;
|
||||||
|
goto retry_mdl;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Find or open a table handle for the virtual column template
|
||||||
|
@param[in] thd thread handle
|
||||||
|
@param[in,out] table InnoDB table whose virtual column template
|
||||||
|
is to be updated
|
||||||
|
@return table handle
|
||||||
|
@retval NULL if the table is dropped, unaccessible or corrupted
|
||||||
|
for purge thread */
|
||||||
|
static TABLE* innodb_find_table_for_vc(THD* thd, dict_table_t* table)
|
||||||
|
{
|
||||||
|
if (THDVAR(thd, background_thread)) {
|
||||||
|
/* Purge thread acquires dict_operation_lock while
|
||||||
|
processing undo log record. Release the dict_operation_lock
|
||||||
|
before acquiring MDL on the table. */
|
||||||
|
rw_lock_s_unlock(dict_operation_lock);
|
||||||
|
return innodb_acquire_mdl(thd, table);
|
||||||
|
} else {
|
||||||
|
if (table->vc_templ->mysql_table_query_id
|
||||||
|
== thd_get_query_id(thd)) {
|
||||||
return table->vc_templ->mysql_table;
|
return table->vc_templ->mysql_table;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
char dbname[MAX_DATABASE_NAME_LEN + 1];
|
char db_buf[NAME_LEN + 1];
|
||||||
char tbname[MAX_TABLE_NAME_LEN + 1];
|
char tbl_buf[NAME_LEN + 1];
|
||||||
char* name = table->name.m_name;
|
ulint db_buf_len, tbl_buf_len;
|
||||||
uint dbnamelen = (uint) dict_get_db_name_len(name);
|
|
||||||
uint tbnamelen = (uint) strlen(name) - dbnamelen - 1;
|
|
||||||
char t_dbname[MAX_DATABASE_NAME_LEN + 1];
|
|
||||||
char t_tbname[MAX_TABLE_NAME_LEN + 1];
|
|
||||||
|
|
||||||
strncpy(dbname, name, dbnamelen);
|
if (!table_name_parse(table->name, db_buf, tbl_buf,
|
||||||
dbname[dbnamelen] = 0;
|
db_buf_len, tbl_buf_len)) {
|
||||||
strncpy(tbname, name + dbnamelen + 1, tbnamelen);
|
ut_ad(!"invalid table name");
|
||||||
tbname[tbnamelen] =0;
|
return NULL;
|
||||||
|
|
||||||
/* For partition table, remove the partition name and use the
|
|
||||||
"main" table name to build the template */
|
|
||||||
char* is_part = is_partition(tbname);
|
|
||||||
|
|
||||||
if (is_part != NULL) {
|
|
||||||
*is_part = '\0';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dbnamelen = filename_to_tablename(dbname, t_dbname,
|
TABLE* mysql_table = find_fk_open_table(thd, db_buf, db_buf_len,
|
||||||
MAX_DATABASE_NAME_LEN + 1);
|
tbl_buf, tbl_buf_len);
|
||||||
tbnamelen = filename_to_tablename(tbname, t_tbname,
|
|
||||||
MAX_TABLE_NAME_LEN + 1);
|
|
||||||
|
|
||||||
if (bg_thread) {
|
|
||||||
return open_purge_table(thd, t_dbname, dbnamelen,
|
|
||||||
t_tbname, tbnamelen);
|
|
||||||
}
|
|
||||||
|
|
||||||
mysql_table = find_fk_open_table(thd, t_dbname, dbnamelen,
|
|
||||||
t_tbname, tbnamelen);
|
|
||||||
|
|
||||||
table->vc_templ->mysql_table = mysql_table;
|
table->vc_templ->mysql_table = mysql_table;
|
||||||
table->vc_templ->mysql_table_query_id = thd_get_query_id(thd);
|
table->vc_templ->mysql_table_query_id = thd_get_query_id(thd);
|
||||||
@ -20697,7 +20788,7 @@ innobase_init_vc_templ(
|
|||||||
|
|
||||||
table->vc_templ = UT_NEW_NOKEY(dict_vcol_templ_t());
|
table->vc_templ = UT_NEW_NOKEY(dict_vcol_templ_t());
|
||||||
|
|
||||||
TABLE *mysql_table= innobase_find_mysql_table_for_vc(current_thd, table);
|
TABLE *mysql_table= innodb_find_table_for_vc(current_thd, table);
|
||||||
|
|
||||||
ut_ad(mysql_table);
|
ut_ad(mysql_table);
|
||||||
if (!mysql_table) {
|
if (!mysql_table) {
|
||||||
@ -20794,12 +20885,13 @@ innobase_get_field_from_update_vector(
|
|||||||
@param[in] thd MariaDB THD
|
@param[in] thd MariaDB THD
|
||||||
@param[in] index Index in use
|
@param[in] index Index in use
|
||||||
@param[out] heap Heap that holds temporary row
|
@param[out] heap Heap that holds temporary row
|
||||||
@param[in,out] mysql_table MariaDB table
|
@param[in,out] table MariaDB table
|
||||||
@param[out] rec Pointer to allocated MariaDB record
|
@param[out] record Pointer to allocated MariaDB record
|
||||||
@param[out] storage Internal storage for blobs etc
|
@param[out] storage Internal storage for blobs etc
|
||||||
|
|
||||||
@return FALSE ok
|
@retval false on success
|
||||||
@return TRUE malloc failure
|
@retval true on malloc failure or failed to open the maria table
|
||||||
|
for purge thread.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
bool innobase_allocate_row_for_vcol(
|
bool innobase_allocate_row_for_vcol(
|
||||||
@ -20813,7 +20905,12 @@ bool innobase_allocate_row_for_vcol(
|
|||||||
TABLE *maria_table;
|
TABLE *maria_table;
|
||||||
String *blob_value_storage;
|
String *blob_value_storage;
|
||||||
if (!*table)
|
if (!*table)
|
||||||
*table= innobase_find_mysql_table_for_vc(thd, index->table);
|
*table= innodb_find_table_for_vc(thd, index->table);
|
||||||
|
|
||||||
|
/* For purge thread, there is a possiblity that table could have
|
||||||
|
dropped, corrupted or unaccessible. */
|
||||||
|
if (!*table)
|
||||||
|
return true;
|
||||||
maria_table= *table;
|
maria_table= *table;
|
||||||
if (!*heap && !(*heap= mem_heap_create(srv_page_size)))
|
if (!*heap && !(*heap= mem_heap_create(srv_page_size)))
|
||||||
{
|
{
|
||||||
|
@ -121,7 +121,15 @@ enum btr_latch_mode {
|
|||||||
/** Attempt to purge a secondary index record
|
/** Attempt to purge a secondary index record
|
||||||
while holding the dict_index_t::lock S-latch. */
|
while holding the dict_index_t::lock S-latch. */
|
||||||
BTR_PURGE_LEAF_ALREADY_S_LATCHED = BTR_PURGE_LEAF
|
BTR_PURGE_LEAF_ALREADY_S_LATCHED = BTR_PURGE_LEAF
|
||||||
| BTR_ALREADY_S_LATCHED
|
| BTR_ALREADY_S_LATCHED,
|
||||||
|
|
||||||
|
/** In the case of BTR_MODIFY_TREE, the caller specifies
|
||||||
|
the intention to delete record only. It is used to optimize
|
||||||
|
block->lock range.*/
|
||||||
|
BTR_LATCH_FOR_DELETE = 65536,
|
||||||
|
|
||||||
|
/** Attempt to purge a secondary index record in the tree. */
|
||||||
|
BTR_PURGE_TREE = BTR_MODIFY_TREE | BTR_LATCH_FOR_DELETE
|
||||||
};
|
};
|
||||||
|
|
||||||
/** This flag ORed to btr_latch_mode says that we do the search in query
|
/** This flag ORed to btr_latch_mode says that we do the search in query
|
||||||
@ -137,10 +145,6 @@ the insert buffer to speed up inserts */
|
|||||||
to insert record only. It is used to optimize block->lock range.*/
|
to insert record only. It is used to optimize block->lock range.*/
|
||||||
#define BTR_LATCH_FOR_INSERT 32768U
|
#define BTR_LATCH_FOR_INSERT 32768U
|
||||||
|
|
||||||
/** In the case of BTR_MODIFY_TREE, the caller specifies the intention
|
|
||||||
to delete record only. It is used to optimize block->lock range.*/
|
|
||||||
#define BTR_LATCH_FOR_DELETE 65536U
|
|
||||||
|
|
||||||
/** This flag is for undo insert of rtree. For rtree, we need this flag
|
/** This flag is for undo insert of rtree. For rtree, we need this flag
|
||||||
to find proper rec to undo insert.*/
|
to find proper rec to undo insert.*/
|
||||||
#define BTR_RTREE_UNDO_INS 131072U
|
#define BTR_RTREE_UNDO_INS 131072U
|
||||||
|
@ -301,6 +301,21 @@ btr_pcur_commit_specify_mtr(
|
|||||||
/*========================*/
|
/*========================*/
|
||||||
btr_pcur_t* pcur, /*!< in: persistent cursor */
|
btr_pcur_t* pcur, /*!< in: persistent cursor */
|
||||||
mtr_t* mtr); /*!< in: mtr to commit */
|
mtr_t* mtr); /*!< in: mtr to commit */
|
||||||
|
|
||||||
|
/** Commits the mtr and sets the clustered index pcur and secondary index
|
||||||
|
pcur latch mode to BTR_NO_LATCHES, that is, the cursor becomes detached.
|
||||||
|
Function btr_pcur_store_position should be used for both cursor before
|
||||||
|
calling this, if restoration of cursor is wanted later.
|
||||||
|
@param[in] pcur persistent cursor
|
||||||
|
@param[in] sec_pcur secondary index persistent cursor
|
||||||
|
@param[in] mtr mtr to commit */
|
||||||
|
UNIV_INLINE
|
||||||
|
void
|
||||||
|
btr_pcurs_commit_specify_mtr(
|
||||||
|
btr_pcur_t* pcur,
|
||||||
|
btr_pcur_t* sec_pcur,
|
||||||
|
mtr_t* mtr);
|
||||||
|
|
||||||
/*********************************************************//**
|
/*********************************************************//**
|
||||||
Moves the persistent cursor to the next record in the tree. If no records are
|
Moves the persistent cursor to the next record in the tree. If no records are
|
||||||
left, the cursor stays 'after last in tree'.
|
left, the cursor stays 'after last in tree'.
|
||||||
|
@ -365,6 +365,32 @@ btr_pcur_commit_specify_mtr(
|
|||||||
pcur->pos_state = BTR_PCUR_WAS_POSITIONED;
|
pcur->pos_state = BTR_PCUR_WAS_POSITIONED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Commits the mtr and sets the clustered index pcur and secondary index
|
||||||
|
pcur latch mode to BTR_NO_LATCHES, that is, the cursor becomes detached.
|
||||||
|
Function btr_pcur_store_position should be used for both cursor before
|
||||||
|
calling this, if restoration of cursor is wanted later.
|
||||||
|
@param[in] pcur persistent cursor
|
||||||
|
@param[in] sec_pcur secondary index persistent cursor
|
||||||
|
@param[in] mtr mtr to commit */
|
||||||
|
UNIV_INLINE
|
||||||
|
void
|
||||||
|
btr_pcurs_commit_specify_mtr(
|
||||||
|
btr_pcur_t* pcur,
|
||||||
|
btr_pcur_t* sec_pcur,
|
||||||
|
mtr_t* mtr)
|
||||||
|
{
|
||||||
|
ut_ad(pcur->pos_state == BTR_PCUR_IS_POSITIONED);
|
||||||
|
ut_ad(sec_pcur->pos_state == BTR_PCUR_IS_POSITIONED);
|
||||||
|
|
||||||
|
pcur->latch_mode = BTR_NO_LATCHES;
|
||||||
|
sec_pcur->latch_mode = BTR_NO_LATCHES;
|
||||||
|
|
||||||
|
mtr_commit(mtr);
|
||||||
|
|
||||||
|
pcur->pos_state = BTR_PCUR_WAS_POSITIONED;
|
||||||
|
sec_pcur->pos_state = BTR_PCUR_WAS_POSITIONED;
|
||||||
|
}
|
||||||
|
|
||||||
/**************************************************************//**
|
/**************************************************************//**
|
||||||
Sets the old_rec_buf field to NULL. */
|
Sets the old_rec_buf field to NULL. */
|
||||||
UNIV_INLINE
|
UNIV_INLINE
|
||||||
|
@ -36,6 +36,7 @@ Created 3/14/1997 Heikki Tuuri
|
|||||||
#include "que0types.h"
|
#include "que0types.h"
|
||||||
#include "row0types.h"
|
#include "row0types.h"
|
||||||
#include "ut0vec.h"
|
#include "ut0vec.h"
|
||||||
|
#include "row0mysql.h"
|
||||||
|
|
||||||
/** Create a purge node to a query graph.
|
/** Create a purge node to a query graph.
|
||||||
@param[in] parent parent node, i.e., a thr node
|
@param[in] parent parent node, i.e., a thr node
|
||||||
@ -47,8 +48,7 @@ row_purge_node_create(
|
|||||||
mem_heap_t* heap)
|
mem_heap_t* heap)
|
||||||
MY_ATTRIBUTE((warn_unused_result));
|
MY_ATTRIBUTE((warn_unused_result));
|
||||||
|
|
||||||
/***********************************************************//**
|
/** Determines if it is possible to remove a secondary index entry.
|
||||||
Determines if it is possible to remove a secondary index entry.
|
|
||||||
Removal is possible if the secondary index entry does not refer to any
|
Removal is possible if the secondary index entry does not refer to any
|
||||||
not delete marked version of a clustered index record where DB_TRX_ID
|
not delete marked version of a clustered index record where DB_TRX_ID
|
||||||
is newer than the purge view.
|
is newer than the purge view.
|
||||||
@ -61,14 +61,27 @@ inserts a record that the secondary index entry would refer to.
|
|||||||
However, in that case, the user transaction would also re-insert the
|
However, in that case, the user transaction would also re-insert the
|
||||||
secondary index entry after purge has removed it and released the leaf
|
secondary index entry after purge has removed it and released the leaf
|
||||||
page latch.
|
page latch.
|
||||||
|
@param[in,out] node row purge node
|
||||||
|
@param[in] index secondary index
|
||||||
|
@param[in] entry secondary index entry
|
||||||
|
@param[in,out] sec_pcur secondary index cursor or NULL
|
||||||
|
if it is called for purge buffering
|
||||||
|
operation.
|
||||||
|
@param[in,out] sec_mtr mini-transaction which holds
|
||||||
|
secondary index entry or NULL if it is
|
||||||
|
called for purge buffering operation.
|
||||||
|
@param[in] is_tree true=pessimistic purge,
|
||||||
|
false=optimistic (leaf-page only)
|
||||||
@return true if the secondary index record can be purged */
|
@return true if the secondary index record can be purged */
|
||||||
bool
|
bool
|
||||||
row_purge_poss_sec(
|
row_purge_poss_sec(
|
||||||
/*===============*/
|
purge_node_t* node,
|
||||||
purge_node_t* node, /*!< in/out: row purge node */
|
dict_index_t* index,
|
||||||
dict_index_t* index, /*!< in: secondary index */
|
const dtuple_t* entry,
|
||||||
const dtuple_t* entry) /*!< in: secondary index entry */
|
btr_pcur_t* sec_pcur=NULL,
|
||||||
MY_ATTRIBUTE((nonnull, warn_unused_result));
|
mtr_t* sec_mtr=NULL,
|
||||||
|
bool is_tree=false);
|
||||||
|
|
||||||
/***************************************************************
|
/***************************************************************
|
||||||
Does the purge operation for a single undo log record. This is a high-level
|
Does the purge operation for a single undo log record. This is a high-level
|
||||||
function used in an SQL execution graph.
|
function used in an SQL execution graph.
|
||||||
@ -117,6 +130,10 @@ struct purge_node_t{
|
|||||||
ibool done; /* Debug flag */
|
ibool done; /* Debug flag */
|
||||||
trx_id_t trx_id; /*!< trx id for this purging record */
|
trx_id_t trx_id; /*!< trx id for this purging record */
|
||||||
|
|
||||||
|
/** Virtual column information about opening of MariaDB table.
|
||||||
|
It resets after processing each undo log record. */
|
||||||
|
purge_vcol_info_t vcol_info;
|
||||||
|
|
||||||
#ifdef UNIV_DEBUG
|
#ifdef UNIV_DEBUG
|
||||||
/***********************************************************//**
|
/***********************************************************//**
|
||||||
Validate the persisent cursor. The purge node has two references
|
Validate the persisent cursor. The purge node has two references
|
||||||
@ -127,6 +144,11 @@ struct purge_node_t{
|
|||||||
the ref member.*/
|
the ref member.*/
|
||||||
bool validate_pcur();
|
bool validate_pcur();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/** Whether purge failed to open the maria table for virtual column
|
||||||
|
computation.
|
||||||
|
@return true if the table failed to open. */
|
||||||
|
bool vcol_op_failed() const { return !vcol_info.validate(); }
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
/*****************************************************************************
|
/*****************************************************************************
|
||||||
|
|
||||||
Copyright (c) 1996, 2012, Oracle and/or its affiliates. All Rights Reserved.
|
Copyright (c) 1996, 2012, Oracle and/or its affiliates. All Rights Reserved.
|
||||||
|
Copyright (c) 2018, MariaDB Corporation.
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify it under
|
This program is free software; you can redistribute it and/or modify it under
|
||||||
the terms of the GNU General Public License as published by the Free Software
|
the terms of the GNU General Public License as published by the Free Software
|
||||||
@ -52,4 +53,55 @@ struct row_log_t;
|
|||||||
/* MySQL data types */
|
/* MySQL data types */
|
||||||
struct TABLE;
|
struct TABLE;
|
||||||
|
|
||||||
|
/** Purge virtual column node information. */
|
||||||
|
struct purge_vcol_info_t
|
||||||
|
{
|
||||||
|
/** Is there a possible need to evaluate virtual columns? */
|
||||||
|
bool requested;
|
||||||
|
/** Do we have to evaluate virtual columns (using mariadb_table)? */
|
||||||
|
bool used;
|
||||||
|
|
||||||
|
/** True if it is used for the first time. */
|
||||||
|
bool first_use;
|
||||||
|
|
||||||
|
/** MariaDB table opened for virtual column computation. */
|
||||||
|
TABLE* mariadb_table;
|
||||||
|
|
||||||
|
/** Reset the state. */
|
||||||
|
void reset()
|
||||||
|
{
|
||||||
|
requested = false;
|
||||||
|
used = false;
|
||||||
|
first_use = false;
|
||||||
|
mariadb_table = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Validate the virtual column information.
|
||||||
|
@return true if the mariadb table opened successfully
|
||||||
|
or doesn't try to calculate virtual column. */
|
||||||
|
bool validate() const { return !used || mariadb_table; }
|
||||||
|
|
||||||
|
/** Note that the virtual column information is needed. */
|
||||||
|
void set_used()
|
||||||
|
{
|
||||||
|
ut_ad(requested);
|
||||||
|
|
||||||
|
if (first_use) {
|
||||||
|
first_use = false;
|
||||||
|
ut_ad(used);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
first_use = used = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Check whether it fetches mariadb table for the first time.
|
||||||
|
@return true if first time tries to open mariadb table. */
|
||||||
|
bool is_first_fetch() const
|
||||||
|
{
|
||||||
|
ut_ad(!first_use || used);
|
||||||
|
return first_use;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -35,6 +35,7 @@ Created 2/6/1997 Heikki Tuuri
|
|||||||
#include "rem0types.h"
|
#include "rem0types.h"
|
||||||
#include "mtr0mtr.h"
|
#include "mtr0mtr.h"
|
||||||
#include "dict0mem.h"
|
#include "dict0mem.h"
|
||||||
|
#include "row0types.h"
|
||||||
|
|
||||||
// Forward declaration
|
// Forward declaration
|
||||||
class ReadView;
|
class ReadView;
|
||||||
@ -54,27 +55,34 @@ row_vers_impl_x_locked(
|
|||||||
dict_index_t* index,
|
dict_index_t* index,
|
||||||
const ulint* offsets);
|
const ulint* offsets);
|
||||||
|
|
||||||
/*****************************************************************//**
|
/** Finds out if a version of the record, where the version >= the current
|
||||||
Finds out if a version of the record, where the version >= the current
|
|
||||||
purge view, should have ientry as its secondary index entry. We check
|
purge view, should have ientry as its secondary index entry. We check
|
||||||
if there is any not delete marked version of the record where the trx
|
if there is any not delete marked version of the record where the trx
|
||||||
id >= purge view, and the secondary index entry == ientry; exactly in
|
id >= purge view, and the secondary index entry == ientry; exactly in
|
||||||
this case we return TRUE.
|
this case we return TRUE.
|
||||||
|
@param[in] also_curr TRUE if also rec is included in the versions
|
||||||
|
to search; otherwise only versions prior
|
||||||
|
to it are searched
|
||||||
|
@param[in] rec record in the clustered index; the caller
|
||||||
|
must have a latch on the page
|
||||||
|
@param[in] mtr mtr holding the latch on rec; it will
|
||||||
|
also hold the latch on purge_view
|
||||||
|
@param[in] index secondary index
|
||||||
|
@param[in] ientry secondary index entry
|
||||||
|
@param[in] roll_ptr roll_ptr for the purge record
|
||||||
|
@param[in] trx_id transaction ID on the purging record
|
||||||
|
@param[in,out] vcol_info virtual column information for purge thread.
|
||||||
@return TRUE if earlier version should have */
|
@return TRUE if earlier version should have */
|
||||||
ibool
|
bool
|
||||||
row_vers_old_has_index_entry(
|
row_vers_old_has_index_entry(
|
||||||
/*=========================*/
|
bool also_curr,
|
||||||
ibool also_curr,/*!< in: TRUE if also rec is included in the
|
const rec_t* rec,
|
||||||
versions to search; otherwise only versions
|
mtr_t* mtr,
|
||||||
prior to it are searched */
|
dict_index_t* index,
|
||||||
const rec_t* rec, /*!< in: record in the clustered index; the
|
const dtuple_t* ientry,
|
||||||
caller must have a latch on the page */
|
roll_ptr_t roll_ptr,
|
||||||
mtr_t* mtr, /*!< in: mtr holding the latch on rec; it will
|
trx_id_t trx_id,
|
||||||
also hold the latch on purge_view */
|
purge_vcol_info_t* vcol_info=NULL);
|
||||||
dict_index_t* index, /*!< in: the secondary index */
|
|
||||||
const dtuple_t* ientry, /*!< in: the secondary index entry */
|
|
||||||
roll_ptr_t roll_ptr,/*!< in: roll_ptr for the purge record */
|
|
||||||
trx_id_t trx_id);/*!< in: transaction ID on the purging record */
|
|
||||||
|
|
||||||
/*****************************************************************//**
|
/*****************************************************************//**
|
||||||
Constructs the version of a clustered index record which a consistent
|
Constructs the version of a clustered index record which a consistent
|
||||||
|
@ -136,7 +136,8 @@ row_purge_remove_clust_if_poss_low(
|
|||||||
ulint offsets_[REC_OFFS_NORMAL_SIZE];
|
ulint offsets_[REC_OFFS_NORMAL_SIZE];
|
||||||
rec_offs_init(offsets_);
|
rec_offs_init(offsets_);
|
||||||
|
|
||||||
ut_ad(rw_lock_own(dict_operation_lock, RW_LOCK_S));
|
ut_ad(rw_lock_own(dict_operation_lock, RW_LOCK_S)
|
||||||
|
|| node->vcol_info.used);
|
||||||
|
|
||||||
index = dict_table_get_first_index(node->table);
|
index = dict_table_get_first_index(node->table);
|
||||||
|
|
||||||
@ -230,8 +231,55 @@ row_purge_remove_clust_if_poss(
|
|||||||
return(false);
|
return(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/***********************************************************//**
|
/** Tries to store secondary index cursor before openin mysql table for
|
||||||
Determines if it is possible to remove a secondary index entry.
|
virtual index condition computation.
|
||||||
|
@param[in,out] node row purge node
|
||||||
|
@param[in] index secondary index
|
||||||
|
@param[in,out] sec_pcur secondary index cursor
|
||||||
|
@param[in,out] sec_mtr mini-transaction which holds
|
||||||
|
secondary index entry */
|
||||||
|
static void row_purge_store_vsec_cur(
|
||||||
|
purge_node_t* node,
|
||||||
|
dict_index_t* index,
|
||||||
|
btr_pcur_t* sec_pcur,
|
||||||
|
mtr_t* sec_mtr)
|
||||||
|
{
|
||||||
|
row_purge_reposition_pcur(BTR_SEARCH_LEAF, node, sec_mtr);
|
||||||
|
|
||||||
|
if (!node->found_clust) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
node->vcol_info.requested = true;
|
||||||
|
|
||||||
|
btr_pcur_store_position(sec_pcur, sec_mtr);
|
||||||
|
|
||||||
|
btr_pcurs_commit_specify_mtr(&node->pcur, sec_pcur, sec_mtr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Tries to restore secondary index cursor after opening the mysql table
|
||||||
|
@param[in,out] node row purge node
|
||||||
|
@param[in] index secondary index
|
||||||
|
@param[in,out] sec_mtr mini-transaction which holds secondary index entry
|
||||||
|
@param[in] is_tree true=pessimistic purge,
|
||||||
|
false=optimistic (leaf-page only)
|
||||||
|
@return false in case of restore failure. */
|
||||||
|
static bool row_purge_restore_vsec_cur(
|
||||||
|
purge_node_t* node,
|
||||||
|
dict_index_t* index,
|
||||||
|
btr_pcur_t* sec_pcur,
|
||||||
|
mtr_t* sec_mtr,
|
||||||
|
bool is_tree)
|
||||||
|
{
|
||||||
|
sec_mtr->start();
|
||||||
|
index->set_modified(*sec_mtr);
|
||||||
|
|
||||||
|
return btr_pcur_restore_position(
|
||||||
|
is_tree ? BTR_PURGE_TREE : BTR_PURGE_LEAF,
|
||||||
|
sec_pcur, sec_mtr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Determines if it is possible to remove a secondary index entry.
|
||||||
Removal is possible if the secondary index entry does not refer to any
|
Removal is possible if the secondary index entry does not refer to any
|
||||||
not delete marked version of a clustered index record where DB_TRX_ID
|
not delete marked version of a clustered index record where DB_TRX_ID
|
||||||
is newer than the purge view.
|
is newer than the purge view.
|
||||||
@ -244,25 +292,66 @@ inserts a record that the secondary index entry would refer to.
|
|||||||
However, in that case, the user transaction would also re-insert the
|
However, in that case, the user transaction would also re-insert the
|
||||||
secondary index entry after purge has removed it and released the leaf
|
secondary index entry after purge has removed it and released the leaf
|
||||||
page latch.
|
page latch.
|
||||||
|
@param[in,out] node row purge node
|
||||||
|
@param[in] index secondary index
|
||||||
|
@param[in] entry secondary index entry
|
||||||
|
@param[in,out] sec_pcur secondary index cursor or NULL
|
||||||
|
if it is called for purge buffering
|
||||||
|
operation.
|
||||||
|
@param[in,out] sec_mtr mini-transaction which holds
|
||||||
|
secondary index entry or NULL if it is
|
||||||
|
called for purge buffering operation.
|
||||||
|
@param[in] is_tree true=pessimistic purge,
|
||||||
|
false=optimistic (leaf-page only)
|
||||||
@return true if the secondary index record can be purged */
|
@return true if the secondary index record can be purged */
|
||||||
bool
|
bool
|
||||||
row_purge_poss_sec(
|
row_purge_poss_sec(
|
||||||
/*===============*/
|
purge_node_t* node,
|
||||||
purge_node_t* node, /*!< in/out: row purge node */
|
dict_index_t* index,
|
||||||
dict_index_t* index, /*!< in: secondary index */
|
const dtuple_t* entry,
|
||||||
const dtuple_t* entry) /*!< in: secondary index entry */
|
btr_pcur_t* sec_pcur,
|
||||||
|
mtr_t* sec_mtr,
|
||||||
|
bool is_tree)
|
||||||
{
|
{
|
||||||
bool can_delete;
|
bool can_delete;
|
||||||
mtr_t mtr;
|
mtr_t mtr;
|
||||||
|
|
||||||
ut_ad(!dict_index_is_clust(index));
|
ut_ad(!dict_index_is_clust(index));
|
||||||
|
|
||||||
|
const bool store_cur = sec_mtr && !node->vcol_info.used
|
||||||
|
&& dict_index_has_virtual(index);
|
||||||
|
|
||||||
|
if (store_cur) {
|
||||||
|
row_purge_store_vsec_cur(node, index, sec_pcur, sec_mtr);
|
||||||
|
|
||||||
|
/* The PRIMARY KEY value was not found in the clustered
|
||||||
|
index. The secondary index record found. We can purge
|
||||||
|
the secondary index record. */
|
||||||
|
if (!node->vcol_info.requested) {
|
||||||
|
ut_ad(!node->found_clust);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
retry_purge_sec:
|
||||||
mtr_start(&mtr);
|
mtr_start(&mtr);
|
||||||
|
|
||||||
can_delete = !row_purge_reposition_pcur(BTR_SEARCH_LEAF, node, &mtr)
|
can_delete = !row_purge_reposition_pcur(BTR_SEARCH_LEAF, node, &mtr)
|
||||||
|| !row_vers_old_has_index_entry(TRUE,
|
|| !row_vers_old_has_index_entry(true,
|
||||||
btr_pcur_get_rec(&node->pcur),
|
btr_pcur_get_rec(&node->pcur),
|
||||||
&mtr, index, entry,
|
&mtr, index, entry,
|
||||||
node->roll_ptr, node->trx_id);
|
node->roll_ptr, node->trx_id,
|
||||||
|
&node->vcol_info);
|
||||||
|
|
||||||
|
if (node->vcol_info.is_first_fetch()) {
|
||||||
|
if (node->vcol_info.mariadb_table) {
|
||||||
|
goto retry_purge_sec;
|
||||||
|
}
|
||||||
|
|
||||||
|
node->table = NULL;
|
||||||
|
sec_pcur = NULL;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/* Persistent cursor is closed if reposition fails. */
|
/* Persistent cursor is closed if reposition fails. */
|
||||||
if (node->found_clust) {
|
if (node->found_clust) {
|
||||||
@ -271,7 +360,12 @@ row_purge_poss_sec(
|
|||||||
mtr_commit(&mtr);
|
mtr_commit(&mtr);
|
||||||
}
|
}
|
||||||
|
|
||||||
return(can_delete);
|
if (store_cur && !row_purge_restore_vsec_cur(
|
||||||
|
node, index, sec_pcur, sec_mtr, is_tree)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return can_delete;
|
||||||
}
|
}
|
||||||
|
|
||||||
/***************************************************************
|
/***************************************************************
|
||||||
@ -287,7 +381,6 @@ row_purge_remove_sec_if_poss_tree(
|
|||||||
const dtuple_t* entry) /*!< in: index entry */
|
const dtuple_t* entry) /*!< in: index entry */
|
||||||
{
|
{
|
||||||
btr_pcur_t pcur;
|
btr_pcur_t pcur;
|
||||||
btr_cur_t* btr_cur;
|
|
||||||
ibool success = TRUE;
|
ibool success = TRUE;
|
||||||
dberr_t err;
|
dberr_t err;
|
||||||
mtr_t mtr;
|
mtr_t mtr;
|
||||||
@ -348,16 +441,16 @@ row_purge_remove_sec_if_poss_tree(
|
|||||||
ut_error;
|
ut_error;
|
||||||
}
|
}
|
||||||
|
|
||||||
btr_cur = btr_pcur_get_btr_cur(&pcur);
|
|
||||||
|
|
||||||
/* We should remove the index record if no later version of the row,
|
/* We should remove the index record if no later version of the row,
|
||||||
which cannot be purged yet, requires its existence. If some requires,
|
which cannot be purged yet, requires its existence. If some requires,
|
||||||
we should do nothing. */
|
we should do nothing. */
|
||||||
|
|
||||||
if (row_purge_poss_sec(node, index, entry)) {
|
if (row_purge_poss_sec(node, index, entry, &pcur, &mtr, true)) {
|
||||||
|
|
||||||
/* Remove the index record, which should have been
|
/* Remove the index record, which should have been
|
||||||
marked for deletion. */
|
marked for deletion. */
|
||||||
if (!rec_get_deleted_flag(btr_cur_get_rec(btr_cur),
|
if (!rec_get_deleted_flag(btr_cur_get_rec(
|
||||||
|
btr_pcur_get_btr_cur(&pcur)),
|
||||||
dict_table_is_comp(index->table))) {
|
dict_table_is_comp(index->table))) {
|
||||||
ib::error()
|
ib::error()
|
||||||
<< "tried to purge non-delete-marked record"
|
<< "tried to purge non-delete-marked record"
|
||||||
@ -365,15 +458,18 @@ row_purge_remove_sec_if_poss_tree(
|
|||||||
<< " of table " << index->table->name
|
<< " of table " << index->table->name
|
||||||
<< ": tuple: " << *entry
|
<< ": tuple: " << *entry
|
||||||
<< ", record: " << rec_index_print(
|
<< ", record: " << rec_index_print(
|
||||||
btr_cur_get_rec(btr_cur), index);
|
btr_cur_get_rec(
|
||||||
|
btr_pcur_get_btr_cur(&pcur)),
|
||||||
|
index);
|
||||||
|
|
||||||
ut_ad(0);
|
ut_ad(0);
|
||||||
|
|
||||||
goto func_exit;
|
goto func_exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
btr_cur_pessimistic_delete(&err, FALSE, btr_cur, 0,
|
btr_cur_pessimistic_delete(&err, FALSE,
|
||||||
false, &mtr);
|
btr_pcur_get_btr_cur(&pcur),
|
||||||
|
0, false, &mtr);
|
||||||
switch (UNIV_EXPECT(err, DB_SUCCESS)) {
|
switch (UNIV_EXPECT(err, DB_SUCCESS)) {
|
||||||
case DB_SUCCESS:
|
case DB_SUCCESS:
|
||||||
break;
|
break;
|
||||||
@ -385,6 +481,13 @@ row_purge_remove_sec_if_poss_tree(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (node->vcol_op_failed()) {
|
||||||
|
ut_ad(mtr.has_committed());
|
||||||
|
ut_ad(!pcur.old_rec_buf);
|
||||||
|
ut_ad(pcur.pos_state == BTR_PCUR_NOT_POSITIONED);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
func_exit:
|
func_exit:
|
||||||
btr_pcur_close(&pcur);
|
btr_pcur_close(&pcur);
|
||||||
func_exit_no_pcur:
|
func_exit_no_pcur:
|
||||||
@ -445,8 +548,10 @@ row_purge_remove_sec_if_poss_leaf(
|
|||||||
index->is_committed(). */
|
index->is_committed(). */
|
||||||
ut_ad(!dict_index_is_online_ddl(index));
|
ut_ad(!dict_index_is_online_ddl(index));
|
||||||
|
|
||||||
/* Change buffering is disabled for spatial index. */
|
/* Change buffering is disabled for spatial index and
|
||||||
mode = dict_index_is_spatial(index)
|
virtual index. */
|
||||||
|
mode = (dict_index_is_spatial(index)
|
||||||
|
|| dict_index_has_virtual(index))
|
||||||
? BTR_MODIFY_LEAF
|
? BTR_MODIFY_LEAF
|
||||||
: BTR_PURGE_LEAF;
|
: BTR_PURGE_LEAF;
|
||||||
}
|
}
|
||||||
@ -474,7 +579,7 @@ row_purge_remove_sec_if_poss_leaf(
|
|||||||
case ROW_FOUND:
|
case ROW_FOUND:
|
||||||
/* Before attempting to purge a record, check
|
/* Before attempting to purge a record, check
|
||||||
if it is safe to do so. */
|
if it is safe to do so. */
|
||||||
if (row_purge_poss_sec(node, index, entry)) {
|
if (row_purge_poss_sec(node, index, entry, &pcur, &mtr, false)) {
|
||||||
btr_cur_t* btr_cur = btr_pcur_get_btr_cur(&pcur);
|
btr_cur_t* btr_cur = btr_pcur_get_btr_cur(&pcur);
|
||||||
|
|
||||||
/* Only delete-marked records should be purged. */
|
/* Only delete-marked records should be purged. */
|
||||||
@ -540,6 +645,12 @@ row_purge_remove_sec_if_poss_leaf(
|
|||||||
success = false;
|
success = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (node->vcol_op_failed()) {
|
||||||
|
btr_pcur_close(&pcur);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/* (The index entry is still needed,
|
/* (The index entry is still needed,
|
||||||
or the deletion succeeded) */
|
or the deletion succeeded) */
|
||||||
/* fall through */
|
/* fall through */
|
||||||
@ -586,6 +697,10 @@ row_purge_remove_sec_if_poss(
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
retry:
|
retry:
|
||||||
|
if (node->vcol_op_failed()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
success = row_purge_remove_sec_if_poss_tree(node, index, entry);
|
success = row_purge_remove_sec_if_poss_tree(node, index, entry);
|
||||||
/* The delete operation may fail if we have little
|
/* The delete operation may fail if we have little
|
||||||
file space left: TODO: easiest to crash the database
|
file space left: TODO: easiest to crash the database
|
||||||
@ -652,6 +767,12 @@ row_purge_del_mark(
|
|||||||
node->row, NULL, node->index,
|
node->row, NULL, node->index,
|
||||||
heap, ROW_BUILD_FOR_PURGE);
|
heap, ROW_BUILD_FOR_PURGE);
|
||||||
row_purge_remove_sec_if_poss(node, node->index, entry);
|
row_purge_remove_sec_if_poss(node, node->index, entry);
|
||||||
|
|
||||||
|
if (node->vcol_op_failed()) {
|
||||||
|
mem_heap_free(heap);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
mem_heap_empty(heap);
|
mem_heap_empty(heap);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -667,11 +788,10 @@ row_purge_del_mark(
|
|||||||
whose old history can no longer be observed.
|
whose old history can no longer be observed.
|
||||||
@param[in,out] node purge node
|
@param[in,out] node purge node
|
||||||
@param[in,out] mtr mini-transaction (will be started and committed) */
|
@param[in,out] mtr mini-transaction (will be started and committed) */
|
||||||
static
|
static void row_purge_reset_trx_id(purge_node_t* node, mtr_t* mtr)
|
||||||
void
|
|
||||||
row_purge_reset_trx_id(purge_node_t* node, mtr_t* mtr)
|
|
||||||
{
|
{
|
||||||
ut_ad(rw_lock_own(dict_operation_lock, RW_LOCK_S));
|
ut_ad(rw_lock_own(dict_operation_lock, RW_LOCK_S)
|
||||||
|
|| node->vcol_info.used);
|
||||||
/* Reset DB_TRX_ID, DB_ROLL_PTR for old records. */
|
/* Reset DB_TRX_ID, DB_ROLL_PTR for old records. */
|
||||||
mtr->start();
|
mtr->start();
|
||||||
|
|
||||||
@ -746,7 +866,8 @@ row_purge_upd_exist_or_extern_func(
|
|||||||
{
|
{
|
||||||
mem_heap_t* heap;
|
mem_heap_t* heap;
|
||||||
|
|
||||||
ut_ad(rw_lock_own(dict_operation_lock, RW_LOCK_S));
|
ut_ad(rw_lock_own(dict_operation_lock, RW_LOCK_S)
|
||||||
|
|| node->vcol_info.used);
|
||||||
ut_ad(!node->table->skip_alter_undo);
|
ut_ad(!node->table->skip_alter_undo);
|
||||||
|
|
||||||
if (node->rec_type == TRX_UNDO_UPD_DEL_REC
|
if (node->rec_type == TRX_UNDO_UPD_DEL_REC
|
||||||
@ -1107,10 +1228,15 @@ row_purge(
|
|||||||
bool purged = row_purge_record(
|
bool purged = row_purge_record(
|
||||||
node, undo_rec, thr, updated_extern);
|
node, undo_rec, thr, updated_extern);
|
||||||
|
|
||||||
|
if (!node->vcol_info.used) {
|
||||||
rw_lock_s_unlock(dict_operation_lock);
|
rw_lock_s_unlock(dict_operation_lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
ut_ad(!rw_lock_own(dict_operation_lock, RW_LOCK_S));
|
||||||
|
|
||||||
if (purged
|
if (purged
|
||||||
|| srv_shutdown_state != SRV_SHUTDOWN_NONE) {
|
|| srv_shutdown_state != SRV_SHUTDOWN_NONE
|
||||||
|
|| node->vcol_op_failed()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1142,6 +1268,8 @@ row_purge_end(
|
|||||||
|
|
||||||
node->done = TRUE;
|
node->done = TRUE;
|
||||||
|
|
||||||
|
node->vcol_info.reset();
|
||||||
|
|
||||||
ut_a(thr->run_node != NULL);
|
ut_a(thr->run_node != NULL);
|
||||||
|
|
||||||
mem_heap_empty(node->heap);
|
mem_heap_empty(node->heap);
|
||||||
@ -1189,6 +1317,7 @@ row_purge_step(
|
|||||||
row_purge_end(thr);
|
row_purge_end(thr);
|
||||||
} else {
|
} else {
|
||||||
thr->run_node = node;
|
thr->run_node = node;
|
||||||
|
node->vcol_info.reset();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
row_purge_end(thr);
|
row_purge_end(thr);
|
||||||
|
@ -1757,6 +1757,8 @@ row_truncate_table_for_mysql(
|
|||||||
trx_set_dict_operation(trx, TRX_DICT_OP_TABLE);
|
trx_set_dict_operation(trx, TRX_DICT_OP_TABLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DEBUG_SYNC_C("row_trunc_before_dict_lock");
|
||||||
|
|
||||||
/* Step-3: Validate ownership of needed locks (Exclusive lock).
|
/* Step-3: Validate ownership of needed locks (Exclusive lock).
|
||||||
Ownership will also ensure there is no active SQL queries, INSERT,
|
Ownership will also ensure there is no active SQL queries, INSERT,
|
||||||
SELECT, .....*/
|
SELECT, .....*/
|
||||||
|
@ -543,7 +543,7 @@ row_undo_mod_del_mark_or_remove_sec_low(
|
|||||||
clustered index entry, because there is no MVCC or purge. */
|
clustered index entry, because there is no MVCC or purge. */
|
||||||
if (node->table->is_temporary()
|
if (node->table->is_temporary()
|
||||||
|| row_vers_old_has_index_entry(
|
|| row_vers_old_has_index_entry(
|
||||||
FALSE, btr_pcur_get_rec(&node->pcur),
|
false, btr_pcur_get_rec(&node->pcur),
|
||||||
&mtr_vers, index, entry, 0, 0)) {
|
&mtr_vers, index, entry, 0, 0)) {
|
||||||
err = btr_cur_del_mark_set_sec_rec(BTR_NO_LOCKING_FLAG,
|
err = btr_cur_del_mark_set_sec_rec(BTR_NO_LOCKING_FLAG,
|
||||||
btr_cur, TRUE, thr, &mtr);
|
btr_cur, TRUE, thr, &mtr);
|
||||||
|
@ -432,14 +432,16 @@ row_vers_impl_x_locked(
|
|||||||
@param[in,out] row the cluster index row in dtuple form
|
@param[in,out] row the cluster index row in dtuple form
|
||||||
@param[in] clust_index clustered index
|
@param[in] clust_index clustered index
|
||||||
@param[in] index the secondary index
|
@param[in] index the secondary index
|
||||||
@param[in] heap heap used to build virtual dtuple */
|
@param[in] heap heap used to build virtual dtuple
|
||||||
|
@param[in,out] vcol_info virtual column information. */
|
||||||
static
|
static
|
||||||
void
|
void
|
||||||
row_vers_build_clust_v_col(
|
row_vers_build_clust_v_col(
|
||||||
dtuple_t* row,
|
dtuple_t* row,
|
||||||
dict_index_t* clust_index,
|
dict_index_t* clust_index,
|
||||||
dict_index_t* index,
|
dict_index_t* index,
|
||||||
mem_heap_t* heap)
|
mem_heap_t* heap,
|
||||||
|
purge_vcol_info_t* vcol_info)
|
||||||
{
|
{
|
||||||
mem_heap_t* local_heap = NULL;
|
mem_heap_t* local_heap = NULL;
|
||||||
VCOL_STORAGE *vcol_storage= NULL;
|
VCOL_STORAGE *vcol_storage= NULL;
|
||||||
@ -449,12 +451,23 @@ row_vers_build_clust_v_col(
|
|||||||
|
|
||||||
ut_ad(dict_index_has_virtual(index));
|
ut_ad(dict_index_has_virtual(index));
|
||||||
|
|
||||||
|
if (vcol_info != NULL) {
|
||||||
|
vcol_info->set_used();
|
||||||
|
maria_table = vcol_info->mariadb_table;
|
||||||
|
}
|
||||||
|
|
||||||
innobase_allocate_row_for_vcol(thd, index,
|
innobase_allocate_row_for_vcol(thd, index,
|
||||||
&local_heap,
|
&local_heap,
|
||||||
&maria_table,
|
&maria_table,
|
||||||
&record,
|
&record,
|
||||||
&vcol_storage);
|
&vcol_storage);
|
||||||
|
|
||||||
|
if (vcol_info && !vcol_info->mariadb_table) {
|
||||||
|
vcol_info->mariadb_table = maria_table;
|
||||||
|
ut_ad(!maria_table || vcol_info->is_first_fetch());
|
||||||
|
goto func_exit;
|
||||||
|
}
|
||||||
|
|
||||||
for (ulint i = 0; i < dict_index_get_n_fields(index); i++) {
|
for (ulint i = 0; i < dict_index_get_n_fields(index); i++) {
|
||||||
const dict_field_t* ind_field = dict_index_get_nth_field(
|
const dict_field_t* ind_field = dict_index_get_nth_field(
|
||||||
index, i);
|
index, i);
|
||||||
@ -472,6 +485,7 @@ row_vers_build_clust_v_col(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func_exit:
|
||||||
if (local_heap) {
|
if (local_heap) {
|
||||||
if (vcol_storage)
|
if (vcol_storage)
|
||||||
innobase_free_row_for_vcol(vcol_storage);
|
innobase_free_row_for_vcol(vcol_storage);
|
||||||
@ -779,6 +793,7 @@ func_exit:
|
|||||||
@param[in,out] heap heap memory
|
@param[in,out] heap heap memory
|
||||||
@param[in,out] v_heap heap memory to keep virtual colum dtuple
|
@param[in,out] v_heap heap memory to keep virtual colum dtuple
|
||||||
@param[in] mtr mtr holding the latch on rec
|
@param[in] mtr mtr holding the latch on rec
|
||||||
|
@param[in,out] vcol_info virtual column information for purge thread
|
||||||
@return dtuple contains virtual column data */
|
@return dtuple contains virtual column data */
|
||||||
static
|
static
|
||||||
const dtuple_t*
|
const dtuple_t*
|
||||||
@ -792,7 +807,8 @@ row_vers_build_cur_vrow(
|
|||||||
trx_id_t trx_id,
|
trx_id_t trx_id,
|
||||||
mem_heap_t* heap,
|
mem_heap_t* heap,
|
||||||
mem_heap_t* v_heap,
|
mem_heap_t* v_heap,
|
||||||
mtr_t* mtr)
|
mtr_t* mtr,
|
||||||
|
purge_vcol_info_t* vcol_info)
|
||||||
{
|
{
|
||||||
const dtuple_t* cur_vrow = NULL;
|
const dtuple_t* cur_vrow = NULL;
|
||||||
|
|
||||||
@ -812,8 +828,17 @@ row_vers_build_cur_vrow(
|
|||||||
rec, *clust_offsets,
|
rec, *clust_offsets,
|
||||||
NULL, NULL, NULL, NULL, heap);
|
NULL, NULL, NULL, NULL, heap);
|
||||||
|
|
||||||
|
if (vcol_info && !vcol_info->used) {
|
||||||
|
mtr->commit();
|
||||||
|
}
|
||||||
|
|
||||||
row_vers_build_clust_v_col(
|
row_vers_build_clust_v_col(
|
||||||
row, clust_index, index, heap);
|
row, clust_index, index, heap, vcol_info);
|
||||||
|
|
||||||
|
if (vcol_info != NULL && vcol_info->is_first_fetch()) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
cur_vrow = dtuple_copy(row, v_heap);
|
cur_vrow = dtuple_copy(row, v_heap);
|
||||||
dtuple_dup_v_fld(cur_vrow, v_heap);
|
dtuple_dup_v_fld(cur_vrow, v_heap);
|
||||||
} else {
|
} else {
|
||||||
@ -828,27 +853,34 @@ row_vers_build_cur_vrow(
|
|||||||
return(cur_vrow);
|
return(cur_vrow);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*****************************************************************//**
|
/** Finds out if a version of the record, where the version >= the current
|
||||||
Finds out if a version of the record, where the version >= the current
|
|
||||||
purge view, should have ientry as its secondary index entry. We check
|
purge view, should have ientry as its secondary index entry. We check
|
||||||
if there is any not delete marked version of the record where the trx
|
if there is any not delete marked version of the record where the trx
|
||||||
id >= purge view, and the secondary index entry and ientry are identified in
|
id >= purge view, and the secondary index entry == ientry; exactly in
|
||||||
the alphabetical ordering; exactly in this case we return TRUE.
|
this case we return TRUE.
|
||||||
|
@param[in] also_curr TRUE if also rec is included in the versions
|
||||||
|
to search; otherwise only versions prior
|
||||||
|
to it are searched
|
||||||
|
@param[in] rec record in the clustered index; the caller
|
||||||
|
must have a latch on the page
|
||||||
|
@param[in] mtr mtr holding the latch on rec; it will
|
||||||
|
also hold the latch on purge_view
|
||||||
|
@param[in] index secondary index
|
||||||
|
@param[in] ientry secondary index entry
|
||||||
|
@param[in] roll_ptr roll_ptr for the purge record
|
||||||
|
@param[in] trx_id transaction ID on the purging record
|
||||||
|
@param[in,out] vcol_info virtual column information for purge thread.
|
||||||
@return TRUE if earlier version should have */
|
@return TRUE if earlier version should have */
|
||||||
ibool
|
bool
|
||||||
row_vers_old_has_index_entry(
|
row_vers_old_has_index_entry(
|
||||||
/*=========================*/
|
bool also_curr,
|
||||||
ibool also_curr,/*!< in: TRUE if also rec is included in the
|
const rec_t* rec,
|
||||||
versions to search; otherwise only versions
|
mtr_t* mtr,
|
||||||
prior to it are searched */
|
dict_index_t* index,
|
||||||
const rec_t* rec, /*!< in: record in the clustered index; the
|
const dtuple_t* ientry,
|
||||||
caller must have a latch on the page */
|
roll_ptr_t roll_ptr,
|
||||||
mtr_t* mtr, /*!< in: mtr holding the latch on rec; it will
|
trx_id_t trx_id,
|
||||||
also hold the latch on purge_view */
|
purge_vcol_info_t* vcol_info)
|
||||||
dict_index_t* index, /*!< in: the secondary index */
|
|
||||||
const dtuple_t* ientry, /*!< in: the secondary index entry */
|
|
||||||
roll_ptr_t roll_ptr,/*!< in: roll_ptr for the purge record */
|
|
||||||
trx_id_t trx_id) /*!< in: transaction ID on the purging record */
|
|
||||||
{
|
{
|
||||||
const rec_t* version;
|
const rec_t* version;
|
||||||
rec_t* prev_version;
|
rec_t* prev_version;
|
||||||
@ -916,8 +948,18 @@ row_vers_old_has_index_entry(
|
|||||||
columns need to be computed */
|
columns need to be computed */
|
||||||
if (trx_undo_roll_ptr_is_insert(t_roll_ptr)
|
if (trx_undo_roll_ptr_is_insert(t_roll_ptr)
|
||||||
|| dbug_v_purge) {
|
|| dbug_v_purge) {
|
||||||
|
|
||||||
|
if (vcol_info && !vcol_info->used) {
|
||||||
|
mtr->commit();
|
||||||
|
}
|
||||||
|
|
||||||
row_vers_build_clust_v_col(
|
row_vers_build_clust_v_col(
|
||||||
row, clust_index, index, heap);
|
row, clust_index, index, heap,
|
||||||
|
vcol_info);
|
||||||
|
|
||||||
|
if (vcol_info && vcol_info->is_first_fetch()) {
|
||||||
|
goto unsafe_to_purge;
|
||||||
|
}
|
||||||
|
|
||||||
entry = row_build_index_entry(
|
entry = row_build_index_entry(
|
||||||
row, ext, index, heap);
|
row, ext, index, heap);
|
||||||
@ -982,7 +1024,7 @@ safe_to_purge:
|
|||||||
if (v_heap) {
|
if (v_heap) {
|
||||||
mem_heap_free(v_heap);
|
mem_heap_free(v_heap);
|
||||||
}
|
}
|
||||||
return(TRUE);
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (dict_index_has_virtual(index)) {
|
} else if (dict_index_has_virtual(index)) {
|
||||||
@ -990,9 +1032,14 @@ safe_to_purge:
|
|||||||
deleted, but the previous version of it might not. We will
|
deleted, but the previous version of it might not. We will
|
||||||
need to get the virtual column data from undo record
|
need to get the virtual column data from undo record
|
||||||
associated with current cluster index */
|
associated with current cluster index */
|
||||||
|
|
||||||
cur_vrow = row_vers_build_cur_vrow(
|
cur_vrow = row_vers_build_cur_vrow(
|
||||||
also_curr, rec, clust_index, &clust_offsets,
|
also_curr, rec, clust_index, &clust_offsets,
|
||||||
index, roll_ptr, trx_id, heap, v_heap, mtr);
|
index, roll_ptr, trx_id, heap, v_heap, mtr, vcol_info);
|
||||||
|
|
||||||
|
if (vcol_info && vcol_info->is_first_fetch()) {
|
||||||
|
goto unsafe_to_purge;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
version = rec;
|
version = rec;
|
||||||
@ -1011,14 +1058,14 @@ safe_to_purge:
|
|||||||
|
|
||||||
if (!prev_version) {
|
if (!prev_version) {
|
||||||
/* Versions end here */
|
/* Versions end here */
|
||||||
|
unsafe_to_purge:
|
||||||
mem_heap_free(heap);
|
mem_heap_free(heap);
|
||||||
|
|
||||||
if (v_heap) {
|
if (v_heap) {
|
||||||
mem_heap_free(v_heap);
|
mem_heap_free(v_heap);
|
||||||
}
|
}
|
||||||
|
|
||||||
return(FALSE);
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
clust_offsets = rec_get_offsets(prev_version, clust_index,
|
clust_offsets = rec_get_offsets(prev_version, clust_index,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user