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:
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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.
|
||||
#
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 #-#-#
|
||||
|
||||
@@ -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#
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
20
mysql-test/suite/heap/char0_key.result
Normal file
20
mysql-test/suite/heap/char0_key.result
Normal 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;
|
||||
25
mysql-test/suite/heap/char0_key.test
Normal file
25
mysql-test/suite/heap/char0_key.test
Normal 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;
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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());
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user