From 661141948fc26c76f14da6a6356681409ececce0 Mon Sep 17 00:00:00 2001 From: Monty Date: Sat, 27 May 2023 14:39:17 +0300 Subject: [PATCH] MDEV-31247 Assertion `c >= 0' failed in COST_MULT upon query with many joins Problem was an overflow when calculating number of join cache refills. --- mysql-test/main/optimizer_crash.result | 38 ++++++++++++++++++++ mysql-test/main/optimizer_crash.test | 48 ++++++++++++++++++++++++++ mysql-test/main/range_mrr_icp.result | 40 +++++++++++++++++++++ sql/sql_select.cc | 8 +++-- 4 files changed, 131 insertions(+), 3 deletions(-) create mode 100644 mysql-test/main/optimizer_crash.result create mode 100644 mysql-test/main/optimizer_crash.test diff --git a/mysql-test/main/optimizer_crash.result b/mysql-test/main/optimizer_crash.result new file mode 100644 index 00000000000..2a9e8dd51ed --- /dev/null +++ b/mysql-test/main/optimizer_crash.result @@ -0,0 +1,38 @@ +# +# MDEV-31247 Assertion `c >= 0' failed in COST_MULT upon query with +# many joins +# +CREATE TABLE t1 (a INT) ENGINE=MyISAM; +INSERT INTO t1 VALUES (1),(2); +CREATE TABLE t2 (b INT) ENGINE=MyISAM; +CREATE TABLE t3 (c INT) ENGINE=MyISAM; +INSERT INTO t3 VALUES (1),(2),(3); +CREATE TABLE t4 (d CHAR(200), e INT, KEY(e)) ENGINE=Aria; +INSERT INTO t4 (e) VALUES (1),(2),(3); +CREATE TABLE t5 (f INT) ENGINE=MyISAM; +INSERT INTO t5 VALUES (1),(2),(3),(4),(5),(6); +create table t1000 engine=memory select seq from seq_1_to_1000; +create table t2000 engine=memory select seq from seq_1_to_2000; +CREATE ALGORITHM=TEMPTABLE VIEW v AS select t1000.seq +from t1000 ml1 +join t1000 ml2 +join t1000; +set @@max_statement_time=10; +SELECT * FROM information_schema.TABLES +JOIN t1000 ts +JOIN t1000 d1 +JOIN t2000 d3 +LEFT JOIN (t1 JOIN t2) ON 1 +JOIN t1000 d5 +JOIN t1000 PROCESSLIST +JOIN t1000 d2 +JOIN t1000 event_name +JOIN t3 +JOIN t4 ON ts.seq = t4.e +JOIN v ON ts.seq+1 = v.seq +JOIN t5 limit rows examined 1000; +TABLE_CATALOG TABLE_SCHEMA TABLE_NAME TABLE_TYPE ENGINE VERSION ROW_FORMAT TABLE_ROWS AVG_ROW_LENGTH DATA_LENGTH MAX_DATA_LENGTH INDEX_LENGTH DATA_FREE AUTO_INCREMENT CREATE_TIME UPDATE_TIME CHECK_TIME TABLE_COLLATION CHECKSUM CREATE_OPTIONS TABLE_COMMENT MAX_INDEX_LENGTH TEMPORARY seq seq seq a b seq seq seq seq c d e seq f +Warnings: +Warning 1931 Query execution was interrupted. The query examined at least ### rows, which exceeds LIMIT ROWS EXAMINED (1000). The query result may be incomplete +DROP VIEW v; +DROP TABLE t1, t2, t3, t4, t5, t1000, t2000; diff --git a/mysql-test/main/optimizer_crash.test b/mysql-test/main/optimizer_crash.test new file mode 100644 index 00000000000..d7aee294353 --- /dev/null +++ b/mysql-test/main/optimizer_crash.test @@ -0,0 +1,48 @@ +--source include/have_innodb.inc +--source include/have_sequence.inc + +--echo # +--echo # MDEV-31247 Assertion `c >= 0' failed in COST_MULT upon query with +--echo # many joins +--echo # + +CREATE TABLE t1 (a INT) ENGINE=MyISAM; +INSERT INTO t1 VALUES (1),(2); + +CREATE TABLE t2 (b INT) ENGINE=MyISAM; + +CREATE TABLE t3 (c INT) ENGINE=MyISAM; +INSERT INTO t3 VALUES (1),(2),(3); + +CREATE TABLE t4 (d CHAR(200), e INT, KEY(e)) ENGINE=Aria; +INSERT INTO t4 (e) VALUES (1),(2),(3); + +CREATE TABLE t5 (f INT) ENGINE=MyISAM; +INSERT INTO t5 VALUES (1),(2),(3),(4),(5),(6); + +create table t1000 engine=memory select seq from seq_1_to_1000; +create table t2000 engine=memory select seq from seq_1_to_2000; + +CREATE ALGORITHM=TEMPTABLE VIEW v AS select t1000.seq + from t1000 ml1 + join t1000 ml2 + join t1000; + +set @@max_statement_time=10; +--replace_regex /least \d* rows/least ### rows/ +SELECT * FROM information_schema.TABLES + JOIN t1000 ts + JOIN t1000 d1 + JOIN t2000 d3 + LEFT JOIN (t1 JOIN t2) ON 1 + JOIN t1000 d5 + JOIN t1000 PROCESSLIST + JOIN t1000 d2 + JOIN t1000 event_name + JOIN t3 + JOIN t4 ON ts.seq = t4.e + JOIN v ON ts.seq+1 = v.seq + JOIN t5 limit rows examined 1000; +# Cleanup +DROP VIEW v; +DROP TABLE t1, t2, t3, t4, t5, t1000, t2000; diff --git a/mysql-test/main/range_mrr_icp.result b/mysql-test/main/range_mrr_icp.result index ba81a6c4cba..b9d74cb3c18 100644 --- a/mysql-test/main/range_mrr_icp.result +++ b/mysql-test/main/range_mrr_icp.result @@ -3783,4 +3783,44 @@ DROP TABLE t1; set global innodb_stats_persistent= @innodb_stats_persistent_save; set global innodb_stats_persistent_sample_pages= @innodb_stats_persistent_sample_pages_save; +# +# MDEV-31258 Assertion `cond_selectivity <= 1.000000001' upon range +# query +# +CREATE TABLE t1 (id int, a int, b char(3), PRIMARY KEY (id), KEY idx (a,b)) ENGINE=InnoDB; +INSERT INTO t1 VALUES +(1,8,'UT'),(2,0,'NU'),(3,1,'SD'),(4,0,'QU'),(5,0,'FL'),(6,0,'ZR'), +(7,3,'LA'),(8,5,'NU'),(9,0,'NU'),(10,0,'SD'),(11,0,'NU'),(12,1,'SD'), +(13,0,'BD'),(14,0,'PA'),(15,0,'VT'),(16,4,'WA'),(17,0,'ME'),(18,6,'OH'), +(19,0,'ME'),(20,4,'NU'),(21,0,'SC'),(22,0,'GA'),(23,1,'CO'),(24,0,'IL'), +(25,0,'GA'),(26,0,'HI'),(27,0,'BU'),(28,0,'NU'),(29,7,'LA'),(30,0,'NU'), +(31,0,'JR'),(32,6,'BR'),(33,0,'NU'),(34,6,'CO'),(35,7,'NU'),(36,2,'LA'), +(37,0,'PR'),(38,1,'UT'),(39,2,'BR'),(40,1,'HI'),(41,0,'SD'),(42,0,'RI'), +(43,2,'LA'),(44,0,'TN'),(45,4,'HI'),(46,0,'VT'),(47,1,'NU'),(48,0,'SC'), +(49,0,'TX'),(50,8,'DC'),(51,4,'NU'),(52,0,'AL'),(53,0,'CO'),(54,9,'PR'), +(55,0,'AR'),(56,0,'SD'),(57,0,'RI'),(58,0,'XE'),(59,0,'NU'),(60,4,'EL'), +(61,2,'LA'),(62,5,'UT'),(63,3,'NU'),(64,0,'RI'),(65,1,'NU'),(66,0,'BR'), +(67,3,'WA'),(68,0,'TN'),(69,3,'HI'),(70,0,'OH'),(71,8,'GA'),(72,6,'AL'), +(73,6,'NU'),(74,1,'HI'),(75,5,'JR'),(76,3,'RI'),(77,0,'DC'),(78,0,'SC'), +(79,0,'CO'),(80,2,'BO'),(81,8,'XE'),(82,1,'NU'),(83,0,'SD'),(84,0,'PA'), +(85,5,'PA'),(86,0,'QU'),(87,0,'PA'),(88,0,'NU'),(89,0,'ND'),(90,0,'UT'), +(91,0,'NU'),(92,0,'NU'),(93,6,'ZR'),(94,0,'NU'),(95,2,'EL'),(96,0,'NU'), +(97,0,'RI'),(98,5,'DC'),(99,7,'JR'),(100,5,'CO'),(101,0,'UT'),(102,0,'QU'), +(103,0,'NU'),(104,0,'GA'),(105,7,'AK'),(106,0,'ZR'),(107,0,'YT'),(108,0,'MD'), +(109,0,'NU'),(110,1,'EL'),(111,0,'ME'),(112,0,'VT'),(113,2,'NU'),(114,0,'CO'), +(115,5,'TN'),(116,0,'OH'),(117,0,'GA'),(118,9,'GA'),(119,0,'CO'),(120,0,'AL'), +(121,0,'NU'),(122,2,'NE'),(123,2,'TX'),(124,3,'CO'),(125,0,'TN'),(126,0,'WA'), +(127,0,'NE'),(128,6,'TN'),(129,0,'BR'),(130,0,'ID'),(131,0,'NU'),(132,2,'EL'), +(133,0,'PR'),(134,0,'NU'),(135,1,'AZ'),(136,7,'EL'),(137,0,'TN'),(138,0,'PA'), +(139,5,'QU'),(140,0,'AR'),(141,0,'DC'),(142,2,'WA'),(143,7,'OH'),(144,2,'CO'), +(145,6,'NU'),(146,9,'FL'),(147,0,'HI'),(148,0,'WA'),(149,1,'BR'),(150,3,'QU'); +SELECT id, MIN(id) FROM t1 +WHERE (b > 'TX' OR b BETWEEN 'NE' AND 'SC') AND id IN (1,7,8) AND a = 5 +GROUP BY id; +id MIN(id) +8 8 +DROP TABLE t1; +# +# End of 11.0 tests +# set optimizer_switch=@mrr_icp_extra_tmp; diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 32485bde46c..ec1ecfd8580 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -104,6 +104,8 @@ #define double_to_rows(A) ((A) >= ((double)HA_ROWS_MAX) ? HA_ROWS_MAX : (ha_rows) (A)) +#define double_to_ulonglong(A) ((A) >= ((double)ULONGLONG_MAX) ? ULONGLONG_MAX : (ulonglong) (A)) + inline double safe_filtered(double a, double b) { return b != 0 ? a/b*100.0 : 0.0; @@ -9168,7 +9170,7 @@ best_access_path(JOIN *join, best.use_join_buffer= TRUE; best.filter= 0; best.type= JT_HASH; - best.refills= (ulonglong) ceil(refills); + best.refills= double_to_ulonglong(ceil(refills)); if (unlikely(trace_access_hash.trace_started())) trace_access_hash. add("type", "hash"). @@ -9443,7 +9445,7 @@ best_access_path(JOIN *join, (record_count / (double) thd->variables.join_buff_size))); cur_cost= COST_MULT(cur_cost, tmp_refills); - refills= (ulonglong) tmp_refills; + refills= double_to_ulonglong(ceil(tmp_refills)); /* We come here only if there are already rows in the join cache */ DBUG_ASSERT(idx != join->const_tables); @@ -9523,7 +9525,7 @@ best_access_path(JOIN *join, /* range/index_merge/ALL/index access method are "independent", so: */ best.ref_depends_map= 0; best.use_join_buffer= use_join_buffer; - best.refills= (ulonglong) ceil(refills); + best.refills= refills; best.spl_plan= 0; best.type= type; trace_access_scan.add("chosen", true);