MDEV-25758 InnoDB spatial indexes miss large geometry fields after MDEV-25459
InnoDB should calculate the MBR for the first field of spatial index and do the comparison with the clustered index field MBR. Due to MDEV-25459 refactoring, InnoDB calculate the length of the first field and fails with too long column error.
This commit is contained in:
parent
ab87fc6c7a
commit
c11c5f36d8
@ -1482,10 +1482,21 @@ FROM buildings, bridges
|
|||||||
WHERE ST_Contains(ST_Buffer(bridges.position, 15.0), buildings.footprint) = 1;
|
WHERE ST_Contains(ST_Buffer(bridges.position, 15.0), buildings.footprint) = 1;
|
||||||
count(*)
|
count(*)
|
||||||
1
|
1
|
||||||
DROP DATABASE gis_ogs;
|
|
||||||
#
|
#
|
||||||
# Bug#13362660 ASSERTION `FIELD_POS < FIELD_COUNT' FAILED. IN PROTOCOL_TEXT::STORE
|
# Bug#13362660 ASSERTION `FIELD_POS < FIELD_COUNT' FAILED. IN PROTOCOL_TEXT::STORE
|
||||||
#
|
#
|
||||||
SELECT ST_Union('', ''), md5(1);
|
SELECT ST_Union('', ''), md5(1);
|
||||||
ST_Union('', '') md5(1)
|
ST_Union('', '') md5(1)
|
||||||
NULL c4ca4238a0b923820dcc509a6f75849b
|
NULL c4ca4238a0b923820dcc509a6f75849b
|
||||||
|
#
|
||||||
|
# MDEV-25758 InnoDB spatial indexes miss large geometry
|
||||||
|
# fields after MDEV-25459
|
||||||
|
#
|
||||||
|
CREATE TABLE t1(l LINESTRING NOT NULL, SPATIAL INDEX(l))ENGINE=InnoDB ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=1;
|
||||||
|
SELECT GROUP_CONCAT(CONCAT(seq, ' ', seq) SEPARATOR ',') INTO @g FROM seq_0_to_190;
|
||||||
|
INSERT INTO t1 SET l=ST_GeomFromText(CONCAT('LINESTRING(',@g,',0 0)'));
|
||||||
|
SELECT COUNT(*) FROM t1 WHERE MBRIntersects(GeomFromText('Polygon((0 0,0 10,10 10,10 0,0 0))'), l);
|
||||||
|
COUNT(*)
|
||||||
|
1
|
||||||
|
DROP TABLE t1;
|
||||||
|
DROP DATABASE gis_ogs;
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
--source include/have_innodb.inc
|
--source include/have_innodb.inc
|
||||||
-- source include/have_geometry.inc
|
-- source include/have_geometry.inc
|
||||||
|
--source include/have_sequence.inc
|
||||||
|
|
||||||
SET default_storage_engine=InnoDB;
|
SET default_storage_engine=InnoDB;
|
||||||
|
|
||||||
@ -1422,10 +1423,20 @@ WHERE ST_Contains(ST_Buffer(bridges.position, 15.0), buildings.footprint) = 1;
|
|||||||
#FROM lakes
|
#FROM lakes
|
||||||
#WHERE lakes.name = 'Blue Lake';
|
#WHERE lakes.name = 'Blue Lake';
|
||||||
|
|
||||||
DROP DATABASE gis_ogs;
|
|
||||||
|
|
||||||
--echo #
|
--echo #
|
||||||
--echo # Bug#13362660 ASSERTION `FIELD_POS < FIELD_COUNT' FAILED. IN PROTOCOL_TEXT::STORE
|
--echo # Bug#13362660 ASSERTION `FIELD_POS < FIELD_COUNT' FAILED. IN PROTOCOL_TEXT::STORE
|
||||||
--echo #
|
--echo #
|
||||||
|
|
||||||
SELECT ST_Union('', ''), md5(1);
|
SELECT ST_Union('', ''), md5(1);
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # MDEV-25758 InnoDB spatial indexes miss large geometry
|
||||||
|
--echo # fields after MDEV-25459
|
||||||
|
--echo #
|
||||||
|
CREATE TABLE t1(l LINESTRING NOT NULL, SPATIAL INDEX(l))ENGINE=InnoDB ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=1;
|
||||||
|
SELECT GROUP_CONCAT(CONCAT(seq, ' ', seq) SEPARATOR ',') INTO @g FROM seq_0_to_190;
|
||||||
|
INSERT INTO t1 SET l=ST_GeomFromText(CONCAT('LINESTRING(',@g,',0 0)'));
|
||||||
|
SELECT COUNT(*) FROM t1 WHERE MBRIntersects(GeomFromText('Polygon((0 0,0 10,10 10,10 0,0 0))'), l);
|
||||||
|
DROP TABLE t1;
|
||||||
|
|
||||||
|
DROP DATABASE gis_ogs;
|
||||||
|
@ -150,6 +150,75 @@ row_sel_sec_rec_is_for_blob(
|
|||||||
return(!cmp_data_data(mtype, prtype, buf, len, sec_field, sec_len));
|
return(!cmp_data_data(mtype, prtype, buf, len, sec_field, sec_len));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Function to read the secondary spatial index, calculate
|
||||||
|
the minimum bounding rectangle for clustered index record
|
||||||
|
and secondary index record and compare it.
|
||||||
|
@param sec_rec secondary index record
|
||||||
|
@param sec_index spatial secondary index
|
||||||
|
@param clust_rec clustered index record
|
||||||
|
@param clust_index clustered index
|
||||||
|
@retval DB_SUCCESS_LOCKED_REC if the secondary record is equal to the
|
||||||
|
corresponding fields in the clustered record, when compared with
|
||||||
|
collation;
|
||||||
|
@retval DB_SUCCESS if not equal */
|
||||||
|
static
|
||||||
|
dberr_t
|
||||||
|
row_sel_spatial_sec_rec_is_for_clust_rec(
|
||||||
|
const rec_t *sec_rec, const dict_index_t *sec_index,
|
||||||
|
const rec_t *clust_rec, dict_index_t *clust_index)
|
||||||
|
{
|
||||||
|
mem_heap_t *heap= mem_heap_create(256);
|
||||||
|
rec_offs clust_offsets_[REC_OFFS_NORMAL_SIZE];
|
||||||
|
rec_offs *clust_offs= clust_offsets_;
|
||||||
|
ulint clust_len;
|
||||||
|
|
||||||
|
rec_offs_init(clust_offsets_);
|
||||||
|
ulint clust_pos= dict_col_get_clust_pos(
|
||||||
|
dict_index_get_nth_col(sec_index, 0), clust_index);
|
||||||
|
clust_offs= rec_get_offsets(clust_rec, clust_index, clust_offs,
|
||||||
|
true, clust_pos + 1, &heap);
|
||||||
|
ut_ad(sec_index->n_user_defined_cols == 1);
|
||||||
|
const byte *clust_field= rec_get_nth_field(clust_rec, clust_offs,
|
||||||
|
clust_pos, &clust_len);
|
||||||
|
if (clust_len == UNIV_SQL_NULL || clust_len < GEO_DATA_HEADER_SIZE)
|
||||||
|
{
|
||||||
|
ut_ad("corrupted geometry column" == 0);
|
||||||
|
err_exit:
|
||||||
|
mem_heap_free(heap);
|
||||||
|
return DB_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* For externally stored field, we need to get full
|
||||||
|
geo data to generate the MBR for comparing. */
|
||||||
|
if (rec_offs_nth_extern(clust_offs, clust_pos))
|
||||||
|
{
|
||||||
|
clust_field= btr_copy_externally_stored_field(
|
||||||
|
&clust_len, clust_field, dict_table_page_size(sec_index->table),
|
||||||
|
clust_len, heap);
|
||||||
|
if (clust_field == NULL)
|
||||||
|
{
|
||||||
|
ut_ad("corrupted geometry blob" == 0);
|
||||||
|
goto err_exit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ut_ad(clust_len >= GEO_DATA_HEADER_SIZE);
|
||||||
|
rtr_mbr_t tmp_mbr;
|
||||||
|
rtr_mbr_t sec_mbr;
|
||||||
|
|
||||||
|
rtree_mbr_from_wkb(
|
||||||
|
clust_field + GEO_DATA_HEADER_SIZE,
|
||||||
|
static_cast<uint>(clust_len - GEO_DATA_HEADER_SIZE),
|
||||||
|
SPDIMS, reinterpret_cast<double*>(&tmp_mbr));
|
||||||
|
|
||||||
|
rtr_read_mbr(sec_rec, &sec_mbr);
|
||||||
|
|
||||||
|
mem_heap_free(heap);
|
||||||
|
return MBR_EQUAL_CMP(&sec_mbr, &tmp_mbr)
|
||||||
|
? DB_SUCCESS_LOCKED_REC
|
||||||
|
: DB_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
/** Returns TRUE if the user-defined column values in a secondary index record
|
/** Returns TRUE if the user-defined column values in a secondary index record
|
||||||
are alphabetically the same as the corresponding columns in the clustered
|
are alphabetically the same as the corresponding columns in the clustered
|
||||||
index record.
|
index record.
|
||||||
@ -177,20 +246,6 @@ row_sel_sec_rec_is_for_clust_rec(
|
|||||||
dict_index_t* clust_index,
|
dict_index_t* clust_index,
|
||||||
que_thr_t* thr)
|
que_thr_t* thr)
|
||||||
{
|
{
|
||||||
const byte* sec_field;
|
|
||||||
ulint sec_len;
|
|
||||||
const byte* clust_field;
|
|
||||||
ulint n;
|
|
||||||
ulint i;
|
|
||||||
mem_heap_t* heap = NULL;
|
|
||||||
rec_offs clust_offsets_[REC_OFFS_NORMAL_SIZE];
|
|
||||||
rec_offs sec_offsets_[REC_OFFS_SMALL_SIZE];
|
|
||||||
rec_offs* clust_offs = clust_offsets_;
|
|
||||||
rec_offs* sec_offs = sec_offsets_;
|
|
||||||
|
|
||||||
rec_offs_init(clust_offsets_);
|
|
||||||
rec_offs_init(sec_offsets_);
|
|
||||||
|
|
||||||
if (rec_get_deleted_flag(clust_rec,
|
if (rec_get_deleted_flag(clust_rec,
|
||||||
dict_table_is_comp(clust_index->table))) {
|
dict_table_is_comp(clust_index->table))) {
|
||||||
/* In delete-marked records, DB_TRX_ID must
|
/* In delete-marked records, DB_TRX_ID must
|
||||||
@ -204,7 +259,27 @@ row_sel_sec_rec_is_for_clust_rec(
|
|||||||
return DB_SUCCESS;
|
return DB_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
heap = mem_heap_create(256);
|
if (sec_index->is_spatial()) {
|
||||||
|
return row_sel_spatial_sec_rec_is_for_clust_rec(
|
||||||
|
sec_rec, sec_index, clust_rec,
|
||||||
|
clust_index);
|
||||||
|
}
|
||||||
|
|
||||||
|
const byte* sec_field;
|
||||||
|
ulint sec_len;
|
||||||
|
const byte* clust_field;
|
||||||
|
ulint n;
|
||||||
|
ulint i;
|
||||||
|
mem_heap_t* heap = mem_heap_create(256);
|
||||||
|
rec_offs clust_offsets_[REC_OFFS_NORMAL_SIZE];
|
||||||
|
rec_offs sec_offsets_[REC_OFFS_SMALL_SIZE];
|
||||||
|
rec_offs* clust_offs = clust_offsets_;
|
||||||
|
rec_offs* sec_offs = sec_offsets_;
|
||||||
|
|
||||||
|
rec_offs_init(clust_offsets_);
|
||||||
|
rec_offs_init(sec_offsets_);
|
||||||
|
|
||||||
|
|
||||||
ib_vcol_row vc(heap);
|
ib_vcol_row vc(heap);
|
||||||
|
|
||||||
clust_offs = rec_get_offsets(clust_rec, clust_index, clust_offs,
|
clust_offs = rec_get_offsets(clust_rec, clust_index, clust_offs,
|
||||||
@ -310,46 +385,12 @@ check_for_blob:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* For spatial index, the first field is MBR, we check
|
|
||||||
if the MBR is equal or not. */
|
|
||||||
if (dict_index_is_spatial(sec_index) && i == 0) {
|
|
||||||
rtr_mbr_t tmp_mbr;
|
|
||||||
rtr_mbr_t sec_mbr;
|
|
||||||
byte* dptr =
|
|
||||||
const_cast<byte*>(clust_field);
|
|
||||||
|
|
||||||
ut_ad(clust_len != UNIV_SQL_NULL);
|
|
||||||
|
|
||||||
/* For externally stored field, we need to get full
|
|
||||||
geo data to generate the MBR for comparing. */
|
|
||||||
if (rec_offs_nth_extern(clust_offs, clust_pos)) {
|
|
||||||
dptr = btr_copy_externally_stored_field(
|
|
||||||
&clust_len, dptr,
|
|
||||||
dict_tf_get_page_size(
|
|
||||||
sec_index->table->flags),
|
|
||||||
len, heap);
|
|
||||||
}
|
|
||||||
|
|
||||||
rtree_mbr_from_wkb(dptr + GEO_DATA_HEADER_SIZE,
|
|
||||||
static_cast<uint>(clust_len
|
|
||||||
- GEO_DATA_HEADER_SIZE),
|
|
||||||
SPDIMS,
|
|
||||||
reinterpret_cast<double*>(
|
|
||||||
&tmp_mbr));
|
|
||||||
rtr_read_mbr(sec_field, &sec_mbr);
|
|
||||||
|
|
||||||
if (!MBR_EQUAL_CMP(&sec_mbr, &tmp_mbr)) {
|
|
||||||
return DB_SUCCESS;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
|
|
||||||
if (0 != cmp_data_data(col->mtype, col->prtype,
|
if (0 != cmp_data_data(col->mtype, col->prtype,
|
||||||
clust_field, len,
|
clust_field, len,
|
||||||
sec_field, sec_len)) {
|
sec_field, sec_len)) {
|
||||||
return DB_SUCCESS;
|
return DB_SUCCESS;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return DB_SUCCESS_LOCKED_REC;
|
return DB_SUCCESS_LOCKED_REC;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user