2014-02-26 19:11:54 +01:00
|
|
|
/*****************************************************************************
|
|
|
|
|
2016-06-21 14:21:03 +02:00
|
|
|
Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved.
|
2019-09-23 08:29:39 +03:00
|
|
|
Copyright (c) 2017, 2019, MariaDB Corporation.
|
2014-02-26 19:11:54 +01:00
|
|
|
|
|
|
|
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
|
|
|
|
Foundation; version 2 of the License.
|
|
|
|
|
|
|
|
This program is distributed in the hope that it will be useful, but WITHOUT
|
|
|
|
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
|
|
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License along with
|
|
|
|
this program; if not, write to the Free Software Foundation, Inc.,
|
2019-05-11 19:25:02 +03:00
|
|
|
51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA
|
2014-02-26 19:11:54 +01:00
|
|
|
|
|
|
|
*****************************************************************************/
|
|
|
|
|
|
|
|
/**************************************************//**
|
|
|
|
@file include/row0ins.h
|
|
|
|
Insert into a table
|
|
|
|
|
|
|
|
Created 4/20/1996 Heikki Tuuri
|
|
|
|
*******************************************************/
|
|
|
|
|
|
|
|
#ifndef row0ins_h
|
|
|
|
#define row0ins_h
|
|
|
|
|
|
|
|
#include "data0data.h"
|
|
|
|
#include "que0types.h"
|
|
|
|
#include "trx0types.h"
|
|
|
|
#include "row0types.h"
|
|
|
|
|
|
|
|
/***************************************************************//**
|
|
|
|
Checks if foreign key constraint fails for an index entry. Sets shared locks
|
|
|
|
which lock either the success or the failure of the constraint. NOTE that
|
|
|
|
the caller must have a shared latch on dict_foreign_key_check_lock.
|
|
|
|
@return DB_SUCCESS, DB_LOCK_WAIT, DB_NO_REFERENCED_ROW, or
|
|
|
|
DB_ROW_IS_REFERENCED */
|
|
|
|
dberr_t
|
|
|
|
row_ins_check_foreign_constraint(
|
|
|
|
/*=============================*/
|
|
|
|
ibool check_ref,/*!< in: TRUE If we want to check that
|
|
|
|
the referenced table is ok, FALSE if we
|
|
|
|
want to check the foreign key table */
|
|
|
|
dict_foreign_t* foreign,/*!< in: foreign constraint; NOTE that the
|
|
|
|
tables mentioned in it must be in the
|
|
|
|
dictionary cache if they exist at all */
|
|
|
|
dict_table_t* table, /*!< in: if check_ref is TRUE, then the foreign
|
|
|
|
table, else the referenced table */
|
|
|
|
dtuple_t* entry, /*!< in: index entry for index */
|
|
|
|
que_thr_t* thr) /*!< in: query thread */
|
2016-06-21 14:21:03 +02:00
|
|
|
MY_ATTRIBUTE((nonnull, warn_unused_result));
|
2014-02-26 19:11:54 +01:00
|
|
|
/*********************************************************************//**
|
|
|
|
Creates an insert node struct.
|
2016-08-12 11:17:45 +03:00
|
|
|
@return own: insert node struct */
|
2014-02-26 19:11:54 +01:00
|
|
|
ins_node_t*
|
|
|
|
ins_node_create(
|
|
|
|
/*============*/
|
|
|
|
ulint ins_type, /*!< in: INS_VALUES, ... */
|
|
|
|
dict_table_t* table, /*!< in: table where to insert */
|
|
|
|
mem_heap_t* heap); /*!< in: mem heap where created */
|
|
|
|
/*********************************************************************//**
|
|
|
|
Sets a new row to insert for an INS_DIRECT node. This function is only used
|
|
|
|
if we have constructed the row separately, which is a rare case; this
|
|
|
|
function is quite slow. */
|
|
|
|
void
|
|
|
|
ins_node_set_new_row(
|
|
|
|
/*=================*/
|
|
|
|
ins_node_t* node, /*!< in: insert node */
|
|
|
|
dtuple_t* row); /*!< in: new row (or first row) for the node */
|
|
|
|
/***************************************************************//**
|
|
|
|
Tries to insert an entry into a clustered index, ignoring foreign key
|
|
|
|
constraints. If a record with the same unique key is found, the other
|
|
|
|
record is necessarily marked deleted by a committed transaction, or a
|
|
|
|
unique key violation error occurs. The delete marked record is then
|
|
|
|
updated to an existing record, and we must write an undo log record on
|
|
|
|
the delete marked record.
|
|
|
|
@retval DB_SUCCESS on success
|
|
|
|
@retval DB_LOCK_WAIT on lock wait when !(flags & BTR_NO_LOCKING_FLAG)
|
|
|
|
@retval DB_FAIL if retry with BTR_MODIFY_TREE is needed
|
|
|
|
@return error code */
|
|
|
|
dberr_t
|
|
|
|
row_ins_clust_index_entry_low(
|
|
|
|
/*==========================*/
|
|
|
|
ulint flags, /*!< in: undo logging and locking flags */
|
|
|
|
ulint mode, /*!< in: BTR_MODIFY_LEAF or BTR_MODIFY_TREE,
|
|
|
|
depending on whether we wish optimistic or
|
|
|
|
pessimistic descent down the index tree */
|
|
|
|
dict_index_t* index, /*!< in: clustered index */
|
|
|
|
ulint n_uniq, /*!< in: 0 or index->n_uniq */
|
|
|
|
dtuple_t* entry, /*!< in/out: index entry to insert */
|
|
|
|
ulint n_ext, /*!< in: number of externally stored columns */
|
2019-09-23 08:29:39 +03:00
|
|
|
que_thr_t* thr) /*!< in: query thread or NULL */
|
2016-09-06 09:43:16 +03:00
|
|
|
MY_ATTRIBUTE((warn_unused_result));
|
2016-08-12 11:17:45 +03:00
|
|
|
|
2014-02-26 19:11:54 +01:00
|
|
|
/***************************************************************//**
|
|
|
|
Tries to insert an entry into a secondary index. If a record with exactly the
|
|
|
|
same fields is found, the other record is necessarily marked deleted.
|
|
|
|
It is then unmarked. Otherwise, the entry is just inserted to the index.
|
|
|
|
@retval DB_SUCCESS on success
|
|
|
|
@retval DB_LOCK_WAIT on lock wait when !(flags & BTR_NO_LOCKING_FLAG)
|
|
|
|
@retval DB_FAIL if retry with BTR_MODIFY_TREE is needed
|
|
|
|
@return error code */
|
|
|
|
dberr_t
|
|
|
|
row_ins_sec_index_entry_low(
|
|
|
|
/*========================*/
|
|
|
|
ulint flags, /*!< in: undo logging and locking flags */
|
|
|
|
ulint mode, /*!< in: BTR_MODIFY_LEAF or BTR_MODIFY_TREE,
|
|
|
|
depending on whether we wish optimistic or
|
|
|
|
pessimistic descent down the index tree */
|
|
|
|
dict_index_t* index, /*!< in: secondary index */
|
|
|
|
mem_heap_t* offsets_heap,
|
|
|
|
/*!< in/out: memory heap that can be emptied */
|
|
|
|
mem_heap_t* heap, /*!< in/out: memory heap */
|
|
|
|
dtuple_t* entry, /*!< in/out: index entry to insert */
|
|
|
|
trx_id_t trx_id, /*!< in: PAGE_MAX_TRX_ID during
|
|
|
|
row_log_table_apply(), or 0 */
|
2019-09-23 08:29:39 +03:00
|
|
|
que_thr_t* thr) /*!< in: query thread */
|
2016-09-06 09:43:16 +03:00
|
|
|
MY_ATTRIBUTE((warn_unused_result));
|
2016-08-12 11:17:45 +03:00
|
|
|
|
2014-02-26 19:11:54 +01:00
|
|
|
/***************************************************************//**
|
|
|
|
Inserts an entry into a clustered index. Tries first optimistic,
|
|
|
|
then pessimistic descent down the tree. If the entry matches enough
|
|
|
|
to a delete marked record, performs the insert by updating or delete
|
|
|
|
unmarking the delete marked record.
|
2016-08-12 11:17:45 +03:00
|
|
|
@return DB_SUCCESS, DB_LOCK_WAIT, DB_DUPLICATE_KEY, or some other error code */
|
2014-02-26 19:11:54 +01:00
|
|
|
dberr_t
|
|
|
|
row_ins_clust_index_entry(
|
|
|
|
/*======================*/
|
|
|
|
dict_index_t* index, /*!< in: clustered index */
|
|
|
|
dtuple_t* entry, /*!< in/out: index entry to insert */
|
|
|
|
que_thr_t* thr, /*!< in: query thread */
|
2019-09-23 08:29:39 +03:00
|
|
|
ulint n_ext) /*!< in: number of externally stored columns */
|
2016-09-06 09:43:16 +03:00
|
|
|
MY_ATTRIBUTE((warn_unused_result));
|
2014-02-26 19:11:54 +01:00
|
|
|
/***************************************************************//**
|
|
|
|
Inserts an entry into a secondary index. Tries first optimistic,
|
|
|
|
then pessimistic descent down the tree. If the entry matches enough
|
|
|
|
to a delete marked record, performs the insert by updating or delete
|
|
|
|
unmarking the delete marked record.
|
2016-08-12 11:17:45 +03:00
|
|
|
@return DB_SUCCESS, DB_LOCK_WAIT, DB_DUPLICATE_KEY, or some other error code */
|
2014-02-26 19:11:54 +01:00
|
|
|
dberr_t
|
|
|
|
row_ins_sec_index_entry(
|
|
|
|
/*====================*/
|
|
|
|
dict_index_t* index, /*!< in: secondary index */
|
|
|
|
dtuple_t* entry, /*!< in/out: index entry to insert */
|
2018-05-30 13:19:03 +03:00
|
|
|
que_thr_t* thr, /*!< in: query thread */
|
|
|
|
bool check_ref) /*!< in: TRUE if we want to check that
|
|
|
|
the referenced table is ok, FALSE if we
|
|
|
|
want to check the foreign key table */
|
2016-09-06 09:43:16 +03:00
|
|
|
MY_ATTRIBUTE((warn_unused_result));
|
2014-02-26 19:11:54 +01:00
|
|
|
/***********************************************************//**
|
|
|
|
Inserts a row to a table. This is a high-level function used in
|
|
|
|
SQL execution graphs.
|
2016-08-12 11:17:45 +03:00
|
|
|
@return query thread to run next or NULL */
|
2014-02-26 19:11:54 +01:00
|
|
|
que_thr_t*
|
|
|
|
row_ins_step(
|
|
|
|
/*=========*/
|
|
|
|
que_thr_t* thr); /*!< in: query thread */
|
|
|
|
|
|
|
|
/* Insert node structure */
|
|
|
|
|
|
|
|
struct ins_node_t{
|
|
|
|
que_common_t common; /*!< node type: QUE_NODE_INSERT */
|
|
|
|
ulint ins_type;/* INS_VALUES, INS_SEARCHED, or INS_DIRECT */
|
|
|
|
dtuple_t* row; /*!< row to insert */
|
|
|
|
dict_table_t* table; /*!< table where to insert */
|
|
|
|
sel_node_t* select; /*!< select in searched insert */
|
|
|
|
que_node_t* values_list;/* list of expressions to evaluate and
|
|
|
|
insert in an INS_VALUES insert */
|
|
|
|
ulint state; /*!< node execution state */
|
|
|
|
dict_index_t* index; /*!< NULL, or the next index where the index
|
|
|
|
entry should be inserted */
|
|
|
|
dtuple_t* entry; /*!< NULL, or entry to insert in the index;
|
|
|
|
after a successful insert of the entry,
|
|
|
|
this should be reset to NULL */
|
|
|
|
UT_LIST_BASE_NODE_T(dtuple_t)
|
|
|
|
entry_list;/* list of entries, one for each index */
|
MDEV-14407 Assertion failure during rollback
Rollback attempted to dereference DB_ROLL_PTR=0, which cannot possibly
be a valid undo log pointer. A safer canonical value would be
roll_ptr_t(1) << ROLL_PTR_INSERT_FLAG_POS
which is what was chosen in MDEV-12288, corresponding to reset_trx_id.
No deterministic test case for the bug was found. The simplest test
cases may be related to MDEV-11415, which suppresses undo logging for
ALGORITHM=COPY operations. In those operations, in the spirit of
MDEV-12288, we should actually have written reset_trx_id instead of
using the transaction identifier of the current transaction
(and a bogus value of DB_ROLL_PTR=0). However, thanks to MySQL Bug#28432
which I had fixed in MySQL 5.6.8 as part of WL#6255, access to the
rebuilt table by earlier-started transactions should actually have been
refused with ER_TABLE_DEF_CHANGED.
reset_trx_id: Move the definition to data0type.cc and the declaration
to data0type.h.
btr_cur_ins_lock_and_undo(): When undo logging is disabled, use the
safe value that corresponds to reset_trx_id.
btr_cur_optimistic_insert(): Validate the DB_TRX_ID,DB_ROLL_PTR before
inserting into a clustered index leaf page.
ins_node_t::sys_buf[]: Replaces row_id_buf and trx_id_buf and some
heap usage.
row_ins_alloc_sys_fields(): Init ins_node_t::sys_buf[] to reset_trx_id.
row_ins_buf(): Only if undo logging is enabled, copy trx->id
to node->sys_buf. Otherwise, rely on the initialization in
row_ins_alloc_sys_fields().
row_purge_reset_trx_id(): Invoke mlog_write_string() with reset_trx_id
directly. (No functional change.)
trx_undo_page_report_modify(): Assert that the DB_ROLL_PTR is not 0.
trx_undo_get_undo_rec_low(): Assert that the roll_ptr is valid before
trying to dereference it.
dict_index_t::is_primary(): Check if the index is the primary key.
PageConverter::adjust_cluster_record(): Fix
MDEV-15249 Crash in MVCC read after IMPORT TABLESPACE
by resetting the system fields to reset_trx_id instead of writing
the current transaction ID (which will be committed at the
end of the IMPORT TABLESPACE) and DB_ROLL_PTR=0.
This can partially be viewed as a follow-up fix of MDEV-12288,
because IMPORT should already then have written
DB_TRX_ID=0 and DB_ROLL_PTR=1<<55 to prevent unnecessary
DB_TRX_ID lookups in subsequent accesses to the table.
2018-02-07 16:44:46 +02:00
|
|
|
/** buffer for the system columns */
|
|
|
|
byte sys_buf[DATA_ROW_ID_LEN
|
|
|
|
+ DATA_TRX_ID_LEN + DATA_ROLL_PTR_LEN];
|
2014-02-26 19:11:54 +01:00
|
|
|
trx_id_t trx_id; /*!< trx id or the last trx which executed the
|
|
|
|
node */
|
2017-11-20 15:22:07 +03:00
|
|
|
byte vers_start_buf[8]; /* Buffers for System Versioning */
|
|
|
|
byte vers_end_buf[8]; /* system fields. */
|
2014-02-26 19:11:54 +01:00
|
|
|
mem_heap_t* entry_sys_heap;
|
|
|
|
/* memory heap used as auxiliary storage;
|
|
|
|
entry_list and sys fields are stored here;
|
|
|
|
if this is NULL, entry list should be created
|
|
|
|
and buffers for sys fields in row allocated */
|
|
|
|
ulint magic_n;
|
|
|
|
};
|
|
|
|
|
|
|
|
#define INS_NODE_MAGIC_N 15849075
|
|
|
|
|
|
|
|
/* Insert node types */
|
|
|
|
#define INS_SEARCHED 0 /* INSERT INTO ... SELECT ... */
|
|
|
|
#define INS_VALUES 1 /* INSERT INTO ... VALUES ... */
|
|
|
|
#define INS_DIRECT 2 /* this is for internal use in dict0crea:
|
|
|
|
insert the row directly */
|
|
|
|
|
|
|
|
/* Node execution states */
|
|
|
|
#define INS_NODE_SET_IX_LOCK 1 /* we should set an IX lock on table */
|
|
|
|
#define INS_NODE_ALLOC_ROW_ID 2 /* row id should be allocated */
|
|
|
|
#define INS_NODE_INSERT_ENTRIES 3 /* index entries should be built and
|
|
|
|
inserted */
|
|
|
|
#endif
|