3903 Marko Mäkelä 2012-05-30
WL#6255 refactoring.
row_ins_duplicate_error_in_clust(): In online table rebuild,
if the PRIMARY KEY,DB_TRX_ID,DB_ROLL_PTR match with the record,
return the special status code DB_SUCCESS_LOCKED_REC.
row_log_table_apply_insert_low(): If the record already existed
in the clustered index, return DB_SUCCESS.
modified:
storage/innobase/row/row0ins.cc
storage/innobase/row/row0log.cc
3902 Marko Mäkelä 2012-05-30
WL#6255 refactoring of record comparison.
cmp_dtuple_rec_with_match_low(): Renamed from cmp_dtuple_rec_with_match().
Add the parameter n_cmp, to override dtuple->n_fields_cmp.
cmp_dtuple_rec_with_match(): A macro wrapper for the above.
cmp_debug_dtuple_rec_with_match(): Add the parameter n_cmp.
modified:
storage/innobase/include/rem0cmp.h
storage/innobase/rem/rem0cmp.cc
3901 Marko Mäkelä 2012-05-30
WL#6255 bug fix.
row_tab_op: Use more distinguishable values for the operation codes,
so that it is easier to inspect the buffered data.
row_log_table_apply_op(): Fix a bug in ROW_T_UPDATE parsing when
the definition of the PRIMARY KEY is changed.
modified:
storage/innobase/row/row0log.cc
=== modified file 'storage/innobase/include/rem0cmp.h'
--- a/storage/innobase/include/rem0cmp.h revid:marko.makela@strippedqv1f9
+++ b/storage/innobase/include/rem0cmp.h revid:marko.makela@stripped
@@ -156,21 +156,28 @@ respectively, when only the common first
the first externally stored field in rec */
UNIV_INTERN
int
-cmp_dtuple_rec_with_match(
-/*======================*/
+cmp_dtuple_rec_with_match_low(
+/*==========================*/
const dtuple_t* dtuple, /*!< in: data tuple */
const rec_t* rec, /*!< in: physical record which differs from
dtuple in some of the common fields, or which
has an equal number or more fields than
dtuple */
const ulint* offsets,/*!< in: array returned by rec_get_offsets() */
- ulint* matched_fields, /*!< in/out: number of already completely
+ ulint n_cmp, /*!< in: number of fields to compare */
+ ulint* matched_fields,
+ /*!< in/out: number of already completely
matched fields; when function returns,
contains the value for current comparison */
- ulint* matched_bytes); /*!< in/out: number of already matched
+ ulint* matched_bytes)
+ /*!< in/out: number of already matched
bytes within the first field not completely
matched; when function returns, contains the
value for current comparison */
+ __attribute__((nonnull));
+#define cmp_dtuple_rec_with_match(tuple,rec,offsets,fields,bytes) \
+ cmp_dtuple_rec_with_match_low( \
+ tuple,rec,offsets,dtuple_get_n_fields_cmp(tuple),fields,bytes)
/**************************************************************//**
Compares a data tuple to a physical record.
@see cmp_dtuple_rec_with_match
=== modified file 'storage/innobase/rem/rem0cmp.cc'
--- a/storage/innobase/rem/rem0cmp.cc revid:marko.makela@stripped9
+++ b/storage/innobase/rem/rem0cmp.cc revid:marko.makela@stripped
@@ -70,10 +70,12 @@ cmp_debug_dtuple_rec_with_match(
has an equal number or more fields than
dtuple */
const ulint* offsets,/*!< in: array returned by rec_get_offsets() */
- ulint* matched_fields);/*!< in/out: number of already
+ ulint n_cmp, /*!< in: number of fields to compare */
+ ulint* matched_fields)/*!< in/out: number of already
completely matched fields; when function
returns, contains the value for current
comparison */
+ __attribute__((nonnull, warn_unused_result));
#endif /* UNIV_DEBUG */
/*************************************************************//**
This function is used to compare two data fields for which the data type
@@ -622,14 +624,15 @@ respectively, when only the common first
the first externally stored field in rec */
UNIV_INTERN
int
-cmp_dtuple_rec_with_match(
-/*======================*/
+cmp_dtuple_rec_with_match_low(
+/*==========================*/
const dtuple_t* dtuple, /*!< in: data tuple */
const rec_t* rec, /*!< in: physical record which differs from
dtuple in some of the common fields, or which
has an equal number or more fields than
dtuple */
const ulint* offsets,/*!< in: array returned by rec_get_offsets() */
+ ulint n_cmp, /*!< in: number of fields to compare */
ulint* matched_fields, /*!< in/out: number of already completely
matched fields; when function returns,
contains the value for current comparison */
@@ -653,7 +656,7 @@ cmp_dtuple_rec_with_match(
ulint cur_field; /* current field number */
ulint cur_bytes; /* number of already matched bytes
in current field */
- int ret = 3333; /* return value */
+ int ret; /* return value */
ut_ad(dtuple && rec && matched_fields && matched_bytes);
ut_ad(dtuple_check_typed(dtuple));
@@ -662,7 +665,9 @@ cmp_dtuple_rec_with_match(
cur_field = *matched_fields;
cur_bytes = *matched_bytes;
- ut_ad(cur_field <= dtuple_get_n_fields_cmp(dtuple));
+ ut_ad(n_cmp > 0);
+ ut_ad(n_cmp <= dtuple_get_n_fields(dtuple));
+ ut_ad(cur_field <= n_cmp);
ut_ad(cur_field <= rec_offs_n_fields(offsets));
if (cur_bytes == 0 && cur_field == 0) {
@@ -682,7 +687,7 @@ cmp_dtuple_rec_with_match(
/* Match fields in a loop; stop if we run out of fields in dtuple
or find an externally stored field */
- while (cur_field < dtuple_get_n_fields_cmp(dtuple)) {
+ while (cur_field < n_cmp) {
ulint mtype;
ulint prtype;
@@ -839,7 +844,7 @@ next_field:
order_resolved:
ut_ad((ret >= - 1) && (ret <= 1));
ut_ad(ret == cmp_debug_dtuple_rec_with_match(dtuple, rec, offsets,
- matched_fields));
+ n_cmp, matched_fields));
ut_ad(*matched_fields == cur_field); /* In the debug version, the
above cmp_debug_... sets
*matched_fields to a value */
@@ -1352,6 +1357,7 @@ cmp_debug_dtuple_rec_with_match(
has an equal number or more fields than
dtuple */
const ulint* offsets,/*!< in: array returned by rec_get_offsets() */
+ ulint n_cmp, /*!< in: number of fields to compare */
ulint* matched_fields) /*!< in/out: number of already
completely matched fields; when function
returns, contains the value for current
@@ -1364,14 +1370,16 @@ cmp_debug_dtuple_rec_with_match(
field data */
ulint rec_f_len; /* length of current field in rec */
const byte* rec_f_data; /* pointer to the current rec field */
- int ret = 3333; /* return value */
+ int ret; /* return value */
ulint cur_field; /* current field number */
ut_ad(dtuple && rec && matched_fields);
ut_ad(dtuple_check_typed(dtuple));
ut_ad(rec_offs_validate(rec, NULL, offsets));
- ut_ad(*matched_fields <= dtuple_get_n_fields_cmp(dtuple));
+ ut_ad(n_cmp > 0);
+ ut_ad(n_cmp <= dtuple_get_n_fields(dtuple));
+ ut_ad(*matched_fields <= n_cmp);
ut_ad(*matched_fields <= rec_offs_n_fields(offsets));
cur_field = *matched_fields;
@@ -1397,7 +1405,7 @@ cmp_debug_dtuple_rec_with_match(
/* Match fields in a loop; stop if we run out of fields in dtuple */
- while (cur_field < dtuple_get_n_fields_cmp(dtuple)) {
+ while (cur_field < n_cmp) {
ulint mtype;
ulint prtype;
=== modified file 'storage/innobase/row/row0ins.cc'
--- a/storage/innobase/row/row0ins.cc revid:marko.makela@oracle.com-20120530065248-5e3vm24c9d5qv1f9
+++ b/storage/innobase/row/row0ins.cc revid:marko.makela@stripped120530082121-5klorcbaz3z1zuin
@@ -1951,9 +1951,12 @@ end_scan:
Checks if a unique key violation error would occur at an index entry
insert. Sets shared locks on possible duplicate records. Works only
for a clustered index!
-@return DB_SUCCESS if no error, DB_DUPLICATE_KEY if error,
-DB_LOCK_WAIT if we have to wait for a lock on a possible duplicate
-record */
+@retval DB_SUCCESS if no error
+@retval DB_DUPLICATE_KEY if error,
+@retval DB_LOCK_WAIT if we have to wait for a lock on a possible duplicate
+record
+@retval DB_SUCCESS_LOCKED_REC if an exact match of the record was found
+in online table rebuild (flags & (BTR_KEEP_SYS_FLAG | BTR_NO_LOCKING_FLAG)) */
static __attribute__((nonnull, warn_unused_result))
dberr_t
row_ins_duplicate_error_in_clust(
@@ -2037,8 +2040,43 @@ row_ins_duplicate_error_in_clust(
goto func_exit;
}
- if (row_ins_dupl_error_with_rec(
- rec, entry, cursor->index, offsets)) {
+ if (flags
+ & (BTR_KEEP_SYS_FLAG | BTR_NO_LOCKING_FLAG)) {
+ /* We are inserting into the rebuilt table.
+ See if this is a real duplicate, or an
+ exact match of a previous insert. */
+ ulint fields = 0;
+ ulint bytes = 0;
+
+ /* During rebuild, there should not be any
+ delete-marked rows in the new table. */
+ ut_ad(!rec_get_deleted_flag(
+ rec, rec_offs_comp(offsets)));
+ ut_ad(dtuple_get_n_fields_cmp(entry)
+ == n_unique);
+
+ /* Compare the PRIMARY KEY fields and the
+ DB_TRX_ID, DB_ROLL_PTR. */
+ cmp_dtuple_rec_with_match_low(
+ entry, rec, offsets,
+ n_unique + 2, &fields, &bytes);
+
+ if (fields >= n_unique) {
+ if (fields == n_unique + 2) {
+ /* This is an exact match. */
+ ut_ad(bytes == 0);
+ /* Special return code to
+ indicate that the row was
+ already inserted. */
+ err = DB_SUCCESS_LOCKED_REC;
+ goto func_exit;
+ }
+
+ goto duplicate;
+ }
+ } else if (row_ins_dupl_error_with_rec(
+ rec, entry, cursor->index, offsets)) {
+duplicate:
trx->error_info = cursor->index;
err = DB_DUPLICATE_KEY;
goto func_exit;
@@ -2087,9 +2125,7 @@ row_ins_duplicate_error_in_clust(
if (row_ins_dupl_error_with_rec(
rec, entry, cursor->index, offsets)) {
- trx->error_info = cursor->index;
- err = DB_DUPLICATE_KEY;
- goto func_exit;
+ goto duplicate;
}
}
=== modified file 'storage/innobase/row/row0log.cc'
--- a/storage/innobase/row/row0log.cc revid:marko.makela@strippedm-20120530065248-5e3vm24c9d5qv1f9
+++ b/storage/innobase/row/row0log.cc revid:marko.makela@stripped21-5klorcbaz3z1zuin
@@ -1000,13 +1000,21 @@ row_log_table_apply_insert_low(
error = row_ins_clust_index_entry_low(
flags, BTR_MODIFY_TREE, index, entry, 0, thr);
- if (error == DB_DUPLICATE_KEY) {
+ switch (error) {
+ case DB_SUCCESS:
+ break;
+ case DB_SUCCESS_LOCKED_REC:
+ /* The row had already been copied to the table. */
+ return(DB_SUCCESS);
+ case DB_DUPLICATE_KEY:
/* TODO: report the duplicate key unless the record is
a full match of what we tried to insert */
+ /* fall through */
+ default:
return(error);
}
- while (error == DB_SUCCESS) {
+ do {
if (!(index = dict_table_get_next_index(index))) {
break;
}
@@ -1015,10 +1023,10 @@ row_log_table_apply_insert_low(
error = row_ins_sec_index_entry_low(
flags, BTR_MODIFY_TREE,
index, offsets_heap, heap, entry, thr);
- }
+ } while (error == DB_SUCCESS);
if (error == DB_DUPLICATE_KEY) {
- /* TODO: report dup */
+ /* TODO: report a duplicate */
}
return(error);
No bundle (reason: useless for push emails).| Thread |
|---|
| • bzr push into mysql-trunk-wl6255 branch (marko.makela:3901 to 3903) WL#6255 | marko.makela | 30 May |