1
1
/*****************************************************************************
3
Copyright (C) 1996, 2010, Innobase Oy. All Rights Reserved.
3
Copyright (c) 1996, 2009, Innobase Oy. All Rights Reserved.
5
5
This program is free software; you can redistribute it and/or modify it under
6
6
the terms of the GNU General Public License as published by the Free Software
92
92
searched delete is obviously to keep the x-latch for several
93
93
steps of query graph execution. */
95
/*************************************************************************
96
IMPORTANT NOTE: Any operation that generates redo MUST check that there
97
is enough space in the redo log before for that operation. This is
98
done by calling log_free_check(). The reason for checking the
99
availability of the redo log space before the start of the operation is
100
that we MUST not hold any synchonization objects when performing the
102
If you make a change in this module make sure that no codepath is
103
introduced where a call to log_free_check() is bypassed. */
105
/*************************************************************************
106
IMPORTANT NOTE: Any operation that generates redo MUST check that there
107
is enough space in the redo log before for that operation. This is
108
done by calling log_free_check(). The reason for checking the
109
availability of the redo log space before the start of the operation is
110
that we MUST not hold any synchonization objects when performing the
112
If you make a change in this module make sure that no codepath is
113
introduced where a call to log_free_check() is bypassed. */
115
95
/***********************************************************//**
116
96
Checks if an update vector changes some of the first ordering fields of an
117
97
index record. This is only used in foreign key checks and we can assume
314
294
upd_node_t* node;
316
node = static_cast<upd_node_t *>(mem_heap_alloc(heap, sizeof(upd_node_t)));
296
node = mem_heap_alloc(heap, sizeof(upd_node_t));
317
297
node->common.type = QUE_NODE_UPDATE;
319
299
node->state = UPD_NODE_UPDATE_CLUSTERED;
382
362
row_upd_index_entry_sys_field(
383
363
/*==========================*/
384
dtuple_t* entry, /*!< in/out: index entry, where the memory
385
buffers for sys fields are already allocated:
364
const dtuple_t* entry, /*!< in: index entry, where the memory buffers
365
for sys fields are already allocated:
386
366
the function just copies the new values to
388
368
dict_index_t* index, /*!< in: clustered index */
389
369
ulint type, /*!< in: DATA_TRX_ID or DATA_ROLL_PTR */
390
ib_uint64_t val) /*!< in: value to write */
370
dulint val) /*!< in: value to write */
392
372
dfield_t* dfield;
398
378
pos = dict_index_get_sys_col_pos(index, type);
400
380
dfield = dtuple_get_nth_field(entry, pos);
401
field = static_cast<byte *>(dfield_get_data(dfield));
381
field = dfield_get_data(dfield);
403
383
if (type == DATA_TRX_ID) {
404
384
trx_write_trx_id(field, val);
476
456
#endif /* !UNIV_HOTBACKUP */
478
458
/***********************************************************//**
479
Replaces the new column values stored in the update vector to the
480
record given. No field size changes are allowed. This function is
481
usually invoked on a clustered index. The only use case for a
482
secondary index is row_ins_sec_index_entry_by_modify() or its
483
counterpart in ibuf_insert_to_index_page(). */
459
Replaces the new column values stored in the update vector to the record
460
given. No field size changes are allowed. */
486
463
row_upd_rec_in_place(
537
514
roll_ptr_t roll_ptr,/*!< in: roll ptr of the undo log record */
538
515
byte* log_ptr,/*!< pointer to a buffer of size > 20 opened
540
mtr_t* /*mtr __attribute__((unused))*/) /*!< in: mtr */
517
mtr_t* mtr __attribute__((unused))) /*!< in: mtr */
542
519
ut_ad(dict_index_is_clust(index));
549
526
trx_write_roll_ptr(log_ptr, roll_ptr);
550
527
log_ptr += DATA_ROLL_PTR_LEN;
552
log_ptr += mach_ull_write_compressed(log_ptr, trx->id);
529
log_ptr += mach_dulint_write_compressed(log_ptr, trx->id);
583
560
*roll_ptr = trx_read_roll_ptr(ptr);
584
561
ptr += DATA_ROLL_PTR_LEN;
586
ptr = mach_ull_parse_compressed(ptr, end_ptr, trx_id);
563
ptr = mach_dulint_parse_compressed(ptr, end_ptr, trx_id);
648
625
mlog_close(mtr, log_ptr);
650
627
mlog_catenate_string(mtr,
651
static_cast<byte *>(dfield_get_data(new_val)),
628
dfield_get_data(new_val),
654
631
log_ptr = mlog_open(mtr, MLOG_BUF_MARGIN);
907
884
out: fetched length of the prefix */
908
885
mem_heap_t* heap) /*!< in: heap where to allocate */
910
byte* buf = static_cast<byte *>(mem_heap_alloc(heap, *len));
887
byte* buf = mem_heap_alloc(heap, *len);
912
889
*len = btr_copy_externally_stored_field_prefix(buf, *len,
947
924
len = dfield_get_len(dfield);
948
data = static_cast<const byte *>(dfield_get_data(dfield));
925
data = dfield_get_data(dfield);
950
927
if (field->prefix_len > 0) {
951
928
ibool fetch_ext = dfield_is_ext(dfield)
996
973
stored part of the column. The data
997
974
will have to be copied. */
998
975
ut_a(uf->orig_len > BTR_EXTERN_FIELD_REF_SIZE);
999
buf = static_cast<byte *>(mem_heap_alloc(heap, uf->orig_len));
976
buf = mem_heap_alloc(heap, uf->orig_len);
1000
977
/* Copy the locally stored prefix. */
1001
978
memcpy(buf, data,
1002
979
uf->orig_len - BTR_EXTERN_FIELD_REF_SIZE);
1146
1123
table = index->table;
1147
1124
ut_ad(n_cols == dict_table_get_n_cols(table));
1149
ext_cols = static_cast<ulint *>(mem_heap_alloc(heap, n_cols * sizeof *ext_cols));
1126
ext_cols = mem_heap_alloc(heap, n_cols * sizeof *ext_cols);
1150
1127
n_ext_cols = 0;
1152
1129
dtuple_set_info_bits(row, update->info_bits);
1429
1405
offsets = rec_get_offsets(rec, clust_index, offsets_,
1430
1406
ULINT_UNDEFINED, &heap);
1432
if (dict_table_get_format(node->table) >= DICT_TF_FORMAT_ZIP) {
1433
/* In DYNAMIC or COMPRESSED format, there is no prefix
1434
of externally stored columns in the clustered index
1435
record. Build a cache of column prefixes. */
1438
/* REDUNDANT and COMPACT formats store a local
1439
768-byte prefix of each externally stored column.
1440
No cache is needed. */
1445
1407
node->row = row_build(ROW_COPY_DATA, clust_index, rec, offsets,
1446
NULL, ext, node->heap);
1408
NULL, &node->ext, node->heap);
1447
1409
if (node->is_delete) {
1448
1410
node->upd_row = NULL;
1449
1411
node->upd_ext = NULL;
1469
1431
upd_node_t* node, /*!< in: row update node */
1470
1432
que_thr_t* thr) /*!< in: query thread */
1477
dict_index_t* index;
1480
ulint err = DB_SUCCESS;
1481
trx_t* trx = thr_get_trx(thr);
1482
ulint mode = BTR_MODIFY_LEAF;
1483
enum row_search_result search_result;
1436
dict_index_t* index;
1442
ulint err = DB_SUCCESS;
1444
trx_t* trx = thr_get_trx(thr);
1485
1446
index = node->index;
1487
referenced = row_upd_index_is_referenced(index, trx);
1448
check_ref = row_upd_index_is_referenced(index, trx);
1489
1450
heap = mem_heap_create(1024);
1492
1453
entry = row_build_index_entry(node->row, node->ext, index, heap);
1495
1457
mtr_start(&mtr);
1497
/* Set the query thread, so that ibuf_insert_low() will be
1498
able to invoke thd_get_trx(). */
1499
btr_pcur_get_btr_cur(&pcur)->thr = thr;
1501
/* We can only try to use the insert/delete buffer to buffer
1502
delete-mark operations if the index we're modifying has no foreign
1503
key constraints referring to it. */
1505
mode |= BTR_DELETE_MARK;
1508
search_result = row_search_index_entry(index, entry, mode,
1459
found = row_search_index_entry(index, entry, BTR_MODIFY_LEAF, &pcur,
1511
1461
btr_cur = btr_pcur_get_btr_cur(&pcur);
1513
1463
rec = btr_cur_get_rec(btr_cur);
1515
switch (search_result) {
1516
case ROW_NOT_DELETED_REF: /* should only occur for BTR_DELETE */
1520
/* Entry was delete marked already. */
1465
if (UNIV_UNLIKELY(!found)) {
1524
1466
fputs("InnoDB: error in sec index entry update in\n"
1525
1467
"InnoDB: ", stderr);
1526
1468
dict_index_name_print(stderr, trx, index);
1538
1480
"InnoDB: Submit a detailed bug report"
1539
1481
" to http://bugs.mysql.com\n", stderr);
1542
1483
/* Delete mark the old index record; it can already be
1543
1484
delete marked if we return after a lock wait in
1544
1485
row_ins_index_entry below */
1546
if (!rec_get_deleted_flag(
1547
rec, dict_table_is_comp(index->table))) {
1549
err = btr_cur_del_mark_set_sec_rec(
1550
0, btr_cur, TRUE, thr, &mtr);
1552
if (err == DB_SUCCESS && referenced) {
1556
offsets = rec_get_offsets(
1557
rec, index, NULL, ULINT_UNDEFINED,
1487
if (!rec_get_deleted_flag(rec,
1488
dict_table_is_comp(index->table))) {
1489
err = btr_cur_del_mark_set_sec_rec(0, btr_cur, TRUE,
1491
if (err == DB_SUCCESS && check_ref) {
1493
ulint* offsets = rec_get_offsets(
1495
ULINT_UNDEFINED, &heap);
1560
1496
/* NOTE that the following call loses
1561
1497
the position of pcur ! */
1562
1498
err = row_upd_check_references_constraints(
1626
1561
row_upd_clust_rec_by_insert(
1627
1562
/*========================*/
1628
upd_node_t* node, /*!< in/out: row update node */
1563
upd_node_t* node, /*!< in: row update node */
1629
1564
dict_index_t* index, /*!< in: clustered index of the record */
1630
1565
que_thr_t* thr, /*!< in: query thread */
1631
ibool referenced,/*!< in: TRUE if index may be referenced in
1566
ibool check_ref,/*!< in: TRUE if index may be referenced in
1632
1567
a foreign key constraint */
1633
mtr_t* mtr) /*!< in/out: mtr; gets committed here */
1568
mtr_t* mtr) /*!< in: mtr; gets committed here */
1635
1570
mem_heap_t* heap = NULL;
1636
1571
btr_pcur_t* pcur;
1669
1603
record is removed from the index tree, or updated. */
1671
1605
rec = btr_cur_get_rec(btr_cur);
1672
node_index = dict_table_get_first_index(table);
1673
offsets = rec_get_offsets(rec, node_index, offsets_,
1606
index = dict_table_get_first_index(table);
1607
offsets = rec_get_offsets(rec, index, offsets_,
1674
1608
ULINT_UNDEFINED, &heap);
1675
change_ownership = btr_cur_mark_extern_inherited_fields(
1676
btr_cur_get_page_zip(btr_cur), rec, node_index, offsets,
1609
btr_cur_mark_extern_inherited_fields(
1610
btr_cur_get_page_zip(btr_cur),
1611
rec, index, offsets, node->update, mtr);
1679
1613
/* NOTE that the following call loses
1680
1614
the position of pcur ! */
1682
1615
err = row_upd_check_references_constraints(
1683
node, pcur, table, node_index, offsets, thr, mtr);
1616
node, pcur, table, index, offsets, thr, mtr);
1685
1617
if (err != DB_SUCCESS) {
1687
1618
mtr_commit(mtr);
1689
1619
if (UNIV_LIKELY_NULL(heap)) {
1690
1620
mem_heap_free(heap);
1709
1638
row_upd_index_entry_sys_field(entry, index, DATA_TRX_ID, trx->id);
1711
if (change_ownership) {
1640
if (node->upd_ext) {
1712
1641
/* If we return from a lock wait, for example, we may have
1713
1642
extern fields marked as not-owned in entry (marked in the
1714
if-branch above). We must unmark them, take the ownership
1643
if-branch above). We must unmark them. */
1717
1645
btr_cur_unmark_dtuple_extern_fields(entry);
1845
1773
ulint* offsets,/*!< in/out: rec_get_offsets() for the
1846
1774
record under the cursor */
1847
1775
que_thr_t* thr, /*!< in: query thread */
1849
/*!< in: TRUE if index may be referenced in
1776
ibool check_ref,/*!< in: TRUE if index may be referenced in
1850
1777
a foreign key constraint */
1851
1778
mtr_t* mtr) /*!< in: mtr; gets committed here */
1872
1799
err = btr_cur_del_mark_set_clust_rec(BTR_NO_LOCKING_FLAG,
1873
1800
btr_cur, TRUE, thr, mtr);
1874
if (err == DB_SUCCESS && referenced) {
1801
if (err == DB_SUCCESS && check_ref) {
1875
1802
/* NOTE that the following call loses the position of pcur ! */
1877
err = row_upd_check_references_constraints(
1878
node, pcur, index->table, index, offsets, thr, mtr);
1804
err = row_upd_check_references_constraints(node,
1881
1810
mtr_commit(mtr);
1904
1834
mem_heap_t* heap = NULL;
1905
1835
ulint offsets_[REC_OFFS_NORMAL_SIZE];
1906
1836
ulint* offsets;
1908
1837
rec_offs_init(offsets_);
1910
1839
index = dict_table_get_first_index(node->table);
1912
referenced = row_upd_index_is_referenced(index, thr_get_trx(thr));
1841
check_ref = row_upd_index_is_referenced(index, thr_get_trx(thr));
1914
1843
pcur = node->pcur;
1942
1871
then we have to free the file segments of the index tree associated
1943
1872
with the index */
1945
if (node->is_delete && node->table->id == DICT_INDEXES_ID) {
1875
&& ut_dulint_cmp(node->table->id, DICT_INDEXES_ID) == 0) {
1947
1877
dict_drop_index_tree(btr_pcur_get_rec(pcur), mtr);
1978
1908
/* NOTE: the following function calls will also commit mtr */
1980
1910
if (node->is_delete) {
1981
err = row_upd_del_mark_clust_rec(
1982
node, index, offsets, thr, referenced, mtr);
1911
err = row_upd_del_mark_clust_rec(node, index, offsets,
1912
thr, check_ref, mtr);
1984
1913
if (err == DB_SUCCESS) {
1985
1914
node->state = UPD_NODE_UPDATE_ALL_SEC;
1986
1915
node->index = dict_table_get_next_index(index);
2028
1957
choosing records to update. MySQL solves now the problem
2031
err = row_upd_clust_rec_by_insert(
2032
node, index, thr, referenced, mtr);
1960
err = row_upd_clust_rec_by_insert(node, index, thr, check_ref,
2034
1962
if (err != DB_SUCCESS) {