Commit d05a43f6 authored by Marko Mäkelä's avatar Marko Mäkelä

BLOB instrumentation for Bug#12612184 Race condition in row_upd_clust_rec()

If UNIV_DEBUG or UNIV_BLOB_LIGHT_DEBUG is enabled, add
!rec_offs_any_null_extern() assertions, ensuring that records do not
contain null pointers to externally stored columns in inappropriate
places.

btr_cur_optimistic_update(): Assert !rec_offs_any_null_extern().
Incomplete records must never be updated or deleted. This assertion
will cover also the pessimistic route.

row_build(): Assert !rec_offs_any_null_extern(). Search tuples must
never be built from incomplete index entries.

row_rec_to_index_entry(): Assert !rec_offs_any_null_extern() unless
ROW_COPY_DATA is requested. ROW_COPY_DATA is used for
multi-versioning, and therefore it might be valid to copy the most
recent (uncommitted) version while it contains a null pointer to
off-page columns.

row_vers_build_for_consistent_read(),
row_vers_build_for_semi_consistent_read(): Assert !rec_offs_any_null_extern()
on all versions except the most recent one.

trx_undo_prev_version_build(): Assert !rec_offs_any_null_extern() on
the previous version.

rb:682 approved by Sunny Bains
parent 4c506680
...@@ -73,6 +73,13 @@ this many index pages */ ...@@ -73,6 +73,13 @@ this many index pages */
+ not_empty) \ + not_empty) \
/ (BTR_KEY_VAL_ESTIMATE_N_PAGES + ext_size)) / (BTR_KEY_VAL_ESTIMATE_N_PAGES + ext_size))
#if defined UNIV_DEBUG || defined UNIV_BLOB_LIGHT_DEBUG
/* A BLOB field reference full of zero, for use in assertions and tests.
Initially, BLOB field references are set to zero, in
dtuple_convert_big_rec(). */
const byte field_ref_zero[BTR_EXTERN_FIELD_REF_SIZE];
#endif /* UNIV_DEBUG || UNIV_BLOB_LIGHT_DEBUG */
/*********************************************************************** /***********************************************************************
Marks all extern fields in a record as owned by the record. This function Marks all extern fields in a record as owned by the record. This function
should be called if the delete mark of a record is removed: a not delete should be called if the delete mark of a record is removed: a not delete
...@@ -1585,6 +1592,9 @@ btr_cur_optimistic_update( ...@@ -1585,6 +1592,9 @@ btr_cur_optimistic_update(
heap = mem_heap_create(1024); heap = mem_heap_create(1024);
offsets = rec_get_offsets(rec, index, NULL, ULINT_UNDEFINED, &heap); offsets = rec_get_offsets(rec, index, NULL, ULINT_UNDEFINED, &heap);
#if defined UNIV_DEBUG || defined UNIV_BLOB_LIGHT_DEBUG
ut_a(!rec_offs_any_null_extern(rec, offsets));
#endif /* UNIV_DEBUG || UNIV_BLOB_LIGHT_DEBUG */
#ifdef UNIV_DEBUG #ifdef UNIV_DEBUG
if (btr_cur_print_record_ops && thr) { if (btr_cur_print_record_ops && thr) {
......
...@@ -18,4 +18,9 @@ typedef struct btr_pcur_struct btr_pcur_t; ...@@ -18,4 +18,9 @@ typedef struct btr_pcur_struct btr_pcur_t;
typedef struct btr_cur_struct btr_cur_t; typedef struct btr_cur_struct btr_cur_t;
typedef struct btr_search_struct btr_search_t; typedef struct btr_search_struct btr_search_t;
#if defined UNIV_DEBUG || defined UNIV_BLOB_LIGHT_DEBUG
#define BTR_EXTERN_FIELD_REF_SIZE 20
extern const byte field_ref_zero[BTR_EXTERN_FIELD_REF_SIZE];
#endif /* UNIV_DEBUG || UNIV_BLOB_LIGHT_DEBUG */
#endif #endif
...@@ -339,6 +339,19 @@ rec_offs_any_extern( ...@@ -339,6 +339,19 @@ rec_offs_any_extern(
/*================*/ /*================*/
/* out: TRUE if a field is stored externally */ /* out: TRUE if a field is stored externally */
const ulint* offsets);/* in: array returned by rec_get_offsets() */ const ulint* offsets);/* in: array returned by rec_get_offsets() */
#if defined UNIV_DEBUG || defined UNIV_BLOB_LIGHT_DEBUG
/********************************************************
Determine if the offsets are for a record containing null BLOB pointers. */
UNIV_INLINE
const byte*
rec_offs_any_null_extern(
/*=====================*/
/* out: first field containing
a null BLOB pointer,
or NULL if none found */
rec_t* rec, /*!< in: record */
const ulint* offsets); /*!< in: rec_get_offsets(rec) */
#endif /* UNIV_DEBUG || UNIV_BLOB_LIGHT_DEBUG */
/*************************************************************** /***************************************************************
Sets the value of the ith field extern storage bit. */ Sets the value of the ith field extern storage bit. */
UNIV_INLINE UNIV_INLINE
......
...@@ -9,6 +9,7 @@ Created 5/30/1994 Heikki Tuuri ...@@ -9,6 +9,7 @@ Created 5/30/1994 Heikki Tuuri
#include "mach0data.h" #include "mach0data.h"
#include "ut0byte.h" #include "ut0byte.h"
#include "dict0dict.h" #include "dict0dict.h"
#include "btr0types.h"
/* Compact flag ORed to the extra size returned by rec_get_offsets() */ /* Compact flag ORed to the extra size returned by rec_get_offsets() */
#define REC_OFFS_COMPACT ((ulint) 1 << 31) #define REC_OFFS_COMPACT ((ulint) 1 << 31)
...@@ -1020,6 +1021,42 @@ rec_offs_any_extern( ...@@ -1020,6 +1021,42 @@ rec_offs_any_extern(
return(FALSE); return(FALSE);
} }
#if defined UNIV_DEBUG || defined UNIV_BLOB_LIGHT_DEBUG
/********************************************************
Determine if the offsets are for a record containing null BLOB pointers. */
UNIV_INLINE
const byte*
rec_offs_any_null_extern(
/*=====================*/
/* out: first field containing
a null BLOB pointer,
or NULL if none found */
rec_t* rec, /*!< in: record */
const ulint* offsets) /*!< in: rec_get_offsets(rec) */
{
ulint i;
ut_ad(rec_offs_validate(rec, NULL, offsets));
for (i = 0; i < rec_offs_n_fields(offsets); i++) {
if (rec_offs_nth_extern(offsets, i)) {
ulint len;
const byte* field
= rec_get_nth_field(rec, offsets, i, &len);
ut_a(len >= BTR_EXTERN_FIELD_REF_SIZE);
if (!memcmp(field + len
- BTR_EXTERN_FIELD_REF_SIZE,
field_ref_zero,
BTR_EXTERN_FIELD_REF_SIZE)) {
return(field);
}
}
}
return(NULL);
}
#endif /* UNIV_DEBUG || UNIV_BLOB_LIGHT_DEBUG */
/*************************************************************** /***************************************************************
Sets the value of the ith field extern storage bit. */ Sets the value of the ith field extern storage bit. */
UNIV_INLINE UNIV_INLINE
......
...@@ -88,6 +88,8 @@ memory is read outside the allocated blocks. */ ...@@ -88,6 +88,8 @@ memory is read outside the allocated blocks. */
#if 0 #if 0
#define UNIV_DEBUG_VALGRIND /* Enable extra #define UNIV_DEBUG_VALGRIND /* Enable extra
Valgrind instrumentation */ Valgrind instrumentation */
#define UNIV_BLOB_LIGHT_DEBUG /* Enable off-page column
debugging without UNIV_DEBUG */
#define UNIV_DEBUG /* Enable ut_ad() assertions */ #define UNIV_DEBUG /* Enable ut_ad() assertions */
#define UNIV_LIST_DEBUG /* debug UT_LIST_ macros */ #define UNIV_LIST_DEBUG /* debug UT_LIST_ macros */
#define UNIV_MEM_DEBUG /* detect memory leaks etc */ #define UNIV_MEM_DEBUG /* detect memory leaks etc */
......
...@@ -210,6 +210,10 @@ row_build( ...@@ -210,6 +210,10 @@ row_build(
ut_ad(rec_offs_validate(rec, index, offsets)); ut_ad(rec_offs_validate(rec, index, offsets));
} }
#if defined UNIV_DEBUG || defined UNIV_BLOB_LIGHT_DEBUG
ut_a(!rec_offs_any_null_extern(rec, offsets));
#endif /* UNIV_DEBUG || UNIV_BLOB_LIGHT_DEBUG */
if (type != ROW_COPY_POINTERS) { if (type != ROW_COPY_POINTERS) {
/* Take a copy of rec to heap */ /* Take a copy of rec to heap */
buf = mem_heap_alloc(heap, rec_offs_size(offsets)); buf = mem_heap_alloc(heap, rec_offs_size(offsets));
...@@ -302,6 +306,10 @@ row_rec_to_index_entry( ...@@ -302,6 +306,10 @@ row_rec_to_index_entry(
rec = rec_copy(buf, rec, offsets); rec = rec_copy(buf, rec, offsets);
/* Avoid a debug assertion in rec_offs_validate(). */ /* Avoid a debug assertion in rec_offs_validate(). */
rec_offs_make_valid(rec, index, offsets); rec_offs_make_valid(rec, index, offsets);
#if defined UNIV_DEBUG || defined UNIV_BLOB_LIGHT_DEBUG
} else {
ut_a(!rec_offs_any_null_extern(rec, offsets));
#endif /* UNIV_DEBUG || UNIV_BLOB_LIGHT_DEBUG */
} }
rec_len = rec_offs_n_fields(offsets); rec_len = rec_offs_n_fields(offsets);
......
...@@ -473,6 +473,11 @@ row_vers_build_for_consistent_read( ...@@ -473,6 +473,11 @@ row_vers_build_for_consistent_read(
/* The view already sees this version: we can /* The view already sees this version: we can
copy it to in_heap and return */ copy it to in_heap and return */
#if defined UNIV_DEBUG || defined UNIV_BLOB_LIGHT_DEBUG
ut_a(!rec_offs_any_null_extern(
version, *offsets));
#endif /* UNIV_DEBUG || UNIV_BLOB_LIGHT_DEBUG */
buf = mem_heap_alloc(in_heap, buf = mem_heap_alloc(in_heap,
rec_offs_size(*offsets)); rec_offs_size(*offsets));
*old_vers = rec_copy(buf, version, *offsets); *old_vers = rec_copy(buf, version, *offsets);
...@@ -506,6 +511,10 @@ row_vers_build_for_consistent_read( ...@@ -506,6 +511,10 @@ row_vers_build_for_consistent_read(
*offsets = rec_get_offsets(prev_version, index, *offsets, *offsets = rec_get_offsets(prev_version, index, *offsets,
ULINT_UNDEFINED, offset_heap); ULINT_UNDEFINED, offset_heap);
#if defined UNIV_DEBUG || defined UNIV_BLOB_LIGHT_DEBUG
ut_a(!rec_offs_any_null_extern(prev_version, *offsets));
#endif /* UNIV_DEBUG || UNIV_BLOB_LIGHT_DEBUG */
trx_id = row_get_rec_trx_id(prev_version, index, *offsets); trx_id = row_get_rec_trx_id(prev_version, index, *offsets);
if (read_view_sees_trx_id(view, trx_id)) { if (read_view_sees_trx_id(view, trx_id)) {
...@@ -606,6 +615,10 @@ row_vers_build_for_semi_consistent_read( ...@@ -606,6 +615,10 @@ row_vers_build_for_semi_consistent_read(
/* We found a version that belongs to a /* We found a version that belongs to a
committed transaction: return it. */ committed transaction: return it. */
#if defined UNIV_DEBUG || defined UNIV_BLOB_LIGHT_DEBUG
ut_a(!rec_offs_any_null_extern(version, *offsets));
#endif /* UNIV_DEBUG || UNIV_BLOB_LIGHT_DEBUG */
if (rec == version) { if (rec == version) {
*old_vers = rec; *old_vers = rec;
err = DB_SUCCESS; err = DB_SUCCESS;
...@@ -663,6 +676,9 @@ row_vers_build_for_semi_consistent_read( ...@@ -663,6 +676,9 @@ row_vers_build_for_semi_consistent_read(
version = prev_version; version = prev_version;
*offsets = rec_get_offsets(version, index, *offsets, *offsets = rec_get_offsets(version, index, *offsets,
ULINT_UNDEFINED, offset_heap); ULINT_UNDEFINED, offset_heap);
#if defined UNIV_DEBUG || defined UNIV_BLOB_LIGHT_DEBUG
ut_a(!rec_offs_any_null_extern(version, *offsets));
#endif /* UNIV_DEBUG || UNIV_BLOB_LIGHT_DEBUG */
}/* for (;;) */ }/* for (;;) */
if (heap) { if (heap) {
......
...@@ -1397,6 +1397,10 @@ trx_undo_prev_version_build( ...@@ -1397,6 +1397,10 @@ trx_undo_prev_version_build(
return(DB_ERROR); return(DB_ERROR);
} }
# if defined UNIV_DEBUG || defined UNIV_BLOB_LIGHT_DEBUG
ut_a(!rec_offs_any_null_extern(rec, offsets));
# endif /* UNIV_DEBUG || UNIV_BLOB_LIGHT_DEBUG */
if (row_upd_changes_field_size_or_external(index, offsets, update)) { if (row_upd_changes_field_size_or_external(index, offsets, update)) {
ulint* ext_vect; ulint* ext_vect;
ulint n_ext_vect; ulint n_ext_vect;
......
2011-06-09 The InnoDB Team
* btr/btr0cur.c, include/rem0rec.h, include/rem0rec.ic,
* row/row0row.c, row/row0vers.c, trx/trx0rec.c:
Instrumentation for Bug#12612184 Race condition in row_upd_clust_rec()
2011-04-07 The InnoDB Team 2011-04-07 The InnoDB Team
* handler/ha_innodb.cc, handler/ha_innodb.h, handler/handler0alter.cc: * handler/ha_innodb.cc, handler/ha_innodb.h, handler/handler0alter.cc:
......
/***************************************************************************** /*****************************************************************************
Copyright (c) 1994, 2010, Innobase Oy. All Rights Reserved. Copyright (c) 1994, 2011, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2008, Google Inc. Copyright (c) 2008, Google Inc.
Portions of this file contain modifications contributed and copyrighted by Portions of this file contain modifications contributed and copyrighted by
...@@ -1871,6 +1871,9 @@ btr_cur_optimistic_update( ...@@ -1871,6 +1871,9 @@ btr_cur_optimistic_update(
heap = mem_heap_create(1024); heap = mem_heap_create(1024);
offsets = rec_get_offsets(rec, index, NULL, ULINT_UNDEFINED, &heap); offsets = rec_get_offsets(rec, index, NULL, ULINT_UNDEFINED, &heap);
#if defined UNIV_DEBUG || defined UNIV_BLOB_LIGHT_DEBUG
ut_a(!rec_offs_any_null_extern(rec, offsets));
#endif /* UNIV_DEBUG || UNIV_BLOB_LIGHT_DEBUG */
#ifdef UNIV_DEBUG #ifdef UNIV_DEBUG
if (btr_cur_print_record_ops && thr) { if (btr_cur_print_record_ops && thr) {
......
/***************************************************************************** /*****************************************************************************
Copyright (c) 1994, 2009, Innobase Oy. All Rights Reserved. Copyright (c) 1994, 2011, Oracle and/or its affiliates. All Rights Reserved.
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
...@@ -480,6 +480,18 @@ ulint ...@@ -480,6 +480,18 @@ ulint
rec_offs_any_extern( rec_offs_any_extern(
/*================*/ /*================*/
const ulint* offsets);/*!< in: array returned by rec_get_offsets() */ const ulint* offsets);/*!< in: array returned by rec_get_offsets() */
#if defined UNIV_DEBUG || defined UNIV_BLOB_LIGHT_DEBUG
/******************************************************//**
Determine if the offsets are for a record containing null BLOB pointers.
@return first field containing a null BLOB pointer, or NULL if none found */
UNIV_INLINE
const byte*
rec_offs_any_null_extern(
/*=====================*/
const rec_t* rec, /*!< in: record */
const ulint* offsets) /*!< in: rec_get_offsets(rec) */
__attribute__((nonnull, warn_unused_result));
#endif /* UNIV_DEBUG || UNIV_BLOB_LIGHT_DEBUG */
/******************************************************//** /******************************************************//**
Returns nonzero if the extern bit is set in nth field of rec. Returns nonzero if the extern bit is set in nth field of rec.
@return nonzero if externally stored */ @return nonzero if externally stored */
......
/***************************************************************************** /*****************************************************************************
Copyright (c) 1994, 2009, Innobase Oy. All Rights Reserved. Copyright (c) 1994, 2011, Oracle and/or its affiliates. All Rights Reserved.
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
...@@ -26,6 +26,7 @@ Created 5/30/1994 Heikki Tuuri ...@@ -26,6 +26,7 @@ Created 5/30/1994 Heikki Tuuri
#include "mach0data.h" #include "mach0data.h"
#include "ut0byte.h" #include "ut0byte.h"
#include "dict0dict.h" #include "dict0dict.h"
#include "btr0types.h"
/* Compact flag ORed to the extra size returned by rec_get_offsets() */ /* Compact flag ORed to the extra size returned by rec_get_offsets() */
#define REC_OFFS_COMPACT ((ulint) 1 << 31) #define REC_OFFS_COMPACT ((ulint) 1 << 31)
...@@ -1087,6 +1088,44 @@ rec_offs_any_extern( ...@@ -1087,6 +1088,44 @@ rec_offs_any_extern(
return(UNIV_UNLIKELY(*rec_offs_base(offsets) & REC_OFFS_EXTERNAL)); return(UNIV_UNLIKELY(*rec_offs_base(offsets) & REC_OFFS_EXTERNAL));
} }
#if defined UNIV_DEBUG || defined UNIV_BLOB_LIGHT_DEBUG
/******************************************************//**
Determine if the offsets are for a record containing null BLOB pointers.
@return first field containing a null BLOB pointer, or NULL if none found */
UNIV_INLINE
const byte*
rec_offs_any_null_extern(
/*=====================*/
const rec_t* rec, /*!< in: record */
const ulint* offsets) /*!< in: rec_get_offsets(rec) */
{
ulint i;
ut_ad(rec_offs_validate(rec, NULL, offsets));
if (!rec_offs_any_extern(offsets)) {
return(NULL);
}
for (i = 0; i < rec_offs_n_fields(offsets); i++) {
if (rec_offs_nth_extern(offsets, i)) {
ulint len;
const byte* field
= rec_get_nth_field(rec, offsets, i, &len);
ut_a(len >= BTR_EXTERN_FIELD_REF_SIZE);
if (!memcmp(field + len
- BTR_EXTERN_FIELD_REF_SIZE,
field_ref_zero,
BTR_EXTERN_FIELD_REF_SIZE)) {
return(field);
}
}
}
return(NULL);
}
#endif /* UNIV_DEBUG || UNIV_BLOB_LIGHT_DEBUG */
/******************************************************//** /******************************************************//**
Returns nonzero if the extern bit is set in nth field of rec. Returns nonzero if the extern bit is set in nth field of rec.
@return nonzero if externally stored */ @return nonzero if externally stored */
......
/***************************************************************************** /*****************************************************************************
Copyright (c) 1996, 2010, Innobase Oy. All Rights Reserved. Copyright (c) 1996, 2011, Oracle and/or its affiliates. All Rights Reserved.
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
...@@ -231,6 +231,10 @@ row_build( ...@@ -231,6 +231,10 @@ row_build(
ut_ad(rec_offs_validate(rec, index, offsets)); ut_ad(rec_offs_validate(rec, index, offsets));
} }
#if defined UNIV_DEBUG || defined UNIV_BLOB_LIGHT_DEBUG
ut_a(!rec_offs_any_null_extern(rec, offsets));
#endif /* UNIV_DEBUG || UNIV_BLOB_LIGHT_DEBUG */
if (type != ROW_COPY_POINTERS) { if (type != ROW_COPY_POINTERS) {
/* Take a copy of rec to heap */ /* Take a copy of rec to heap */
buf = mem_heap_alloc(heap, rec_offs_size(offsets)); buf = mem_heap_alloc(heap, rec_offs_size(offsets));
...@@ -415,6 +419,10 @@ row_rec_to_index_entry( ...@@ -415,6 +419,10 @@ row_rec_to_index_entry(
rec = rec_copy(buf, rec, offsets); rec = rec_copy(buf, rec, offsets);
/* Avoid a debug assertion in rec_offs_validate(). */ /* Avoid a debug assertion in rec_offs_validate(). */
rec_offs_make_valid(rec, index, offsets); rec_offs_make_valid(rec, index, offsets);
#if defined UNIV_DEBUG || defined UNIV_BLOB_LIGHT_DEBUG
} else {
ut_a(!rec_offs_any_null_extern(rec, offsets));
#endif /* UNIV_DEBUG || UNIV_BLOB_LIGHT_DEBUG */
} }
entry = row_rec_to_index_entry_low(rec, index, offsets, n_ext, heap); entry = row_rec_to_index_entry_low(rec, index, offsets, n_ext, heap);
......
/***************************************************************************** /*****************************************************************************
Copyright (c) 1997, 2009, Innobase Oy. All Rights Reserved. Copyright (c) 1997, 2011, Oracle and/or its affiliates. All Rights Reserved.
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
...@@ -550,6 +550,11 @@ row_vers_build_for_consistent_read( ...@@ -550,6 +550,11 @@ row_vers_build_for_consistent_read(
/* The view already sees this version: we can /* The view already sees this version: we can
copy it to in_heap and return */ copy it to in_heap and return */
#if defined UNIV_DEBUG || defined UNIV_BLOB_LIGHT_DEBUG
ut_a(!rec_offs_any_null_extern(
version, *offsets));
#endif /* UNIV_DEBUG || UNIV_BLOB_LIGHT_DEBUG */
buf = mem_heap_alloc(in_heap, buf = mem_heap_alloc(in_heap,
rec_offs_size(*offsets)); rec_offs_size(*offsets));
*old_vers = rec_copy(buf, version, *offsets); *old_vers = rec_copy(buf, version, *offsets);
...@@ -583,6 +588,10 @@ row_vers_build_for_consistent_read( ...@@ -583,6 +588,10 @@ row_vers_build_for_consistent_read(
*offsets = rec_get_offsets(prev_version, index, *offsets, *offsets = rec_get_offsets(prev_version, index, *offsets,
ULINT_UNDEFINED, offset_heap); ULINT_UNDEFINED, offset_heap);
#if defined UNIV_DEBUG || defined UNIV_BLOB_LIGHT_DEBUG
ut_a(!rec_offs_any_null_extern(prev_version, *offsets));
#endif /* UNIV_DEBUG || UNIV_BLOB_LIGHT_DEBUG */
trx_id = row_get_rec_trx_id(prev_version, index, *offsets); trx_id = row_get_rec_trx_id(prev_version, index, *offsets);
if (read_view_sees_trx_id(view, trx_id)) { if (read_view_sees_trx_id(view, trx_id)) {
...@@ -682,6 +691,10 @@ row_vers_build_for_semi_consistent_read( ...@@ -682,6 +691,10 @@ row_vers_build_for_semi_consistent_read(
/* We found a version that belongs to a /* We found a version that belongs to a
committed transaction: return it. */ committed transaction: return it. */
#if defined UNIV_DEBUG || defined UNIV_BLOB_LIGHT_DEBUG
ut_a(!rec_offs_any_null_extern(version, *offsets));
#endif /* UNIV_DEBUG || UNIV_BLOB_LIGHT_DEBUG */
if (rec == version) { if (rec == version) {
*old_vers = rec; *old_vers = rec;
err = DB_SUCCESS; err = DB_SUCCESS;
...@@ -739,6 +752,9 @@ row_vers_build_for_semi_consistent_read( ...@@ -739,6 +752,9 @@ row_vers_build_for_semi_consistent_read(
version = prev_version; version = prev_version;
*offsets = rec_get_offsets(version, index, *offsets, *offsets = rec_get_offsets(version, index, *offsets,
ULINT_UNDEFINED, offset_heap); ULINT_UNDEFINED, offset_heap);
#if defined UNIV_DEBUG || defined UNIV_BLOB_LIGHT_DEBUG
ut_a(!rec_offs_any_null_extern(version, *offsets));
#endif /* UNIV_DEBUG || UNIV_BLOB_LIGHT_DEBUG */
}/* for (;;) */ }/* for (;;) */
if (heap) { if (heap) {
......
/***************************************************************************** /*****************************************************************************
Copyright (c) 1996, 2010, Innobase Oy. All Rights Reserved. Copyright (c) 1996, 2011, Oracle and/or its affiliates. All Rights Reserved.
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
...@@ -1577,6 +1577,10 @@ trx_undo_prev_version_build( ...@@ -1577,6 +1577,10 @@ trx_undo_prev_version_build(
return(DB_ERROR); return(DB_ERROR);
} }
# if defined UNIV_DEBUG || defined UNIV_BLOB_LIGHT_DEBUG
ut_a(!rec_offs_any_null_extern(rec, offsets));
# endif /* UNIV_DEBUG || UNIV_BLOB_LIGHT_DEBUG */
if (row_upd_changes_field_size_or_external(index, offsets, update)) { if (row_upd_changes_field_size_or_external(index, offsets, update)) {
ulint n_ext; ulint n_ext;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment