1
0
mirror of https://github.com/MariaDB/server.git synced 2026-10-23 18:49:29 +03:00

Fix CI regressions from MDEV-38975 forward-port to main

Seven code fixes, a new test, and test re-recordings for issues found
by CI on PR #5222.

**NULL dereference in `create_tmp_field()`**: `SYS_REFCURSOR` plugin
returns NULL from `make_new_field()` (cursor values cannot be
materialized). The feature added `result->flags |= FIELD_PART_OF_TMP_UNIQUE`
without a NULL check. Added `if (result)` guard.

**xmltype identity loss and recursive CTE reclength mismatch in
`Item_type_holder::create_tmp_field_ex()`**: the blob_key dispatch now
requires both: (1) `type_handler_for_tmp_table()` returns
`blob_key_type_handler()`, AND (2) `dynamic_cast<Type_handler_blob_common*>`
confirms the original type is a native blob. Condition 1 excludes xmltype
(its override returns itself). Condition 2 excludes VARCHAR types promoted
via `varstring_type_handler()` -> `too_big_for_varchar()` ->
`blob_type_handler()`. Without condition 2, wide VARCHAR in recursive CTEs
(e.g. `cast('...' as varchar(1000))`) was promoted to `Field_blob_key` in
the main UNION DISTINCT table (`part_of_unique_key=true`) but stayed as
`Field_varchar` in the incremental table (`part_of_unique_key=false`),
causing a `reclength` mismatch assertion in
`select_union_recursive::send_data()` (`main.json_equals` crash).

**Spurious `reclength > HA_MAX_REC_LENGTH` in `pick_engine()`**: the
original `choose_engine()` (both 10.11 and upstream/main) never had a
reclength check. MDEV-38975 introduced it when replacing the
`blob_fields` condition. HEAP has no internal reclength limit --
`hp_create.c` stores `uint reclength` and allocates blocks of that size;
`max_supported_record_length()` is only checked in `unireg.cc` during
user-facing CREATE TABLE. I_S tables like SLAVE_STATUS routinely have
reclength ~880KB (13 bare `Varchar()` columns). The check forced them to
Aria where `fill_slave_status()` returned 0 rows. Removed the check and
the unused `reclength` parameter from `pick_engine()`.

**Multi-update `tmp_memory_table_size` override**: the 10.11 feature
overrode `big_tables=FALSE` for multi-update dedup tables. The forward-port
translated this as `tmp_memory_table_size=SIZE_T_MAX` when the variable
was 0. But `big_tables=FALSE` was a soft "don't force disk" hint, while
`tmp_memory_table_size=SIZE_T_MAX` overrides the user's explicit
`tmp_memory_table_size=0` directive. Since main removed `big_tables`
entirely (MDEV-19713), the override is not needed. Removed.

**Zero-length key rejection in `check_tmp_key()`**: reject `key_len == 0`
to prevent useless zero-length keys from being created by `add_tmp_key()`.
Reachable when all key parts are CHAR(0) NOT NULL: `key_length()` returns
0, the field is not nullable (no HA_KEY_NULL_LENGTH) and not
VARCHAR/BLOB/GEOMETRY (no HA_KEY_BLOB_LENGTH), so `fld_store_len` is 0
for every part. Without this guard, `check_tmp_key()` would accept the
key (0 <= max_key_length), and the optimizer would create a ref key that
cannot distinguish any rows. Added `heap.char0_key` test exercising this
via a materialized derived table with CHAR(0) NOT NULL join columns.

**Non-deterministic `column_compression` test**: HEAP blob support allows
compressed VARCHAR/TEXT temp tables to stay in HEAP instead of falling to
Aria, changing row iteration order. Added `--sorted_result` to the two
MDEV-24726 subqueries that lack `ORDER BY`.

Test changes:
- `spatial_utility_function_collect`: added ORDER BY to window function
  that lacked it (results were engine-row-order-dependent)
- `tmp_space_usage`: removed multi-update override; forced disk for
  MDEV-34016/34060 Aria-specific test sections (blob I_S tables now
  stay in MEMORY)
- `blob_update_overflow`: replaced `SHOW STATUS LIKE 'Created_tmp_%'`
  with targeted I_S query (Created_tmp_files varies on sanitizer builds)
- 'funcs_1.is_tables_is' ; re-recorded test as
  INFORMATION_SCHEMA.SLAVE_STATUS is now back as MEMORY table
- `column_compression`: added `--sorted_result` for MDEV-24726 queries
- `char0_key` (new): CHAR(0) NOT NULL derived table ref key rejection
- Re-recorded 8 tests for expected "temp table stays in MEMORY" changes
This commit is contained in:
Arcadiy Ivanov
2026-06-13 13:12:29 -04:00
committed by Monty
parent 3331b76240
commit 11f859d9d3
22 changed files with 169 additions and 82 deletions

View File

@@ -3035,9 +3035,9 @@ create algorithm=temptable view v1 as select * from t1;
insert into t1 values ('foo'),('bar'),('foo');
select * from v1 where a in (select a from t1);
a
foo
foo
bar
foo
foo
drop view v1;
drop table t1;
create table t1 (f1 varchar(8)) charset=eucjpms collate=eucjpms_nopad_bin;
@@ -3054,9 +3054,9 @@ create algorithm=temptable view v1 as select * from t1;
insert into t1 values ('foo'),('bar'),('foo');
select * from v1 where a in (select a from t1);
a
foo
foo
bar
foo
foo
drop view v1;
drop table t1;
create table t1 (f1 text) charset=eucjpms collate=eucjpms_nopad_bin;

View File

@@ -533,6 +533,7 @@ DROP TABLE t1;
create table t1 (a varchar(8) compressed) character set utf8mb4;
create algorithm=temptable view v1 as select * from t1;
insert into t1 values ('foo'),('bar'),('foo');
--sorted_result
select * from v1 where a in (select a from t1);
# cleanup
drop view v1;
@@ -550,6 +551,7 @@ drop table t1, t2;
create table t1 (a text compressed) character set utf8mb4;
create algorithm=temptable view v1 as select * from t1;
insert into t1 values ('foo'),('bar'),('foo');
--sorted_result
select * from v1 where a in (select a from t1);
# cleanup
drop view v1;

View File

@@ -172,7 +172,7 @@ def 1 1 3 2 1 N 49157 0 63
1
select * from (select 1 union select 1) aaa;
Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr
def aaa 1 1 3 2 1 N 49153 0 63
def aaa 1 1 3 2 1 N 49157 0 63
1
1
drop table t1;

View File

@@ -13887,7 +13887,7 @@ OPTIMIZER_TRACE CREATE TEMPORARY TABLE `OPTIMIZER_TRACE` (
`TRACE` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
`MISSING_BYTES_BEYOND_MAX_MEM_SIZE` int(20) NOT NULL,
`INSUFFICIENT_PRIVILEGES` tinyint(1) NOT NULL
) ENGINE=Aria DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_general_ci PAGE_CHECKSUM=0
) ENGINE=MEMORY DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_general_ci
#
# MDEV-39720: Optimizer Trace may have invalid JSON due to quoting.
#

View File

@@ -62,8 +62,8 @@ INSERT INTO table_simple_aggregation (location) VALUES
( ST_GEOMFROMTEXT('POINT(0 -0)' ,4326)),
( NULL),
( NULL);
SELECT ST_ASTEXT(ST_COLLECT(location) OVER ( ROWS BETWEEN 1 PRECEDING AND
CURRENT ROW)) c FROM table_simple_aggregation;
SELECT ST_ASTEXT(ST_COLLECT(location) OVER ( ORDER BY running_number
ROWS BETWEEN 1 PRECEDING AND CURRENT ROW)) c FROM table_simple_aggregation;
c
MULTIPOINT(0 0)
MULTIPOINT(0 0,0 0)

View File

@@ -72,8 +72,8 @@ INSERT INTO table_simple_aggregation (location) VALUES
( ST_GEOMFROMTEXT('POINT(0 -0)' ,4326)),
( NULL),
( NULL);
SELECT ST_ASTEXT(ST_COLLECT(location) OVER ( ROWS BETWEEN 1 PRECEDING AND
CURRENT ROW)) c FROM table_simple_aggregation;
SELECT ST_ASTEXT(ST_COLLECT(location) OVER ( ORDER BY running_number
ROWS BETWEEN 1 PRECEDING AND CURRENT ROW)) c FROM table_simple_aggregation;
--echo Excercising multiple code paths.

View File

@@ -350,7 +350,7 @@ Created_tmp_tables 2
Handler_tmp_delete 0
Handler_tmp_update 2
Handler_tmp_write 6
Max_tmp_space_used 32768
Max_tmp_space_used 0
Rows_tmp_read 44
drop table t1;
CREATE TABLE t1 (i int(11) DEFAULT NULL, KEY i (i) ) ENGINE=MyISAM;

View File

@@ -187,8 +187,9 @@ CREATE TABLE t1 (a varchar(1024)) engine=aria CHARSET=latin1;
INSERT INTO t1 VALUES ('this'),('is'),('just'),('a'),('filling'),('for'),(REPEAT('a',500));
set @@global.max_tmp_total_space_usage=2*1024*1024;
SET max_tmp_session_space_usage= 1024*1024, max_heap_table_size= 4*1024*1024;
SET tmp_memory_table_size= 0;
SELECT DISTINCT a, seq FROM t1 JOIN seq_1_to_600;
ERROR HY000: Got error 201 "Local temporary space limit reached" when merging index
ERROR HY000: Local temporary space limit reached
DROP TABLE t1;
connection default;
disconnect c1;
@@ -210,6 +211,7 @@ CREATE OR REPLACE TABLE t1 (a DATETIME) ENGINE=InnoDB;
BEGIN;
INSERT INTO t1 SELECT NOW() FROM seq_1_to_6000;
SET max_tmp_session_space_usage = 64*1024;
SET tmp_memory_table_size= 0;
SELECT * FROM information_schema.ALL_PLUGINS LIMIT 2;
ERROR HY000: Local temporary space limit reached
ROLLBACK;

View File

@@ -247,7 +247,8 @@ CREATE TABLE t1 (a varchar(1024)) engine=aria CHARSET=latin1;
INSERT INTO t1 VALUES ('this'),('is'),('just'),('a'),('filling'),('for'),(REPEAT('a',500));
set @@global.max_tmp_total_space_usage=2*1024*1024;
SET max_tmp_session_space_usage= 1024*1024, max_heap_table_size= 4*1024*1024;
--error ER_NOT_KEYFILE
SET tmp_memory_table_size= 0;
--error HA_ERR_LOCAL_TMP_SPACE_FULL
SELECT DISTINCT a, seq FROM t1 JOIN seq_1_to_600;
DROP TABLE t1;
connection default;
@@ -277,6 +278,7 @@ BEGIN;
INSERT INTO t1 SELECT NOW() FROM seq_1_to_6000;
SET max_tmp_session_space_usage = 64*1024;
SET tmp_memory_table_size= 0;
--error HA_ERR_LOCAL_TMP_SPACE_FULL
SELECT * FROM information_schema.ALL_PLUGINS LIMIT 2;
ROLLBACK;

View File

@@ -57,7 +57,7 @@ master-bin.000001 # Query # # use `test`; CREATE TEMPORARY TABLE `t1` (
`INFO_BINARY` blob,
`TID` bigint(10) NOT NULL,
`TMP_SPACE_USED` bigint(10) NOT NULL
) ENGINE=Aria PAGE_CHECKSUM=0
) ENGINE=MEMORY
master-bin.000001 # Gtid # # GTID #-#-#
master-bin.000001 # Query # # use `test`; CREATE TEMPORARY TABLE t2_tmp like t2
master-bin.000001 # Gtid # # GTID #-#-#
@@ -88,7 +88,7 @@ master-bin.000001 # Query # # use `test`; CREATE TEMPORARY TABLE `t1` (
`INFO_BINARY` blob,
`TID` bigint(10) NOT NULL,
`TMP_SPACE_USED` bigint(10) NOT NULL
) ENGINE=Aria PAGE_CHECKSUM=0
) ENGINE=MEMORY
master-bin.000001 # Gtid # # GTID #-#-#
master-bin.000001 # Query # # use `test`; CREATE TEMPORARY TABLE t2_tmp like t2
master-bin.000001 # Gtid # # GTID #-#-#

View File

@@ -916,9 +916,9 @@ TABLE_CATALOG def
TABLE_SCHEMA information_schema
TABLE_NAME SLAVE_STATUS
TABLE_TYPE SYSTEM VIEW
ENGINE MYISAM_OR_MARIA
ENGINE MEMORY
VERSION 11
ROW_FORMAT DYNAMIC_OR_PAGE
ROW_FORMAT Fixed
TABLE_ROWS #TBLR#
AVG_ROW_LENGTH #ARL#
DATA_LENGTH #DL#
@@ -2257,9 +2257,9 @@ TABLE_CATALOG def
TABLE_SCHEMA information_schema
TABLE_NAME SLAVE_STATUS
TABLE_TYPE SYSTEM VIEW
ENGINE MYISAM_OR_MARIA
ENGINE MEMORY
VERSION 11
ROW_FORMAT DYNAMIC_OR_PAGE
ROW_FORMAT Fixed
TABLE_ROWS #TBLR#
AVG_ROW_LENGTH #ARL#
DATA_LENGTH #DL#

View File

@@ -53,7 +53,7 @@ ID root HOST_NAME information_schema Query TIME starting SHOW processlist TIME_M
ID ddicttestuser1 HOST_NAME information_schema Sleep TIME NULL TIME_MS
SELECT * FROM processlist ORDER BY id;
ID USER HOST DB COMMAND TIME STATE INFO TIME_MS STAGE MAX_STAGE PROGRESS MEMORY_USED MAX_MEMORY_USED EXAMINED_ROWS SENT_ROWS QUERY_ID INFO_BINARY TID TMP_SPACE_USED
ID root HOST_NAME information_schema Query TIME Filling schema table SELECT * FROM processlist ORDER BY id TIME_MS 0 0 0.000 MEMORY MAX_MEMORY E_ROWS S_ROWS QUERY_ID SELECT * FROM processlist ORDER BY id TID 16384
ID root HOST_NAME information_schema Query TIME Filling schema table SELECT * FROM processlist ORDER BY id TIME_MS 0 0 0.000 MEMORY MAX_MEMORY E_ROWS S_ROWS QUERY_ID SELECT * FROM processlist ORDER BY id TID 0
ID ddicttestuser1 HOST_NAME information_schema Sleep TIME NULL TIME_MS 0 0 0.000 MEMORY MAX_MEMORY E_ROWS S_ROWS QUERY_ID NULL TID 0
SELECT ID, USER, HOST, DB, COMMAND, TIME, STATE, INFO, TIME_MS, STAGE, MAX_STAGE, PROGRESS, MEMORY_USED, EXAMINED_ROWS, QUERY_ID, INFO_BINARY FROM processlist ORDER BY id;
ID USER HOST DB COMMAND TIME STATE INFO TIME_MS STAGE MAX_STAGE PROGRESS MEMORY_USED EXAMINED_ROWS QUERY_ID INFO_BINARY

View File

@@ -53,7 +53,7 @@ ID root HOST_NAME information_schema Query TIME starting SHOW processlist TIME_M
ID ddicttestuser1 HOST_NAME information_schema Sleep TIME NULL TIME_MS
SELECT * FROM processlist ORDER BY id;
ID USER HOST DB COMMAND TIME STATE INFO TIME_MS STAGE MAX_STAGE PROGRESS MEMORY_USED MAX_MEMORY_USED EXAMINED_ROWS SENT_ROWS QUERY_ID INFO_BINARY TID TMP_SPACE_USED
ID root HOST_NAME information_schema Execute TIME Filling schema table SELECT * FROM processlist ORDER BY id TIME_MS 0 0 0.000 MEMORY MAX_MEMORY E_ROWS S_ROWS QUERY_ID SELECT * FROM processlist ORDER BY id TID 16384
ID root HOST_NAME information_schema Execute TIME Filling schema table SELECT * FROM processlist ORDER BY id TIME_MS 0 0 0.000 MEMORY MAX_MEMORY E_ROWS S_ROWS QUERY_ID SELECT * FROM processlist ORDER BY id TID 0
ID ddicttestuser1 HOST_NAME information_schema Sleep TIME NULL TIME_MS 0 0 0.000 MEMORY MAX_MEMORY E_ROWS S_ROWS QUERY_ID NULL TID 0
SELECT ID, USER, HOST, DB, COMMAND, TIME, STATE, INFO, TIME_MS, STAGE, MAX_STAGE, PROGRESS, MEMORY_USED, EXAMINED_ROWS, QUERY_ID, INFO_BINARY FROM processlist ORDER BY id;
ID USER HOST DB COMMAND TIME STATE INFO TIME_MS STAGE MAX_STAGE PROGRESS MEMORY_USED EXAMINED_ROWS QUERY_ID INFO_BINARY

View File

@@ -35,11 +35,12 @@ grp max_len
2 29600
3 29800
# Verify HEAP->Aria conversion happened
SHOW STATUS LIKE 'Created_tmp_%';
Variable_name Value
Created_tmp_disk_tables 1
Created_tmp_files 0
Created_tmp_tables 2
SELECT variable_name, variable_value FROM information_schema.session_status
WHERE variable_name IN ('Created_tmp_disk_tables', 'Created_tmp_tables')
ORDER BY variable_name;
variable_name variable_value
CREATED_TMP_DISK_TABLES 2
CREATED_TMP_TABLES 4
DROP TABLE t1;
#
# Test 2: Verify result correctness after overflow
@@ -62,11 +63,12 @@ grp max_len prefix suffix
1 30000 aaaaa aaaaa
2 29600 aaaaa aaaaa
3 29800 aaaaa aaaaa
SHOW STATUS LIKE 'Created_tmp_%';
Variable_name Value
Created_tmp_disk_tables 1
Created_tmp_files 0
Created_tmp_tables 2
SELECT variable_name, variable_value FROM information_schema.session_status
WHERE variable_name IN ('Created_tmp_disk_tables', 'Created_tmp_tables')
ORDER BY variable_name;
variable_name variable_value
CREATED_TMP_DISK_TABLES 2
CREATED_TMP_TABLES 4
DROP TABLE t1;
#
# Test 3: Multiple blob aggregates (two MAX columns)
@@ -85,11 +87,12 @@ grp max1_len max2_len
1 30000 22500
2 29600 22200
3 29800 22350
SHOW STATUS LIKE 'Created_tmp_%';
Variable_name Value
Created_tmp_disk_tables 1
Created_tmp_files 0
Created_tmp_tables 2
SELECT variable_name, variable_value FROM information_schema.session_status
WHERE variable_name IN ('Created_tmp_disk_tables', 'Created_tmp_tables')
ORDER BY variable_name;
variable_name variable_value
CREATED_TMP_DISK_TABLES 2
CREATED_TMP_TABLES 4
DROP TABLE t1;
#
# Test 4: MIN(TEXT) with monotonically shrinking minimum
@@ -118,11 +121,12 @@ grp max_len min_len
1 30000 50
2 29600 50
3 29200 50
SHOW STATUS LIKE 'Created_tmp_%';
Variable_name Value
Created_tmp_disk_tables 1
Created_tmp_files 0
Created_tmp_tables 2
SELECT variable_name, variable_value FROM information_schema.session_status
WHERE variable_name IN ('Created_tmp_disk_tables', 'Created_tmp_tables')
ORDER BY variable_name;
variable_name variable_value
CREATED_TMP_DISK_TABLES 2
CREATED_TMP_TABLES 4
DROP TABLE t1;
#
# Cleanup

View File

@@ -44,7 +44,11 @@ SELECT grp, LENGTH(MAX(val)) AS max_len
FROM t1 GROUP BY grp ORDER BY grp;
--echo # Verify HEAP->Aria conversion happened
SHOW STATUS LIKE 'Created_tmp_%';
--disable_warnings
SELECT variable_name, variable_value FROM information_schema.session_status
WHERE variable_name IN ('Created_tmp_disk_tables', 'Created_tmp_tables')
ORDER BY variable_name;
--enable_warnings
--enable_cursor_protocol
--enable_view_protocol
--enable_ps2_protocol
@@ -76,7 +80,11 @@ SELECT grp,
RIGHT(MAX(val), 5) AS suffix
FROM t1 GROUP BY grp ORDER BY grp;
SHOW STATUS LIKE 'Created_tmp_%';
--disable_warnings
SELECT variable_name, variable_value FROM information_schema.session_status
WHERE variable_name IN ('Created_tmp_disk_tables', 'Created_tmp_tables')
ORDER BY variable_name;
--enable_warnings
--enable_cursor_protocol
--enable_view_protocol
--enable_ps2_protocol
@@ -103,7 +111,11 @@ SELECT grp,
LENGTH(MAX(v2)) AS max2_len
FROM t1 GROUP BY grp ORDER BY grp;
SHOW STATUS LIKE 'Created_tmp_%';
--disable_warnings
SELECT variable_name, variable_value FROM information_schema.session_status
WHERE variable_name IN ('Created_tmp_disk_tables', 'Created_tmp_tables')
ORDER BY variable_name;
--enable_warnings
--enable_cursor_protocol
--enable_view_protocol
--enable_ps2_protocol
@@ -140,7 +152,11 @@ SELECT grp,
LENGTH(MIN(val)) AS min_len
FROM t1 GROUP BY grp ORDER BY grp;
SHOW STATUS LIKE 'Created_tmp_%';
--disable_warnings
SELECT variable_name, variable_value FROM information_schema.session_status
WHERE variable_name IN ('Created_tmp_disk_tables', 'Created_tmp_tables')
ORDER BY variable_name;
--enable_warnings
--enable_cursor_protocol
--enable_view_protocol
--enable_ps2_protocol

View File

@@ -0,0 +1,20 @@
SET optimizer_switch='derived_merge=off';
CREATE TABLE t1 (a CHAR(0) NOT NULL, b INT) ENGINE=MEMORY;
INSERT INTO t1 VALUES ('', 1), ('', 2), ('', 3);
CREATE TABLE t2 (c CHAR(0) NOT NULL, d INT) ENGINE=MEMORY;
INSERT INTO t2 VALUES ('', 10), ('', 20);
EXPLAIN SELECT * FROM t2, (SELECT * FROM t1) dt WHERE dt.a = t2.c;
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t2 ALL NULL NULL NULL NULL 2
1 PRIMARY <derived2> ALL NULL NULL NULL NULL 3 Using where; Using join buffer (flat, BNL join)
2 DERIVED t1 ALL NULL NULL NULL NULL 3
SELECT * FROM t2, (SELECT * FROM t1) dt WHERE dt.a = t2.c;
c d a b
10 1
10 2
10 3
20 1
20 2
20 3
DROP TABLE t1, t2;
SET optimizer_switch=DEFAULT;

View File

@@ -0,0 +1,25 @@
#
# Test that check_tmp_key rejects zero-length keys from CHAR(0) NOT NULL.
# The optimizer tries to add a ref key on a materialized derived table,
# but CHAR(0) NOT NULL has key_length()=0, producing a useless zero-length
# key that must be rejected.
#
SET optimizer_switch='derived_merge=off';
CREATE TABLE t1 (a CHAR(0) NOT NULL, b INT) ENGINE=MEMORY;
INSERT INTO t1 VALUES ('', 1), ('', 2), ('', 3);
CREATE TABLE t2 (c CHAR(0) NOT NULL, d INT) ENGINE=MEMORY;
INSERT INTO t2 VALUES ('', 10), ('', 20);
# Materialized derived table: the optimizer sees the equi-join dt.a = t2.c
# and tries to add a key on column a. check_tmp_key() must reject the
# zero-length key. Without the guard the server would create a key with
# key_length=0 which is invalid.
EXPLAIN SELECT * FROM t2, (SELECT * FROM t1) dt WHERE dt.a = t2.c;
--sorted_result
SELECT * FROM t2, (SELECT * FROM t1) dt WHERE dt.a = t2.c;
DROP TABLE t1, t2;
SET optimizer_switch=DEFAULT;

View File

@@ -1,6 +1,6 @@
DESC sys.schema_object_overview;
Field Type Null Key Default Extra
db varchar(64) NO
object_type varchar(64) YES NULL
count bigint(21) NO 0
db varchar(64) NO UNI
object_type varchar(64) YES UNI NULL
count bigint(21) NO UNI 0
SELECT * FROM sys.schema_object_overview;

View File

@@ -60,7 +60,7 @@ public:
Create_tmp_table(ORDER *group, bool distinct, bool save_sum_fields,
ulonglong select_options, ha_rows rows_limit);
virtual ~Create_tmp_table() {}
handlerton *pick_engine(THD *thd, uint reclength);
handlerton *pick_engine(THD *thd);
virtual bool choose_engine(THD *thd, TABLE *table, TMP_TABLE_PARAM *param);
void add_field(TABLE *table, Field *field, uint fieldnr,
bool force_not_null_cols);

View File

@@ -21837,21 +21837,37 @@ Field *Item_type_holder::create_tmp_field_ex(MEM_ROOT *root, TABLE *table,
Tmp_field_src *src,
const Tmp_field_param *param)
{
Type_handler const *type_handler= Item_type_holder::real_type_handler();
Type_handler_blob_common const *blob_handler;
if (param->part_of_unique_key() &&
(blob_handler=
dynamic_cast<const Type_handler_blob_common*>(type_handler)))
const Type_handler *type_handler= Item_type_holder::real_type_handler();
const Type_handler *tmp_handler=
type_handler->type_handler_for_tmp_table(this, param);
/*
Only enter the blob_key path when BOTH conditions hold:
1. type_handler_for_tmp_table() returned blob_key_type_handler()
(implies part_of_unique_key is true)
2. The original type IS a blob (dynamic_cast succeeds)
Condition 1 excludes xmltype (its override returns itself, never
blob_key). Condition 2 excludes VARCHAR types that were promoted
to blob_key via varstring_type_handler() -> too_big_for_varchar()
-> blob_type_handler(). Without condition 2, wide VARCHAR columns
would get promoted to blob in the main table (which has
part_of_unique_key=true for UNION DISTINCT) but stay as VARCHAR in
the incremental table of a recursive CTE (which has
part_of_unique_key=false), causing a reclength mismatch assertion.
*/
if (tmp_handler == Type_handler::blob_key_type_handler() &&
dynamic_cast<const Type_handler_blob_common*>(type_handler))
{
Field_blob *blob_field= (Field_blob*) type_handler_blob_key.
Field *field= tmp_handler->
make_and_init_table_field(root, &name, Record_addr(maybe_null()),
*this, table);
if (blob_field)
if (field)
{
/* Fix length of blob to be able to return the original blob type */
blob_field->set_pack_length(blob_handler->length_bytes());
((Field_blob*) field)->set_pack_length(
static_cast<const Type_handler_blob_common*>(
Type_handler::blob_type_handler(max_length, NULL))->length_bytes());
}
return blob_field;
return field;
}
return type_handler->
make_and_init_table_field(root, &name, Record_addr(maybe_null()),
@@ -21994,10 +22010,13 @@ Field *create_tmp_field(TABLE *table, Item *item,
*default_field= src.default_field();
if (src.item_result_field())
*((*copy_func)++)= src.item_result_field();
if (part_of_unique_key)
result->flags|= FIELD_PART_OF_TMP_UNIQUE | UNIQUE_KEY_FLAG;
if (group)
result->flags|= UNIQUE_KEY_FLAG;
if (result)
{
if (part_of_unique_key)
result->flags|= FIELD_PART_OF_TMP_UNIQUE | UNIQUE_KEY_FLAG;
if (group)
result->flags|= UNIQUE_KEY_FLAG;
}
return result;
}
@@ -22171,20 +22190,17 @@ TABLE *Create_tmp_table::start(THD *thd,
fn_format(path, path, mysql_tmpdir, "", MY_REPLACE_EXT|MY_UNPACK_FILENAME);
/*
Early engine prediction: reclength is not known yet (fields haven't been
added), so pass 0 -- this is safe because pick_engine()'s only reclength
check is "> HA_MAX_REC_LENGTH", which 0 never triggers. Returns
heap_hton unless session-level overrides (tmp_memory_table_size=0,
etc.) force a disk-based engine. We use this
to avoid the too_big_for_varchar() / group_length >= MAX_BLOB_WIDTH
bail-outs that would force m_using_unique_constraint for HEAP tables
that natively support blob keys.
Early engine prediction. Returns heap_hton unless session-level
overrides (tmp_memory_table_size=0, etc.) force a disk-based engine.
We use this to avoid the too_big_for_varchar() / group_length >=
MAX_BLOB_WIDTH bail-outs that would force m_using_unique_constraint
for HEAP tables that natively support blob keys.
Note: pick_engine() also reads m_using_unique_constraint, which is
false at this point. The guards below that set it to true are gated
by !m_heap_expected, so there is no circular dependency in practice.
*/
m_heap_expected= (pick_engine(thd, 0) == heap_hton);
m_heap_expected= (pick_engine(thd) == heap_hton);
if (m_group)
{
@@ -22570,14 +22586,13 @@ err:
/*
Predict which engine a temporary table will use, based on session
variables and the current m_using_unique_constraint / m_select_options
state. Called early (before fields are added) with reclength=0 to set
m_heap_expected, and again from choose_engine() with the real reclength.
state. Called early (before fields are added) to set m_heap_expected,
and again from choose_engine().
*/
handlerton *Create_tmp_table::pick_engine(THD *thd, uint reclength)
handlerton *Create_tmp_table::pick_engine(THD *thd)
{
if (m_using_unique_constraint ||
reclength > HA_MAX_REC_LENGTH ||
(m_select_options & TMP_TABLE_FORCE_MYISAM) ||
thd->variables.tmp_memory_table_size == 0)
return TMP_ENGINE_HTON;
@@ -22591,7 +22606,7 @@ bool Create_tmp_table::choose_engine(THD *thd, TABLE *table,
TABLE_SHARE *share= table->s;
DBUG_ENTER("Create_tmp_table::choose_engine");
handlerton *engine= pick_engine(thd, share->reclength);
handlerton *engine= pick_engine(thd);
share->db_plugin= ha_lock_engine(0, engine);
table->file= get_new_handler(share, &table->mem_root, share->db_type());

View File

@@ -2312,15 +2312,10 @@ loop_end:
tmp_param->field_count= temp_fields.elements;
tmp_param->func_count= temp_fields.elements - 1;
calc_group_buffer(tmp_param, group);
/* small table, ignore @@tmp_memory_table_size=0 */
ulonglong save_tmp_memory_table_size= thd->variables.tmp_memory_table_size;
if (!save_tmp_memory_table_size)
thd->variables.tmp_memory_table_size= SIZE_T_MAX;
tmp_tables[index]=create_tmp_table(thd, tmp_param, temp_fields,
(ORDER*) group, 0, 0,
TMP_TABLE_ALL_COLUMNS, HA_POS_ERROR,
&empty_clex_str);
thd->variables.tmp_memory_table_size= save_tmp_memory_table_size;
if (!tmp_tables[index])
DBUG_RETURN(1);
tmp_tables[index]->file->extra(HA_EXTRA_WRITE_CACHE);

View File

@@ -8870,6 +8870,12 @@ bool TABLE::check_tmp_key(uint key, uint key_parts,
key_len+= fld_store_len;
}
/*
Reject zero-length keys (e.g. all parts are CHAR(0) NOT NULL):
such a key cannot distinguish rows and would be useless for lookup.
*/
if (!key_len)
return FALSE;
// We use the on-disk storage engine's limit
return key_len <= tmp_table_max_key_length() &&
key_parts <= tmp_table_max_key_parts();