mirror of
https://github.com/MariaDB/server.git
synced 2025-08-08 11:22:35 +03:00
MDEV-36015: unrepresentable value in row_parse_int()
row_parse_int(): Refactor the code and define the function static in one compilation unit. For any negative values, we must return 0. row_search_get_max_rec(), row_search_max_autoinc(): Moved to the same compilation unit with row_parse_int(). We also remove a work-around of an internal compiler error when targeting ARMv8 on GCC 4.8.5, a compiler that is no longer supported. Reviewed by: Debarun Banerjee
This commit is contained in:
committed by
Sergei Golubchik
parent
44e1f7238a
commit
c07e355c40
@@ -190,8 +190,7 @@ a
|
|||||||
100000000000
|
100000000000
|
||||||
100000000006
|
100000000006
|
||||||
CREATE TABLE t11(a FLOAT AUTO_INCREMENT KEY) ENGINE = InnoDB;
|
CREATE TABLE t11(a FLOAT AUTO_INCREMENT KEY) ENGINE = InnoDB;
|
||||||
INSERT INTO t11 VALUES(0), (0), (0), (0), (-1), (-10), (0),
|
INSERT INTO t11 VALUES(0), (0), (0), (0), (-1), (-10), (0), (20), (30), (31);
|
||||||
(20), (30), (31);
|
|
||||||
SELECT * FROM t11;
|
SELECT * FROM t11;
|
||||||
a
|
a
|
||||||
-10
|
-10
|
||||||
@@ -204,9 +203,22 @@ a
|
|||||||
20
|
20
|
||||||
30
|
30
|
||||||
31
|
31
|
||||||
|
CREATE TABLE t11u(a FLOAT UNSIGNED AUTO_INCREMENT KEY) ENGINE = InnoDB;
|
||||||
|
INSERT INTO t11u VALUES(0), (0), (0), (0), (-1), (-10), (0), (20), (30), (31);
|
||||||
|
ERROR 22003: Out of range value for column 'a' at row 5
|
||||||
|
INSERT INTO t11u VALUES(0), (0), (0), (0), (0), (20), (30), (31);
|
||||||
|
SELECT * FROM t11u;
|
||||||
|
a
|
||||||
|
11
|
||||||
|
12
|
||||||
|
13
|
||||||
|
14
|
||||||
|
15
|
||||||
|
20
|
||||||
|
30
|
||||||
|
31
|
||||||
CREATE TABLE t12(a DOUBLE AUTO_INCREMENT KEY) ENGINE = InnoDB;
|
CREATE TABLE t12(a DOUBLE AUTO_INCREMENT KEY) ENGINE = InnoDB;
|
||||||
INSERT INTO t12 VALUES(0), (0), (0), (0), (-1), (-10), (0),
|
INSERT INTO t12 VALUES(0), (0), (0), (0), (-1), (-10), (0), (20), (30), (31);
|
||||||
(20), (30), (31);
|
|
||||||
SELECT * FROM t12;
|
SELECT * FROM t12;
|
||||||
a
|
a
|
||||||
-10
|
-10
|
||||||
@@ -219,6 +231,20 @@ a
|
|||||||
20
|
20
|
||||||
30
|
30
|
||||||
31
|
31
|
||||||
|
CREATE TABLE t12u(a DOUBLE UNSIGNED AUTO_INCREMENT KEY) ENGINE = InnoDB;
|
||||||
|
INSERT INTO t12u VALUES(0), (0), (0), (0), (-1), (-10), (0), (20), (30), (31);
|
||||||
|
ERROR 22003: Out of range value for column 'a' at row 5
|
||||||
|
INSERT INTO t12u VALUES(0), (0), (0), (0), (0), (20), (30), (31);
|
||||||
|
SELECT * FROM t12u;
|
||||||
|
a
|
||||||
|
11
|
||||||
|
12
|
||||||
|
13
|
||||||
|
14
|
||||||
|
15
|
||||||
|
20
|
||||||
|
30
|
||||||
|
31
|
||||||
# Scenario 1: Normal restart, to test if the counters are persisted
|
# Scenario 1: Normal restart, to test if the counters are persisted
|
||||||
# Scenario 2: Delete some values, to test the counters should not be the
|
# Scenario 2: Delete some values, to test the counters should not be the
|
||||||
# one which is the largest in current table
|
# one which is the largest in current table
|
||||||
@@ -981,4 +1007,5 @@ a b
|
|||||||
10 1
|
10 1
|
||||||
2 2
|
2 2
|
||||||
3 4
|
3 4
|
||||||
DROP TABLE t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t30, t32, t33;
|
DROP TABLE t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t11u, t12u,
|
||||||
|
t30, t32, t33;
|
||||||
|
@@ -82,15 +82,25 @@ INSERT INTO t10 VALUES(0), (0), (0), (0), (8), (10), (0),
|
|||||||
SELECT * FROM t10;
|
SELECT * FROM t10;
|
||||||
|
|
||||||
CREATE TABLE t11(a FLOAT AUTO_INCREMENT KEY) ENGINE = InnoDB;
|
CREATE TABLE t11(a FLOAT AUTO_INCREMENT KEY) ENGINE = InnoDB;
|
||||||
INSERT INTO t11 VALUES(0), (0), (0), (0), (-1), (-10), (0),
|
INSERT INTO t11 VALUES(0), (0), (0), (0), (-1), (-10), (0), (20), (30), (31);
|
||||||
(20), (30), (31);
|
|
||||||
SELECT * FROM t11;
|
SELECT * FROM t11;
|
||||||
|
|
||||||
|
CREATE TABLE t11u(a FLOAT UNSIGNED AUTO_INCREMENT KEY) ENGINE = InnoDB;
|
||||||
|
--error ER_WARN_DATA_OUT_OF_RANGE
|
||||||
|
INSERT INTO t11u VALUES(0), (0), (0), (0), (-1), (-10), (0), (20), (30), (31);
|
||||||
|
INSERT INTO t11u VALUES(0), (0), (0), (0), (0), (20), (30), (31);
|
||||||
|
SELECT * FROM t11u;
|
||||||
|
|
||||||
CREATE TABLE t12(a DOUBLE AUTO_INCREMENT KEY) ENGINE = InnoDB;
|
CREATE TABLE t12(a DOUBLE AUTO_INCREMENT KEY) ENGINE = InnoDB;
|
||||||
INSERT INTO t12 VALUES(0), (0), (0), (0), (-1), (-10), (0),
|
INSERT INTO t12 VALUES(0), (0), (0), (0), (-1), (-10), (0), (20), (30), (31);
|
||||||
(20), (30), (31);
|
|
||||||
SELECT * FROM t12;
|
SELECT * FROM t12;
|
||||||
|
|
||||||
|
CREATE TABLE t12u(a DOUBLE UNSIGNED AUTO_INCREMENT KEY) ENGINE = InnoDB;
|
||||||
|
--error ER_WARN_DATA_OUT_OF_RANGE
|
||||||
|
INSERT INTO t12u VALUES(0), (0), (0), (0), (-1), (-10), (0), (20), (30), (31);
|
||||||
|
INSERT INTO t12u VALUES(0), (0), (0), (0), (0), (20), (30), (31);
|
||||||
|
SELECT * FROM t12u;
|
||||||
|
|
||||||
--echo # Scenario 1: Normal restart, to test if the counters are persisted
|
--echo # Scenario 1: Normal restart, to test if the counters are persisted
|
||||||
--echo # Scenario 2: Delete some values, to test the counters should not be the
|
--echo # Scenario 2: Delete some values, to test the counters should not be the
|
||||||
--echo # one which is the largest in current table
|
--echo # one which is the largest in current table
|
||||||
@@ -556,4 +566,5 @@ INSERT INTO t33 VALUES(3, NULL);
|
|||||||
SELECT MAX(b) AS `Expect 4` FROM t33;
|
SELECT MAX(b) AS `Expect 4` FROM t33;
|
||||||
SELECT * FROM t33;
|
SELECT * FROM t33;
|
||||||
|
|
||||||
DROP TABLE t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t30, t32, t33;
|
DROP TABLE t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t11u, t12u,
|
||||||
|
t30, t32, t33;
|
||||||
|
@@ -328,22 +328,6 @@ row_get_clust_rec(
|
|||||||
mtr_t* mtr) /*!< in: mtr */
|
mtr_t* mtr) /*!< in: mtr */
|
||||||
MY_ATTRIBUTE((nonnull, warn_unused_result));
|
MY_ATTRIBUTE((nonnull, warn_unused_result));
|
||||||
|
|
||||||
/** Parse the integer data from specified data, which could be
|
|
||||||
DATA_INT, DATA_FLOAT or DATA_DOUBLE. If the value is less than 0
|
|
||||||
and the type is not unsigned then we reset the value to 0
|
|
||||||
@param[in] data data to read
|
|
||||||
@param[in] len length of data
|
|
||||||
@param[in] mtype mtype of data
|
|
||||||
@param[in] unsigned_type if the data is unsigned
|
|
||||||
@return the integer value from the data */
|
|
||||||
inline
|
|
||||||
ib_uint64_t
|
|
||||||
row_parse_int(
|
|
||||||
const byte* data,
|
|
||||||
ulint len,
|
|
||||||
ulint mtype,
|
|
||||||
bool unsigned_type);
|
|
||||||
|
|
||||||
/** Result of row_search_index_entry */
|
/** Result of row_search_index_entry */
|
||||||
enum row_search_result {
|
enum row_search_result {
|
||||||
ROW_FOUND = 0, /*!< the record was found */
|
ROW_FOUND = 0, /*!< the record was found */
|
||||||
|
@@ -170,52 +170,3 @@ row_build_row_ref_fast(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Parse the integer data from specified data, which could be
|
|
||||||
DATA_INT, DATA_FLOAT or DATA_DOUBLE. If the value is less than 0
|
|
||||||
and the type is not unsigned then we reset the value to 0
|
|
||||||
@param[in] data data to read
|
|
||||||
@param[in] len length of data
|
|
||||||
@param[in] mtype mtype of data
|
|
||||||
@param[in] unsigned_type if the data is unsigned
|
|
||||||
@return the integer value from the data */
|
|
||||||
ib_uint64_t
|
|
||||||
row_parse_int(
|
|
||||||
const byte* data,
|
|
||||||
ulint len,
|
|
||||||
ulint mtype,
|
|
||||||
bool unsigned_type)
|
|
||||||
{
|
|
||||||
ib_uint64_t value = 0;
|
|
||||||
|
|
||||||
switch (mtype) {
|
|
||||||
case DATA_INT:
|
|
||||||
|
|
||||||
ut_a(len <= sizeof value);
|
|
||||||
value = mach_read_int_type(data, len, unsigned_type);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case DATA_FLOAT:
|
|
||||||
|
|
||||||
ut_a(len == sizeof(float));
|
|
||||||
value = static_cast<ib_uint64_t>(mach_float_read(data));
|
|
||||||
break;
|
|
||||||
|
|
||||||
case DATA_DOUBLE:
|
|
||||||
|
|
||||||
ut_a(len == sizeof(double));
|
|
||||||
value = static_cast<ib_uint64_t>(mach_double_read(data));
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
ut_error;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!unsigned_type && static_cast<int64_t>(value) < 0) {
|
|
||||||
value = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
@@ -182,9 +182,8 @@ dberr_t row_check_index(row_prebuilt_t *prebuilt, ulint *n_rows)
|
|||||||
@param[in] index index starting with an AUTO_INCREMENT column
|
@param[in] index index starting with an AUTO_INCREMENT column
|
||||||
@return the largest AUTO_INCREMENT value
|
@return the largest AUTO_INCREMENT value
|
||||||
@retval 0 if no records were found */
|
@retval 0 if no records were found */
|
||||||
ib_uint64_t
|
uint64_t row_search_max_autoinc(dict_index_t *index) noexcept
|
||||||
row_search_max_autoinc(dict_index_t* index)
|
MY_ATTRIBUTE((nonnull, warn_unused_result));
|
||||||
MY_ATTRIBUTE((nonnull, warn_unused_result));
|
|
||||||
|
|
||||||
/** A structure for caching column values for prefetched rows */
|
/** A structure for caching column values for prefetched rows */
|
||||||
struct sel_buf_t{
|
struct sel_buf_t{
|
||||||
|
@@ -2560,12 +2560,44 @@ row_ins_index_entry_big_rec(
|
|||||||
return(error);
|
return(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined __aarch64__&&defined __GNUC__&&__GNUC__==4&&!defined __clang__
|
/** Parse the integer data from specified data, which could be
|
||||||
/* Avoid GCC 4.8.5 internal compiler error due to srw_mutex::wr_unlock().
|
DATA_INT, DATA_FLOAT or DATA_DOUBLE. If the value is less than 0
|
||||||
We would only need this for row_ins_clust_index_entry_low(),
|
and the type is not unsigned then we reset the value to 0
|
||||||
but GCC 4.8.5 does not support pop_options. */
|
@param data data to read
|
||||||
# pragma GCC optimize ("O0")
|
@param len length of data
|
||||||
#endif
|
@param mtype main type of the column
|
||||||
|
@param prtype precise type of the column
|
||||||
|
@return the integer value from the data
|
||||||
|
@retval 0 if the value is negative or the type or length invalid */
|
||||||
|
static uint64_t row_parse_int(const byte *data, size_t len,
|
||||||
|
ulint mtype, ulint prtype) noexcept
|
||||||
|
{
|
||||||
|
switch (mtype) {
|
||||||
|
case DATA_FLOAT:
|
||||||
|
if (len != sizeof(float))
|
||||||
|
return 0;
|
||||||
|
{
|
||||||
|
float f= mach_float_read(data);
|
||||||
|
return f <= 0.0 ? 0 : uint64_t(f);
|
||||||
|
}
|
||||||
|
case DATA_DOUBLE:
|
||||||
|
if (len != sizeof(double))
|
||||||
|
return 0;
|
||||||
|
{
|
||||||
|
double d= mach_double_read(data);
|
||||||
|
return d <= 0.0 ? 0 : uint64_t(d);
|
||||||
|
}
|
||||||
|
case DATA_INT:
|
||||||
|
if (len == 0 || len > 8)
|
||||||
|
return 0;
|
||||||
|
const ibool unsigned_type{prtype & DATA_UNSIGNED};
|
||||||
|
uint64_t value= mach_read_int_type(data, len, unsigned_type);
|
||||||
|
return !unsigned_type && int64_t(value) < 0 ? 0 : value;
|
||||||
|
}
|
||||||
|
|
||||||
|
ut_ad("invalid type" == 0);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/***************************************************************//**
|
/***************************************************************//**
|
||||||
Tries to insert an entry into a clustered index, ignoring foreign key
|
Tries to insert an entry into a clustered index, ignoring foreign key
|
||||||
@@ -2652,8 +2684,7 @@ row_ins_clust_index_entry_low(
|
|||||||
dfield->data),
|
dfield->data),
|
||||||
dfield->len,
|
dfield->len,
|
||||||
dfield->type.mtype,
|
dfield->type.mtype,
|
||||||
dfield->type.prtype
|
dfield->type.prtype);
|
||||||
& DATA_UNSIGNED);
|
|
||||||
if (auto_inc
|
if (auto_inc
|
||||||
&& mode != BTR_MODIFY_TREE) {
|
&& mode != BTR_MODIFY_TREE) {
|
||||||
mode = btr_latch_mode(
|
mode = btr_latch_mode(
|
||||||
@@ -3810,3 +3841,65 @@ error_handling:
|
|||||||
|
|
||||||
return(thr);
|
return(thr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Read the AUTOINC column from an index record
|
||||||
|
@param index index of the record
|
||||||
|
@param rec the record
|
||||||
|
@return value read from the first column
|
||||||
|
@retval 0 if the value would be NULL or negative */
|
||||||
|
static uint64_t row_read_autoinc(const dict_index_t &index, const rec_t *rec)
|
||||||
|
noexcept
|
||||||
|
{
|
||||||
|
const dict_field_t &field= index.fields[0];
|
||||||
|
ut_ad(!DATA_BIG_COL(field.col));
|
||||||
|
ut_ad(!(rec_get_info_bits(rec, index.table->not_redundant()) &
|
||||||
|
(REC_INFO_MIN_REC_FLAG | REC_INFO_DELETED_FLAG)));
|
||||||
|
mem_heap_t *heap= nullptr;
|
||||||
|
rec_offs offsets_[REC_OFFS_HEADER_SIZE + 2];
|
||||||
|
rec_offs_init(offsets_);
|
||||||
|
rec_offs *offsets= rec_get_offsets(rec, &index, offsets_,
|
||||||
|
index.n_core_fields, 1, &heap);
|
||||||
|
ut_ad(!heap);
|
||||||
|
|
||||||
|
size_t len;
|
||||||
|
ut_d(size_t first_offset=) rec_get_nth_field_offs(offsets, 0, &len);
|
||||||
|
ut_ad(!first_offset);
|
||||||
|
return row_parse_int(rec, len, field.col->mtype, field.col->prtype);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Get the maximum and non-delete-marked record in an index.
|
||||||
|
@param index index B-tree
|
||||||
|
@param mtr mini-transaction (may be committed and restarted)
|
||||||
|
@return maximum record, page s-latched in mtr
|
||||||
|
@retval nullptr if there are no records, or if all of them are delete-marked */
|
||||||
|
static
|
||||||
|
const rec_t *row_search_get_max_rec(dict_index_t *index, mtr_t *mtr) noexcept
|
||||||
|
{
|
||||||
|
btr_pcur_t pcur;
|
||||||
|
/* Open at the high/right end (false), and init cursor */
|
||||||
|
if (pcur.open_leaf(false, index, BTR_SEARCH_LEAF, mtr) != DB_SUCCESS)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
const page_t *page= btr_pcur_get_page(&pcur);
|
||||||
|
const rec_t *rec= page_find_rec_max_not_deleted(page);
|
||||||
|
if (page_rec_is_user_rec_low(rec - page))
|
||||||
|
return rec;
|
||||||
|
btr_pcur_move_before_first_on_page(&pcur);
|
||||||
|
}
|
||||||
|
while (btr_pcur_move_to_prev(&pcur, mtr));
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t row_search_max_autoinc(dict_index_t *index) noexcept
|
||||||
|
{
|
||||||
|
uint64_t value= 0;
|
||||||
|
mtr_t mtr;
|
||||||
|
mtr.start();
|
||||||
|
if (const rec_t *rec= row_search_get_max_rec(index, &mtr))
|
||||||
|
value= row_read_autoinc(*index, rec);
|
||||||
|
mtr.commit();
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
@@ -6856,111 +6856,3 @@ next_rec:
|
|||||||
|
|
||||||
goto rec_loop;
|
goto rec_loop;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*******************************************************************//**
|
|
||||||
Read the AUTOINC column from the current row. If the value is less than
|
|
||||||
0 and the type is not unsigned then we reset the value to 0.
|
|
||||||
@return value read from the column */
|
|
||||||
static
|
|
||||||
ib_uint64_t
|
|
||||||
row_search_autoinc_read_column(
|
|
||||||
/*===========================*/
|
|
||||||
dict_index_t* index, /*!< in: index to read from */
|
|
||||||
const rec_t* rec, /*!< in: current rec */
|
|
||||||
ulint col_no, /*!< in: column number */
|
|
||||||
ulint mtype, /*!< in: column main type */
|
|
||||||
ibool unsigned_type) /*!< in: signed or unsigned flag */
|
|
||||||
{
|
|
||||||
ulint len;
|
|
||||||
const byte* data;
|
|
||||||
ib_uint64_t value;
|
|
||||||
mem_heap_t* heap = NULL;
|
|
||||||
rec_offs offsets_[REC_OFFS_NORMAL_SIZE];
|
|
||||||
rec_offs* offsets = offsets_;
|
|
||||||
|
|
||||||
rec_offs_init(offsets_);
|
|
||||||
ut_ad(page_rec_is_leaf(rec));
|
|
||||||
|
|
||||||
offsets = rec_get_offsets(rec, index, offsets, index->n_core_fields,
|
|
||||||
col_no + 1, &heap);
|
|
||||||
|
|
||||||
if (rec_offs_nth_sql_null(offsets, col_no)) {
|
|
||||||
/* There is no non-NULL value in the auto-increment column. */
|
|
||||||
value = 0;
|
|
||||||
goto func_exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
data = rec_get_nth_field(rec, offsets, col_no, &len);
|
|
||||||
|
|
||||||
value = row_parse_int(data, len, mtype, unsigned_type);
|
|
||||||
|
|
||||||
func_exit:
|
|
||||||
if (UNIV_LIKELY_NULL(heap)) {
|
|
||||||
mem_heap_free(heap);
|
|
||||||
}
|
|
||||||
|
|
||||||
return(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Get the maximum and non-delete-marked record in an index.
|
|
||||||
@param[in] index index tree
|
|
||||||
@param[in,out] mtr mini-transaction (may be committed and restarted)
|
|
||||||
@return maximum record, page s-latched in mtr
|
|
||||||
@retval NULL if there are no records, or if all of them are delete-marked */
|
|
||||||
static
|
|
||||||
const rec_t*
|
|
||||||
row_search_get_max_rec(
|
|
||||||
dict_index_t* index,
|
|
||||||
mtr_t* mtr)
|
|
||||||
{
|
|
||||||
btr_pcur_t pcur;
|
|
||||||
const rec_t* rec;
|
|
||||||
/* Open at the high/right end (false), and init cursor */
|
|
||||||
if (pcur.open_leaf(false, index, BTR_SEARCH_LEAF, mtr) != DB_SUCCESS) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
do {
|
|
||||||
const page_t* page;
|
|
||||||
|
|
||||||
page = btr_pcur_get_page(&pcur);
|
|
||||||
rec = page_find_rec_max_not_deleted(page);
|
|
||||||
|
|
||||||
if (page_rec_is_user_rec(rec)) {
|
|
||||||
break;
|
|
||||||
} else {
|
|
||||||
rec = NULL;
|
|
||||||
}
|
|
||||||
btr_pcur_move_before_first_on_page(&pcur);
|
|
||||||
} while (btr_pcur_move_to_prev(&pcur, mtr));
|
|
||||||
|
|
||||||
ut_ad(!rec
|
|
||||||
|| !(rec_get_info_bits(rec, dict_table_is_comp(index->table))
|
|
||||||
& (REC_INFO_MIN_REC_FLAG | REC_INFO_DELETED_FLAG)));
|
|
||||||
return(rec);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Read the max AUTOINC value from an index.
|
|
||||||
@param[in] index index starting with an AUTO_INCREMENT column
|
|
||||||
@return the largest AUTO_INCREMENT value
|
|
||||||
@retval 0 if no records were found */
|
|
||||||
ib_uint64_t
|
|
||||||
row_search_max_autoinc(dict_index_t* index)
|
|
||||||
{
|
|
||||||
const dict_field_t* dfield = dict_index_get_nth_field(index, 0);
|
|
||||||
|
|
||||||
ib_uint64_t value = 0;
|
|
||||||
|
|
||||||
mtr_t mtr;
|
|
||||||
mtr.start();
|
|
||||||
|
|
||||||
if (const rec_t* rec = row_search_get_max_rec(index, &mtr)) {
|
|
||||||
value = row_search_autoinc_read_column(
|
|
||||||
index, rec, 0,
|
|
||||||
dfield->col->mtype,
|
|
||||||
dfield->col->prtype & DATA_UNSIGNED);
|
|
||||||
}
|
|
||||||
|
|
||||||
mtr.commit();
|
|
||||||
return(value);
|
|
||||||
}
|
|
||||||
|
Reference in New Issue
Block a user